bazilion 0.15.0 → 0.16.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 (94) hide show
  1. package/dist/cli.js +816 -681
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon.js +6605 -4313
  4. package/dist/daemon.js.map +1 -1
  5. package/dist/migrations/0001_init.sql +47 -0
  6. package/dist/web/client/assets/ChatPane-CQZzxOir.js +76 -0
  7. package/dist/web/client/assets/{ConfirmDialog-CGZzom9E.js → ConfirmDialog-MicTTwdy.js} +1 -1
  8. package/dist/web/client/assets/{FieldRow-DYNU9gWb.js → FieldRow-DJ2Gx4Du.js} +1 -1
  9. package/dist/web/client/assets/{ProductionTeamPolicyEditor-DT5Sl8jd.js → ProductionTeamPolicyEditor-DqUnN_ce.js} +1 -1
  10. package/dist/web/client/assets/{ProfileCommunicationEditor-TyCU5vXX.js → ProfileCommunicationEditor-DArXub0b.js} +1 -1
  11. package/dist/web/client/assets/{ResultSourceConversation-CGhKTSTD.js → ResultSourceConversation-CtzJ8QA-.js} +1 -1
  12. package/dist/web/client/assets/{TeamTabs-BZHyRnbd.js → TeamTabs-DbIk5vvT.js} +1 -1
  13. package/dist/web/client/assets/{TemplatesTabs-BHzkPMRC.js → TemplatesTabs-CatJIjGi.js} +1 -1
  14. package/dist/web/client/assets/{UnsavedChangesGuard-CFQcKsrf.js → UnsavedChangesGuard-BCsLw-mU.js} +1 -1
  15. package/dist/web/client/assets/_id-B5Ov7cdO.js +1 -0
  16. package/dist/web/client/assets/{_id-D_eKokkd.js → _id-BEDmIXVf.js} +1 -1
  17. package/dist/web/client/assets/{_id-9nCIhbVd.js → _id-BFM_tn_s.js} +1 -1
  18. package/dist/web/client/assets/{_id-CGd21j3k.js → _id-CrnEVcw8.js} +1 -1
  19. package/dist/web/client/assets/{_id-BSu3AqKA.js → _id-DxopIW-y.js} +1 -1
  20. package/dist/web/client/assets/{activity-Cn2-9PpZ.js → activity-CrG8Bg60.js} +1 -1
  21. package/dist/web/client/assets/{agents-NY3VrZgB.js → agents-CMPOFcs-.js} +1 -1
  22. package/dist/web/client/assets/{agents-CCmiZek6.js → agents-O4soKZND.js} +1 -1
  23. package/dist/web/client/assets/{approvals-CPDAPgrM.js → approvals-CwDu_lrA.js} +1 -1
  24. package/dist/web/client/assets/{attention-Qra_9_OI.js → attention-BY8MMuM_.js} +1 -1
  25. package/dist/web/client/assets/chevron-right-Cf6vKeLq.js +1 -0
  26. package/dist/web/client/assets/{config-D8EO0LPB.js → config-Cn4iBJFz.js} +1 -1
  27. package/dist/web/client/assets/{inbox-C5W-sm1q.js → inbox-CWXql0K3.js} +1 -1
  28. package/dist/web/client/assets/{index-BUhhk_u9.js → index-Bq2zrG2_.js} +2 -2
  29. package/dist/web/client/assets/{learning-Dr-7_7J4.js → learning-DAm4dyyc.js} +1 -1
  30. package/dist/web/client/assets/{login-Bu5UxbJh.js → login-BsABI8Ux.js} +1 -1
  31. package/dist/web/client/assets/{mcp-BueuwQiv.js → mcp-loLB0wuh.js} +1 -1
  32. package/dist/web/client/assets/{members-ZikuYNcy.js → members-BJ0ikkTl.js} +1 -1
  33. package/dist/web/client/assets/{memory-1JUJlPrn.js → memory-Drn9Gv53.js} +1 -1
  34. package/dist/web/client/assets/{policy-DbkhsFNA.js → policy-pQadZyk0.js} +1 -1
  35. package/dist/web/client/assets/{results-mMr8Ar2u.js → results-9exU6f7m.js} +1 -1
  36. package/dist/web/client/assets/{routes-DJYB-MS9.js → routes-jw1PuqiR.js} +1 -1
  37. package/dist/web/client/assets/{services-kfQA9cpJ.js → services-BLso1BhA.js} +1 -1
  38. package/dist/web/client/assets/{skills-C6pcgxaC.js → skills-BodqX3OI.js} +1 -1
  39. package/dist/web/client/assets/styles-d1yjBpud.css +2 -0
  40. package/dist/web/client/assets/{teams-LB0KBXY9.js → teams-ByQedXZi.js} +1 -1
  41. package/dist/web/client/assets/{teams-C6_Noz5X.js → teams-SYsF1bOR.js} +1 -1
  42. package/dist/web/client/assets/{telegram-A2jaI1QM.js → telegram-DC9PLFbB.js} +1 -1
  43. package/dist/web/client/assets/{tokens-BGlUpJcL.js → tokens-DGy8Ijpo.js} +1 -1
  44. package/dist/web/client/assets/{triggers-C54_feGg.js → triggers-BXpVmHDG.js} +1 -1
  45. package/dist/web/client/assets/{welcome-DyUIswRi.js → welcome-BKsnsCxJ.js} +1 -1
  46. package/dist/web/client/assets/{x-BY2MPLr9.js → x-BK4xNCzS.js} +1 -1
  47. package/dist/web/server/assets/{ChatPane-DJ30FdFG.js → ChatPane-CS5oI7ef.js} +235 -13
  48. package/dist/web/server/assets/{ResultSourceConversation-zYogeOWp.js → ResultSourceConversation-BpVWBRYq.js} +1 -1
  49. package/dist/web/server/assets/{_id-1LwoHhJg.js → _id-5pgKoid8.js} +1 -1
  50. package/dist/web/server/assets/{_id-BvSWsPI5.js → _id-BG2nkGxa.js} +1 -1
  51. package/dist/web/server/assets/{_id-1hTvnKLN2.js → _id-BnqodC1c2.js} +3 -3
  52. package/dist/web/server/assets/{_id-DDNVQx3y.js → _id-CeyHEsCZ.js} +1 -1
  53. package/dist/web/server/assets/{_id-T_8btpbB.js → _id-DOnInzLb.js} +1 -1
  54. package/dist/web/server/assets/{_id-DxFLSIio.js → _id-DrB9uR1b.js} +1 -1
  55. package/dist/web/server/assets/{_id-B2EEyStS.js → _id-DtIYuJJX.js} +1 -1
  56. package/dist/web/server/assets/_id-DwZXhLlL.js +779 -0
  57. package/dist/web/server/assets/{_tanstack-start-manifest_v-DP4ZUBw3.js → _tanstack-start-manifest_v-D7gKv6m6.js} +85 -85
  58. package/dist/web/server/assets/{activity-D73w4mkZ.js → activity-0VUkStOu.js} +1 -1
  59. package/dist/web/server/assets/{agents-DB5hCSAI.js → agents-C86K6HvS.js} +1 -1
  60. package/dist/web/server/assets/{agents-DRSo7lRX.js → agents-CSXLaM2W.js} +1 -1
  61. package/dist/web/server/assets/{approvals-4y9bZF4r.js → approvals-C3MysI6l.js} +1 -1
  62. package/dist/web/server/assets/{attention-BFx8ZkmH.js → attention-DLeLCKah.js} +1 -1
  63. package/dist/web/server/assets/{auth-_eaCwhyq.js → auth-CDZp9aEk.js} +1 -1
  64. package/dist/web/server/assets/{config-B7JIfv_7.js → config-BVTHvljR.js} +1 -1
  65. package/dist/web/server/assets/{daemon-client-B06W1Qa2.js → daemon-client-xWyYKAcx.js} +5 -0
  66. package/dist/web/server/assets/{inbox-YRpDQcvp.js → inbox-PQTrjtOw.js} +1 -1
  67. package/dist/web/server/assets/{learning-UBZb6h6M.js → learning-K0cmDsZR.js} +1 -1
  68. package/dist/web/server/assets/{mcp-Dv6RXMaS.js → mcp-Rtraochg.js} +1 -1
  69. package/dist/web/server/assets/{members-BFTKSlOe.js → members-grAKFWgv.js} +1 -1
  70. package/dist/web/server/assets/{memory-D0PQgZAn.js → memory-egFpBD1g.js} +1 -1
  71. package/dist/web/server/assets/{policy-C-p8HIhA.js → policy-ooSBgiDS.js} +1 -1
  72. package/dist/web/server/assets/{results-Cj-Dlw3C.js → results-CfNsFncJ.js} +2 -2
  73. package/dist/web/server/assets/{results-Cfev4KNt.js → results-DXdYtHaq.js} +1 -1
  74. package/dist/web/server/assets/{results-CwEQ5EUL.js → results-N-kP4iFT.js} +1 -1
  75. package/dist/web/server/assets/{router-d3sTMpMX.js → router-B6g_s7W3.js} +6 -6
  76. package/dist/web/server/assets/{routes-cW4MWU18.js → routes-BqSaZvlu.js} +1 -1
  77. package/dist/web/server/assets/{routes-MIZz6uMr.js → routes-Dsh8F_7i.js} +2 -2
  78. package/dist/web/server/assets/{routes-B765DVhj.js → routes-pcRy_Sf8.js} +1 -1
  79. package/dist/web/server/assets/{services-BCbdn3R9.js → services-DlZA8fRL.js} +1 -1
  80. package/dist/web/server/assets/{skills-Bpoa8MIp.js → skills-i2duvgW-.js} +1 -1
  81. package/dist/web/server/assets/{teams-CXzwqzcE.js → teams-6RYIj1Xm.js} +1 -1
  82. package/dist/web/server/assets/{teams-hWGjbpUA.js → teams-B1AI3NfN.js} +1 -1
  83. package/dist/web/server/assets/{telegram-DhpvtGUc.js → telegram-C4q0YTVn.js} +1 -1
  84. package/dist/web/server/assets/{tokens-Bjp19Vkn.js → tokens-RFquA2Bx.js} +1 -1
  85. package/dist/web/server/assets/{triggers-DJlcvXzn.js → triggers-DVD-iE-N.js} +1 -1
  86. package/dist/web/server/server.js +28 -28
  87. package/dist/worker.js +1553 -688
  88. package/dist/worker.js.map +1 -1
  89. package/package.json +3 -3
  90. package/dist/web/client/assets/ChatPane-55j13bBj.js +0 -74
  91. package/dist/web/client/assets/_id-SRMFlIgP.js +0 -1
  92. package/dist/web/client/assets/chevron-right-DXE4CWf2.js +0 -1
  93. package/dist/web/client/assets/styles-CcNf8jT_.css +0 -2
  94. package/dist/web/server/assets/_id-CDBtO_jL.js +0 -381
@@ -1 +1 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-CGZzom9E.js";import{T as a}from"./index-BUhhk_u9.js";import{a as o,i as s,n as c,r as l,t as u}from"./Page-NV96O47A.js";import{t as d}from"./Button-ByiV6fpd.js";var f=e(n()),p=t();function m(){let{teams:e,memberCounts:t,policies:n,readiness:m}=a.useLoaderData(),g=r(),[_,v]=(0,f.useState)(null),[y,b]=(0,f.useState)(null);async function x(e){let t=n[e]?.revision;if(!t)throw Error(`The Team policy revision is unavailable. Nothing was removed.`);let r=await fetch(`/api/teams/${encodeURIComponent(e)}?expectedTeamPolicyRevision=${t}`,{method:`DELETE`});if(!r.ok&&r.status!==204){let e=await r.json().catch(()=>null);throw Error(e?.error??`Could not remove Team (${r.status})`)}await g.invalidate()}return(0,p.jsxs)(l,{size:`wide`,children:[(0,p.jsx)(c,{eyebrow:`Workspace`,title:`Teams`,description:`Each Team owns one workspace, one live membership roster, and one effective communication policy. Every agent belongs to exactly one Team.`}),(0,p.jsx)(s,{title:`Policy enforcement`,description:`Management contract v${m.contractVersion} is ready for this daemon.`,actions:(0,p.jsx)(o,{variant:m.enforcementActive?`success`:`warning`,children:m.enforcementActive?`Enforcement on`:`Enforcement off`}),"aria-label":`Team Policy enforcement readiness`,children:(0,p.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:m.enforcementActive?`Communication boundaries are currently enforcing each Team policy.`:(0,p.jsxs)(p.Fragment,{children:[`Set `,(0,p.jsx)(`code`,{children:`BAZILION_TEAM_POLICY_ENFORCEMENT=on`}),` and restart the daemon to enforce Team policies.`]})})}),(0,p.jsx)(h,{onRegistered:()=>g.invalidate()}),y&&(0,p.jsx)(`p`,{role:`alert`,className:`err`,children:y}),(0,p.jsx)(s,{title:`Registered teams`,description:`Open a Team to manage its context, members, shared memory, and policy.`,children:e.length===0?(0,p.jsx)(u,{title:`No teams registered`,description:`Register a Team above to create a workspace for your agents.`}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,p.jsxs)(`table`,{className:`min-w-[820px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{children:[(0,p.jsx)(`th`,{children:`ID`}),(0,p.jsx)(`th`,{children:`Name`}),(0,p.jsx)(`th`,{children:`Members`}),(0,p.jsx)(`th`,{children:`Policy`}),(0,p.jsx)(`th`,{children:`Baseline`}),(0,p.jsx)(`th`,{children:(0,p.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,p.jsx)(`tbody`,{children:e.map(e=>{let r=t[e.id]??0,i=n[e.id];return(0,p.jsxs)(`tr`,{children:[(0,p.jsx)(`td`,{children:(0,p.jsx)(`code`,{children:e.id})}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`a`,{href:`/teams/${e.id}`,children:e.name})}),(0,p.jsx)(`td`,{children:r}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`a`,{href:`/teams/${e.id}/policy`,children:i?`r${i.revision} · ${i.edges} edges`:`Unavailable`})}),(0,p.jsx)(`td`,{children:i?.baseline??`None`}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`div`,{className:`flex justify-end`,children:r===0?(0,p.jsx)(d,{variant:`danger`,onClick:()=>v(e),children:`Remove`}):(0,p.jsx)(o,{variant:`neutral`,title:`${r} agent(s) belong to this Team`,children:`In use`})})})]},e.id)})})]})}),(0,p.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:e.map(e=>{let r=t[e.id]??0,i=n[e.id];return(0,p.jsxs)(`article`,{className:`min-w-0 rounded-xl border border-border bg-muted/20 p-4`,children:[(0,p.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,p.jsxs)(`div`,{className:`min-w-0`,children:[(0,p.jsx)(`a`,{href:`/teams/${encodeURIComponent(e.id)}`,className:`block truncate font-semibold text-foreground`,children:e.name}),(0,p.jsx)(`p`,{className:`mt-0.5 truncate font-mono text-xs text-muted-foreground`,children:e.id})]}),(0,p.jsxs)(o,{variant:r>0?`success`:`neutral`,children:[r,` member`,r===1?``:`s`]})]}),(0,p.jsxs)(`dl`,{className:`mt-3 grid gap-2 text-xs sm:grid-cols-2`,children:[(0,p.jsxs)(`div`,{className:`rounded-lg bg-muted p-2`,children:[(0,p.jsx)(`dt`,{className:`font-semibold text-muted-foreground`,children:`Policy`}),(0,p.jsx)(`dd`,{className:`mt-0.5`,children:(0,p.jsx)(`a`,{href:`/teams/${encodeURIComponent(e.id)}/policy`,children:i?`Revision ${i.revision} · ${i.edges} edges`:`Unavailable`})})]}),(0,p.jsxs)(`div`,{className:`rounded-lg bg-muted p-2`,children:[(0,p.jsx)(`dt`,{className:`font-semibold text-muted-foreground`,children:`Baseline`}),(0,p.jsx)(`dd`,{className:`mt-0.5 break-words`,children:i?.baseline??`None`})]})]}),r===0&&(0,p.jsx)(`div`,{className:`mt-3`,children:(0,p.jsx)(d,{variant:`danger`,onClick:()=>v(e),children:`Remove Team`})})]},e.id)})})]})}),(0,p.jsx)(i,{open:_!==null,onOpenChange:e=>{e||v(null)},title:`Remove ${_?.name??`Team`}?`,description:(0,p.jsx)(`p`,{children:`This removes the empty Team registration and its Bazilion-managed workspace slot. If the slot is a symlink, its external target is not deleted. This action cannot be undone from the web UI.`}),confirmLabel:`Remove Team`,onConfirm:async()=>{if(_)try{await x(_.id)}catch(e){throw b(e instanceof Error?e.message:String(e)),e}}})]})}function h({onRegistered:e}){let[t,n]=(0,f.useState)(``),[r,i]=(0,f.useState)(``),[a,o]=(0,f.useState)(``),[c,l]=(0,f.useState)(null),[u,m]=(0,f.useState)(!1);async function h(s){if(s.preventDefault(),l(null),!t.trim()){l(`id is required`);return}m(!0);try{let s=await fetch(`/api/teams`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.trim(),name:r.trim()||void 0,link:a.trim()||void 0})});if(!s.ok){let e=await s.json().catch(()=>null);throw Error(e?.error??s.statusText)}n(``),i(``),o(``),e()}catch(e){l(e.message)}finally{m(!1)}}return(0,p.jsx)(s,{title:`Register a team`,description:(0,p.jsxs)(p.Fragment,{children:[`Teams live under `,(0,p.jsx)(`code`,{children:`~/.bazilion/teams/<slug>/`}),`. Link an existing project directory or leave the target blank to create a fresh workspace.`]}),children:(0,p.jsxs)(`form`,{onSubmit:h,children:[c&&(0,p.jsx)(`div`,{role:`alert`,className:`err`,children:c}),(0,p.jsxs)(`div`,{className:`grid gap-4 sm:grid-cols-2`,children:[(0,p.jsxs)(`label`,{children:[`ID (slug)`,(0,p.jsx)(`input`,{value:t,onChange:e=>n(e.target.value),required:!0,placeholder:`my-project`})]}),(0,p.jsxs)(`label`,{children:[`Name`,(0,p.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`My project`})]}),(0,p.jsxs)(`label`,{className:`sm:col-span-2`,children:[`Link target (optional, absolute path)`,(0,p.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),placeholder:`/home/user/projects/my-project`})]})]}),(0,p.jsx)(`div`,{className:`mt-4`,children:(0,p.jsx)(d,{variant:`primary`,type:`submit`,disabled:u,children:u?`Registering…`:`Register team`})})]})})}export{m as component};
1
+ import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-MicTTwdy.js";import{T as a}from"./index-Bq2zrG2_.js";import{a as o,i as s,n as c,r as l,t as u}from"./Page-NV96O47A.js";import{t as d}from"./Button-ByiV6fpd.js";var f=e(n()),p=t();function m(){let{teams:e,memberCounts:t,policies:n,readiness:m}=a.useLoaderData(),g=r(),[_,v]=(0,f.useState)(null),[y,b]=(0,f.useState)(null);async function x(e){let t=n[e]?.revision;if(!t)throw Error(`The Team policy revision is unavailable. Nothing was removed.`);let r=await fetch(`/api/teams/${encodeURIComponent(e)}?expectedTeamPolicyRevision=${t}`,{method:`DELETE`});if(!r.ok&&r.status!==204){let e=await r.json().catch(()=>null);throw Error(e?.error??`Could not remove Team (${r.status})`)}await g.invalidate()}return(0,p.jsxs)(l,{size:`wide`,children:[(0,p.jsx)(c,{eyebrow:`Workspace`,title:`Teams`,description:`Each Team owns one workspace, one live membership roster, and one effective communication policy. Every agent belongs to exactly one Team.`}),(0,p.jsx)(s,{title:`Policy enforcement`,description:`Management contract v${m.contractVersion} is ready for this daemon.`,actions:(0,p.jsx)(o,{variant:m.enforcementActive?`success`:`warning`,children:m.enforcementActive?`Enforcement on`:`Enforcement off`}),"aria-label":`Team Policy enforcement readiness`,children:(0,p.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:m.enforcementActive?`Communication boundaries are currently enforcing each Team policy.`:(0,p.jsxs)(p.Fragment,{children:[`Set `,(0,p.jsx)(`code`,{children:`BAZILION_TEAM_POLICY_ENFORCEMENT=on`}),` and restart the daemon to enforce Team policies.`]})})}),(0,p.jsx)(h,{onRegistered:()=>g.invalidate()}),y&&(0,p.jsx)(`p`,{role:`alert`,className:`err`,children:y}),(0,p.jsx)(s,{title:`Registered teams`,description:`Open a Team to manage its context, members, shared memory, and policy.`,children:e.length===0?(0,p.jsx)(u,{title:`No teams registered`,description:`Register a Team above to create a workspace for your agents.`}):(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,p.jsxs)(`table`,{className:`min-w-[820px]`,children:[(0,p.jsx)(`thead`,{children:(0,p.jsxs)(`tr`,{children:[(0,p.jsx)(`th`,{children:`ID`}),(0,p.jsx)(`th`,{children:`Name`}),(0,p.jsx)(`th`,{children:`Members`}),(0,p.jsx)(`th`,{children:`Policy`}),(0,p.jsx)(`th`,{children:`Baseline`}),(0,p.jsx)(`th`,{children:(0,p.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,p.jsx)(`tbody`,{children:e.map(e=>{let r=t[e.id]??0,i=n[e.id];return(0,p.jsxs)(`tr`,{children:[(0,p.jsx)(`td`,{children:(0,p.jsx)(`code`,{children:e.id})}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`a`,{href:`/teams/${e.id}`,children:e.name})}),(0,p.jsx)(`td`,{children:r}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`a`,{href:`/teams/${e.id}/policy`,children:i?`r${i.revision} · ${i.edges} edges`:`Unavailable`})}),(0,p.jsx)(`td`,{children:i?.baseline??`None`}),(0,p.jsx)(`td`,{children:(0,p.jsx)(`div`,{className:`flex justify-end`,children:r===0?(0,p.jsx)(d,{variant:`danger`,onClick:()=>v(e),children:`Remove`}):(0,p.jsx)(o,{variant:`neutral`,title:`${r} agent(s) belong to this Team`,children:`In use`})})})]},e.id)})})]})}),(0,p.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:e.map(e=>{let r=t[e.id]??0,i=n[e.id];return(0,p.jsxs)(`article`,{className:`min-w-0 rounded-xl border border-border bg-muted/20 p-4`,children:[(0,p.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,p.jsxs)(`div`,{className:`min-w-0`,children:[(0,p.jsx)(`a`,{href:`/teams/${encodeURIComponent(e.id)}`,className:`block truncate font-semibold text-foreground`,children:e.name}),(0,p.jsx)(`p`,{className:`mt-0.5 truncate font-mono text-xs text-muted-foreground`,children:e.id})]}),(0,p.jsxs)(o,{variant:r>0?`success`:`neutral`,children:[r,` member`,r===1?``:`s`]})]}),(0,p.jsxs)(`dl`,{className:`mt-3 grid gap-2 text-xs sm:grid-cols-2`,children:[(0,p.jsxs)(`div`,{className:`rounded-lg bg-muted p-2`,children:[(0,p.jsx)(`dt`,{className:`font-semibold text-muted-foreground`,children:`Policy`}),(0,p.jsx)(`dd`,{className:`mt-0.5`,children:(0,p.jsx)(`a`,{href:`/teams/${encodeURIComponent(e.id)}/policy`,children:i?`Revision ${i.revision} · ${i.edges} edges`:`Unavailable`})})]}),(0,p.jsxs)(`div`,{className:`rounded-lg bg-muted p-2`,children:[(0,p.jsx)(`dt`,{className:`font-semibold text-muted-foreground`,children:`Baseline`}),(0,p.jsx)(`dd`,{className:`mt-0.5 break-words`,children:i?.baseline??`None`})]})]}),r===0&&(0,p.jsx)(`div`,{className:`mt-3`,children:(0,p.jsx)(d,{variant:`danger`,onClick:()=>v(e),children:`Remove Team`})})]},e.id)})})]})}),(0,p.jsx)(i,{open:_!==null,onOpenChange:e=>{e||v(null)},title:`Remove ${_?.name??`Team`}?`,description:(0,p.jsx)(`p`,{children:`This removes the empty Team registration and its Bazilion-managed workspace slot. If the slot is a symlink, its external target is not deleted. This action cannot be undone from the web UI.`}),confirmLabel:`Remove Team`,onConfirm:async()=>{if(_)try{await x(_.id)}catch(e){throw b(e instanceof Error?e.message:String(e)),e}}})]})}function h({onRegistered:e}){let[t,n]=(0,f.useState)(``),[r,i]=(0,f.useState)(``),[a,o]=(0,f.useState)(``),[c,l]=(0,f.useState)(null),[u,m]=(0,f.useState)(!1);async function h(s){if(s.preventDefault(),l(null),!t.trim()){l(`id is required`);return}m(!0);try{let s=await fetch(`/api/teams`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.trim(),name:r.trim()||void 0,link:a.trim()||void 0})});if(!s.ok){let e=await s.json().catch(()=>null);throw Error(e?.error??s.statusText)}n(``),i(``),o(``),e()}catch(e){l(e.message)}finally{m(!1)}}return(0,p.jsx)(s,{title:`Register a team`,description:(0,p.jsxs)(p.Fragment,{children:[`Teams live under `,(0,p.jsx)(`code`,{children:`~/.bazilion/teams/<slug>/`}),`. Link an existing project directory or leave the target blank to create a fresh workspace.`]}),children:(0,p.jsxs)(`form`,{onSubmit:h,children:[c&&(0,p.jsx)(`div`,{role:`alert`,className:`err`,children:c}),(0,p.jsxs)(`div`,{className:`grid gap-4 sm:grid-cols-2`,children:[(0,p.jsxs)(`label`,{children:[`ID (slug)`,(0,p.jsx)(`input`,{value:t,onChange:e=>n(e.target.value),required:!0,placeholder:`my-project`})]}),(0,p.jsxs)(`label`,{children:[`Name`,(0,p.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`My project`})]}),(0,p.jsxs)(`label`,{className:`sm:col-span-2`,children:[`Link target (optional, absolute path)`,(0,p.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),placeholder:`/home/user/projects/my-project`})]})]}),(0,p.jsx)(`div`,{className:`mt-4`,children:(0,p.jsx)(d,{variant:`primary`,type:`submit`,disabled:u,children:u?`Registering…`:`Register team`})})]})})}export{m as component};
@@ -1 +1 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-CGZzom9E.js";import{o as a}from"./index-BUhhk_u9.js";import{t as o}from"./Button-ByiV6fpd.js";import{t as s}from"./ConfigPage-BCLp-FUC.js";var c=e(n(),1),l=t(),u={communication_approval:`Communication approvals`,lesson_proposal:`Lesson proposals`,review_failure:`Review failures`,trigger_failure:`Scheduled trigger failures`,agent_loop_break:`Agent message loop breaks`};async function d(e,t=`GET`,n){let r=await fetch(`/api/notifications${e}`,{method:t,cache:`no-store`,...n===void 0?{}:{headers:{"Content-Type":`application/json`},body:JSON.stringify(n)}}),i=await r.json();if(!r.ok)throw Error(i.error??`Notification request failed`);return i}function f(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(!1),[a,s]=(0,c.useState)(``),[f,p]=(0,c.useState)([]),[m,h]=(0,c.useState)(`UTC`),[g,_]=(0,c.useState)(!1),[v,y]=(0,c.useState)(`22:00`),[b,x]=(0,c.useState)(`07:00`),[S,C]=(0,c.useState)({receipts:[],nextCursor:null}),[w,T]=(0,c.useState)(!1),[E,D]=(0,c.useState)(null),[O,k]=(0,c.useState)(null),[A,j]=(0,c.useState)(null),[M,N]=(0,c.useState)(null);async function P(){let[e,n]=await Promise.all([d(``),d(`/receipts`)]);t(e),C(n),r(e.settings.enabled),s(e.settings.destination?.id??``),p(e.settings.kinds),h(e.settings.timezone),_(e.settings.quietHours!==null),y(e.settings.quietHours?.start??`22:00`),x(e.settings.quietHours?.end??`07:00`)}(0,c.useEffect)(()=>{P().catch(e=>D(String(e.message)))},[]);async function F(e){T(!0),D(null),k(null);try{await e()}catch(e){D(e instanceof Error?e.message:`Notification request failed`)}finally{T(!1)}}async function I(t){e&&(await d(``,`PUT`,{expectedRevision:e.settings.revision,enabled:n,destinationId:a||void 0,kinds:f,timezone:m,quietHours:g?{start:v,end:b}:null,includeOpenPreview:t}),await P(),j(null),k(`Notification settings saved. Delivery does not resolve Attention items.`))}return(0,l.jsxs)(`section`,{className:`card`,style:{marginTop:`1.5rem`,padding:`1.25rem`,minWidth:0},"aria-labelledby":`notification-title`,children:[(0,l.jsx)(`h2`,{id:`notification-title`,children:`Attention notifications`}),(0,l.jsx)(`p`,{className:`muted`,children:`Optional Telegram notices for items that need your attention. New enablement sends future items only. Agent-topic error mirrors may also report the same failure.`}),E&&(0,l.jsxs)(`p`,{role:`alert`,children:[E,`. Refresh settings before retrying a conflicting change.`]}),O&&(0,l.jsx)(`p`,{role:`status`,children:O}),e?(0,l.jsxs)(l.Fragment,{children:[e.settings.restorePaused&&(0,l.jsx)(`p`,{role:`status`,children:`Paused after restore. Telegram may have newer messages than this backup. Re-enable for future items, or explicitly preview old open items with possible duplicates.`}),!e.readiness.ready&&(0,l.jsx)(`p`,{children:`Destination unavailable. Configure and pair the private Telegram forum, start the bot, then refresh.`}),e.diagnostic&&(0,l.jsxs)(`p`,{role:`status`,children:[`Delivery status: `,e.diagnostic]}),(0,l.jsx)(`form`,{onSubmit:e=>{e.preventDefault(),F(()=>I())},children:(0,l.jsxs)(`fieldset`,{disabled:w,style:{border:0,padding:0,minWidth:0},children:[(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.75rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:n,onChange:e=>r(e.target.checked)}),` `,`Enable Attention notifications`]}),(0,l.jsxs)(`label`,{style:{display:`grid`,gap:`.35rem`,marginBlock:`.75rem`},children:[`Destination`,(0,l.jsxs)(`select`,{value:a,onChange:e=>s(e.target.value),required:n,style:{maxWidth:`100%`},children:[(0,l.jsx)(`option`,{value:``,children:`Choose the paired service topic`}),e.readiness.destination&&(0,l.jsx)(`option`,{value:e.readiness.destination.id,children:`Paired group · Bazilion service topic`}),e.settings.destination&&e.settings.destination.id!==e.readiness.destination?.id&&(0,l.jsx)(`option`,{value:e.settings.destination.id,children:`Previous destination (unavailable)`})]})]}),(0,l.jsx)(`p`,{className:`m-0 text-sm text-mocha`,children:`Notices go to the operational thread in your paired Telegram group.`}),e.readiness.destination&&(0,l.jsxs)(`details`,{className:`mt-2 text-xs text-mocha`,children:[(0,l.jsx)(`summary`,{className:`cursor-pointer`,children:`Telegram destination IDs`}),(0,l.jsxs)(`p`,{className:`mt-2 break-all`,children:[`Group `,e.readiness.destination.chatId,` · Topic `,e.readiness.destination.topicId]})]}),(0,l.jsxs)(`fieldset`,{style:{marginBlock:`1rem`,minWidth:0},children:[(0,l.jsx)(`legend`,{children:`Include these Attention kinds`}),Object.keys(u).map(e=>(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.5rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:f.includes(e),onChange:t=>p(t.target.checked?[...f,e]:f.filter(t=>t!==e))}),` `,u[e]]},e))]}),(0,l.jsxs)(`label`,{style:{display:`grid`,gap:`.35rem`},children:[`Timezone (IANA)`,(0,l.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:`Europe/Warsaw`,required:!0,style:{maxWidth:`100%`,minWidth:0}})]}),(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.75rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:g,onChange:e=>_(e.target.checked)}),` `,`Use quiet hours for all selected kinds`]}),g&&(0,l.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`1rem`},children:[(0,l.jsxs)(`label`,{children:[`Start`,` `,(0,l.jsx)(`input`,{type:`time`,value:v,required:!0,onChange:e=>y(e.target.value)})]}),(0,l.jsxs)(`label`,{children:[`End`,` `,(0,l.jsx)(`input`,{type:`time`,value:b,required:!0,onChange:e=>x(e.target.value)})]})]}),(0,l.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`.5rem`,marginTop:`1rem`},children:[(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:!f.length||n&&(!e.readiness.ready||!a),children:`Save settings`}),(0,l.jsx)(o,{variant:`ghost`,disabled:!n||!e.readiness.ready||!a||!f.length,onClick:()=>void F(async()=>j(await d(`/preview`,`POST`,{kinds:f}))),children:`Preview open items`})]})]})}),(0,l.jsxs)(`section`,{"aria-label":`Delivery receipts`,className:`mt-6 flex min-w-0 flex-col gap-4 border-t border-frost pt-5`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,l.jsx)(`h3`,{className:`m-0`,children:`Delivery receipts`}),(0,l.jsx)(o,{variant:`ghost`,disabled:w,onClick:()=>void F(async()=>C(await d(`/receipts`))),children:`Refresh receipts`})]}),(0,l.jsx)(`p`,{className:`m-0 text-sm text-mocha`,children:`Delivery confirms Telegram received the notice. It does not approve or resolve the Attention item.`}),S.receipts.length===0&&(0,l.jsx)(`p`,{className:`m-0`,children:`No notification receipts yet.`}),(0,l.jsx)(`ul`,{className:`m-0 grid list-none gap-3 p-0`,children:S.receipts.map(t=>(0,l.jsxs)(`li`,{className:`flex min-w-0 flex-col gap-3 rounded-lg border border-frost bg-ivory p-4 [overflow-wrap:anywhere]`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,l.jsx)(`strong`,{children:u[t.sourceKind]}),(0,l.jsx)(`span`,{className:`rounded-full bg-frost px-2 py-1 text-xs font-semibold capitalize`,children:t.state})]}),(0,l.jsxs)(`p`,{className:`m-0 text-xs text-mocha`,children:[new Date(t.updatedAt).toLocaleString(),` · `,t.attempts,` `,t.attempts===1?`attempt`:`attempts`]}),t.state===`uncertain`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Telegram may have received this notice. Retrying could send a duplicate.`}),t.state===`deferred`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Waiting for an eligible delivery opportunity.`}),t.state===`failed`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Delivery failed. Check the details before retrying.`}),(0,l.jsxs)(`details`,{className:`text-xs text-mocha`,children:[(0,l.jsx)(`summary`,{className:`cursor-pointer`,children:`Technical details`}),(0,l.jsxs)(`dl`,{className:`mt-3 grid min-w-0 gap-2`,children:[(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Source`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.sourceId})]}),(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Receipt`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.id})]}),t.telegramMessageId&&(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Telegram message`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.telegramMessageId})]}),t.diagnostic&&(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Diagnostic`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.diagnostic})]})]})]}),[`failed`,`uncertain`].includes(t.state)&&(0,l.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:(0,l.jsx)(o,{variant:`ghost`,disabled:w||!e.settings.enabled||e.settings.restorePaused,onClick:()=>N(t),children:`Retry notice`})})]},t.id))})]}),S.nextCursor&&(0,l.jsx)(o,{variant:`ghost`,disabled:w,onClick:()=>void F(async()=>{let e=await d(`/receipts?cursor=${encodeURIComponent(S.nextCursor)}`);C({receipts:[...S.receipts,...e.receipts],nextCursor:e.nextCursor})}),children:`More receipts`})]}):(0,l.jsx)(`p`,{children:`Loading notification settings…`}),(0,l.jsx)(o,{variant:`ghost`,className:`mt-4`,disabled:w,onClick:()=>void F(P),children:`Refresh settings and destination`}),(0,l.jsx)(i,{open:A!==null,title:`Include currently open items?`,confirmLabel:`Save and include preview`,confirmVariant:`primary`,description:(0,l.jsxs)(`p`,{children:[A?.count??0,` currently eligible items will be considered. Resolved items are omitted.`,` `,A?.possibleDuplicates?`This restored backup may be missing later Telegram receipts, so duplicate messages are possible.`:`Confirmed deliveries will not be repeated.`]}),onOpenChange:e=>{e||j(null)},onConfirm:()=>I(A?.id)}),(0,l.jsx)(i,{open:M!==null,title:`Retry this notification?`,confirmLabel:`Retry, allowing a possible duplicate`,confirmVariant:`primary`,description:`Telegram may already have received this notice. Retry only if you accept a possible duplicate. The source, destination and policy will be checked again.`,onOpenChange:e=>{e||N(null)},onConfirm:async()=>{M&&(await d(`/receipts/${encodeURIComponent(M.id)}/retry`,`POST`,{expectedUpdatedAt:M.updatedAt,acknowledgePossibleDuplicate:!0}),C(await d(`/receipts`)),N(null))}})]})}function p(){let e=a.useLoaderData(),t=r(),[n,u]=(0,c.useState)(``),[d,p]=(0,c.useState)(e.chatId),[y,b]=(0,c.useState)(!1),[x,S]=(0,c.useState)(null),[C,w]=(0,c.useState)(!1),[T,E]=(0,c.useState)(!1),[D,O]=(0,c.useState)(null),[k,A]=(0,c.useState)(!1);async function j(r){if(r.preventDefault(),e.configured&&n.trim().length===0){w(!1),S(d.trim()===e.chatId?`Nothing changed. Paste a replacement token to update credentials.`:`Paste the bot token again when changing the supergroup, so the existing secret is never cleared or reused silently.`);return}b(!0),S(null),w(!1);try{let e=await fetch(`/api/config/telegram`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({botToken:n,chatId:d})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`${e.status} ${e.statusText}`)}u(``),w(!0),await t.invalidate()}catch(e){S(e.message)}finally{b(!1)}}async function M(){let e=await fetch(`/api/config/telegram`,{method:`DELETE`});if(!e.ok&&e.status!==204){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not clear Telegram credentials (${e.status})`)}u(``),p(``),O(null),w(!1),S(null),await t.invalidate()}async function N(){A(!0),O(null);try{O(await(await fetch(`/api/config/telegram/health`)).json())}catch(e){O({configured:!0,preflight:null,error:{step:`getMe`,message:e.message},polling:null})}finally{A(!1)}}return(0,l.jsxs)(s,{active:`integrations`,title:`Telegram`,description:`Connect one forum-supergroup bot with one topic per agent, so conversations stay reachable from your phone.`,size:`narrow`,children:[e.migratedChatId&&(0,l.jsx)(g,{toChatId:e.migratedChatId}),(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-3`,children:`Credentials`}),e.configured&&(0,l.jsxs)(`p`,{className:`text-xs text-success mb-3`,children:[`✓ Stored: `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.botTokenPreview}),` `,e.chatId&&(0,l.jsxs)(l.Fragment,{children:[`· chat `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.chatId})]})]}),(0,l.jsxs)(`form`,{onSubmit:j,className:`space-y-3`,children:[(0,l.jsxs)(`label`,{className:`block`,children:[(0,l.jsx)(`span`,{className:`block text-sm font-medium mb-1`,children:`Bot token`}),(0,l.jsx)(`input`,{type:`password`,autoComplete:`off`,value:n,onChange:e=>{u(e.target.value),S(null)},placeholder:e.configured?`(leave blank to keep stored value)`:`1234567890:ABC...`,className:`w-full rounded-md border bg-background px-2 py-1.5 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`,required:!e.configured}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[`From @BotFather → /newbot. Disable Privacy Mode in `,(0,l.jsx)(`em`,{children:`Bot Settings → Team Privacy → Turn off`}),`.`]}),e.configured&&(0,l.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`Blank preserves the stored token. To remove it, use clear credentials and confirm the integration shutdown.`})]}),(0,l.jsxs)(`label`,{className:`block`,children:[(0,l.jsx)(`span`,{className:`block text-sm font-medium mb-1`,children:`Supergroup chat ID`}),(0,l.jsx)(`input`,{type:`text`,value:d,onChange:e=>{p(e.target.value),S(null)},placeholder:`-1001234567890`,className:`w-full rounded-md border bg-background px-2 py-1.5 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`,required:!0}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[`Forum-enabled supergroup the bot is admin in (with`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`can_manage_topics`}),`).`]})]}),(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 pt-1`,children:[(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:y,children:y?`saving…`:`save credentials`}),e.configured&&(0,l.jsx)(o,{variant:`danger`,onClick:()=>E(!0),children:`clear credentials`}),C&&(0,l.jsx)(`span`,{className:`text-xs text-success`,children:`saved ✓`}),x&&(0,l.jsxs)(`span`,{role:`alert`,className:`text-xs text-danger`,children:[`error: `,x]})]})]})]}),(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsxs)(`div`,{className:`mb-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground`,children:`Preflight checks`}),(0,l.jsx)(o,{variant:`ghost`,onClick:N,disabled:k||!e.configured,children:k?`checking…`:`run preflight`})]}),!e.configured&&(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground italic`,children:`Save credentials above first.`}),e.configured&&!D&&!k&&(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground italic`,children:[`Click `,(0,l.jsx)(`em`,{children:`run preflight`}),` to validate the stored credentials against the Telegram Bot API.`]}),D&&(0,l.jsx)(v,{health:D}),D?.polling&&(0,l.jsx)(_,{polling:D.polling})]}),e.configured&&(0,l.jsx)(m,{}),(0,l.jsx)(f,{}),e.configured&&(0,l.jsx)(h,{}),(0,l.jsx)(i,{open:T,title:`Disconnect Telegram?`,description:(0,l.jsx)(`p`,{children:`This permanently removes the saved bot token and supergroup ID. Telegram polling, ingress, and outbound delivery stop until new credentials are saved and pairing is completed again.`}),confirmLabel:`clear credentials and disconnect`,onConfirm:async()=>{try{await M()}catch(e){throw S(e instanceof Error?e.message:String(e)),e}},onOpenChange:E})]})}function m(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(null),[a,s]=(0,c.useState)(null),[u,d]=(0,c.useState)(!1),f=async()=>{let e=await fetch(`/api/config/telegram/pairing`);if(!e.ok)throw Error(e.statusText);t(await e.json())};(0,c.useEffect)(()=>{f().catch(e=>s(e.message))},[]);async function p(){s(null);let e=await fetch(`/api/config/telegram/pairing/challenge`,{method:`POST`}),n=await e.json().catch(()=>({}));if(!e.ok||!n.code)return s(n.error??e.statusText);r(n.code),t(n)}async function m(){let e=await fetch(`/api/config/telegram/pairing/challenge`,{method:`DELETE`});if(!e.ok&&e.status!==204){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not cancel the pairing code`)}r(null),await f()}async function h(){let e=await fetch(`/api/config/telegram/pairing/reset`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({confirm:!0})});if(!e.ok){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not reset Telegram owner`)}r(null),await f()}return(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-1`,children:`Owner pairing`}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mb-3`,children:[`Telegram stays closed until one owner consumes a short-lived code in the configured`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`⚙ bazilion`}),` service topic.`]}),e?.paired?(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,l.jsx)(`span`,{className:`text-sm text-success`,children:`✓ owner paired`}),(0,l.jsx)(o,{variant:`danger`,onClick:()=>d(!0),children:`reset owner`})]}):(0,l.jsxs)(`div`,{className:`space-y-2`,children:[(0,l.jsx)(`p`,{className:`text-sm text-warning`,children:`Unpaired — all Telegram ingress is closed.`}),n?(0,l.jsxs)(`div`,{className:`rounded-md border bg-muted/30 p-3 text-sm`,children:[`Send `,(0,l.jsxs)(`code`,{className:`font-mono`,children:[`/pair `,n]}),` in the service topic. This code is shown once and expires in ten minutes.`]}):null,(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,l.jsx)(o,{variant:`primary`,onClick:p,children:`generate pairing code`}),e?.challengeActive&&(0,l.jsx)(o,{variant:`ghost`,onClick:()=>void m().catch(e=>s(e instanceof Error?e.message:String(e))),children:`cancel code`})]})]}),a&&(0,l.jsx)(`p`,{role:`alert`,className:`mt-2 text-xs text-danger`,children:a}),(0,l.jsx)(i,{open:u,title:`Revoke the paired Telegram owner?`,description:(0,l.jsx)(`p`,{children:`This immediately revokes the current owner and closes all Telegram ingress. No one can use the bot until a new one-time pairing code is generated and consumed.`}),confirmLabel:`revoke owner and close ingress`,onConfirm:async()=>{try{await h()}catch(e){throw s(e instanceof Error?e.message:String(e)),e}},onOpenChange:d})]})}function h(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(``),[a,s]=(0,c.useState)(``),[u,d]=(0,c.useState)(!1),[f,p]=(0,c.useState)(null),[m,h]=(0,c.useState)(null);async function g(){try{let e=await fetch(`/api/config/telegram/acl`);if(!e.ok)throw Error(e.statusText);t(await e.json())}catch(e){p(e.message)}}(0,c.useEffect)(()=>{g()},[]);async function _(e){e.preventDefault();let t=Number(n);if(!Number.isInteger(t)){p(`user id must be an integer`);return}d(!0),p(null);try{let e=await fetch(`/api/config/telegram/acl`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({userId:t,label:a.trim()||null})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??e.statusText)}r(``),s(``),await g()}catch(e){p(e.message)}finally{d(!1)}}async function v(e){p(null);let t=await fetch(`/api/config/telegram/acl/${e}`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??t.statusText)}await g()}return(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-1`,children:`Access control`}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mb-3`,children:[`Allowlisted Telegram users can use the bot (commands + chat). An empty list is closed; ownership begins only through the one-time pairing flow. Users find their id via`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`/whoami`}),`.`]}),e===null?(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground italic`,children:`loading…`}):e.length===0?(0,l.jsx)(`p`,{className:`text-xs text-warning mb-3`,children:`Closed — no paired owner or allowlisted members.`}):(0,l.jsx)(`ul`,{className:`mb-3 space-y-1 text-sm`,children:e.map(e=>(0,l.jsxs)(`li`,{className:`flex flex-wrap items-center gap-2`,children:[(0,l.jsx)(`code`,{className:`font-mono`,children:e.userId}),(0,l.jsxs)(`span`,{className:`text-muted-foreground`,children:[e.label??(e.username?`@${e.username}`:`—`),` · `,e.role]}),e.role!==`owner`&&(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>h(e),children:`remove`})]},e.userId))}),(0,l.jsxs)(`form`,{onSubmit:_,className:`flex flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-end`,children:[(0,l.jsxs)(`label`,{className:`m-0 flex flex-col gap-1 text-xs font-medium text-foreground`,children:[`Telegram user ID`,(0,l.jsx)(`input`,{value:n,onChange:e=>r(e.target.value),placeholder:`123456789`,inputMode:`numeric`,className:`w-full rounded-md border bg-background px-2 py-1 font-mono text-sm sm:w-32`})]}),(0,l.jsxs)(`label`,{className:`m-0 flex flex-col gap-1 text-xs font-medium text-foreground`,children:[`Label `,(0,l.jsx)(`span`,{className:`font-normal text-muted-foreground`,children:`(optional)`}),(0,l.jsx)(`input`,{value:a,onChange:e=>s(e.target.value),placeholder:`e.g. Pat`,className:`w-full rounded-md border bg-background px-2 py-1 text-sm sm:w-40`})]}),(0,l.jsx)(o,{variant:`ghost`,type:`submit`,disabled:u,children:`add`}),f&&(0,l.jsx)(`span`,{role:`alert`,className:`text-xs text-danger`,children:f})]}),(0,l.jsx)(i,{open:m!==null,title:`Remove ${m?.label??m?.username??m?.userId??``}?`,description:(0,l.jsxs)(`p`,{children:[`Telegram user `,(0,l.jsx)(`code`,{className:`font-mono`,children:m?.userId}),` immediately loses command and chat access. Their Telegram account is not changed, and they can be allowlisted again later.`]}),confirmLabel:`remove Telegram access`,onConfirm:async()=>{if(m)try{await v(m.userId)}catch(e){throw p(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||h(null)}})]})}function g({toChatId:e}){let[t,n]=(0,c.useState)(!1),[r,i]=(0,c.useState)(null);async function a(){n(!0),i(null);try{let e=await fetch(`/api/config/telegram/reconnect`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??e.statusText)}window.location.reload()}catch(e){i(e.message),n(!1)}}return(0,l.jsxs)(`div`,{className:`rounded-md border-2 border-danger/25 bg-danger/10 px-4 py-3 text-sm`,children:[(0,l.jsx)(`div`,{className:`font-semibold text-danger mb-1`,children:`Supergroup chat id changed`}),(0,l.jsxs)(`p`,{className:`text-danger mb-2`,children:[`Telegram migrated this supergroup to a new chat id (`,(0,l.jsx)(`code`,{className:`font-mono`,children:e}),`). The bot is still pointed at the old id. Reconnect to repoint it and re-create the `,(0,l.jsx)(`code`,{className:`font-mono`,children:`⚙ bazilion`}),` `,`service chat in the new team. Agent topic bindings will reconcile on next use.`]}),(0,l.jsx)(o,{variant:`primary`,onClick:a,disabled:t,children:t?`reconnecting…`:`Reconnect to ${e}`}),r&&(0,l.jsx)(`span`,{role:`alert`,className:`ml-3 text-xs text-danger`,children:r})]})}function _({polling:e}){let t=e.startedAt?new Date(e.startedAt).toISOString():null,n=e.lastSuccessfulPollAt?new Date(e.lastSuccessfulPollAt).toISOString():null;return(0,l.jsxs)(`div`,{className:`mt-4 rounded-md border bg-muted/30 px-3 py-2 text-xs space-y-1`,children:[(0,l.jsx)(`p`,{className:`font-semibold uppercase tracking-wide text-muted-foreground`,children:`Polling state`}),(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1 font-mono`,children:[(0,l.jsx)(`span`,{className:e.running?`text-success`:`text-danger`,children:e.running?`running`:`stopped`}),(0,l.jsx)(`span`,{className:e.activated?`text-success`:`text-warning`,children:e.activated?`activated`:`awaiting activation`}),e.lastUpdateId!==null&&(0,l.jsxs)(`span`,{children:[`last update `,e.lastUpdateId]}),t&&(0,l.jsxs)(`span`,{children:[`started `,t]}),n&&(0,l.jsxs)(`span`,{children:[`last poll `,n]})]}),e.error&&(0,l.jsxs)(`p`,{role:`alert`,className:`text-danger`,children:[`error: `,e.error]})]})}function v({health:e}){if(e.error)return(0,l.jsxs)(`div`,{role:`alert`,className:`rounded-md border border-danger/25 bg-danger/10 px-3 py-2 text-sm`,children:[(0,l.jsxs)(`p`,{className:`font-semibold text-danger`,children:[`Failed at `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.error.step})]}),(0,l.jsx)(`p`,{className:`text-danger mt-1`,children:e.error.message}),b(e.error.step)]});if(!e.preflight)return(0,l.jsx)(`p`,{role:`status`,className:`text-xs text-muted-foreground italic`,children:`No preflight data.`});let t=e.preflight;return(0,l.jsxs)(`ul`,{role:`status`,"aria-live":`polite`,"aria-atomic":`true`,className:`space-y-1.5`,children:[(0,l.jsxs)(y,{ok:t.botUsername.length>0,label:`Bot identity`,children:[`@`,t.botUsername]}),(0,l.jsx)(y,{ok:t.chatTitle.length>0,label:`Supergroup reachable`,children:t.chatTitle}),(0,l.jsx)(y,{ok:t.isForum,label:`Forum topics enabled`,children:t.isForum?`is_forum: true`:`is_forum: false — the supergroup owner must enable Topics in team settings`}),(0,l.jsx)(y,{ok:t.hasManageTopics,label:`Bot has can_manage_topics`,children:t.hasManageTopics?`admin with can_manage_topics`:`promote the bot to admin in the supergroup with the "Manage topics" permission`}),(0,l.jsx)(y,{ok:t.privacyModeOff,label:`Privacy Mode is OFF`,children:t.privacyModeOff?`can_read_all_group_messages: true`:`BotFather → /mybots → select bot → Bot Settings → Team Privacy → Turn off`}),(0,l.jsx)(y,{ok:t.chatIsPrivate,label:`Supergroup is private`,children:t.chatIsPrivate?`no public @username`:`public groups expose topic content to readers`}),(0,l.jsx)(y,{ok:t.memberCount===2,label:`Expected membership`,children:t.memberCount===null?`member count unavailable — verify one owner plus the bot manually`:`${t.memberCount} members reported; secure posture is one owner plus the bot`}),t.ownerPresent!==null&&(0,l.jsx)(y,{ok:t.ownerPresent,label:`Paired owner is present`,children:t.ownerPresent?`owner membership confirmed`:`owner missing — Telegram ingress is degraded`})]})}function y({ok:e,label:t,children:n}){return(0,l.jsxs)(`li`,{className:`flex items-start gap-2 text-sm`,children:[(0,l.jsx)(`span`,{className:`mt-0.5 inline-flex h-4 w-4 items-center justify-center rounded-full text-[10px] font-bold leading-none ${e?`bg-success/10 text-success`:`bg-danger/10 text-danger`}`,"aria-hidden":!0,children:e?`✓`:`✕`}),(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`span`,{className:`font-medium`,children:t}),(0,l.jsx)(`span`,{className:`ml-2 text-xs ${e?`text-muted-foreground`:`text-danger`}`,children:n})]})]})}function b(e){switch(e){case`getMe`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The token is invalid or revoked. Re-issue with @BotFather → /token, or paste a fresh one above.`});case`getChat`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The chat id either doesn't exist, points at a basic team (not a supergroup), or the bot isn't a member. Forward any message from the supergroup to the bot to double-check the id, then add the bot to the team.`});case`getChatMember`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The bot is in the chat but the membership lookup failed. Usually means the bot was kicked or the chat id was migrated — confirm the bot is still in the supergroup.`})}}export{p as component};
1
+ import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-MicTTwdy.js";import{o as a}from"./index-Bq2zrG2_.js";import{t as o}from"./Button-ByiV6fpd.js";import{t as s}from"./ConfigPage-BCLp-FUC.js";var c=e(n(),1),l=t(),u={communication_approval:`Communication approvals`,lesson_proposal:`Lesson proposals`,review_failure:`Review failures`,trigger_failure:`Scheduled trigger failures`,agent_loop_break:`Agent message loop breaks`};async function d(e,t=`GET`,n){let r=await fetch(`/api/notifications${e}`,{method:t,cache:`no-store`,...n===void 0?{}:{headers:{"Content-Type":`application/json`},body:JSON.stringify(n)}}),i=await r.json();if(!r.ok)throw Error(i.error??`Notification request failed`);return i}function f(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(!1),[a,s]=(0,c.useState)(``),[f,p]=(0,c.useState)([]),[m,h]=(0,c.useState)(`UTC`),[g,_]=(0,c.useState)(!1),[v,y]=(0,c.useState)(`22:00`),[b,x]=(0,c.useState)(`07:00`),[S,C]=(0,c.useState)({receipts:[],nextCursor:null}),[w,T]=(0,c.useState)(!1),[E,D]=(0,c.useState)(null),[O,k]=(0,c.useState)(null),[A,j]=(0,c.useState)(null),[M,N]=(0,c.useState)(null);async function P(){let[e,n]=await Promise.all([d(``),d(`/receipts`)]);t(e),C(n),r(e.settings.enabled),s(e.settings.destination?.id??``),p(e.settings.kinds),h(e.settings.timezone),_(e.settings.quietHours!==null),y(e.settings.quietHours?.start??`22:00`),x(e.settings.quietHours?.end??`07:00`)}(0,c.useEffect)(()=>{P().catch(e=>D(String(e.message)))},[]);async function F(e){T(!0),D(null),k(null);try{await e()}catch(e){D(e instanceof Error?e.message:`Notification request failed`)}finally{T(!1)}}async function I(t){e&&(await d(``,`PUT`,{expectedRevision:e.settings.revision,enabled:n,destinationId:a||void 0,kinds:f,timezone:m,quietHours:g?{start:v,end:b}:null,includeOpenPreview:t}),await P(),j(null),k(`Notification settings saved. Delivery does not resolve Attention items.`))}return(0,l.jsxs)(`section`,{className:`card`,style:{marginTop:`1.5rem`,padding:`1.25rem`,minWidth:0},"aria-labelledby":`notification-title`,children:[(0,l.jsx)(`h2`,{id:`notification-title`,children:`Attention notifications`}),(0,l.jsx)(`p`,{className:`muted`,children:`Optional Telegram notices for items that need your attention. New enablement sends future items only. Agent-topic error mirrors may also report the same failure.`}),E&&(0,l.jsxs)(`p`,{role:`alert`,children:[E,`. Refresh settings before retrying a conflicting change.`]}),O&&(0,l.jsx)(`p`,{role:`status`,children:O}),e?(0,l.jsxs)(l.Fragment,{children:[e.settings.restorePaused&&(0,l.jsx)(`p`,{role:`status`,children:`Paused after restore. Telegram may have newer messages than this backup. Re-enable for future items, or explicitly preview old open items with possible duplicates.`}),!e.readiness.ready&&(0,l.jsx)(`p`,{children:`Destination unavailable. Configure and pair the private Telegram forum, start the bot, then refresh.`}),e.diagnostic&&(0,l.jsxs)(`p`,{role:`status`,children:[`Delivery status: `,e.diagnostic]}),(0,l.jsx)(`form`,{onSubmit:e=>{e.preventDefault(),F(()=>I())},children:(0,l.jsxs)(`fieldset`,{disabled:w,style:{border:0,padding:0,minWidth:0},children:[(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.75rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:n,onChange:e=>r(e.target.checked)}),` `,`Enable Attention notifications`]}),(0,l.jsxs)(`label`,{style:{display:`grid`,gap:`.35rem`,marginBlock:`.75rem`},children:[`Destination`,(0,l.jsxs)(`select`,{value:a,onChange:e=>s(e.target.value),required:n,style:{maxWidth:`100%`},children:[(0,l.jsx)(`option`,{value:``,children:`Choose the paired service topic`}),e.readiness.destination&&(0,l.jsx)(`option`,{value:e.readiness.destination.id,children:`Paired group · Bazilion service topic`}),e.settings.destination&&e.settings.destination.id!==e.readiness.destination?.id&&(0,l.jsx)(`option`,{value:e.settings.destination.id,children:`Previous destination (unavailable)`})]})]}),(0,l.jsx)(`p`,{className:`m-0 text-sm text-mocha`,children:`Notices go to the operational thread in your paired Telegram group.`}),e.readiness.destination&&(0,l.jsxs)(`details`,{className:`mt-2 text-xs text-mocha`,children:[(0,l.jsx)(`summary`,{className:`cursor-pointer`,children:`Telegram destination IDs`}),(0,l.jsxs)(`p`,{className:`mt-2 break-all`,children:[`Group `,e.readiness.destination.chatId,` · Topic `,e.readiness.destination.topicId]})]}),(0,l.jsxs)(`fieldset`,{style:{marginBlock:`1rem`,minWidth:0},children:[(0,l.jsx)(`legend`,{children:`Include these Attention kinds`}),Object.keys(u).map(e=>(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.5rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:f.includes(e),onChange:t=>p(t.target.checked?[...f,e]:f.filter(t=>t!==e))}),` `,u[e]]},e))]}),(0,l.jsxs)(`label`,{style:{display:`grid`,gap:`.35rem`},children:[`Timezone (IANA)`,(0,l.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:`Europe/Warsaw`,required:!0,style:{maxWidth:`100%`,minWidth:0}})]}),(0,l.jsxs)(`label`,{style:{display:`block`,marginBlock:`.75rem`},children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:g,onChange:e=>_(e.target.checked)}),` `,`Use quiet hours for all selected kinds`]}),g&&(0,l.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`1rem`},children:[(0,l.jsxs)(`label`,{children:[`Start`,` `,(0,l.jsx)(`input`,{type:`time`,value:v,required:!0,onChange:e=>y(e.target.value)})]}),(0,l.jsxs)(`label`,{children:[`End`,` `,(0,l.jsx)(`input`,{type:`time`,value:b,required:!0,onChange:e=>x(e.target.value)})]})]}),(0,l.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`.5rem`,marginTop:`1rem`},children:[(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:!f.length||n&&(!e.readiness.ready||!a),children:`Save settings`}),(0,l.jsx)(o,{variant:`ghost`,disabled:!n||!e.readiness.ready||!a||!f.length,onClick:()=>void F(async()=>j(await d(`/preview`,`POST`,{kinds:f}))),children:`Preview open items`})]})]})}),(0,l.jsxs)(`section`,{"aria-label":`Delivery receipts`,className:`mt-6 flex min-w-0 flex-col gap-4 border-t border-frost pt-5`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,l.jsx)(`h3`,{className:`m-0`,children:`Delivery receipts`}),(0,l.jsx)(o,{variant:`ghost`,disabled:w,onClick:()=>void F(async()=>C(await d(`/receipts`))),children:`Refresh receipts`})]}),(0,l.jsx)(`p`,{className:`m-0 text-sm text-mocha`,children:`Delivery confirms Telegram received the notice. It does not approve or resolve the Attention item.`}),S.receipts.length===0&&(0,l.jsx)(`p`,{className:`m-0`,children:`No notification receipts yet.`}),(0,l.jsx)(`ul`,{className:`m-0 grid list-none gap-3 p-0`,children:S.receipts.map(t=>(0,l.jsxs)(`li`,{className:`flex min-w-0 flex-col gap-3 rounded-lg border border-frost bg-ivory p-4 [overflow-wrap:anywhere]`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,l.jsx)(`strong`,{children:u[t.sourceKind]}),(0,l.jsx)(`span`,{className:`rounded-full bg-frost px-2 py-1 text-xs font-semibold capitalize`,children:t.state})]}),(0,l.jsxs)(`p`,{className:`m-0 text-xs text-mocha`,children:[new Date(t.updatedAt).toLocaleString(),` · `,t.attempts,` `,t.attempts===1?`attempt`:`attempts`]}),t.state===`uncertain`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Telegram may have received this notice. Retrying could send a duplicate.`}),t.state===`deferred`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Waiting for an eligible delivery opportunity.`}),t.state===`failed`&&(0,l.jsx)(`p`,{className:`m-0 text-sm`,children:`Delivery failed. Check the details before retrying.`}),(0,l.jsxs)(`details`,{className:`text-xs text-mocha`,children:[(0,l.jsx)(`summary`,{className:`cursor-pointer`,children:`Technical details`}),(0,l.jsxs)(`dl`,{className:`mt-3 grid min-w-0 gap-2`,children:[(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Source`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.sourceId})]}),(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Receipt`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.id})]}),t.telegramMessageId&&(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Telegram message`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.telegramMessageId})]}),t.diagnostic&&(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`dt`,{className:`font-semibold`,children:`Diagnostic`}),(0,l.jsx)(`dd`,{className:`m-0`,children:t.diagnostic})]})]})]}),[`failed`,`uncertain`].includes(t.state)&&(0,l.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:(0,l.jsx)(o,{variant:`ghost`,disabled:w||!e.settings.enabled||e.settings.restorePaused,onClick:()=>N(t),children:`Retry notice`})})]},t.id))})]}),S.nextCursor&&(0,l.jsx)(o,{variant:`ghost`,disabled:w,onClick:()=>void F(async()=>{let e=await d(`/receipts?cursor=${encodeURIComponent(S.nextCursor)}`);C({receipts:[...S.receipts,...e.receipts],nextCursor:e.nextCursor})}),children:`More receipts`})]}):(0,l.jsx)(`p`,{children:`Loading notification settings…`}),(0,l.jsx)(o,{variant:`ghost`,className:`mt-4`,disabled:w,onClick:()=>void F(P),children:`Refresh settings and destination`}),(0,l.jsx)(i,{open:A!==null,title:`Include currently open items?`,confirmLabel:`Save and include preview`,confirmVariant:`primary`,description:(0,l.jsxs)(`p`,{children:[A?.count??0,` currently eligible items will be considered. Resolved items are omitted.`,` `,A?.possibleDuplicates?`This restored backup may be missing later Telegram receipts, so duplicate messages are possible.`:`Confirmed deliveries will not be repeated.`]}),onOpenChange:e=>{e||j(null)},onConfirm:()=>I(A?.id)}),(0,l.jsx)(i,{open:M!==null,title:`Retry this notification?`,confirmLabel:`Retry, allowing a possible duplicate`,confirmVariant:`primary`,description:`Telegram may already have received this notice. Retry only if you accept a possible duplicate. The source, destination and policy will be checked again.`,onOpenChange:e=>{e||N(null)},onConfirm:async()=>{M&&(await d(`/receipts/${encodeURIComponent(M.id)}/retry`,`POST`,{expectedUpdatedAt:M.updatedAt,acknowledgePossibleDuplicate:!0}),C(await d(`/receipts`)),N(null))}})]})}function p(){let e=a.useLoaderData(),t=r(),[n,u]=(0,c.useState)(``),[d,p]=(0,c.useState)(e.chatId),[y,b]=(0,c.useState)(!1),[x,S]=(0,c.useState)(null),[C,w]=(0,c.useState)(!1),[T,E]=(0,c.useState)(!1),[D,O]=(0,c.useState)(null),[k,A]=(0,c.useState)(!1);async function j(r){if(r.preventDefault(),e.configured&&n.trim().length===0){w(!1),S(d.trim()===e.chatId?`Nothing changed. Paste a replacement token to update credentials.`:`Paste the bot token again when changing the supergroup, so the existing secret is never cleared or reused silently.`);return}b(!0),S(null),w(!1);try{let e=await fetch(`/api/config/telegram`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({botToken:n,chatId:d})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`${e.status} ${e.statusText}`)}u(``),w(!0),await t.invalidate()}catch(e){S(e.message)}finally{b(!1)}}async function M(){let e=await fetch(`/api/config/telegram`,{method:`DELETE`});if(!e.ok&&e.status!==204){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not clear Telegram credentials (${e.status})`)}u(``),p(``),O(null),w(!1),S(null),await t.invalidate()}async function N(){A(!0),O(null);try{O(await(await fetch(`/api/config/telegram/health`)).json())}catch(e){O({configured:!0,preflight:null,error:{step:`getMe`,message:e.message},polling:null})}finally{A(!1)}}return(0,l.jsxs)(s,{active:`integrations`,title:`Telegram`,description:`Connect one forum-supergroup bot with one topic per agent, so conversations stay reachable from your phone.`,size:`narrow`,children:[e.migratedChatId&&(0,l.jsx)(g,{toChatId:e.migratedChatId}),(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-3`,children:`Credentials`}),e.configured&&(0,l.jsxs)(`p`,{className:`text-xs text-success mb-3`,children:[`✓ Stored: `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.botTokenPreview}),` `,e.chatId&&(0,l.jsxs)(l.Fragment,{children:[`· chat `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.chatId})]})]}),(0,l.jsxs)(`form`,{onSubmit:j,className:`space-y-3`,children:[(0,l.jsxs)(`label`,{className:`block`,children:[(0,l.jsx)(`span`,{className:`block text-sm font-medium mb-1`,children:`Bot token`}),(0,l.jsx)(`input`,{type:`password`,autoComplete:`off`,value:n,onChange:e=>{u(e.target.value),S(null)},placeholder:e.configured?`(leave blank to keep stored value)`:`1234567890:ABC...`,className:`w-full rounded-md border bg-background px-2 py-1.5 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`,required:!e.configured}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[`From @BotFather → /newbot. Disable Privacy Mode in `,(0,l.jsx)(`em`,{children:`Bot Settings → Team Privacy → Turn off`}),`.`]}),e.configured&&(0,l.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground`,children:`Blank preserves the stored token. To remove it, use clear credentials and confirm the integration shutdown.`})]}),(0,l.jsxs)(`label`,{className:`block`,children:[(0,l.jsx)(`span`,{className:`block text-sm font-medium mb-1`,children:`Supergroup chat ID`}),(0,l.jsx)(`input`,{type:`text`,value:d,onChange:e=>{p(e.target.value),S(null)},placeholder:`-1001234567890`,className:`w-full rounded-md border bg-background px-2 py-1.5 font-mono text-sm outline-none focus:ring-2 focus:ring-ring/30`,required:!0}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[`Forum-enabled supergroup the bot is admin in (with`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`can_manage_topics`}),`).`]})]}),(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 pt-1`,children:[(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:y,children:y?`saving…`:`save credentials`}),e.configured&&(0,l.jsx)(o,{variant:`danger`,onClick:()=>E(!0),children:`clear credentials`}),C&&(0,l.jsx)(`span`,{className:`text-xs text-success`,children:`saved ✓`}),x&&(0,l.jsxs)(`span`,{role:`alert`,className:`text-xs text-danger`,children:[`error: `,x]})]})]})]}),(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsxs)(`div`,{className:`mb-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground`,children:`Preflight checks`}),(0,l.jsx)(o,{variant:`ghost`,onClick:N,disabled:k||!e.configured,children:k?`checking…`:`run preflight`})]}),!e.configured&&(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground italic`,children:`Save credentials above first.`}),e.configured&&!D&&!k&&(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground italic`,children:[`Click `,(0,l.jsx)(`em`,{children:`run preflight`}),` to validate the stored credentials against the Telegram Bot API.`]}),D&&(0,l.jsx)(v,{health:D}),D?.polling&&(0,l.jsx)(_,{polling:D.polling})]}),e.configured&&(0,l.jsx)(m,{}),(0,l.jsx)(f,{}),e.configured&&(0,l.jsx)(h,{}),(0,l.jsx)(i,{open:T,title:`Disconnect Telegram?`,description:(0,l.jsx)(`p`,{children:`This permanently removes the saved bot token and supergroup ID. Telegram polling, ingress, and outbound delivery stop until new credentials are saved and pairing is completed again.`}),confirmLabel:`clear credentials and disconnect`,onConfirm:async()=>{try{await M()}catch(e){throw S(e instanceof Error?e.message:String(e)),e}},onOpenChange:E})]})}function m(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(null),[a,s]=(0,c.useState)(null),[u,d]=(0,c.useState)(!1),f=async()=>{let e=await fetch(`/api/config/telegram/pairing`);if(!e.ok)throw Error(e.statusText);t(await e.json())};(0,c.useEffect)(()=>{f().catch(e=>s(e.message))},[]);async function p(){s(null);let e=await fetch(`/api/config/telegram/pairing/challenge`,{method:`POST`}),n=await e.json().catch(()=>({}));if(!e.ok||!n.code)return s(n.error??e.statusText);r(n.code),t(n)}async function m(){let e=await fetch(`/api/config/telegram/pairing/challenge`,{method:`DELETE`});if(!e.ok&&e.status!==204){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not cancel the pairing code`)}r(null),await f()}async function h(){let e=await fetch(`/api/config/telegram/pairing/reset`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({confirm:!0})});if(!e.ok){let t=await e.json().catch(()=>null);throw Error(t?.error??`Could not reset Telegram owner`)}r(null),await f()}return(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-1`,children:`Owner pairing`}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mb-3`,children:[`Telegram stays closed until one owner consumes a short-lived code in the configured`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`⚙ bazilion`}),` service topic.`]}),e?.paired?(0,l.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,l.jsx)(`span`,{className:`text-sm text-success`,children:`✓ owner paired`}),(0,l.jsx)(o,{variant:`danger`,onClick:()=>d(!0),children:`reset owner`})]}):(0,l.jsxs)(`div`,{className:`space-y-2`,children:[(0,l.jsx)(`p`,{className:`text-sm text-warning`,children:`Unpaired — all Telegram ingress is closed.`}),n?(0,l.jsxs)(`div`,{className:`rounded-md border bg-muted/30 p-3 text-sm`,children:[`Send `,(0,l.jsxs)(`code`,{className:`font-mono`,children:[`/pair `,n]}),` in the service topic. This code is shown once and expires in ten minutes.`]}):null,(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,l.jsx)(o,{variant:`primary`,onClick:p,children:`generate pairing code`}),e?.challengeActive&&(0,l.jsx)(o,{variant:`ghost`,onClick:()=>void m().catch(e=>s(e instanceof Error?e.message:String(e))),children:`cancel code`})]})]}),a&&(0,l.jsx)(`p`,{role:`alert`,className:`mt-2 text-xs text-danger`,children:a}),(0,l.jsx)(i,{open:u,title:`Revoke the paired Telegram owner?`,description:(0,l.jsx)(`p`,{children:`This immediately revokes the current owner and closes all Telegram ingress. No one can use the bot until a new one-time pairing code is generated and consumed.`}),confirmLabel:`revoke owner and close ingress`,onConfirm:async()=>{try{await h()}catch(e){throw s(e instanceof Error?e.message:String(e)),e}},onOpenChange:d})]})}function h(){let[e,t]=(0,c.useState)(null),[n,r]=(0,c.useState)(``),[a,s]=(0,c.useState)(``),[u,d]=(0,c.useState)(!1),[f,p]=(0,c.useState)(null),[m,h]=(0,c.useState)(null);async function g(){try{let e=await fetch(`/api/config/telegram/acl`);if(!e.ok)throw Error(e.statusText);t(await e.json())}catch(e){p(e.message)}}(0,c.useEffect)(()=>{g()},[]);async function _(e){e.preventDefault();let t=Number(n);if(!Number.isInteger(t)){p(`user id must be an integer`);return}d(!0),p(null);try{let e=await fetch(`/api/config/telegram/acl`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({userId:t,label:a.trim()||null})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??e.statusText)}r(``),s(``),await g()}catch(e){p(e.message)}finally{d(!1)}}async function v(e){p(null);let t=await fetch(`/api/config/telegram/acl/${e}`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??t.statusText)}await g()}return(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-1`,children:`Access control`}),(0,l.jsxs)(`p`,{className:`text-xs text-muted-foreground mb-3`,children:[`Allowlisted Telegram users can use the bot (commands + chat). An empty list is closed; ownership begins only through the one-time pairing flow. Users find their id via`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`/whoami`}),`.`]}),e===null?(0,l.jsx)(`p`,{className:`text-xs text-muted-foreground italic`,children:`loading…`}):e.length===0?(0,l.jsx)(`p`,{className:`text-xs text-warning mb-3`,children:`Closed — no paired owner or allowlisted members.`}):(0,l.jsx)(`ul`,{className:`mb-3 space-y-1 text-sm`,children:e.map(e=>(0,l.jsxs)(`li`,{className:`flex flex-wrap items-center gap-2`,children:[(0,l.jsx)(`code`,{className:`font-mono`,children:e.userId}),(0,l.jsxs)(`span`,{className:`text-muted-foreground`,children:[e.label??(e.username?`@${e.username}`:`—`),` · `,e.role]}),e.role!==`owner`&&(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>h(e),children:`remove`})]},e.userId))}),(0,l.jsxs)(`form`,{onSubmit:_,className:`flex flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-end`,children:[(0,l.jsxs)(`label`,{className:`m-0 flex flex-col gap-1 text-xs font-medium text-foreground`,children:[`Telegram user ID`,(0,l.jsx)(`input`,{value:n,onChange:e=>r(e.target.value),placeholder:`123456789`,inputMode:`numeric`,className:`w-full rounded-md border bg-background px-2 py-1 font-mono text-sm sm:w-32`})]}),(0,l.jsxs)(`label`,{className:`m-0 flex flex-col gap-1 text-xs font-medium text-foreground`,children:[`Label `,(0,l.jsx)(`span`,{className:`font-normal text-muted-foreground`,children:`(optional)`}),(0,l.jsx)(`input`,{value:a,onChange:e=>s(e.target.value),placeholder:`e.g. Pat`,className:`w-full rounded-md border bg-background px-2 py-1 text-sm sm:w-40`})]}),(0,l.jsx)(o,{variant:`ghost`,type:`submit`,disabled:u,children:`add`}),f&&(0,l.jsx)(`span`,{role:`alert`,className:`text-xs text-danger`,children:f})]}),(0,l.jsx)(i,{open:m!==null,title:`Remove ${m?.label??m?.username??m?.userId??``}?`,description:(0,l.jsxs)(`p`,{children:[`Telegram user `,(0,l.jsx)(`code`,{className:`font-mono`,children:m?.userId}),` immediately loses command and chat access. Their Telegram account is not changed, and they can be allowlisted again later.`]}),confirmLabel:`remove Telegram access`,onConfirm:async()=>{if(m)try{await v(m.userId)}catch(e){throw p(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||h(null)}})]})}function g({toChatId:e}){let[t,n]=(0,c.useState)(!1),[r,i]=(0,c.useState)(null);async function a(){n(!0),i(null);try{let e=await fetch(`/api/config/telegram/reconnect`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??e.statusText)}window.location.reload()}catch(e){i(e.message),n(!1)}}return(0,l.jsxs)(`div`,{className:`rounded-md border-2 border-danger/25 bg-danger/10 px-4 py-3 text-sm`,children:[(0,l.jsx)(`div`,{className:`font-semibold text-danger mb-1`,children:`Supergroup chat id changed`}),(0,l.jsxs)(`p`,{className:`text-danger mb-2`,children:[`Telegram migrated this supergroup to a new chat id (`,(0,l.jsx)(`code`,{className:`font-mono`,children:e}),`). The bot is still pointed at the old id. Reconnect to repoint it and re-create the `,(0,l.jsx)(`code`,{className:`font-mono`,children:`⚙ bazilion`}),` `,`service chat in the new team. Agent topic bindings will reconcile on next use.`]}),(0,l.jsx)(o,{variant:`primary`,onClick:a,disabled:t,children:t?`reconnecting…`:`Reconnect to ${e}`}),r&&(0,l.jsx)(`span`,{role:`alert`,className:`ml-3 text-xs text-danger`,children:r})]})}function _({polling:e}){let t=e.startedAt?new Date(e.startedAt).toISOString():null,n=e.lastSuccessfulPollAt?new Date(e.lastSuccessfulPollAt).toISOString():null;return(0,l.jsxs)(`div`,{className:`mt-4 rounded-md border bg-muted/30 px-3 py-2 text-xs space-y-1`,children:[(0,l.jsx)(`p`,{className:`font-semibold uppercase tracking-wide text-muted-foreground`,children:`Polling state`}),(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1 font-mono`,children:[(0,l.jsx)(`span`,{className:e.running?`text-success`:`text-danger`,children:e.running?`running`:`stopped`}),(0,l.jsx)(`span`,{className:e.activated?`text-success`:`text-warning`,children:e.activated?`activated`:`awaiting activation`}),e.lastUpdateId!==null&&(0,l.jsxs)(`span`,{children:[`last update `,e.lastUpdateId]}),t&&(0,l.jsxs)(`span`,{children:[`started `,t]}),n&&(0,l.jsxs)(`span`,{children:[`last poll `,n]})]}),e.error&&(0,l.jsxs)(`p`,{role:`alert`,className:`text-danger`,children:[`error: `,e.error]})]})}function v({health:e}){if(e.error)return(0,l.jsxs)(`div`,{role:`alert`,className:`rounded-md border border-danger/25 bg-danger/10 px-3 py-2 text-sm`,children:[(0,l.jsxs)(`p`,{className:`font-semibold text-danger`,children:[`Failed at `,(0,l.jsx)(`code`,{className:`font-mono`,children:e.error.step})]}),(0,l.jsx)(`p`,{className:`text-danger mt-1`,children:e.error.message}),b(e.error.step)]});if(!e.preflight)return(0,l.jsx)(`p`,{role:`status`,className:`text-xs text-muted-foreground italic`,children:`No preflight data.`});let t=e.preflight;return(0,l.jsxs)(`ul`,{role:`status`,"aria-live":`polite`,"aria-atomic":`true`,className:`space-y-1.5`,children:[(0,l.jsxs)(y,{ok:t.botUsername.length>0,label:`Bot identity`,children:[`@`,t.botUsername]}),(0,l.jsx)(y,{ok:t.chatTitle.length>0,label:`Supergroup reachable`,children:t.chatTitle}),(0,l.jsx)(y,{ok:t.isForum,label:`Forum topics enabled`,children:t.isForum?`is_forum: true`:`is_forum: false — the supergroup owner must enable Topics in team settings`}),(0,l.jsx)(y,{ok:t.hasManageTopics,label:`Bot has can_manage_topics`,children:t.hasManageTopics?`admin with can_manage_topics`:`promote the bot to admin in the supergroup with the "Manage topics" permission`}),(0,l.jsx)(y,{ok:t.privacyModeOff,label:`Privacy Mode is OFF`,children:t.privacyModeOff?`can_read_all_group_messages: true`:`BotFather → /mybots → select bot → Bot Settings → Team Privacy → Turn off`}),(0,l.jsx)(y,{ok:t.chatIsPrivate,label:`Supergroup is private`,children:t.chatIsPrivate?`no public @username`:`public groups expose topic content to readers`}),(0,l.jsx)(y,{ok:t.memberCount===2,label:`Expected membership`,children:t.memberCount===null?`member count unavailable — verify one owner plus the bot manually`:`${t.memberCount} members reported; secure posture is one owner plus the bot`}),t.ownerPresent!==null&&(0,l.jsx)(y,{ok:t.ownerPresent,label:`Paired owner is present`,children:t.ownerPresent?`owner membership confirmed`:`owner missing — Telegram ingress is degraded`})]})}function y({ok:e,label:t,children:n}){return(0,l.jsxs)(`li`,{className:`flex items-start gap-2 text-sm`,children:[(0,l.jsx)(`span`,{className:`mt-0.5 inline-flex h-4 w-4 items-center justify-center rounded-full text-[10px] font-bold leading-none ${e?`bg-success/10 text-success`:`bg-danger/10 text-danger`}`,"aria-hidden":!0,children:e?`✓`:`✕`}),(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`span`,{className:`font-medium`,children:t}),(0,l.jsx)(`span`,{className:`ml-2 text-xs ${e?`text-muted-foreground`:`text-danger`}`,children:n})]})]})}function b(e){switch(e){case`getMe`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The token is invalid or revoked. Re-issue with @BotFather → /token, or paste a fresh one above.`});case`getChat`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The chat id either doesn't exist, points at a basic team (not a supergroup), or the bot isn't a member. Forward any message from the supergroup to the bot to double-check the id, then add the bot to the team.`});case`getChatMember`:return(0,l.jsx)(`p`,{className:`text-xs text-danger mt-1`,children:`The bot is in the chat but the membership lookup failed. Usually means the bot was kicked or the chat id was migrated — confirm the bot is still in the supergroup.`})}}export{p as component};
@@ -1 +1 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-CGZzom9E.js";import{v as a}from"./index-BUhhk_u9.js";import{t as o}from"./Button-ByiV6fpd.js";import{t as s}from"./ConfigPage-BCLp-FUC.js";var c=e(n()),l=t();function u(e){return new Date(e).toISOString().slice(0,16).replace(`T`,` `)}function d(){let{tokens:e,sessions:t}=a.useLoaderData(),{all:n}=a.useSearch(),d=n===`1`,f=r(),[p,m]=(0,c.useState)(``),[h,g]=(0,c.useState)(null),[_,v]=(0,c.useState)(`90`),[y,b]=(0,c.useState)(null),[x,S]=(0,c.useState)(!1),[C,w]=(0,c.useState)(null),[T,E]=(0,c.useState)(null);async function D(e){e.preventDefault(),b(null),S(!0);try{let e=await fetch(`/api/tokens`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({label:p,expiresInDays:Number(_)})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`${e.status} ${e.statusText}`)}g((await e.json()).token),m(``),await f.invalidate()}catch(e){b(e.message)}finally{S(!1)}}async function O(e,t){let n=await fetch(`/api/tokens/${encodeURIComponent(e)}`,{method:`DELETE`});if(!n.ok&&n.status!==204){let e=await n.json().catch(()=>({}));throw Error(e.error??`Could not revoke API token`)}t?window.location.assign(`/login`):await f.invalidate()}async function k(e,t){let n=await fetch(`/api/sessions/${encodeURIComponent(e)}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Could not revoke browser session`)}t?window.location.assign(`/login`):await f.invalidate()}return(0,l.jsxs)(s,{active:`tokens`,title:`API tokens`,description:(0,l.jsxs)(l.Fragment,{children:[`Manage per-client credentials for the HTTP API and CLI. The`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`bootstrap`}),` token from`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`~/.bazilion/auth.json`}),` remains protected; mint separate credentials for mobile, LAN, and remote clients.`]}),children:[(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`font-serif text-xl mb-3`,children:`Mint a new token`}),(0,l.jsxs)(`form`,{onSubmit:D,className:`mb-3 flex flex-col items-stretch gap-2 sm:flex-row sm:items-end`,children:[(0,l.jsxs)(`label`,{className:`w-full text-sm sm:w-auto`,children:[`Label`,(0,l.jsx)(`input`,{type:`text`,value:p,onChange:e=>m(e.target.value),required:!0,placeholder:`e.g. laptop-tailscale`,autoComplete:`off`,className:`mt-1 block w-full rounded-md border bg-background px-3 py-2 text-sm sm:w-72`})]}),(0,l.jsxs)(`label`,{className:`w-full text-sm sm:w-auto`,children:[`Expires in days`,(0,l.jsx)(`input`,{type:`number`,min:1,max:365,value:_,onChange:e=>v(e.target.value),required:!0,className:`mt-1 block w-full rounded-md border bg-background px-3 py-2 text-sm sm:w-36`})]}),(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:x,children:x?`creating…`:`create`})]}),h&&(0,l.jsxs)(`div`,{className:`rounded-md border border-warning/25 bg-warning/10 p-3`,children:[(0,l.jsx)(`p`,{className:`text-xs text-warning mb-1`,children:`copy this token now — it is not recoverable later.`}),(0,l.jsx)(`pre`,{className:`font-mono text-xs whitespace-pre-wrap break-all`,children:h})]}),y&&(0,l.jsx)(`p`,{role:`alert`,className:`text-sm text-danger`,children:y})]}),(0,l.jsx)(`div`,{children:(0,l.jsxs)(`label`,{className:`text-sm flex items-center gap-2`,children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:d,onChange:e=>{window.location.assign(e.target.checked?`/config/tokens?all=1`:`/config/tokens`)}}),`show revoked`]})}),(0,l.jsx)(`div`,{className:`overflow-x-auto`,children:(0,l.jsxs)(`table`,{className:`w-full min-w-[720px] text-sm`,children:[(0,l.jsx)(`thead`,{className:`text-left text-muted-foreground border-b`,children:(0,l.jsxs)(`tr`,{children:[(0,l.jsx)(`th`,{className:`py-2`,children:`label`}),(0,l.jsx)(`th`,{children:`kind`}),(0,l.jsx)(`th`,{children:`id`}),(0,l.jsx)(`th`,{children:`state`}),(0,l.jsx)(`th`,{children:`created`}),(0,l.jsx)(`th`,{children:`last used`}),(0,l.jsx)(`th`,{children:`expires`}),(0,l.jsx)(`th`,{})]})}),(0,l.jsxs)(`tbody`,{children:[e.length===0&&(0,l.jsx)(`tr`,{children:(0,l.jsx)(`td`,{colSpan:8,className:`py-6 text-center text-muted-foreground italic`,children:`no tokens yet — mint one above`})}),e.map(e=>{let t=e.kind===`bootstrap`;return(0,l.jsxs)(`tr`,{className:`border-b last:border-0 hover:bg-accent/30`,children:[(0,l.jsxs)(`td`,{className:`py-2`,children:[e.label,t&&(0,l.jsx)(`span`,{className:`ml-2 text-[0.7em] uppercase tracking-wide text-muted-foreground`,children:`auth.json`})]}),(0,l.jsx)(`td`,{children:e.kind}),(0,l.jsx)(`td`,{children:(0,l.jsx)(`code`,{className:`font-mono text-xs`,children:e.id})}),(0,l.jsx)(`td`,{children:e.revokedAt?(0,l.jsx)(`span`,{className:`text-muted-foreground`,children:`revoked`}):(0,l.jsx)(`span`,{className:`text-success`,children:`active`})}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:u(e.createdAt)}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:e.lastUsedAt?u(e.lastUsedAt):`(never)`}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:e.expiresAt?u(e.expiresAt):`(never)`}),(0,l.jsx)(`td`,{children:!e.revokedAt&&!t&&(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>{b(null),w(e)},children:`revoke`})})]},e.id)})]})]})}),(0,l.jsxs)(`section`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`h3`,{className:`font-serif text-xl`,children:`Browser sessions`}),(0,l.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Sessions expire after 12 idle hours or seven days absolute. Revoking a device also revokes every session created from it.`})]}),(0,l.jsx)(`div`,{className:`overflow-x-auto`,children:(0,l.jsxs)(`table`,{className:`w-full min-w-[720px] text-sm`,children:[(0,l.jsx)(`thead`,{className:`border-b text-left text-muted-foreground`,children:(0,l.jsxs)(`tr`,{children:[(0,l.jsx)(`th`,{className:`py-2`,children:`device`}),(0,l.jsx)(`th`,{children:`session`}),(0,l.jsx)(`th`,{children:`last seen`}),(0,l.jsx)(`th`,{children:`idle expiry`}),(0,l.jsx)(`th`,{children:`absolute expiry`}),(0,l.jsx)(`th`,{})]})}),(0,l.jsxs)(`tbody`,{children:[t.length===0&&(0,l.jsx)(`tr`,{children:(0,l.jsx)(`td`,{colSpan:6,className:`py-6 text-center italic text-muted-foreground`,children:`no active browser sessions`})}),t.map(e=>(0,l.jsxs)(`tr`,{className:`border-b last:border-0 hover:bg-accent/30`,children:[(0,l.jsxs)(`td`,{className:`py-2`,children:[e.deviceLabel,` `,e.current&&(0,l.jsx)(`span`,{className:`text-xs text-success`,children:`current`})]}),(0,l.jsx)(`td`,{children:(0,l.jsx)(`code`,{className:`font-mono text-xs`,children:e.id})}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.lastSeenAt)}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.idleExpiresAt)}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.absoluteExpiresAt)}),(0,l.jsx)(`td`,{children:(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>{b(null),E(e)},children:`revoke`})})]},e.id))]})]})})]}),(0,l.jsx)(i,{open:C!==null,title:`Revoke ${C?.label??``}?`,description:(0,l.jsxs)(`p`,{children:[`This permanently revokes device token`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:C?.id}),` and every browser session created from it. Clients using it will be signed out and cannot reconnect with this credential.`,t.some(e=>e.current&&e.deviceTokenId===C?.id)&&` This includes the browser session you are using now.`]}),confirmLabel:`revoke token and sessions`,onConfirm:async()=>{if(C)try{await O(C.id,t.some(e=>e.current&&e.deviceTokenId===C.id))}catch(e){throw b(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||w(null)}}),(0,l.jsx)(i,{open:T!==null,title:`Revoke ${T?.deviceLabel??``} browser session?`,description:(0,l.jsxs)(`p`,{children:[`This ends browser session `,(0,l.jsx)(`code`,{className:`font-mono`,children:T?.id}),T?.current?` and signs this browser out immediately.`:`. The device token remains active for future logins.`]}),confirmLabel:T?.current?`sign out this browser`:`revoke session`,onConfirm:async()=>{if(T)try{await k(T.id,T.current)}catch(e){throw b(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||E(null)}})]})}export{d as component};
1
+ import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-MicTTwdy.js";import{v as a}from"./index-Bq2zrG2_.js";import{t as o}from"./Button-ByiV6fpd.js";import{t as s}from"./ConfigPage-BCLp-FUC.js";var c=e(n()),l=t();function u(e){return new Date(e).toISOString().slice(0,16).replace(`T`,` `)}function d(){let{tokens:e,sessions:t}=a.useLoaderData(),{all:n}=a.useSearch(),d=n===`1`,f=r(),[p,m]=(0,c.useState)(``),[h,g]=(0,c.useState)(null),[_,v]=(0,c.useState)(`90`),[y,b]=(0,c.useState)(null),[x,S]=(0,c.useState)(!1),[C,w]=(0,c.useState)(null),[T,E]=(0,c.useState)(null);async function D(e){e.preventDefault(),b(null),S(!0);try{let e=await fetch(`/api/tokens`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({label:p,expiresInDays:Number(_)})});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`${e.status} ${e.statusText}`)}g((await e.json()).token),m(``),await f.invalidate()}catch(e){b(e.message)}finally{S(!1)}}async function O(e,t){let n=await fetch(`/api/tokens/${encodeURIComponent(e)}`,{method:`DELETE`});if(!n.ok&&n.status!==204){let e=await n.json().catch(()=>({}));throw Error(e.error??`Could not revoke API token`)}t?window.location.assign(`/login`):await f.invalidate()}async function k(e,t){let n=await fetch(`/api/sessions/${encodeURIComponent(e)}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Could not revoke browser session`)}t?window.location.assign(`/login`):await f.invalidate()}return(0,l.jsxs)(s,{active:`tokens`,title:`API tokens`,description:(0,l.jsxs)(l.Fragment,{children:[`Manage per-client credentials for the HTTP API and CLI. The`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`bootstrap`}),` token from`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:`~/.bazilion/auth.json`}),` remains protected; mint separate credentials for mobile, LAN, and remote clients.`]}),children:[(0,l.jsxs)(`section`,{className:`rounded-lg border bg-card p-5`,children:[(0,l.jsx)(`h3`,{className:`font-serif text-xl mb-3`,children:`Mint a new token`}),(0,l.jsxs)(`form`,{onSubmit:D,className:`mb-3 flex flex-col items-stretch gap-2 sm:flex-row sm:items-end`,children:[(0,l.jsxs)(`label`,{className:`w-full text-sm sm:w-auto`,children:[`Label`,(0,l.jsx)(`input`,{type:`text`,value:p,onChange:e=>m(e.target.value),required:!0,placeholder:`e.g. laptop-tailscale`,autoComplete:`off`,className:`mt-1 block w-full rounded-md border bg-background px-3 py-2 text-sm sm:w-72`})]}),(0,l.jsxs)(`label`,{className:`w-full text-sm sm:w-auto`,children:[`Expires in days`,(0,l.jsx)(`input`,{type:`number`,min:1,max:365,value:_,onChange:e=>v(e.target.value),required:!0,className:`mt-1 block w-full rounded-md border bg-background px-3 py-2 text-sm sm:w-36`})]}),(0,l.jsx)(o,{variant:`primary`,type:`submit`,disabled:x,children:x?`creating…`:`create`})]}),h&&(0,l.jsxs)(`div`,{className:`rounded-md border border-warning/25 bg-warning/10 p-3`,children:[(0,l.jsx)(`p`,{className:`text-xs text-warning mb-1`,children:`copy this token now — it is not recoverable later.`}),(0,l.jsx)(`pre`,{className:`font-mono text-xs whitespace-pre-wrap break-all`,children:h})]}),y&&(0,l.jsx)(`p`,{role:`alert`,className:`text-sm text-danger`,children:y})]}),(0,l.jsx)(`div`,{children:(0,l.jsxs)(`label`,{className:`text-sm flex items-center gap-2`,children:[(0,l.jsx)(`input`,{type:`checkbox`,checked:d,onChange:e=>{window.location.assign(e.target.checked?`/config/tokens?all=1`:`/config/tokens`)}}),`show revoked`]})}),(0,l.jsx)(`div`,{className:`overflow-x-auto`,children:(0,l.jsxs)(`table`,{className:`w-full min-w-[720px] text-sm`,children:[(0,l.jsx)(`thead`,{className:`text-left text-muted-foreground border-b`,children:(0,l.jsxs)(`tr`,{children:[(0,l.jsx)(`th`,{className:`py-2`,children:`label`}),(0,l.jsx)(`th`,{children:`kind`}),(0,l.jsx)(`th`,{children:`id`}),(0,l.jsx)(`th`,{children:`state`}),(0,l.jsx)(`th`,{children:`created`}),(0,l.jsx)(`th`,{children:`last used`}),(0,l.jsx)(`th`,{children:`expires`}),(0,l.jsx)(`th`,{})]})}),(0,l.jsxs)(`tbody`,{children:[e.length===0&&(0,l.jsx)(`tr`,{children:(0,l.jsx)(`td`,{colSpan:8,className:`py-6 text-center text-muted-foreground italic`,children:`no tokens yet — mint one above`})}),e.map(e=>{let t=e.kind===`bootstrap`;return(0,l.jsxs)(`tr`,{className:`border-b last:border-0 hover:bg-accent/30`,children:[(0,l.jsxs)(`td`,{className:`py-2`,children:[e.label,t&&(0,l.jsx)(`span`,{className:`ml-2 text-[0.7em] uppercase tracking-wide text-muted-foreground`,children:`auth.json`})]}),(0,l.jsx)(`td`,{children:e.kind}),(0,l.jsx)(`td`,{children:(0,l.jsx)(`code`,{className:`font-mono text-xs`,children:e.id})}),(0,l.jsx)(`td`,{children:e.revokedAt?(0,l.jsx)(`span`,{className:`text-muted-foreground`,children:`revoked`}):(0,l.jsx)(`span`,{className:`text-success`,children:`active`})}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:u(e.createdAt)}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:e.lastUsedAt?u(e.lastUsedAt):`(never)`}),(0,l.jsx)(`td`,{className:`text-muted-foreground text-xs`,children:e.expiresAt?u(e.expiresAt):`(never)`}),(0,l.jsx)(`td`,{children:!e.revokedAt&&!t&&(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>{b(null),w(e)},children:`revoke`})})]},e.id)})]})]})}),(0,l.jsxs)(`section`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{children:[(0,l.jsx)(`h3`,{className:`font-serif text-xl`,children:`Browser sessions`}),(0,l.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Sessions expire after 12 idle hours or seven days absolute. Revoking a device also revokes every session created from it.`})]}),(0,l.jsx)(`div`,{className:`overflow-x-auto`,children:(0,l.jsxs)(`table`,{className:`w-full min-w-[720px] text-sm`,children:[(0,l.jsx)(`thead`,{className:`border-b text-left text-muted-foreground`,children:(0,l.jsxs)(`tr`,{children:[(0,l.jsx)(`th`,{className:`py-2`,children:`device`}),(0,l.jsx)(`th`,{children:`session`}),(0,l.jsx)(`th`,{children:`last seen`}),(0,l.jsx)(`th`,{children:`idle expiry`}),(0,l.jsx)(`th`,{children:`absolute expiry`}),(0,l.jsx)(`th`,{})]})}),(0,l.jsxs)(`tbody`,{children:[t.length===0&&(0,l.jsx)(`tr`,{children:(0,l.jsx)(`td`,{colSpan:6,className:`py-6 text-center italic text-muted-foreground`,children:`no active browser sessions`})}),t.map(e=>(0,l.jsxs)(`tr`,{className:`border-b last:border-0 hover:bg-accent/30`,children:[(0,l.jsxs)(`td`,{className:`py-2`,children:[e.deviceLabel,` `,e.current&&(0,l.jsx)(`span`,{className:`text-xs text-success`,children:`current`})]}),(0,l.jsx)(`td`,{children:(0,l.jsx)(`code`,{className:`font-mono text-xs`,children:e.id})}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.lastSeenAt)}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.idleExpiresAt)}),(0,l.jsx)(`td`,{className:`text-xs text-muted-foreground`,children:u(e.absoluteExpiresAt)}),(0,l.jsx)(`td`,{children:(0,l.jsx)(o,{variant:`danger`,className:`text-xs`,onClick:()=>{b(null),E(e)},children:`revoke`})})]},e.id))]})]})})]}),(0,l.jsx)(i,{open:C!==null,title:`Revoke ${C?.label??``}?`,description:(0,l.jsxs)(`p`,{children:[`This permanently revokes device token`,` `,(0,l.jsx)(`code`,{className:`font-mono`,children:C?.id}),` and every browser session created from it. Clients using it will be signed out and cannot reconnect with this credential.`,t.some(e=>e.current&&e.deviceTokenId===C?.id)&&` This includes the browser session you are using now.`]}),confirmLabel:`revoke token and sessions`,onConfirm:async()=>{if(C)try{await O(C.id,t.some(e=>e.current&&e.deviceTokenId===C.id))}catch(e){throw b(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||w(null)}}),(0,l.jsx)(i,{open:T!==null,title:`Revoke ${T?.deviceLabel??``} browser session?`,description:(0,l.jsxs)(`p`,{children:[`This ends browser session `,(0,l.jsx)(`code`,{className:`font-mono`,children:T?.id}),T?.current?` and signs this browser out immediately.`:`. The device token remains active for future logins.`]}),confirmLabel:T?.current?`sign out this browser`:`revoke session`,onConfirm:async()=>{if(T)try{await k(T.id,T.current)}catch(e){throw b(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||E(null)}})]})}export{d as component};
@@ -1 +1 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-CGZzom9E.js";import{a}from"./index-BUhhk_u9.js";import{r as o}from"./Page-NV96O47A.js";import{t as s}from"./AgentTabs-BcmmwYJc.js";import{t as c}from"./Button-ByiV6fpd.js";var l=e(n()),u=t();function d(){let{resolved:e,triggers:t,dispatches:n}=a.useLoaderData(),d=r(),[p,m]=(0,l.useState)(null),[h,g]=(0,l.useState)(null),[_,v]=(0,l.useState)(null);async function y(e){v(e.id),g(null);try{let t=await fetch(`/api/triggers/${encodeURIComponent(e.id)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({enabled:!e.enabled})});if(!t.ok){let n=await t.json().catch(()=>null);throw Error(n?.error??`Could not ${e.enabled?`disable`:`enable`} trigger`)}await d.invalidate()}catch(e){g(e instanceof Error?e.message:String(e))}finally{v(null)}}async function b(e){let t=await fetch(`/api/triggers/${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok&&t.status!==204){let e=await t.json().catch(()=>null);throw Error(e?.error??`Could not delete trigger`)}await d.invalidate()}return(0,u.jsxs)(o,{children:[(0,u.jsx)(`header`,{className:`mb-6`,children:(0,u.jsx)(`h1`,{children:e.agent.name})}),(0,u.jsx)(s,{agentId:e.agent.id,active:`triggers`,archived:e.agent.status===`archived`}),(0,u.jsx)(f,{agentId:e.agent.id,onAdded:()=>d.invalidate()}),h&&(0,u.jsx)(`p`,{role:`alert`,className:`err mt-4`,children:h}),(0,u.jsx)(`h3`,{className:`mb-3 mt-6 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light`,children:`Active triggers`}),t.length===0?(0,u.jsx)(`p`,{className:`muted`,children:`no triggers yet — add one above.`}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:t.map(e=>{let t=e.kind===`interval`?`every ${e.intervalSec}s`:e.cronExpr,n=e.lastFiredAt?new Date(e.lastFiredAt).toLocaleString():`Never`;return(0,u.jsxs)(`article`,{className:`card min-w-0 ${e.enabled?``:`opacity-60`}`,children:[(0,u.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,u.jsxs)(`div`,{className:`min-w-0`,children:[(0,u.jsx)(`p`,{className:`m-0 break-all font-mono text-xs text-muted-foreground`,children:e.id}),(0,u.jsx)(`p`,{className:`mb-0 mt-1 font-medium text-foreground`,children:t})]}),(0,u.jsx)(`span`,{className:`shrink-0 rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-xs text-mocha`,children:e.kind})]}),(0,u.jsx)(`p`,{className:`my-3 break-words text-sm text-foreground`,children:e.message}),(0,u.jsxs)(`p`,{className:`mb-3 text-xs text-muted-foreground`,children:[`Last fired: `,n]}),(0,u.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,u.jsx)(c,{variant:`ghost`,disabled:_===e.id,onClick:()=>void y(e),children:_===e.id?`Working…`:e.enabled?`Disable`:`Enable`}),(0,u.jsx)(c,{variant:`danger`,disabled:_===e.id,onClick:()=>{g(null),m(e)},children:`Delete`})]})]},e.id)})}),(0,u.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,u.jsxs)(`table`,{className:`min-w-full`,children:[(0,u.jsx)(`thead`,{children:(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`th`,{children:`id`}),(0,u.jsx)(`th`,{children:`kind`}),(0,u.jsx)(`th`,{children:`spec`}),(0,u.jsx)(`th`,{children:`message`}),(0,u.jsx)(`th`,{children:`last fired`}),(0,u.jsx)(`th`,{})]})}),(0,u.jsx)(`tbody`,{children:t.map(e=>{let t=e.kind===`interval`?`every ${e.intervalSec}s`:e.cronExpr,n=e.lastFiredAt?new Date(e.lastFiredAt).toLocaleString():`(never)`;return(0,u.jsxs)(`tr`,{className:e.enabled?``:`opacity-60`,children:[(0,u.jsx)(`td`,{children:(0,u.jsxs)(`code`,{children:[e.id.slice(0,8),`…`]})}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`span`,{className:`inline-block rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-[0.8em] text-mocha`,children:e.kind})}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`code`,{children:t})}),(0,u.jsx)(`td`,{children:e.message.length>60?`${e.message.slice(0,60)}…`:e.message}),(0,u.jsx)(`td`,{className:`text-[0.82em] text-mocha-light`,children:n}),(0,u.jsx)(`td`,{children:(0,u.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,u.jsx)(c,{variant:`ghost`,disabled:_===e.id,onClick:()=>void y(e),children:_===e.id?`working…`:e.enabled?`disable`:`enable`}),(0,u.jsx)(c,{variant:`danger`,disabled:_===e.id,onClick:()=>{g(null),m(e)},children:`delete`})]})})]},e.id)})})]})})]}),(0,u.jsx)(`h3`,{className:`mb-3 mt-8 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light`,children:`Recent dispatches`}),n.length===0?(0,u.jsx)(`p`,{className:`muted`,children:`no scheduled occurrences yet.`}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:n.map(e=>(0,u.jsxs)(`article`,{className:`card min-w-0`,children:[(0,u.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,u.jsx)(`time`,{className:`text-sm text-foreground`,children:new Date(e.scheduledAt).toLocaleString()}),(0,u.jsx)(`code`,{className:`shrink-0`,children:e.status})]}),(0,u.jsxs)(`p`,{className:`mb-0 mt-2 text-xs text-muted-foreground`,children:[e.attemptCount,` attempt`,e.attemptCount===1?``:`s`]}),e.lastError&&(0,u.jsx)(`p`,{className:`mb-0 mt-2 break-words text-sm text-danger`,children:e.lastError})]},e.id))}),(0,u.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,u.jsxs)(`table`,{className:`min-w-full`,children:[(0,u.jsx)(`thead`,{children:(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`th`,{children:`scheduled`}),(0,u.jsx)(`th`,{children:`status`}),(0,u.jsx)(`th`,{children:`attempts`}),(0,u.jsx)(`th`,{children:`error`})]})}),(0,u.jsx)(`tbody`,{children:n.map(e=>(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`td`,{className:`text-[0.82em]`,children:new Date(e.scheduledAt).toLocaleString()}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`code`,{children:e.status})}),(0,u.jsx)(`td`,{children:e.attemptCount}),(0,u.jsx)(`td`,{className:`text-[0.82em] text-mocha-light`,children:e.lastError??`—`})]},e.id))})]})})]}),(0,u.jsx)(i,{open:p!==null,title:`Delete ${p?.kind??``} trigger?`,description:(0,u.jsxs)(`p`,{children:[`This permanently removes trigger`,` `,(0,u.jsx)(`code`,{className:`font-mono`,children:p?.id}),`, its recorded dispatch history, and every future scheduled occurrence for `,e.agent.name,`. The Agent itself is not deleted.`]}),confirmLabel:`delete trigger and history`,onConfirm:async()=>{if(p)try{await b(p.id)}catch(e){throw g(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||m(null)}})]})}function f({agentId:e,onAdded:t}){let[n,r]=(0,l.useState)(`interval`),[i,a]=(0,l.useState)(300),[o,s]=(0,l.useState)(``),[d,f]=(0,l.useState)(``),[p,m]=(0,l.useState)(null),[h,g]=(0,l.useState)(!1);async function _(r){if(r.preventDefault(),m(null),!d.trim()){m(`message is required`);return}if(n===`interval`&&(!Number.isFinite(i)||i<=0)){m(`interval must be a positive number`);return}if(n===`cron`&&!o.trim()){m(`cron expression is required`);return}g(!0);try{let r={kind:n,message:d.trim()};n===`interval`?r.intervalSec=i:r.cronExpr=o.trim();let c=await fetch(`/api/agents/${encodeURIComponent(e)}/triggers`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(r)});if(!c.ok){let e=await c.json().catch(()=>null);throw Error(e?.error??c.statusText)}f(``),s(``),a(300),t()}catch(e){m(e.message)}finally{g(!1)}}return(0,u.jsxs)(`form`,{className:`card`,onSubmit:_,children:[(0,u.jsx)(`h3`,{children:`Add trigger`}),(0,u.jsxs)(`div`,{className:`mb-3 flex gap-3`,children:[(0,u.jsxs)(`label`,{className:`m-0 inline-flex cursor-pointer items-center gap-1`,children:[(0,u.jsx)(`input`,{type:`radio`,checked:n===`interval`,onChange:()=>r(`interval`)}),`interval (every N seconds)`]}),(0,u.jsxs)(`label`,{className:`m-0 inline-flex cursor-pointer items-center gap-1`,children:[(0,u.jsx)(`input`,{type:`radio`,checked:n===`cron`,onChange:()=>r(`cron`)}),`cron (5-field)`]})]}),n===`interval`?(0,u.jsxs)(`label`,{children:[`interval (seconds)`,(0,u.jsx)(`input`,{type:`number`,min:1,value:i,onChange:e=>a(Number(e.target.value))})]}):(0,u.jsxs)(`label`,{children:[`cron expression (minute hour dom month dow)`,(0,u.jsx)(`input`,{type:`text`,placeholder:`*/15 * * * *`,value:o,onChange:e=>s(e.target.value)})]}),(0,u.jsxs)(`label`,{children:[`message`,(0,u.jsx)(`textarea`,{placeholder:`e.g. check your inbox and act on anything new`,value:d,onChange:e=>f(e.target.value),className:`font-mono text-[0.9em] min-h-[80px]`})]}),(0,u.jsxs)(`div`,{className:`mt-3 flex items-center gap-3`,children:[(0,u.jsx)(c,{variant:`primary`,type:`submit`,disabled:h,children:h?`adding…`:`add`}),p&&(0,u.jsx)(`span`,{role:`alert`,className:`text-[0.85em] text-danger`,children:p})]})]})}export{d as component};
1
+ import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{t as n}from"./react-3W8R1pOO.js";import{d as r}from"./preload-helper-bztXdkDj.js";import{t as i}from"./ConfirmDialog-MicTTwdy.js";import{a}from"./index-Bq2zrG2_.js";import{r as o}from"./Page-NV96O47A.js";import{t as s}from"./AgentTabs-BcmmwYJc.js";import{t as c}from"./Button-ByiV6fpd.js";var l=e(n()),u=t();function d(){let{resolved:e,triggers:t,dispatches:n}=a.useLoaderData(),d=r(),[p,m]=(0,l.useState)(null),[h,g]=(0,l.useState)(null),[_,v]=(0,l.useState)(null);async function y(e){v(e.id),g(null);try{let t=await fetch(`/api/triggers/${encodeURIComponent(e.id)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify({enabled:!e.enabled})});if(!t.ok){let n=await t.json().catch(()=>null);throw Error(n?.error??`Could not ${e.enabled?`disable`:`enable`} trigger`)}await d.invalidate()}catch(e){g(e instanceof Error?e.message:String(e))}finally{v(null)}}async function b(e){let t=await fetch(`/api/triggers/${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok&&t.status!==204){let e=await t.json().catch(()=>null);throw Error(e?.error??`Could not delete trigger`)}await d.invalidate()}return(0,u.jsxs)(o,{children:[(0,u.jsx)(`header`,{className:`mb-6`,children:(0,u.jsx)(`h1`,{children:e.agent.name})}),(0,u.jsx)(s,{agentId:e.agent.id,active:`triggers`,archived:e.agent.status===`archived`}),(0,u.jsx)(f,{agentId:e.agent.id,onAdded:()=>d.invalidate()}),h&&(0,u.jsx)(`p`,{role:`alert`,className:`err mt-4`,children:h}),(0,u.jsx)(`h3`,{className:`mb-3 mt-6 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light`,children:`Active triggers`}),t.length===0?(0,u.jsx)(`p`,{className:`muted`,children:`no triggers yet — add one above.`}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:t.map(e=>{let t=e.kind===`interval`?`every ${e.intervalSec}s`:e.cronExpr,n=e.lastFiredAt?new Date(e.lastFiredAt).toLocaleString():`Never`;return(0,u.jsxs)(`article`,{className:`card min-w-0 ${e.enabled?``:`opacity-60`}`,children:[(0,u.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,u.jsxs)(`div`,{className:`min-w-0`,children:[(0,u.jsx)(`p`,{className:`m-0 break-all font-mono text-xs text-muted-foreground`,children:e.id}),(0,u.jsx)(`p`,{className:`mb-0 mt-1 font-medium text-foreground`,children:t})]}),(0,u.jsx)(`span`,{className:`shrink-0 rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-xs text-mocha`,children:e.kind})]}),(0,u.jsx)(`p`,{className:`my-3 break-words text-sm text-foreground`,children:e.message}),(0,u.jsxs)(`p`,{className:`mb-3 text-xs text-muted-foreground`,children:[`Last fired: `,n]}),(0,u.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,u.jsx)(c,{variant:`ghost`,disabled:_===e.id,onClick:()=>void y(e),children:_===e.id?`Working…`:e.enabled?`Disable`:`Enable`}),(0,u.jsx)(c,{variant:`danger`,disabled:_===e.id,onClick:()=>{g(null),m(e)},children:`Delete`})]})]},e.id)})}),(0,u.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,u.jsxs)(`table`,{className:`min-w-full`,children:[(0,u.jsx)(`thead`,{children:(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`th`,{children:`id`}),(0,u.jsx)(`th`,{children:`kind`}),(0,u.jsx)(`th`,{children:`spec`}),(0,u.jsx)(`th`,{children:`message`}),(0,u.jsx)(`th`,{children:`last fired`}),(0,u.jsx)(`th`,{})]})}),(0,u.jsx)(`tbody`,{children:t.map(e=>{let t=e.kind===`interval`?`every ${e.intervalSec}s`:e.cronExpr,n=e.lastFiredAt?new Date(e.lastFiredAt).toLocaleString():`(never)`;return(0,u.jsxs)(`tr`,{className:e.enabled?``:`opacity-60`,children:[(0,u.jsx)(`td`,{children:(0,u.jsxs)(`code`,{children:[e.id.slice(0,8),`…`]})}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`span`,{className:`inline-block rounded-sm border border-frost bg-ivory px-2 py-0.5 font-mono text-[0.8em] text-mocha`,children:e.kind})}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`code`,{children:t})}),(0,u.jsx)(`td`,{children:e.message.length>60?`${e.message.slice(0,60)}…`:e.message}),(0,u.jsx)(`td`,{className:`text-[0.82em] text-mocha-light`,children:n}),(0,u.jsx)(`td`,{children:(0,u.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,u.jsx)(c,{variant:`ghost`,disabled:_===e.id,onClick:()=>void y(e),children:_===e.id?`working…`:e.enabled?`disable`:`enable`}),(0,u.jsx)(c,{variant:`danger`,disabled:_===e.id,onClick:()=>{g(null),m(e)},children:`delete`})]})})]},e.id)})})]})})]}),(0,u.jsx)(`h3`,{className:`mb-3 mt-8 font-body text-[0.85em] font-semibold uppercase tracking-wider text-mocha-light`,children:`Recent dispatches`}),n.length===0?(0,u.jsx)(`p`,{className:`muted`,children:`no scheduled occurrences yet.`}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`grid gap-3 md:hidden`,children:n.map(e=>(0,u.jsxs)(`article`,{className:`card min-w-0`,children:[(0,u.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,u.jsx)(`time`,{className:`text-sm text-foreground`,children:new Date(e.scheduledAt).toLocaleString()}),(0,u.jsx)(`code`,{className:`shrink-0`,children:e.status})]}),(0,u.jsxs)(`p`,{className:`mb-0 mt-2 text-xs text-muted-foreground`,children:[e.attemptCount,` attempt`,e.attemptCount===1?``:`s`]}),e.lastError&&(0,u.jsx)(`p`,{className:`mb-0 mt-2 break-words text-sm text-danger`,children:e.lastError})]},e.id))}),(0,u.jsx)(`div`,{className:`hidden overflow-x-auto md:block`,children:(0,u.jsxs)(`table`,{className:`min-w-full`,children:[(0,u.jsx)(`thead`,{children:(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`th`,{children:`scheduled`}),(0,u.jsx)(`th`,{children:`status`}),(0,u.jsx)(`th`,{children:`attempts`}),(0,u.jsx)(`th`,{children:`error`})]})}),(0,u.jsx)(`tbody`,{children:n.map(e=>(0,u.jsxs)(`tr`,{children:[(0,u.jsx)(`td`,{className:`text-[0.82em]`,children:new Date(e.scheduledAt).toLocaleString()}),(0,u.jsx)(`td`,{children:(0,u.jsx)(`code`,{children:e.status})}),(0,u.jsx)(`td`,{children:e.attemptCount}),(0,u.jsx)(`td`,{className:`text-[0.82em] text-mocha-light`,children:e.lastError??`—`})]},e.id))})]})})]}),(0,u.jsx)(i,{open:p!==null,title:`Delete ${p?.kind??``} trigger?`,description:(0,u.jsxs)(`p`,{children:[`This permanently removes trigger`,` `,(0,u.jsx)(`code`,{className:`font-mono`,children:p?.id}),`, its recorded dispatch history, and every future scheduled occurrence for `,e.agent.name,`. The Agent itself is not deleted.`]}),confirmLabel:`delete trigger and history`,onConfirm:async()=>{if(p)try{await b(p.id)}catch(e){throw g(e instanceof Error?e.message:String(e)),e}},onOpenChange:e=>{e||m(null)}})]})}function f({agentId:e,onAdded:t}){let[n,r]=(0,l.useState)(`interval`),[i,a]=(0,l.useState)(300),[o,s]=(0,l.useState)(``),[d,f]=(0,l.useState)(``),[p,m]=(0,l.useState)(null),[h,g]=(0,l.useState)(!1);async function _(r){if(r.preventDefault(),m(null),!d.trim()){m(`message is required`);return}if(n===`interval`&&(!Number.isFinite(i)||i<=0)){m(`interval must be a positive number`);return}if(n===`cron`&&!o.trim()){m(`cron expression is required`);return}g(!0);try{let r={kind:n,message:d.trim()};n===`interval`?r.intervalSec=i:r.cronExpr=o.trim();let c=await fetch(`/api/agents/${encodeURIComponent(e)}/triggers`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(r)});if(!c.ok){let e=await c.json().catch(()=>null);throw Error(e?.error??c.statusText)}f(``),s(``),a(300),t()}catch(e){m(e.message)}finally{g(!1)}}return(0,u.jsxs)(`form`,{className:`card`,onSubmit:_,children:[(0,u.jsx)(`h3`,{children:`Add trigger`}),(0,u.jsxs)(`div`,{className:`mb-3 flex gap-3`,children:[(0,u.jsxs)(`label`,{className:`m-0 inline-flex cursor-pointer items-center gap-1`,children:[(0,u.jsx)(`input`,{type:`radio`,checked:n===`interval`,onChange:()=>r(`interval`)}),`interval (every N seconds)`]}),(0,u.jsxs)(`label`,{className:`m-0 inline-flex cursor-pointer items-center gap-1`,children:[(0,u.jsx)(`input`,{type:`radio`,checked:n===`cron`,onChange:()=>r(`cron`)}),`cron (5-field)`]})]}),n===`interval`?(0,u.jsxs)(`label`,{children:[`interval (seconds)`,(0,u.jsx)(`input`,{type:`number`,min:1,value:i,onChange:e=>a(Number(e.target.value))})]}):(0,u.jsxs)(`label`,{children:[`cron expression (minute hour dom month dow)`,(0,u.jsx)(`input`,{type:`text`,placeholder:`*/15 * * * *`,value:o,onChange:e=>s(e.target.value)})]}),(0,u.jsxs)(`label`,{children:[`message`,(0,u.jsx)(`textarea`,{placeholder:`e.g. check your inbox and act on anything new`,value:d,onChange:e=>f(e.target.value),className:`font-mono text-[0.9em] min-h-[80px]`})]}),(0,u.jsxs)(`div`,{className:`mt-3 flex items-center gap-3`,children:[(0,u.jsx)(c,{variant:`primary`,type:`submit`,disabled:h,children:h?`adding…`:`add`}),p&&(0,u.jsx)(`span`,{role:`alert`,className:`text-[0.85em] text-danger`,children:p})]})]})}export{d as component};
@@ -1 +1 @@
1
- import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{Y as t}from"./index-BUhhk_u9.js";import{i as n,n as r,r as i}from"./Page-NV96O47A.js";var a=t(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),o=e();function s(){return(0,o.jsxs)(i,{size:`narrow`,children:[(0,o.jsx)(r,{eyebrow:`First run`,title:`Welcome to bazilion`,description:`Configure one model provider to prepare your defaults, then test it before the first conversation.`}),(0,o.jsxs)(n,{title:`Three steps to your first conversation`,children:[(0,o.jsxs)(`p`,{className:`text-sm leading-6 text-muted-foreground`,children:[`Before you can spawn agents, enable a provider and save at least one concrete model id. Bazilion then creates a `,(0,o.jsx)(`code`,{children:`default`}),` Agent template and `,(0,o.jsx)(`code`,{children:`default`}),` Team. Send the small connection test before relying on that model.`]}),(0,o.jsxs)(`ol`,{className:`my-5 space-y-4`,children:[(0,o.jsxs)(c,{n:1,children:[(0,o.jsx)(`strong`,{children:`Choose a provider.`}),` Head to the`,` `,(0,o.jsx)(`a`,{href:`/config`,children:`providers tab`}),`, pick a provider, and set credentials or a local endpoint if that provider needs one. Local providers like Ollama and LM Studio can use their default loopback URLs.`]}),(0,o.jsxs)(c,{n:2,children:[(0,o.jsx)(`strong`,{children:`Enable it and save a model.`}),` Flip the provider's toggle on, then click a catalog chip or type one exact model id (for example`,` `,(0,o.jsx)(`code`,{children:`claude-opus-5`}),`, `,(0,o.jsx)(`code`,{children:`gpt-6-astra`}),`, or `,(0,o.jsx)(`code`,{children:`llama3.3`}),`) and press `,(0,o.jsx)(`em`,{children:`save models`}),`.`]}),(0,o.jsxs)(c,{n:3,children:[(0,o.jsx)(`strong`,{children:`Verify and spawn.`}),` Send the short real-model test. When setup is configured, the page gives you a direct action to spawn the first agent from the`,` `,(0,o.jsx)(`code`,{children:`default`}),` template.`]})]}),(0,o.jsxs)(`a`,{href:`/config`,className:`btn-primary no-underline`,children:[`Configure providers `,(0,o.jsx)(a,{className:`h-4 w-4`,"aria-hidden":`true`})]})]})]})}function c({n:e,children:t}){return(0,o.jsxs)(`li`,{className:`grid grid-cols-[2rem_1fr] gap-3 border-t border-frost pt-3 first:border-t-0 first:pt-0`,children:[(0,o.jsx)(`span`,{className:`text-center font-display text-xl text-sapphire`,children:e}),(0,o.jsx)(`div`,{className:`text-[0.92em] leading-relaxed text-mocha`,children:t})]})}export{s as component};
1
+ import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{Y as t}from"./index-Bq2zrG2_.js";import{i as n,n as r,r as i}from"./Page-NV96O47A.js";var a=t(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),o=e();function s(){return(0,o.jsxs)(i,{size:`narrow`,children:[(0,o.jsx)(r,{eyebrow:`First run`,title:`Welcome to bazilion`,description:`Configure one model provider to prepare your defaults, then test it before the first conversation.`}),(0,o.jsxs)(n,{title:`Three steps to your first conversation`,children:[(0,o.jsxs)(`p`,{className:`text-sm leading-6 text-muted-foreground`,children:[`Before you can spawn agents, enable a provider and save at least one concrete model id. Bazilion then creates a `,(0,o.jsx)(`code`,{children:`default`}),` Agent template and `,(0,o.jsx)(`code`,{children:`default`}),` Team. Send the small connection test before relying on that model.`]}),(0,o.jsxs)(`ol`,{className:`my-5 space-y-4`,children:[(0,o.jsxs)(c,{n:1,children:[(0,o.jsx)(`strong`,{children:`Choose a provider.`}),` Head to the`,` `,(0,o.jsx)(`a`,{href:`/config`,children:`providers tab`}),`, pick a provider, and set credentials or a local endpoint if that provider needs one. Local providers like Ollama and LM Studio can use their default loopback URLs.`]}),(0,o.jsxs)(c,{n:2,children:[(0,o.jsx)(`strong`,{children:`Enable it and save a model.`}),` Flip the provider's toggle on, then click a catalog chip or type one exact model id (for example`,` `,(0,o.jsx)(`code`,{children:`claude-opus-5`}),`, `,(0,o.jsx)(`code`,{children:`gpt-6-astra`}),`, or `,(0,o.jsx)(`code`,{children:`llama3.3`}),`) and press `,(0,o.jsx)(`em`,{children:`save models`}),`.`]}),(0,o.jsxs)(c,{n:3,children:[(0,o.jsx)(`strong`,{children:`Verify and spawn.`}),` Send the short real-model test. When setup is configured, the page gives you a direct action to spawn the first agent from the`,` `,(0,o.jsx)(`code`,{children:`default`}),` template.`]})]}),(0,o.jsxs)(`a`,{href:`/config`,className:`btn-primary no-underline`,children:[`Configure providers `,(0,o.jsx)(a,{className:`h-4 w-4`,"aria-hidden":`true`})]})]})]})}function c({n:e,children:t}){return(0,o.jsxs)(`li`,{className:`grid grid-cols-[2rem_1fr] gap-3 border-t border-frost pt-3 first:border-t-0 first:pt-0`,children:[(0,o.jsx)(`span`,{className:`text-center font-display text-xl text-sapphire`,children:e}),(0,o.jsx)(`div`,{className:`text-[0.92em] leading-relaxed text-mocha`,children:t})]})}export{s as component};
@@ -1 +1 @@
1
- import{Y as e}from"./index-BUhhk_u9.js";var t=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),n=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{t as n,n as t};
1
+ import{Y as e}from"./index-Bq2zrG2_.js";var t=e(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),n=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{t as n,n as t};
@@ -4,6 +4,173 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffec
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import DOMPurify from "dompurify";
6
6
  import { marked } from "marked";
7
+ //#region src/lib/coding-presentation.ts
8
+ /** Presentation only: excerpts are never used for authorization or receipt validity. */
9
+ function codingFailureSummary(diagnostic) {
10
+ const error = diagnostic.split("\n").map((line) => line.trim()).find((line) => /^(?:[A-Za-z]*Error(?: \[[A-Z_]+\])?:|ERR_[A-Z_]+\b)/.test(line));
11
+ if (!error) return null;
12
+ return error.length > 240 ? `${error.slice(0, 237)}…` : error;
13
+ }
14
+ function inboxUpdateLabel(body) {
15
+ const header = body.split("\n").find((line) => line.startsWith("--- from "));
16
+ if (!header) return "Teammate update received";
17
+ const match = /^--- from (.+?) \(message [0-9a-f-]+(?:, reply to [0-9a-f-]+)?\) ---$/.exec(header);
18
+ if (!match) return "Teammate update received";
19
+ const name = match[1]?.replace(/ \([0-9a-f-]{36}\)$/, "").trim();
20
+ if (!name || /^[0-9a-f-]{36}$/.test(name)) return "Teammate update received";
21
+ return `Update from ${name.slice(0, 100)}`;
22
+ }
23
+ //#endregion
24
+ //#region src/components/CodingToolResult.tsx
25
+ /** Presents only already-authorized chat text; never fetches private receipt records. */
26
+ function CodingToolResult({ name, body, pending = false }) {
27
+ if (!pending && body === "Coding context or command evidence retained privately. Captured transport output follows its communication approval; ask the Agent for the relevant result.") return /* @__PURE__ */ jsxs("details", {
28
+ className: "py-1 text-xs font-sans",
29
+ "aria-label": "Private command details",
30
+ children: [/* @__PURE__ */ jsx("summary", {
31
+ className: "cursor-pointer",
32
+ children: "Detailed output isn’t included in this history view"
33
+ }), /* @__PURE__ */ jsx("p", {
34
+ className: "mt-1",
35
+ children: "The Agent’s summary is shown in the conversation. Ask the Agent to summarize its retained command result if you need more detail."
36
+ })]
37
+ });
38
+ let parsed;
39
+ try {
40
+ parsed = JSON.parse(body);
41
+ } catch {
42
+ return /* @__PURE__ */ jsx("span", { children: body });
43
+ }
44
+ if (!parsed || typeof parsed !== "object") return /* @__PURE__ */ jsx("span", { children: body });
45
+ if (pending) {
46
+ const input = parsed;
47
+ return /* @__PURE__ */ jsxs("p", {
48
+ className: "py-1 break-words",
49
+ children: [
50
+ name === "coding_command" ? "Running" : "Inspecting",
51
+ ":",
52
+ " ",
53
+ typeof input.command === "string" ? input.command : typeof input.target === "string" ? input.target : "command evidence"
54
+ ]
55
+ });
56
+ }
57
+ if (name === "repository_context") {
58
+ const report = parsed;
59
+ if (!Array.isArray(report.instructions?.files)) return /* @__PURE__ */ jsx("span", { children: body });
60
+ return /* @__PURE__ */ jsxs("details", {
61
+ className: "py-1",
62
+ children: [
63
+ /* @__PURE__ */ jsxs("summary", {
64
+ className: "cursor-pointer",
65
+ children: [
66
+ "Repository: ",
67
+ report.target,
68
+ " ·",
69
+ " ",
70
+ report.instructions.state === "complete" ? `${report.instructions.files.length} instruction files` : "instructions unavailable"
71
+ ]
72
+ }),
73
+ report.instructions.files.map((file) => /* @__PURE__ */ jsx("p", { children: file.path }, file.path)),
74
+ /* @__PURE__ */ jsxs("p", { children: [
75
+ report.commands?.candidates?.length ?? 0,
76
+ " suggested commands ·",
77
+ " ",
78
+ report.git?.state === "available" ? report.git.branch : "Git unavailable"
79
+ ] }),
80
+ /* @__PURE__ */ jsx("pre", {
81
+ className: "max-h-64 overflow-auto whitespace-pre-wrap break-words",
82
+ children: body
83
+ })
84
+ ]
85
+ });
86
+ }
87
+ if (name === "coding_environment") {
88
+ const value = parsed;
89
+ if (typeof value.posture !== "string") return /* @__PURE__ */ jsx("span", { children: body });
90
+ return /* @__PURE__ */ jsxs("details", {
91
+ className: "py-1",
92
+ children: [
93
+ /* @__PURE__ */ jsxs("summary", {
94
+ className: "cursor-pointer",
95
+ children: [
96
+ "Environment: ",
97
+ value.posture,
98
+ " · ",
99
+ value.cwd
100
+ ]
101
+ }),
102
+ /* @__PURE__ */ jsx("p", {
103
+ className: "break-all",
104
+ children: value.imageId ?? "Host runtime"
105
+ }),
106
+ Array.isArray(value.restrictions) && value.restrictions.filter((x) => typeof x === "string").map((text) => /* @__PURE__ */ jsx("p", { children: text }, text))
107
+ ]
108
+ });
109
+ }
110
+ const view = parsed;
111
+ const receipt = name === "coding_receipt" ? view.receipt : parsed;
112
+ if (!receipt || typeof receipt.state !== "string" || typeof receipt.input?.command !== "string" || typeof receipt.input?.cwd !== "string") return /* @__PURE__ */ jsx("span", { children: body });
113
+ const failure = receipt.state === "failed" && typeof receipt.diagnostic === "string" ? codingFailureSummary(receipt.diagnostic) : null;
114
+ return /* @__PURE__ */ jsxs("div", {
115
+ className: "py-2",
116
+ "aria-label": "Coding command result",
117
+ children: [
118
+ /* @__PURE__ */ jsxs("p", {
119
+ className: "font-sans",
120
+ children: [
121
+ /* @__PURE__ */ jsx("strong", {
122
+ className: receipt.state === "succeeded" ? "text-sapphire-deep" : "text-mocha",
123
+ children: receipt.state.replaceAll("_", " ")
124
+ }),
125
+ " ",
126
+ "· ",
127
+ receipt.input.purpose,
128
+ typeof receipt.exitCode === "number" ? ` · exit ${receipt.exitCode}` : "",
129
+ name === "coding_receipt" ? ` · ${view.applicability}` : ""
130
+ ]
131
+ }),
132
+ /* @__PURE__ */ jsx("p", {
133
+ className: "whitespace-pre-wrap break-words",
134
+ children: receipt.input.command
135
+ }),
136
+ /* @__PURE__ */ jsxs("p", {
137
+ className: "text-xs",
138
+ children: [
139
+ receipt.input.cwd,
140
+ " · ",
141
+ receipt.environment?.posture,
142
+ " · result at execution time"
143
+ ]
144
+ }),
145
+ failure && /* @__PURE__ */ jsx("p", {
146
+ className: "mt-1 font-sans text-rose-baziu",
147
+ "aria-label": "Command failure summary",
148
+ children: failure
149
+ }),
150
+ typeof receipt.reason === "string" && /* @__PURE__ */ jsx("p", { children: receipt.reason }),
151
+ /* @__PURE__ */ jsxs("details", { children: [
152
+ /* @__PURE__ */ jsx("summary", {
153
+ className: "cursor-pointer",
154
+ children: "Output and evidence"
155
+ }),
156
+ /* @__PURE__ */ jsx("pre", {
157
+ className: "max-h-64 overflow-auto whitespace-pre-wrap break-words",
158
+ children: receipt.diagnostic
159
+ }),
160
+ receipt.truncated && /* @__PURE__ */ jsx("p", { children: "Output truncated." }),
161
+ /* @__PURE__ */ jsxs("p", {
162
+ className: "break-all",
163
+ children: ["coding-receipt:", receipt.id]
164
+ }),
165
+ receipt.environment?.imageId && /* @__PURE__ */ jsx("p", {
166
+ className: "break-all",
167
+ children: receipt.environment.imageId
168
+ })
169
+ ] })
170
+ ]
171
+ });
172
+ }
173
+ //#endregion
7
174
  //#region src/lib/md.ts
8
175
  var installed = false;
9
176
  function install() {
@@ -1117,6 +1284,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
1117
1284
  const markdownReady = useSyncExternalStore(subscribeToHydration, browserMarkdownReady, serverMarkdownReady);
1118
1285
  const [serverMessages, setServerMessages] = useState(initialMessages);
1119
1286
  const [liveEntries, setLiveEntries] = useState([]);
1287
+ const deliveredCoding = useRef(/* @__PURE__ */ new Map());
1120
1288
  const [systemBubbles, setSystemBubbles] = useState([]);
1121
1289
  const [thinking, setThinking] = useState(false);
1122
1290
  const [streaming, setStreaming] = useState(false);
@@ -1154,6 +1322,7 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
1154
1322
  currentAbortRef.current?.abort();
1155
1323
  currentAbortRef.current = null;
1156
1324
  commandApprovalTurnRef.current = false;
1325
+ deliveredCoding.current.clear();
1157
1326
  setServerMessages(initialMessages);
1158
1327
  setLiveEntries([]);
1159
1328
  setSystemBubbles([]);
@@ -1691,6 +1860,15 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
1691
1860
  name: ev.name,
1692
1861
  body: ev.error
1693
1862
  };
1863
+ if (ev.type === "tool_result" && [
1864
+ "repository_context",
1865
+ "coding_environment",
1866
+ "coding_command",
1867
+ "coding_receipt"
1868
+ ].includes(ev.name)) {
1869
+ deliveredCoding.current.set(`${ev.name}:${ev.id}`, ev.result);
1870
+ while (deliveredCoding.current.size > 20) deliveredCoding.current.delete(deliveredCoding.current.keys().next().value);
1871
+ }
1694
1872
  const images = ev.type === "tool_result" ? ev.images : void 0;
1695
1873
  setLiveEntries((prev) => {
1696
1874
  const next = [...prev];
@@ -1802,7 +1980,14 @@ function ChatPane({ agentId, agentName, initialMessages, initialSessionHead }) {
1802
1980
  send(input);
1803
1981
  }
1804
1982
  }
1805
- const baseEntries = projectMessages(serverMessages);
1983
+ const baseEntries = projectMessages(serverMessages.map((message) => {
1984
+ if (message.role !== "tool" || !message.toolCallId || !message.toolName) return message;
1985
+ const body = deliveredCoding.current.get(`${message.toolName}:${message.toolCallId}`);
1986
+ return body === void 0 ? message : {
1987
+ ...message,
1988
+ content: body
1989
+ };
1990
+ }));
1806
1991
  visibleEntryCountRef.current = baseEntries.length + liveEntries.length;
1807
1992
  const lastUserIdx = (() => {
1808
1993
  if (liveEntries.length > 0 || turnBusy) return -1;
@@ -2108,15 +2293,23 @@ function Bubble({ entry, markdownReady, isLastUser, isWillDrop, onEdit, onComman
2108
2293
  if (entry.type === "user") {
2109
2294
  if (entry.content.startsWith(INBOX_WAKE_PREFIX)) {
2110
2295
  const body = entry.content.slice(24);
2111
- return /* @__PURE__ */ jsxs("div", {
2112
- className: `my-4 flex flex-col items-end ${dropCls}`,
2113
- children: [/* @__PURE__ */ jsx("span", {
2114
- className: "mb-1 text-[0.72em] font-semibold uppercase tracking-wider text-mocha opacity-90",
2115
- children: "inbox"
2116
- }), /* @__PURE__ */ jsx("div", {
2117
- className: "bubble-content max-w-[85%] whitespace-pre-wrap break-words rounded-[14px_14px_4px_14px] border border-fawn border-l-[3px] border-l-mocha-light bg-ivory px-3 py-2 font-mono text-[0.88em] leading-[1.5] text-mocha",
2118
- children: body
2119
- })]
2296
+ return /* @__PURE__ */ jsxs("details", {
2297
+ className: `my-3 rounded-lg border border-fawn bg-ivory px-3 py-2 text-sm text-mocha ${dropCls}`,
2298
+ "aria-label": "Teammate update",
2299
+ children: [
2300
+ /* @__PURE__ */ jsx("summary", {
2301
+ className: "cursor-pointer font-medium",
2302
+ children: inboxUpdateLabel(body)
2303
+ }),
2304
+ /* @__PURE__ */ jsx("p", {
2305
+ className: "mt-2 text-xs",
2306
+ children: "Original message and Agent instructions"
2307
+ }),
2308
+ /* @__PURE__ */ jsx("pre", {
2309
+ className: "mt-1 max-h-64 overflow-auto whitespace-pre-wrap break-words text-xs",
2310
+ children: body
2311
+ })
2312
+ ]
2120
2313
  });
2121
2314
  }
2122
2315
  return /* @__PURE__ */ jsxs("div", {
@@ -2355,6 +2548,15 @@ function commandApprovalStatusFromConflict(message) {
2355
2548
  }
2356
2549
  }
2357
2550
  function ToolGroup({ items, dropCls }) {
2551
+ const codingNames = [
2552
+ "repository_context",
2553
+ "coding_command",
2554
+ "coding_environment",
2555
+ "coding_receipt",
2556
+ "send_message"
2557
+ ];
2558
+ const hasCoding = items.some((item) => codingNames.includes(item.name));
2559
+ const visibleItems = items.filter((item) => !(item.kind === "call" && codingNames.includes(item.name) && items.some((other) => other.id === item.id && other.kind !== "call")));
2358
2560
  const [expanded, setExpanded] = useState(false);
2359
2561
  const contentRef = useRef(null);
2360
2562
  const [overflows, setOverflows] = useState(false);
@@ -2368,12 +2570,12 @@ function ToolGroup({ items, dropCls }) {
2368
2570
  children: [/* @__PURE__ */ jsxs("div", {
2369
2571
  ref: contentRef,
2370
2572
  className: "relative overflow-hidden",
2371
- style: { maxHeight: expanded ? "none" : `${TOOL_GROUP_MAX_HEIGHT_PX}px` },
2372
- children: [items.map((it, i) => /* @__PURE__ */ jsx(ToolLine, { item: it }, i)), overflows && !expanded && /* @__PURE__ */ jsx("div", {
2573
+ style: { maxHeight: expanded || hasCoding ? "none" : `${TOOL_GROUP_MAX_HEIGHT_PX}px` },
2574
+ children: [visibleItems.map((it, i) => /* @__PURE__ */ jsx(ToolLine, { item: it }, i)), overflows && !expanded && !hasCoding && /* @__PURE__ */ jsx("div", {
2373
2575
  className: "pointer-events-none absolute inset-x-0 bottom-0 h-10",
2374
2576
  style: { background: "linear-gradient(to bottom, rgba(247,240,229,0), var(--color-ivory))" }
2375
2577
  })]
2376
- }), overflows && /* @__PURE__ */ jsx("button", {
2578
+ }), overflows && !hasCoding && /* @__PURE__ */ jsx("button", {
2377
2579
  type: "button",
2378
2580
  onClick: () => setExpanded((v) => !v),
2379
2581
  className: "mt-2 rounded-sm border border-fawn bg-transparent px-2 py-0.5 text-[0.9em] text-mocha hover:border-sapphire hover:text-sapphire-deep",
@@ -2382,6 +2584,26 @@ function ToolGroup({ items, dropCls }) {
2382
2584
  });
2383
2585
  }
2384
2586
  function ToolLine({ item }) {
2587
+ if (item.name === "send_message" && item.kind !== "error") return /* @__PURE__ */ jsxs("details", {
2588
+ className: "py-1 font-sans text-sm",
2589
+ children: [/* @__PURE__ */ jsx("summary", {
2590
+ className: "cursor-pointer",
2591
+ children: item.kind === "call" ? "Sending teammate message…" : item.body.startsWith("sent message ") ? "Teammate message sent" : "Teammate message status"
2592
+ }), /* @__PURE__ */ jsx("pre", {
2593
+ className: "mt-1 max-h-64 overflow-auto whitespace-pre-wrap break-words text-xs",
2594
+ children: item.body
2595
+ })]
2596
+ });
2597
+ if (item.kind !== "error" && [
2598
+ "repository_context",
2599
+ "coding_command",
2600
+ "coding_environment",
2601
+ "coding_receipt"
2602
+ ].includes(item.name)) return /* @__PURE__ */ jsx(CodingToolResult, {
2603
+ name: item.name,
2604
+ body: item.body,
2605
+ pending: item.kind === "call"
2606
+ });
2385
2607
  if (item.kind === "call") {
2386
2608
  const args = prettyArgs(item.body);
2387
2609
  const multiLine = args.includes("\n");
@@ -1,5 +1,5 @@
1
1
  import { t as Button } from "./Button-Dsnw22OF.js";
2
- import { n as ResultTranscript } from "./ChatPane-DJ30FdFG.js";
2
+ import { n as ResultTranscript } from "./ChatPane-CS5oI7ef.js";
3
3
  import { useEffect, useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region src/components/ResultSourceConversation.tsx
@@ -2,7 +2,7 @@ import { n as createServerFn } from "../server.js";
2
2
  import { t as createSsrRpc } from "./createSsrRpc-6LHNEsSK.js";
3
3
  import { createFileRoute, lazyRouteComponent, redirect } from "@tanstack/react-router";
4
4
  //#region src/routes/agents/$id/index.tsx
5
- var $$splitComponentImporter = () => import("./_id-1hTvnKLN2.js");
5
+ var $$splitComponentImporter = () => import("./_id-BnqodC1c2.js");
6
6
  var fetchAgent = createServerFn({ method: "POST" }).validator((d) => d).handler(createSsrRpc("846c9081aed17057351730985f133b0aab67a5dabfca9562552829a90ff30849"));
7
7
  var Route = createFileRoute("/agents/$id/")({
8
8
  validateSearch: (search) => ({
@@ -1,6 +1,6 @@
1
1
  import { n as createServerFn } from "../server.js";
2
2
  import { t as createServerRpc } from "./createServerRpc-B7Yr1K8i.js";
3
- import { n as daemonClient, r as ApiClientError } from "./daemon-client-B06W1Qa2.js";
3
+ import { n as daemonClient, r as ApiClientError } from "./daemon-client-xWyYKAcx.js";
4
4
  //#region src/routes/agents/$id/index.tsx?tss-serverfn-split
5
5
  var fetchAgent_createServerFn_handler = createServerRpc({
6
6
  id: "846c9081aed17057351730985f133b0aab67a5dabfca9562552829a90ff30849",