@kky42/pievo-server 2.2.0 → 2.3.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 (73) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{LoopView-BTXoqfzM.js → LoopView-DjVHUyrR.js} +1 -1
  3. package/.output/public/assets/{Modal-Ba36NAkv.js → Modal-CCRvx959.js} +1 -1
  4. package/.output/public/assets/{SignIn-Cc1zxGnA.js → SignIn-Qxw5zDFq.js} +1 -1
  5. package/.output/public/assets/{actionUi-DDDfD0WX.js → actionUi-CXxhzYe2.js} +1 -1
  6. package/.output/public/assets/{index-BGM1XGY0.js → index-BRN_CQ8U.js} +4 -4
  7. package/.output/public/assets/{invite._token-CUCNcN89.js → invite._token-BIxr8DlP.js} +1 -1
  8. package/.output/public/assets/{invite._token-C3t4JfAY.js → invite._token-j2BTCeG1.js} +1 -1
  9. package/.output/public/assets/lifecycleUi-Qy_8beQK.js +1 -0
  10. package/.output/public/assets/{loops._loopId-CrSSvSVl.js → loops._loopId-BRBQzioy.js} +3 -3
  11. package/.output/public/assets/{loops._loopId_.runs._runId-B5Qacloe.js → loops._loopId_.runs._runId-CMnOJkem.js} +2 -2
  12. package/.output/public/assets/{notifyFns-CYiZT7CK.js → notifyFns-DYD4EKaG.js} +1 -1
  13. package/.output/public/assets/{routes-DsdcURfk.js → routes-3nuEJGdo.js} +1 -1
  14. package/.output/public/assets/{routes-B6Kg4mFC.js → routes-DORLim-C.js} +1 -1
  15. package/.output/public/assets/{t._teamId-Cmm4xdKj.js → t._teamId-F5f4K8kd.js} +1 -1
  16. package/.output/public/assets/{t._teamId-C9uEyAh_.js → t._teamId-XfE_S1Fo.js} +1 -1
  17. package/.output/public/assets/ui-Dhsx6SW0.js +1 -0
  18. package/.output/server/_ssr/{DashboardView-0yoKh8Em.mjs → DashboardView-BF7PciP7.mjs} +9 -6
  19. package/.output/server/_ssr/{LoopPlaybook-uq_sFfgU.mjs → LoopPlaybook-DC7QVvPY.mjs} +2 -2
  20. package/.output/server/_ssr/{LoopView-BlOY-jfJ.mjs → LoopView-DwSrm9Ja.mjs} +4 -4
  21. package/.output/server/_ssr/{Modal-Bc_5TYGr.mjs → Modal-MaCG52Pv.mjs} +2 -2
  22. package/.output/server/_ssr/{SignIn-C4fSJl_j.mjs → SignIn-RmpWm9uy.mjs} +3 -3
  23. package/.output/server/_ssr/{actionUi-BKF6xI3d.mjs → actionUi-BN55TNYE.mjs} +2 -2
  24. package/.output/server/_ssr/{adapters-RReIIwAx.mjs → adapters-BoLkOf1T.mjs} +12 -6
  25. package/.output/server/_ssr/{artifactFiles-C8PQKN6V.mjs → artifactFiles-BCaIIrrT.mjs} +3 -3
  26. package/.output/server/_ssr/artifacts-jQ-bfdhI.mjs +2 -0
  27. package/.output/server/_ssr/{auth-Sie6sQHF.mjs → auth-30Z4lV1w.mjs} +9 -9
  28. package/.output/server/_ssr/{boot-akwC2sQg.mjs → boot-3BNKujyp.mjs} +75 -26
  29. package/.output/server/_ssr/{boot-pVS0wjd0.mjs → boot-CsEFT53K.mjs} +1 -1
  30. package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CLY8cORt.mjs → bun-sqlite-dialect-BW9W1_Ps-_7tfuNRi.mjs} +2 -2
  31. package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-CRsXQNRe.mjs → d1-sqlite-dialect-BLC8LXE6-ucDUbeBk.mjs} +2 -2
  32. package/.output/server/_ssr/db-CXownd1H.mjs +2 -0
  33. package/.output/server/_ssr/{dist-Cc_x6bBb.mjs → dist-Cd6nlLlO.mjs} +2 -2
  34. package/.output/server/_ssr/{factory-CDwHL_zY.mjs → factory-CWWwV7XZ.mjs} +2 -2
  35. package/.output/server/_ssr/{invite._token-BE_QUAVb.mjs → invite._token-BKlz0R2f.mjs} +4 -4
  36. package/.output/server/_ssr/{invite._token-BlbVjz-o.mjs → invite._token-CWl6kipD.mjs} +2 -2
  37. package/.output/server/_ssr/{invite._token-C7GjrJxr.mjs → invite._token-SdWXemIc.mjs} +5 -5
  38. package/.output/server/_ssr/{kysely-adapter-zflsyYBA.mjs → kysely-adapter-C8iS51DB.mjs} +1 -1
  39. package/.output/server/_ssr/{lifecycleUi-Djb44Aj3.mjs → lifecycleUi-DgBQAYzp.mjs} +2 -1
  40. package/.output/server/_ssr/logger-Gy-47z3k.mjs +2 -0
  41. package/.output/server/_ssr/{loopApi-JzmqWENY.mjs → loopApi-ABi9SgWS.mjs} +12 -12
  42. package/.output/server/_ssr/{loops._loopId-DZ-FjscA.mjs → loops._loopId-SON_t43g.mjs} +3 -3
  43. package/.output/server/_ssr/{loops._loopId-D-aCCtrX.mjs → loops._loopId-p1KWsvMM.mjs} +10 -10
  44. package/.output/server/_ssr/{loops._loopId_.runs._runId-rBHW41dx.mjs → loops._loopId_.runs._runId-PUGBrD5q.mjs} +14 -8
  45. package/.output/server/_ssr/{loops._loopId_.runs._runId-Dk1QY49p.mjs → loops._loopId_.runs._runId-Ymy4lwee.mjs} +3 -3
  46. package/.output/server/_ssr/{machineFns-CoqLRLRh.mjs → machineFns-BZ9puxDt.mjs} +3 -3
  47. package/.output/server/_ssr/{node-sqlite-dialect-dmrazfbM.mjs → node-sqlite-dialect-D_3JmkMo.mjs} +2 -2
  48. package/.output/server/_ssr/{notifyFns-CH7-bcmd.mjs → notifyFns-BUCePuF3.mjs} +3 -3
  49. package/.output/server/_ssr/{notifyFns-DXMbgYu2.mjs → notifyFns-DuPR1zd7.mjs} +5 -5
  50. package/.output/server/_ssr/{router-BFPzSTFx.mjs → router-Czxvra6l.mjs} +38 -32
  51. package/.output/server/_ssr/{routes-DebVUmCS.mjs → routes-ClZEdsnB.mjs} +5 -5
  52. package/.output/server/_ssr/{routes-Bx0bRxt9.mjs → routes-ComqHvCL.mjs} +2 -2
  53. package/.output/server/_ssr/{routes-dQCBLTxY.mjs → routes-D5jJJ-30.mjs} +5 -5
  54. package/.output/server/_ssr/runDiff--qLtU4FI.mjs +2 -0
  55. package/.output/server/_ssr/ssr.mjs +49 -49
  56. package/.output/server/_ssr/store-40eVzW1S.mjs +2 -0
  57. package/.output/server/_ssr/{t._teamId-BzWy4Ft2.mjs → t._teamId-BgHV_KFP.mjs} +5 -5
  58. package/.output/server/_ssr/{t._teamId-D9nCEa2h.mjs → t._teamId-DDERNgfn.mjs} +2 -2
  59. package/.output/server/_ssr/{t._teamId-BqOUF-0J.mjs → t._teamId-DRJvKHZn.mjs} +5 -5
  60. package/.output/server/_ssr/{teamFns-BcnGMC-g.mjs → teamFns-Bp81UO-x.mjs} +3 -3
  61. package/.output/server/_ssr/tokens-CbfoRC_s.mjs +2 -0
  62. package/.output/server/_ssr/{ui-B6mE5-5v.mjs → ui-Ww2tTM2u.mjs} +9 -2
  63. package/.output/server/{_tanstack-start-manifest_v-COr27bxK.mjs → _tanstack-start-manifest_v-DwKENYCN.mjs} +25 -25
  64. package/.output/server/index.mjs +100 -100
  65. package/package.json +1 -1
  66. package/.output/public/assets/lifecycleUi-CMFw5Nlj.js +0 -1
  67. package/.output/public/assets/ui-Gb1413-F.js +0 -1
  68. package/.output/server/_ssr/artifacts-B_F6vSih.mjs +0 -2
  69. package/.output/server/_ssr/db-Bdm9PFZF.mjs +0 -2
  70. package/.output/server/_ssr/logger-tfiliKTi.mjs +0 -2
  71. package/.output/server/_ssr/runDiff-qA1C8R_L.mjs +0 -2
  72. package/.output/server/_ssr/store-DWUdkIq2.mjs +0 -2
  73. package/.output/server/_ssr/tokens-DG8z1GIg.mjs +0 -2
@@ -0,0 +1 @@
1
+ import{n as e,s as t,t as n}from"./jsx-runtime-BseJUIpC.js";var r=t(e(),1),i=e=>e?new Date(e).toLocaleString():`—`,a=e=>{if(!e)return``;let t=Math.round((Date.now()-Date.parse(e))/1e3);if(t<60)return`${t}s ago`;let n=Math.round(t/60);if(n<60)return`${n}m ago`;let r=Math.round(n/60);return r<24?`${r}h ago`:`${Math.round(r/24)}d ago`},o=[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`];function s(e){let t=(e||``).trim().split(/\s+/);if(t.length!==5)return e;let[n,r,i,a,s]=t,c=i===`*`&&a===`*`,l=r.match(/^\*\/(\d+)$/);if(l&&c&&s===`*`)return`every ${l[1]}h`;let u=n.match(/^\*\/(\d+)$/);if(u&&r===`*`&&c&&s===`*`)return`every ${u[1]}m`;if(r===`*`&&/^\d+$/.test(n)&&c&&s===`*`)return`hourly :${n.padStart(2,`0`)}`;if(/^\d+$/.test(n)&&/^\d+$/.test(r)&&c){let e=`${r.padStart(2,`0`)}:${n.padStart(2,`0`)}`;if(s===`*`)return`daily ${e}`;if(/^[0-6]$/.test(s))return`${o[Number(s)]} ${e}`}return e}var c=e=>{if(!e)return``;let t=Math.round((Date.parse(e)-Date.now())/1e3);if(t<=0)return`due`;let n=Math.round(t/60);if(n<60)return`in ${n}m`;let r=Math.round(n/60);return r<24?`in ${r}h`:`in ${Math.round(r/24)}d`},l=e=>{let t=new Date(e);return`${t.getMonth()+1}/${t.getDate()}`},u=e=>{if(!e)return`—`;let t=new Date(e),n=e=>String(e).padStart(2,`0`);return`${n(t.getMonth()+1)}/${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`},d=e=>Math.abs(e)>=1e3?`${Math.round(e/100)/10}k`:`${Math.round(e*100)/100}`,f=e=>e?`${Math.round(e/1e3)}s`:``;function p(e){let t=Math.abs(e);return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}var m={kept:{c:`var(--color-run-kept)`,label:`Kept`},"no-change":{c:`var(--color-run-no-change)`,label:`No change`},blocked:{c:`var(--color-run-blocked)`,label:`Blocked`},error:{c:`var(--color-run-error)`,label:`Error`},warning:{c:`var(--color-run-warning)`,label:`Missing status`},canceled:{c:`var(--color-run-canceled)`,label:`Canceled`},queued:{c:`var(--color-run-queued)`,label:`Queued`},reconciling:{c:`var(--color-run-warning)`,label:`Reconciling…`},"active-exec":{c:`var(--color-run-active-exec)`,label:`Running…`},"active-steer":{c:`var(--color-run-active-steer)`,label:`Steering…`},"active-evolve":{c:`var(--color-run-active-evolve)`,label:`Evolving…`}},h=e=>e===`kept`||e===`no-change`||e===`blocked`?m[e]:void 0,g=e=>e.role===`steer`?`steer`:e.role===`evolve`?`evolve`:`exec`,_=e=>g(e)===`steer`?`Steered`:g(e)===`evolve`?`Improved`:`Kept`;function v(e){return e.reconciliation?m.reconciling.c:e.running?m[`active-${g(e)}`].c:e.status===`blocked`?m.blocked.c:e.queued?m.queued.c:e.phase===`error`?m.error.c:e.canceled||e.phase===`canceled`?m.canceled.c:e.phase===`done`&&!h(e.status)?m.warning.c:(h(e.status)??m[`no-change`]).c}function y(e){return e.reconciliation||e.running||e.status===`blocked`||e.phase===`error`?1:e.queued?.7:e.canceled||e.phase===`canceled`?.5:e.phase===`done`&&!h(e.status)?.9:e.status===`no-change`?.55:1}function b(e){return e.reconciliation===`blocking`?`Waiting for machine recovery`:e.reconciliation===`report-only`?`Awaiting late report`:e.queued?m.queued.label:e.running?e.cancelRequested?`Stopping…`:m[`active-${g(e)}`].label:e.status===`blocked`?m.blocked.label:e.phase===`error`?e.cancelRequested?`Failed while stopping`:m.error.label:e.canceled||e.phase===`canceled`?(e.error,`Canceled`):e.cancelRequested&&e.phase===`done`?`Succeeded while stopping`:e.status===`kept`?_(e):e.status===`no-change`?m[`no-change`].label:e.phase===`done`?m.warning.label:m[`no-change`].label}var x=e=>{let t=e.runs??[];return t.length?t[t.length-1]:null},S=n(),C=()=>()=>{},w=()=>(0,r.useSyncExternalStore)(C,()=>!0,()=>!1),T=`focus-visible:outline-none focus-visible:shadow-focus`,E=`inline-flex cursor-pointer items-center gap-1.5 rounded-control px-4 py-2 text-body font-medium transition-colors duration-150 disabled:cursor-default disabled:opacity-40 ${T}`,D=`${E} border border-wire bg-surface text-primary hover:bg-raised`,O=`${E} border border-display bg-display text-paper hover:opacity-85`,k=`${E} border border-transparent bg-rubik-red text-white hover:opacity-85`,A=`${E} border border-display bg-transparent text-display hover:bg-[color:var(--color-display)]/8`,j=`inline-flex shrink-0 cursor-pointer items-center gap-1 rounded-full border border-wire bg-surface px-3 py-1 text-label font-medium text-primary transition-colors duration-150 hover:bg-raised disabled:cursor-default disabled:opacity-40 ${T}`,M=`inline-flex shrink-0 cursor-pointer items-center gap-1.5 rounded-full border border-display bg-display px-4 py-2 text-body font-medium text-paper transition-colors duration-150 hover:opacity-85 disabled:cursor-default disabled:opacity-40 ${T}`,N=`inline-flex cursor-pointer items-center gap-1.5 border-none bg-transparent p-0 text-meta font-medium text-secondary transition-colors hover:text-display`,P=`text-label font-semibold text-secondary`,F=`mb-1.5 mt-3 block text-label font-medium text-secondary`,I=`w-full rounded-control border border-wire bg-surface px-3 py-2.5 text-sm text-primary outline-none transition-shadow focus:border-transparent focus:shadow-focus`,L=`${I} lp-select cursor-pointer`,R={animation:`runPulse 1.1s ease-in-out infinite`},z={background:`var(--color-rubik-yellow)`,...R};function B({message:e,onDismiss:t,className:n=`mb-2`}){return(0,S.jsxs)(`div`,{className:`flex items-start gap-2 text-body text-accent ${n}`,children:[(0,S.jsx)(`span`,{className:`mt-[5px] size-2 shrink-0 rounded-full bg-rubik-red`,"aria-hidden":!0}),(0,S.jsx)(`span`,{children:e}),t&&(0,S.jsx)(`button`,{type:`button`,onClick:t,className:`ml-auto shrink-0 cursor-pointer border-none bg-transparent p-0 text-label text-secondary transition-colors hover:text-display`,children:`Dismiss`})]})}function V({children:e}){return(0,S.jsx)(`pre`,{className:`max-h-[300px] overflow-auto whitespace-pre-wrap rounded-control border border-hairline bg-raised px-4 py-3.5 font-mono text-meta leading-relaxed text-secondary`,children:e})}var H={neutral:`bg-raised text-secondary`,ink:`bg-raised text-primary`,outline:`border border-hairline text-secondary`,running:`bg-running-soft text-running`,success:`bg-success-soft text-success`,accent:`bg-accent-soft text-accent`,warn:`bg-warn-soft text-warn`};function U({tone:e=`neutral`,dot:t,title:n,children:r}){return(0,S.jsxs)(`span`,{title:n,className:`inline-flex h-[22px] items-center gap-1.5 rounded-full px-2.5 text-caption font-medium ${H[e]}`,children:[t&&(0,S.jsx)(`span`,{className:`size-1.5 rounded-full`,style:t===`pulse`?z:{background:`var(--color-rubik-green)`}}),r]})}function W({className:e=``}){return(0,S.jsx)(`div`,{className:`text-body text-disabled ${e}`,children:`Loading…`})}function G({run:e,colorText:t}){return(0,S.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 font-medium`,style:t?{color:v(e)}:void 0,children:[(0,S.jsx)(`span`,{className:`size-2 rounded-full`,style:{background:v(e),opacity:y(e)}}),b(e)]})}export{a as A,y as C,p as D,d as E,c as M,x as O,b as S,i as T,P as _,G as a,s as b,k as c,N as d,j as f,z as g,R as h,V as i,u as j,l as k,O as l,F as m,W as n,D as o,I as p,U as r,A as s,B as t,M as u,L as v,f as w,v as x,w as y};
@@ -1,15 +1,15 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react, t as TooltipProvider } from "../_libs/@base-ui/react+[...].mjs";
3
- import { C as lastRunOf, M as useHydrated, S as labelCls, T as rel, c as btnDanger, f as btnSm, h as dotLabel, k as selectCls, l as btnPrimary, o as btn, p as cronText, r as Pill, t as ErrorBanner, u as btnPrimaryPill, x as inputCls } from "./ui-B6mE5-5v.mjs";
3
+ import { C as lastRunOf, M as useHydrated, S as labelCls, T as rel, c as btnDanger, f as btnSm, h as dotLabel, k as selectCls, l as btnPrimary, o as btn, p as cronText, r as Pill, t as ErrorBanner, u as btnPrimaryPill, x as inputCls } from "./ui-Ww2tTM2u.mjs";
4
4
  import { d as useNavigate } from "../_libs/@tanstack/react-router+[...].mjs";
5
5
  import { _ as loadOlderRuns, h as listMyTeams, m as listJobs, n as claimStatus, u as getConfig, v as mintClaim } from "./loopApi-8_KgBapr.mjs";
6
- import { n as ModalHead, r as ModalSection, t as Modal } from "./Modal-Bc_5TYGr.mjs";
7
- import { i as PievoLogo, n as GitHubIcon, r as LoopPlaybook, t as GITHUB_URL } from "./LoopPlaybook-uq_sFfgU.mjs";
6
+ import { n as ModalHead, r as ModalSection, t as Modal } from "./Modal-MaCG52Pv.mjs";
7
+ import { i as PievoLogo, n as GitHubIcon, r as LoopPlaybook, t as GITHUB_URL } from "./LoopPlaybook-DC7QVvPY.mjs";
8
8
  import { t as setActiveTeamCookie } from "./teamCookie-B7hLOIie.mjs";
9
9
  import { a as getTeamDetail, d as revokeTeamInvite, f as setTeamMemberRole, i as deleteTeam, l as removeTeamMember, n as createTeam, o as leaveTeam, r as createTeamInvite, s as listManagedTeams, t as addTeamMember, u as renameTeam } from "./teamFns-bm82twd5.mjs";
10
- import { r as deriveLoopLifecycle } from "./lifecycleUi-Djb44Aj3.mjs";
11
- import { a as listChannels, c as testChannel, i as deleteChannel, n as Timeline, o as listMachines, r as createChannel, s as mergeRuns, t as MachinesModal } from "./notifyFns-DXMbgYu2.mjs";
12
- //#region node_modules/.nitro/vite/services/ssr/assets/DashboardView-0yoKh8Em.js
10
+ import { r as deriveLoopLifecycle } from "./lifecycleUi-DgBQAYzp.mjs";
11
+ import { a as listChannels, c as testChannel, i as deleteChannel, n as Timeline, o as listMachines, r as createChannel, s as mergeRuns, t as MachinesModal } from "./notifyFns-DuPR1zd7.mjs";
12
+ //#region node_modules/.nitro/vite/services/ssr/assets/DashboardView-BF7PciP7.js
13
13
  var import_react = /* @__PURE__ */ __toESM(require_react());
14
14
  var import_jsx_runtime = require_jsx_runtime();
15
15
  function LoopCard({ job, onOpen, onPickRun }) {
@@ -57,6 +57,9 @@ function LoopCard({ job, onOpen, onPickRun }) {
57
57
  tone: "running",
58
58
  dot: "pulse",
59
59
  children: "Running"
60
+ }) : job.queued && job.reconciliationBlocking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
61
+ tone: "outline",
62
+ children: "Queued · waiting for machine recovery"
60
63
  }) : job.queued ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
61
64
  tone: "outline",
62
65
  children: "Queued"
@@ -1,7 +1,7 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
- import { D as createFetch, K as getBaseURL, P as defu, ht as isSafeUrlScheme, nn as toKebabCase, y as capitalizeFirstLetter } from "./boot-akwC2sQg.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/LoopPlaybook-uq_sFfgU.js
3
+ import { D as createFetch, K as getBaseURL, P as defu, ht as isSafeUrlScheme, rn as toKebabCase, y as capitalizeFirstLetter } from "./boot-3BNKujyp.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/LoopPlaybook-DC7QVvPY.js
5
5
  var import_react = /* @__PURE__ */ __toESM(require_react());
6
6
  var import_jsx_runtime = require_jsx_runtime();
7
7
  var PROTO_POLLUTION_PATTERNS = {
@@ -1,15 +1,15 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
- import { Bt as parseChartSpec, _t as isTaskPath, c as CHART_ATTRS } from "./boot-akwC2sQg.mjs";
4
- import { A as tsShort, v as fmt, w as md, y as fnum } from "./ui-B6mE5-5v.mjs";
3
+ import { Bt as parseChartSpec, _t as isTaskPath, c as CHART_ATTRS } from "./boot-3BNKujyp.mjs";
4
+ import { A as tsShort, v as fmt, w as md, y as fnum } from "./ui-Ww2tTM2u.mjs";
5
5
  import { l as getChartRuns, s as getArtifacts } from "./loopApi-8_KgBapr.mjs";
6
6
  import { t as artifactKind } from "./artifactKind-BW0isV8L.mjs";
7
7
  import { t as purify } from "../_libs/dompurify.mjs";
8
8
  import { i as isMarkdown, r as ViewerHead, t as ArtifactBody } from "./artifactView-iuPsp5aa.mjs";
9
- import { n as ModalHead, t as Modal } from "./Modal-Bc_5TYGr.mjs";
9
+ import { n as ModalHead, t as Modal } from "./Modal-MaCG52Pv.mjs";
10
10
  import { n as import_lib, t as esm_default } from "../_libs/html-react-parser+[...].mjs";
11
11
  import { a as Scatter, c as CartesianGrid, d as ResponsiveContainer, i as XAxis, l as Tooltip, n as ScatterChart, o as Area, r as YAxis, s as Line, t as ComposedChart, u as Legend } from "../_libs/recharts+victory-vendor.mjs";
12
- //#region node_modules/.nitro/vite/services/ssr/assets/LoopView-BlOY-jfJ.js
12
+ //#region node_modules/.nitro/vite/services/ssr/assets/LoopView-DwSrm9Ja.js
13
13
  var import_react = /* @__PURE__ */ __toESM(require_react());
14
14
  var import_jsx_runtime = require_jsx_runtime();
15
15
  function buildBindingContext(runs) {
@@ -1,6 +1,6 @@
1
1
  import { c as DialogRoot, d as DialogClose, f as DialogBackdrop, g as require_jsx_runtime, l as DialogPortal, s as DialogTitle, u as DialogPopup } from "../_libs/@base-ui/react+[...].mjs";
2
- import { O as sectionHeadCls } from "./ui-B6mE5-5v.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/Modal-Bc_5TYGr.js
2
+ import { O as sectionHeadCls } from "./ui-Ww2tTM2u.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/Modal-MaCG52Pv.js
4
4
  var import_jsx_runtime = require_jsx_runtime();
5
5
  /** Shared modal shell — Base UI Dialog handles focus trap, Esc, scroll lock.
6
6
  * Content-height, optically centered — sized for the small form/compose dialogs
@@ -1,8 +1,8 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
- import { l as btnPrimary } from "./ui-B6mE5-5v.mjs";
4
- import { i as PievoLogo, n as GitHubIcon, o as signIn, r as LoopPlaybook, t as GITHUB_URL } from "./LoopPlaybook-uq_sFfgU.mjs";
5
- //#region node_modules/.nitro/vite/services/ssr/assets/SignIn-C4fSJl_j.js
3
+ import { l as btnPrimary } from "./ui-Ww2tTM2u.mjs";
4
+ import { i as PievoLogo, n as GitHubIcon, o as signIn, r as LoopPlaybook, t as GITHUB_URL } from "./LoopPlaybook-DC7QVvPY.mjs";
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/SignIn-RmpWm9uy.js
6
6
  var import_react = /* @__PURE__ */ __toESM(require_react());
7
7
  var import_jsx_runtime = require_jsx_runtime();
8
8
  /**
@@ -1,7 +1,7 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
- import { c as btnDanger, l as btnPrimary, o as btn } from "./ui-B6mE5-5v.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-BKF6xI3d.js
3
+ import { c as btnDanger, l as btnPrimary, o as btn } from "./ui-Ww2tTM2u.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-BN55TNYE.js
5
5
  var import_react = /* @__PURE__ */ __toESM(require_react());
6
6
  var import_jsx_runtime = require_jsx_runtime();
7
7
  /**
@@ -1,5 +1,5 @@
1
- import { It as machinePresence, Ot as listRuns, ct as hasRunningRun, f as MIN_DAEMON_VERSION, j as daemonNeedsUpdate, st as hasPendingRun, tt as getMachine, w as countRuns } from "./boot-akwC2sQg.mjs";
2
- //#region node_modules/.nitro/vite/services/ssr/assets/adapters-RReIIwAx.js
1
+ import { It as machinePresence, Ot as listRuns, Ut as reconciliationStatesForRuns, ct as hasRunningRun, f as MIN_DAEMON_VERSION, j as daemonNeedsUpdate, st as hasPendingRun, tt as getMachine, w as countRuns } from "./boot-3BNKujyp.mjs";
2
+ //#region node_modules/.nitro/vite/services/ssr/assets/adapters-BoLkOf1T.js
3
3
  /**
4
4
  * Map the new relational rows (Loop + Run) onto the shapes the UI already
5
5
  * renders (JobSummary / JobDetail / RunSummary / JobFull), so the dashboard
@@ -9,13 +9,14 @@ var SUMMARY_RUNS = 18;
9
9
  function nextRun(loop) {
10
10
  return [loop.nextRunAt, loop.nextCadenceAt].filter((v) => v != null).sort()[0] ?? null;
11
11
  }
12
- function toRunSummary(r) {
12
+ function toRunSummary(r, reconciliation) {
13
13
  return {
14
14
  id: r.id,
15
15
  loopId: r.loopId,
16
16
  ts: r.ts,
17
17
  queued: r.phase === "pending",
18
18
  running: r.phase === "running",
19
+ ...reconciliation ? { reconciliation } : {},
19
20
  phase: r.phase,
20
21
  requestedBy: r.requestedBy,
21
22
  canceled: r.phase === "canceled",
@@ -40,6 +41,10 @@ function toRunSummary(r) {
40
41
  reportIncident: r.reportIncident ?? null
41
42
  };
42
43
  }
44
+ async function toRunSummaries(loopId, rows) {
45
+ const states = await reconciliationStatesForRuns(loopId, rows.map((run) => run.id));
46
+ return rows.map((run) => toRunSummary(run, states.get(run.id)));
47
+ }
43
48
  /** One live artifact_files row (with its blob meta joined) → the compact UI shape
44
49
  * (metadata only; the bytes are fetched lazily by getArtifact / the download
45
50
  * route. The front-matter `meta` rides along so the
@@ -55,7 +60,7 @@ function toArtifactSummary(row) {
55
60
  };
56
61
  }
57
62
  async function toJobSummary(loop) {
58
- const runs = (await listRuns(loop.id, SUMMARY_RUNS)).map(toRunSummary);
63
+ const runs = await toRunSummaries(loop.id, await listRuns(loop.id, SUMMARY_RUNS));
59
64
  return {
60
65
  id: loop.id,
61
66
  name: loop.name ?? loop.id,
@@ -71,6 +76,7 @@ async function toJobSummary(loop) {
71
76
  nextRun: nextRun(loop),
72
77
  running: await hasRunningRun(loop.id),
73
78
  queued: await hasPendingRun(loop.id),
79
+ reconciliationBlocking: runs.some((run) => run.reconciliation === "blocking"),
74
80
  lastRunTs: runs.length ? runs[runs.length - 1].ts : null,
75
81
  graduation: null,
76
82
  goal: loop.goal ?? null,
@@ -108,7 +114,7 @@ function toJobFull(loop) {
108
114
  };
109
115
  }
110
116
  async function toJobDetail(loop) {
111
- const fullRuns = (await listRuns(loop.id, 100)).map(toRunSummary).reverse();
117
+ const fullRuns = (await toRunSummaries(loop.id, await listRuns(loop.id, 100))).reverse();
112
118
  const m = await getMachine(loop.machineId);
113
119
  const presence = machinePresence(m?.online, m?.lastSeen);
114
120
  return {
@@ -131,4 +137,4 @@ async function toJobDetail(loop) {
131
137
  };
132
138
  }
133
139
  //#endregion
134
- export { toRunSummary as i, toJobDetail as n, toJobSummary as r, toArtifactSummary as t };
140
+ export { toRunSummaries as i, toJobDetail as n, toJobSummary as r, toArtifactSummary as t };
@@ -1,6 +1,6 @@
1
- import { G as getArtifactSync, W as getArtifactFile, Xt as safeRelPath, xt as listArtifactsWithMeta } from "./boot-akwC2sQg.mjs";
2
- import { t as toArtifactSummary } from "./adapters-RReIIwAx.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/artifactFiles-C8PQKN6V.js
1
+ import { G as getArtifactSync, W as getArtifactFile, Zt as safeRelPath, xt as listArtifactsWithMeta } from "./boot-3BNKujyp.mjs";
2
+ import { t as toArtifactSummary } from "./adapters-BoLkOf1T.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/artifactFiles-BCaIIrrT.js
4
4
  /**
5
5
  * Server-side reads over a loop's live-synced artifacts (Phase 2). Pure helpers
6
6
  * (no request/session context) so they're shared by the lazy server fns
@@ -0,0 +1,2 @@
1
+ import { i as BLOB_CAP, p as SYNC_BODY_CAP } from "./boot-3BNKujyp.mjs";
2
+ export { BLOB_CAP, SYNC_BODY_CAP };
@@ -1,6 +1,6 @@
1
1
  import { A as sql, C as or, S as notInArray, _ as isNull$1, b as lte, c as asc, d as eq, f as gt, g as isNotNull, h as inArray, l as desc, m as ilike, o as count, p as gte, u as and, v as like, x as ne, y as lt } from "../_libs/drizzle-orm+postgres.mjs";
2
- import { B as ensureTeam, E as createDefu, K as getBaseURL, N as db, Nt as loginGateEnabled, P as defu, Q as getHost, Rt as normalizePathname, V as env, X as getEnvVar, Yt as resolveBaseURL, a as BetterAuthError, bt as kAPIErrorHeaderSymbol, g as betterFetch, ln as wildcardMatch, lt as isDevelopment, m as ValidationError$1, mt as isRequestLike, n as APIError$1, nt as getOrigin, o as BetterCallError, pt as isProduction, q as getBooleanEnvVar, r as BASE_ERROR_CODES, rt as getProtocol, t as APIError, tn as teamIdForUser, u as ENV, ut as isDynamicBaseURLConfig, vt as isTeamMember, y as capitalizeFirstLetter, yt as isTest } from "./boot-akwC2sQg.mjs";
3
- import { C as withSpan, S as shouldPublishLog, _ as logger, a as __getBetterAuthGlobal, b as runWithTransaction, c as createRandomStringGenerator, d as getAuthTables, f as getBetterAuthVersion, g as initGetModelName, h as initGetFieldName, l as generateId$2, m as import_src, n as ATTR_HOOK_TYPE, o as createAdapterFactory, p as getCurrentAdapter, r as ATTR_OPERATION_ID, s as createLogger, t as ATTR_CONTEXT, u as getAsyncLocalStorage, v as queueAfterTransactionHook, x as safeJSONParse, y as runWithAdapter } from "./factory-CDwHL_zY.mjs";
2
+ import { B as ensureTeam, E as createDefu, K as getBaseURL, N as db, Nt as loginGateEnabled, P as defu, Q as getHost, Rt as normalizePathname, V as env, X as getEnvVar, Xt as resolveBaseURL, a as BetterAuthError, bt as kAPIErrorHeaderSymbol, g as betterFetch, lt as isDevelopment, m as ValidationError$1, mt as isRequestLike, n as APIError$1, nn as teamIdForUser, nt as getOrigin, o as BetterCallError, pt as isProduction, q as getBooleanEnvVar, r as BASE_ERROR_CODES, rt as getProtocol, t as APIError, u as ENV, un as wildcardMatch, ut as isDynamicBaseURLConfig, vt as isTeamMember, y as capitalizeFirstLetter, yt as isTest } from "./boot-3BNKujyp.mjs";
3
+ import { C as withSpan, S as shouldPublishLog, _ as logger, a as __getBetterAuthGlobal, b as runWithTransaction, c as createRandomStringGenerator, d as getAuthTables, f as getBetterAuthVersion, g as initGetModelName, h as initGetFieldName, l as generateId$2, m as import_src, n as ATTR_HOOK_TYPE, o as createAdapterFactory, p as getCurrentAdapter, r as ATTR_OPERATION_ID, s as createLogger, t as ATTR_CONTEXT, u as getAsyncLocalStorage, v as queueAfterTransactionHook, x as safeJSONParse, y as runWithAdapter } from "./factory-CWWwV7XZ.mjs";
4
4
  import { randomBytes, scrypt } from "node:crypto";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
@@ -1700,7 +1700,7 @@ var JOIN_TYPE_SQL = freeze({
1700
1700
  Using: "using"
1701
1701
  });
1702
1702
  //#endregion
1703
- //#region node_modules/.nitro/vite/services/ssr/assets/auth-Sie6sQHF.js
1703
+ //#region node_modules/.nitro/vite/services/ssr/assets/auth-30Z4lV1w.js
1704
1704
  /**
1705
1705
  * @internal
1706
1706
  */
@@ -15993,7 +15993,7 @@ var createKyselyAdapter = async (config) => {
15993
15993
  if ("getConnection" in db) dialect = new MysqlDialect(db);
15994
15994
  if ("connect" in db) dialect = new PostgresDialect({ pool: db });
15995
15995
  if ("fileControl" in db) {
15996
- const { BunSqliteDialect } = await import("./bun-sqlite-dialect-BW9W1_Ps-CLY8cORt.mjs");
15996
+ const { BunSqliteDialect } = await import("./bun-sqlite-dialect-BW9W1_Ps-_7tfuNRi.mjs");
15997
15997
  dialect = new BunSqliteDialect({ database: db });
15998
15998
  }
15999
15999
  if ("createSession" in db) {
@@ -16009,12 +16009,12 @@ var createKyselyAdapter = async (config) => {
16009
16009
  if (error !== null && typeof error === "object" && "code" in error && error.code !== "ERR_UNKNOWN_BUILTIN_MODULE") throw error;
16010
16010
  }
16011
16011
  if (DatabaseSync && db instanceof DatabaseSync) {
16012
- const { NodeSqliteDialect } = await import("./node-sqlite-dialect-dmrazfbM.mjs");
16012
+ const { NodeSqliteDialect } = await import("./node-sqlite-dialect-D_3JmkMo.mjs");
16013
16013
  dialect = new NodeSqliteDialect({ database: db });
16014
16014
  }
16015
16015
  }
16016
16016
  if ("batch" in db && "exec" in db && "prepare" in db) {
16017
- const { D1SqliteDialect } = await import("./d1-sqlite-dialect-BLC8LXE6-CRsXQNRe.mjs");
16017
+ const { D1SqliteDialect } = await import("./d1-sqlite-dialect-BLC8LXE6-ucDUbeBk.mjs");
16018
16018
  dialect = new D1SqliteDialect({ database: db });
16019
16019
  }
16020
16020
  return {
@@ -36526,7 +36526,7 @@ async function getBaseAdapter(options, handleDirectDatabase) {
36526
36526
  acc[key] = [];
36527
36527
  return acc;
36528
36528
  }, {});
36529
- const { memoryAdapter } = await import("./dist-Cc_x6bBb.mjs");
36529
+ const { memoryAdapter } = await import("./dist-Cd6nlLlO.mjs");
36530
36530
  adapter = memoryAdapter(memoryDB)(options);
36531
36531
  } else if (typeof options.database === "function") adapter = options.database(options);
36532
36532
  else adapter = await handleDirectDatabase(options);
@@ -36540,10 +36540,10 @@ async function getBaseAdapter(options, handleDirectDatabase) {
36540
36540
  }
36541
36541
  async function getAdapter(options) {
36542
36542
  return getBaseAdapter(options, async (opts) => {
36543
- const { createKyselyAdapter } = await import("./kysely-adapter-zflsyYBA.mjs");
36543
+ const { createKyselyAdapter } = await import("./kysely-adapter-C8iS51DB.mjs");
36544
36544
  const { kysely, databaseType, transaction } = await createKyselyAdapter(opts);
36545
36545
  if (!kysely) throw new BetterAuthError("Failed to initialize database adapter");
36546
- const { kyselyAdapter } = await import("./kysely-adapter-zflsyYBA.mjs");
36546
+ const { kyselyAdapter } = await import("./kysely-adapter-C8iS51DB.mjs");
36547
36547
  return kyselyAdapter(kysely, {
36548
36548
  type: databaseType || "sqlite",
36549
36549
  debugLogs: opts.database && "debugLogs" in opts.database ? opts.database.debugLogs : false,
@@ -13,7 +13,7 @@ import os from "node:os";
13
13
  import fs$1 from "node:fs/promises";
14
14
  import { lookup } from "node:dns/promises";
15
15
  import { isIP } from "node:net";
16
- //#region node_modules/.nitro/vite/services/ssr/assets/boot-akwC2sQg.js
16
+ //#region node_modules/.nitro/vite/services/ssr/assets/boot-3BNKujyp.js
17
17
  var import_pino = /* @__PURE__ */ __toESM(require_pino());
18
18
  var import_pino_pretty = /* @__PURE__ */ __toESM(require_pino_pretty());
19
19
  function defineErrorCodes(codes) {
@@ -1682,6 +1682,7 @@ var runLeases = pgTable("run_leases", {
1682
1682
  state: text("state", { enum: [
1683
1683
  "active",
1684
1684
  "terminal-grace",
1685
+ "reconciliation-only",
1685
1686
  "retired"
1686
1687
  ] }).notNull().default("active"),
1687
1688
  /** Null while active/retired; ISO only during terminal-grace. */
@@ -2322,7 +2323,12 @@ async function tryDeleteLoop(id) {
2322
2323
  if (!(await tx.select().from(loops).where(eq(loops.id, id)).for("update"))[0]?.deleteRequestedAt) return false;
2323
2324
  const open = (await tx.select({ id: runs.id }).from(runs).where(and(eq(runs.loopId, id), inArray(runs.phase, ["pending", "running"]))).limit(1))[0];
2324
2325
  const authority = (await tx.select({ id: runLeases.tokenHash }).from(runLeases).where(and(eq(runLeases.loopId, id), inArray(runLeases.state, ["active", "terminal-grace"]))).limit(1))[0];
2325
- return open || authority ? false : deleteLoopDataTx(tx, id);
2326
+ if (open || authority) return false;
2327
+ await tx.update(runLeases).set({
2328
+ state: "retired",
2329
+ expiresAt: null
2330
+ }).where(and(eq(runLeases.loopId, id), eq(runLeases.state, "reconciliation-only")));
2331
+ return deleteLoopDataTx(tx, id);
2326
2332
  });
2327
2333
  }
2328
2334
  async function forceDeleteLoop(id) {
@@ -2334,6 +2340,7 @@ async function forceDeleteLoop(id) {
2334
2340
  }).where(and(eq(runLeases.loopId, id), inArray(runLeases.state, [
2335
2341
  "active",
2336
2342
  "terminal-grace",
2343
+ "reconciliation-only",
2337
2344
  "retired"
2338
2345
  ])));
2339
2346
  return deleteLoopDataTx(tx, id);
@@ -2670,10 +2677,11 @@ async function rejectTerminalReport(input) {
2670
2677
  eq(runLeases.tokenHash, input.leaseTokenHash),
2671
2678
  eq(runLeases.runId, input.runId),
2672
2679
  eq(runLeases.loopId, input.loopId),
2673
- eq(runLeases.state, input.leaseState)
2680
+ input.leaseState === "active" ? eq(runLeases.state, "active") : inArray(runLeases.state, ["terminal-grace", "reconciliation-only"])
2674
2681
  ];
2675
- if (input.leaseState === "terminal-grace") leaseConditions.push(gt(runLeases.expiresAt, now));
2676
- if (!(await tx.select().from(runLeases).where(and(...leaseConditions)).limit(1).for("update"))[0]) return { state: "invalid-lease" };
2682
+ if (input.leaseState !== "active") leaseConditions.push(gt(runLeases.expiresAt, now));
2683
+ const lease = (await tx.select().from(runLeases).where(and(...leaseConditions)).limit(1).for("update"))[0];
2684
+ if (!lease) return { state: "invalid-lease" };
2677
2685
  const receiptInput = {
2678
2686
  id: terminalIncidentReceiptId(input.reportId, input.payloadDigest),
2679
2687
  runId: input.runId,
@@ -2683,7 +2691,7 @@ async function rejectTerminalReport(input) {
2683
2691
  ackBody: input.ackBody,
2684
2692
  createdAt: input.incident.at
2685
2693
  };
2686
- if (input.leaseState === "terminal-grace") {
2694
+ if (lease.state !== "active") {
2687
2695
  const run = (await tx.update(runs).set({
2688
2696
  reportIncident: input.incident,
2689
2697
  updatedAt: input.incident.at
@@ -2788,8 +2796,21 @@ async function reclaimRun(runId, expected, reason, at = nowIso$1(), graceMs = 14
2788
2796
  };
2789
2797
  });
2790
2798
  }
2791
- /** Consume one terminal-grace lease and reconcile its reclaimed error exactly
2792
- * once. Keeping the lease check/delete beside the run + loop writes closes the
2799
+ /** A daemon's completed recovery snapshot is authoritative for execution
2800
+ * exclusion. Reclaimed runs absent from that snapshot retain late-report authority
2801
+ * until their original expiry, but stop blocking queued work immediately. */
2802
+ async function releaseAbsentReconciliations(machineId, recoverableRunIds, at = nowIso$1()) {
2803
+ const conditions = [
2804
+ eq(runLeases.machineId, machineId),
2805
+ eq(runLeases.state, "terminal-grace"),
2806
+ gt(runLeases.expiresAt, at)
2807
+ ];
2808
+ const ids = [...new Set(recoverableRunIds)];
2809
+ if (ids.length) conditions.push(notInArray(runLeases.runId, ids));
2810
+ return (await db.update(runLeases).set({ state: "reconciliation-only" }).where(and(...conditions)).returning({ runId: runLeases.runId })).map((row) => row.runId);
2811
+ }
2812
+ /** Consume one terminal reconciliation lease and reconcile its reclaimed error
2813
+ * exactly once. Keeping the lease check/delete beside the run + loop writes closes the
2793
2814
  * error→error double-report hole where a phase CAS alone cannot distinguish the
2794
2815
  * first real failure from a second concurrent one. */
2795
2816
  async function reconcileReclaimedRun(loopId, runId, leaseTokenHash, runPatch, loopPatch = {}, failureAutopauseStreak = 0, receipt) {
@@ -2801,7 +2822,11 @@ async function reconcileReclaimedRun(loopId, runId, leaseTokenHash, runPatch, lo
2801
2822
  if ((await tx.select({ id: terminalReportIncidents.id }).from(terminalReportIncidents).where(eq(terminalReportIncidents.reportId, receipt.reportId)).limit(1))[0]) return void 0;
2802
2823
  }
2803
2824
  const leaseNow = nowIso$1();
2804
- if (!(await tx.select({ tokenHash: runLeases.tokenHash }).from(runLeases).where(and(eq(runLeases.tokenHash, leaseTokenHash), eq(runLeases.runId, runId), eq(runLeases.loopId, loopId), eq(runLeases.state, "terminal-grace"), gt(runLeases.expiresAt, leaseNow))).limit(1).for("update"))[0]) return void 0;
2825
+ const lease = (await tx.select({
2826
+ tokenHash: runLeases.tokenHash,
2827
+ state: runLeases.state
2828
+ }).from(runLeases).where(and(eq(runLeases.tokenHash, leaseTokenHash), eq(runLeases.runId, runId), eq(runLeases.loopId, loopId), inArray(runLeases.state, ["terminal-grace", "reconciliation-only"]), gt(runLeases.expiresAt, leaseNow))).limit(1).for("update"))[0];
2829
+ if (!lease) return void 0;
2805
2830
  const target = (await tx.select().from(runs).where(and(eq(runs.id, runId), eq(runs.loopId, loopId), eq(runs.phase, "error"))).limit(1).for("update"))[0];
2806
2831
  if (!target) return void 0;
2807
2832
  const runIndex = await ensureRunIndexTx(tx, target);
@@ -2812,12 +2837,17 @@ async function reconcileReclaimedRun(loopId, runId, leaseTokenHash, runPatch, lo
2812
2837
  updatedAt: at
2813
2838
  }).where(and(eq(runs.id, runId), eq(runs.loopId, loopId), eq(runs.phase, "error"))).returning())[0];
2814
2839
  if (!run) return void 0;
2815
- const lifecycle = await terminalLifecycleTx(tx, current, run, at, loopPatch, true, failureAutopauseStreak);
2840
+ const lifecycle = lease.state === "reconciliation-only" ? {
2841
+ loop: current,
2842
+ failureStreak: 0,
2843
+ autoPaused: false
2844
+ } : await terminalLifecycleTx(tx, current, run, at, loopPatch, true, failureAutopauseStreak);
2816
2845
  await tx.delete(runLeases).where(eq(runLeases.runId, runId));
2817
2846
  if (receipt) await tx.insert(runReportReceipts).values(receipt);
2818
2847
  return {
2819
2848
  run,
2820
- ...lifecycle
2849
+ ...lifecycle,
2850
+ reportOnly: lease.state === "reconciliation-only"
2821
2851
  };
2822
2852
  });
2823
2853
  }
@@ -2959,6 +2989,15 @@ async function claimReadyRunForMachine(machineId, at = nowIso$1(), excludeRunIds
2959
2989
  async function listRuns(loopId, limit = 30) {
2960
2990
  return (await db.select().from(runs).where(eq(runs.loopId, loopId)).orderBy(desc(runs.ts)).limit(limit)).reverse();
2961
2991
  }
2992
+ /** Live reconciliation projection for dashboard/run-detail reads. */
2993
+ async function reconciliationStatesForRuns(loopId, runIds, at = nowIso$1()) {
2994
+ if (!runIds.length) return /* @__PURE__ */ new Map();
2995
+ const rows = await db.select({
2996
+ runId: runLeases.runId,
2997
+ state: runLeases.state
2998
+ }).from(runLeases).where(and(eq(runLeases.loopId, loopId), inArray(runLeases.runId, [...new Set(runIds)]), inArray(runLeases.state, ["terminal-grace", "reconciliation-only"]), gt(runLeases.expiresAt, at)));
2999
+ return new Map(rows.map((row) => [row.runId, row.state === "terminal-grace" ? "blocking" : "report-only"]));
3000
+ }
2962
3001
  /** Latest successful exec runs for dashboard charts, returned oldest-first. Filtering
2963
3002
  * happens before LIMIT so evolve/steer rows never shrink the chart window. */
2964
3003
  async function listChartRuns(loopId, limit = 100) {
@@ -3954,7 +3993,8 @@ function isIgnoredPath(rel) {
3954
3993
  * LEASE (`rk_…`) is minted per delivery, bound to one run, and carries the
3955
3994
  * run's least-privilege caps — the CLI dispatch authorizes the `pievo` shim
3956
3995
  * against it. Its lifecycle is a small state machine (`active` →
3957
- * `terminal-grace` → `retired`), not a mint→revoke pair; see `RunLease` below.
3996
+ * `terminal-grace` → `reconciliation-only`/`retired`), not a mint→revoke pair;
3997
+ * see `RunLease` below.
3958
3998
  *
3959
3999
  * Leases and connect-key bindings are DURABLE (run_leases / connect_keys
3960
4000
  * tables): they must survive a deploy, or every restart 401s the in-flight
@@ -4056,11 +4096,11 @@ async function resolveLease(token, now = Date.now()) {
4056
4096
  const tokenHash = sha256(token);
4057
4097
  let row = (await db.select().from(runLeases).where(eq(runLeases.tokenHash, tokenHash)))[0];
4058
4098
  if (!row) return void 0;
4059
- if (row.state === "terminal-grace" && row.expiresAt != null && now > Date.parse(row.expiresAt)) {
4099
+ if ((row.state === "terminal-grace" || row.state === "reconciliation-only") && row.expiresAt != null && now > Date.parse(row.expiresAt)) {
4060
4100
  row = (await db.update(runLeases).set({
4061
4101
  state: "retired",
4062
4102
  expiresAt: null
4063
- }).where(and(eq(runLeases.tokenHash, tokenHash), eq(runLeases.state, "terminal-grace"), isNotNull(runLeases.expiresAt), lt(runLeases.expiresAt, new Date(now).toISOString()))).returning())[0] ?? (await db.select().from(runLeases).where(eq(runLeases.tokenHash, tokenHash)))[0];
4103
+ }).where(and(eq(runLeases.tokenHash, tokenHash), inArray(runLeases.state, ["terminal-grace", "reconciliation-only"]), isNotNull(runLeases.expiresAt), lt(runLeases.expiresAt, new Date(now).toISOString()))).returning())[0] ?? (await db.select().from(runLeases).where(eq(runLeases.tokenHash, tokenHash)))[0];
4064
4104
  if (!row) return void 0;
4065
4105
  }
4066
4106
  return leaseFromRow(row);
@@ -4078,7 +4118,7 @@ async function pruneExpiredLeases(now = Date.now()) {
4078
4118
  await db.update(runLeases).set({
4079
4119
  state: "retired",
4080
4120
  expiresAt: null
4081
- }).where(and(eq(runLeases.state, "terminal-grace"), isNotNull(runLeases.expiresAt), lt(runLeases.expiresAt, new Date(now).toISOString())));
4121
+ }).where(and(inArray(runLeases.state, ["terminal-grace", "reconciliation-only"]), isNotNull(runLeases.expiresAt), lt(runLeases.expiresAt, new Date(now).toISOString())));
4082
4122
  }
4083
4123
  var newIdempotency = /* @__PURE__ */ new Map();
4084
4124
  function pruneNewIdempotency(now) {
@@ -5960,7 +6000,7 @@ var MachineGateway = class {
5960
6000
  this.maintenanceRunning = false;
5961
6001
  }
5962
6002
  }
5963
- async pollCore(deviceToken, info, currentRunIds, watchDigest, claimWork = true) {
6003
+ async pollCore(deviceToken, info, currentRunIds, watchDigest, claimWork = true, recoveryComplete = false) {
5964
6004
  if (!isDeviceTokenShape(deviceToken)) return {
5965
6005
  status: 401,
5966
6006
  body: { error: "invalid device token" }
@@ -6015,6 +6055,7 @@ var MachineGateway = class {
6015
6055
  await refreshRunHeartbeats(machineId, [...ids], new Date(now).toISOString(), new Date(now - HEARTBEAT_STAMP_REFRESH_MS).toISOString());
6016
6056
  }
6017
6057
  }
6058
+ if (recoveryComplete) await releaseAbsentReconciliations(machineId, currentRunIds ?? []);
6018
6059
  let delivery = null;
6019
6060
  if (claimWork) {
6020
6061
  await this.scheduler.advanceDueSchedules(machineId);
@@ -6072,12 +6113,19 @@ var MachineGateway = class {
6072
6113
  code: "VALIDATION_ERROR"
6073
6114
  }
6074
6115
  };
6116
+ if (request.recoveryComplete === true && (typeof request.daemonInstanceId !== "string" || !request.daemonInstanceId || request.daemonInstanceId.length > 200)) return {
6117
+ status: 400,
6118
+ body: {
6119
+ error: "daemonInstanceId is required for a completed recovery snapshot",
6120
+ code: "VALIDATION_ERROR"
6121
+ }
6122
+ };
6075
6123
  const currentIds = [...new Set(request.currentRuns.map((run) => run.runId))];
6076
6124
  const machineId = isDeviceTokenShape(deviceToken) ? machineIdFromToken(deviceToken) : "";
6077
6125
  const priorMachine = machineId ? await getMachine(machineId) : void 0;
6078
6126
  const reportedVersion = typeof request.info?.version === "string" ? clipText(request.info.version, 64) : priorMachine?.daemonVersion;
6079
6127
  const needsUpdate = daemonNeedsUpdate(reportedVersion);
6080
- const base = await this.pollCore(deviceToken, request.info, currentIds, request.watchDigest, !needsUpdate);
6128
+ const base = await this.pollCore(deviceToken, request.info, currentIds, request.watchDigest, !needsUpdate, request.recoveryComplete === true);
6081
6129
  if (base.status !== 200) return base;
6082
6130
  if ((await getMachine(machineId))?.daemonProtocol !== 3) await updateMachine(machineId, { daemonProtocol: 3 });
6083
6131
  const running = await runningRunsForMachine(machineId);
@@ -6799,7 +6847,8 @@ var MachineGateway = class {
6799
6847
  };
6800
6848
  }
6801
6849
  const deleting = reconciled.loop.deleteRequestedAt != null;
6802
- if (!deleting) try {
6850
+ const reportOnly = reconciled.reportOnly === true;
6851
+ if (!deleting && !reportOnly) try {
6803
6852
  await putRunSnapshot(lease.runId, lease.loopId, await buildLoopManifest(lease.loopId));
6804
6853
  await pruneRunSnapshots(lease.loopId, snapshotRetention());
6805
6854
  } catch (err) {
@@ -6809,12 +6858,12 @@ var MachineGateway = class {
6809
6858
  }, "snapshot capture failed");
6810
6859
  }
6811
6860
  const finalized = reconciled.run;
6812
- if (!deleting && ok && lease.role !== "evolve" && lease.role !== "steer") {
6861
+ if (!deleting && !reportOnly && ok && lease.role !== "evolve" && lease.role !== "steer") {
6813
6862
  const loop = await getLoop(lease.loopId);
6814
6863
  if (finalized.message && loop && shouldNotify(loop.notify, finalized.status ?? null)) this.pushNotify(loop, finalized.message);
6815
6864
  }
6816
- this.scheduler.addLoop(reconciled.loop);
6817
- if (!deleting && !ok && !canceled && lease.role === "exec") await this.notifyRunFailure(lease.loopId, lease.role, finalized.error ?? null, reconciled, { alert: false });
6865
+ if (!reportOnly) this.scheduler.addLoop(reconciled.loop);
6866
+ if (!deleting && !reportOnly && !ok && !canceled && lease.role === "exec") await this.notifyRunFailure(lease.loopId, lease.role, finalized.error ?? null, reconciled, { alert: false });
6818
6867
  if (deleting) await tryDeleteLoop(lease.loopId);
6819
6868
  log$2.info({
6820
6869
  runId: lease.runId,
@@ -6835,7 +6884,7 @@ var MachineGateway = class {
6835
6884
  async rejectTerminalAttempt(runToken, lease, body, payloadDigest, code, issues) {
6836
6885
  const reportId = body.reportId;
6837
6886
  const run = await getRun(lease.runId);
6838
- const disposition = lease.state === "terminal-grace" && (run?.phase === "done" || run?.phase === "error" || run?.phase === "canceled") ? "telemetry-rejected" : "run-error";
6887
+ const disposition = lease.state !== "active" && (run?.phase === "done" || run?.phase === "error" || run?.phase === "canceled") ? "telemetry-rejected" : "run-error";
6839
6888
  const incident = incidentDiagnosis(code, issues, reportId, payloadDigest);
6840
6889
  const ackBody = {
6841
6890
  ok: true,
@@ -6938,7 +6987,7 @@ var MachineGateway = class {
6938
6987
  reportId
6939
6988
  }
6940
6989
  };
6941
- if (run?.phase === "error" && lease.state === "terminal-grace") return this.reconcileReclaimedReport(runToken, lease, run, body);
6990
+ if (run?.phase === "error" && (lease.state === "terminal-grace" || lease.state === "reconciliation-only")) return this.reconcileReclaimedReport(runToken, lease, run, body);
6942
6991
  const protocolMissing = ok && run ? runProtocolMissing(run) : [];
6943
6992
  const effectiveOk = ok && protocolMissing.length === 0;
6944
6993
  const loopPatch = { ...typeof body.taskFileContent === "string" ? {
@@ -8487,7 +8536,7 @@ var CliGateway = class {
8487
8536
  exitCode: 1
8488
8537
  }
8489
8538
  };
8490
- if (lease.state === "terminal-grace") return {
8539
+ if (lease.state === "terminal-grace" || lease.state === "reconciliation-only") return {
8491
8540
  status: 409,
8492
8541
  body: {
8493
8542
  text: errorBlock(TERMINAL_GRACE_MSG, "CONFLICT"),
@@ -8822,7 +8871,7 @@ var CliGateway = class {
8822
8871
  exitCode: 1
8823
8872
  }
8824
8873
  };
8825
- if (lease.state === "terminal-grace") return {
8874
+ if (lease.state === "terminal-grace" || lease.state === "reconciliation-only") return {
8826
8875
  status: 409,
8827
8876
  body: {
8828
8877
  text: errorBlock(TERMINAL_GRACE_MSG, "CONFLICT"),
@@ -10130,4 +10179,4 @@ async function getCliGateway() {
10130
10179
  return (await ensureServer()).cliGateway;
10131
10180
  }
10132
10181
  //#endregion
10133
- export { getInvite as $, startLoop as $t, createTeam as A, listTeamMembers as At, ensureTeam as B, parseChartSpec as Bt, countLoopsForTeam as C, listChartRuns as Ct, createFetch as D, listPendingInvites as Dt, createDefu as E, listMachinesForTeam as Et, deleteChannel as F, machineIdFromToken as Ft, getArtifactSync as G, removeTeamMemberGuarded as Gt, evolve_default as H, readJsonBody as Ht, deleteInvite as I, machinePresence as It, getChannel as J, requestRunCancel as Jt, getBaseURL as K, renameTeam as Kt, deleteMachine as L, mintDeviceToken as Lt, dashboard_default as M, logger as Mt, db as N, loginGateEnabled as Nt, createInvite as O, listRuns as Ot, defu as P, loopsForMachine as Pt, getHost as Q, sha256 as Qt, deleteTeamCascade as R, normalizePathname as Rt, computeRunDiff as S, listChannels as St, createChannel as T, listMachines as Tt, forceDeleteLoop as U, redeemInviteAtomic as Ut, env as V, pauseLoop as Vt, getArtifactFile as W, rememberConnectKey as Wt, getEnvVar as X, safeRelPath as Xt, getCliGateway as Y, resolveBaseURL as Yt, getGateway as Z, setTeamMemberRoleGuarded as Zt, buildFileEntries as _, isTaskPath as _t, BetterAuthError as a, updateMachine as an, getTeam as at, coerceCodingAgent as b, kAPIErrorHeaderSymbol as bt, CHART_ATTRS as c, validateSteerInstruction as cn, hasRunningRun as ct, MACHINE_BODY_CAP as d, isOutdated as dt, stopLoop as en, getLoop as et, MIN_DAEMON_VERSION as f, isPersonalTeam as ft, betterFetch as g, isTaskEntry as gt, addTeamMember as h, isSafeUrlScheme as ht, BLOB_CAP as i, updateLoop as in, getRun as it, daemonNeedsUpdate as j, listTeamsForUser as jt, createMachine as k, listRunsBefore as kt, CODING_AGENTS as l, wildcardMatch as ln, isDevelopment as lt, ValidationError$1 as m, isRequestLike as mt, APIError$1 as n, toKebabCase as nn, getOrigin as nt, BetterCallError as o, userByEmail as on, getTeamMember as ot, SYNC_BODY_CAP as p, isProduction as pt, getBooleanEnvVar as q, requestDeleteLoop as qt, BASE_ERROR_CODES as r, tryDeleteLoop as rn, getProtocol as rt, CHANNELS as s, validateSchema as sn, hasPendingRun as st, APIError as t, teamIdForUser as tn, getMachine as tt, ENV as u, isDynamicBaseURLConfig as ut, canEvolve as v, isTeamMember as vt, countRuns as w, listLoops as wt, coerceUi as x, listArtifactsWithMeta as xt, capitalizeFirstLetter as y, isTest as yt, ensureServer as z, normalizeProviderSetting as zt };
10182
+ export { getInvite as $, sha256 as $t, createTeam as A, listTeamMembers as At, ensureTeam as B, parseChartSpec as Bt, countLoopsForTeam as C, listChartRuns as Ct, createFetch as D, listPendingInvites as Dt, createDefu as E, listMachinesForTeam as Et, deleteChannel as F, machineIdFromToken as Ft, getArtifactSync as G, rememberConnectKey as Gt, evolve_default as H, readJsonBody as Ht, deleteInvite as I, machinePresence as It, getChannel as J, requestDeleteLoop as Jt, getBaseURL as K, removeTeamMemberGuarded as Kt, deleteMachine as L, mintDeviceToken as Lt, dashboard_default as M, logger as Mt, db as N, loginGateEnabled as Nt, createInvite as O, listRuns as Ot, defu as P, loopsForMachine as Pt, getHost as Q, setTeamMemberRoleGuarded as Qt, deleteTeamCascade as R, normalizePathname as Rt, computeRunDiff as S, listChannels as St, createChannel as T, listMachines as Tt, forceDeleteLoop as U, reconciliationStatesForRuns as Ut, env as V, pauseLoop as Vt, getArtifactFile as W, redeemInviteAtomic as Wt, getEnvVar as X, resolveBaseURL as Xt, getCliGateway as Y, requestRunCancel as Yt, getGateway as Z, safeRelPath as Zt, buildFileEntries as _, isTaskPath as _t, BetterAuthError as a, updateLoop as an, getTeam as at, coerceCodingAgent as b, kAPIErrorHeaderSymbol as bt, CHART_ATTRS as c, validateSchema as cn, hasRunningRun as ct, MACHINE_BODY_CAP as d, isOutdated as dt, startLoop as en, getLoop as et, MIN_DAEMON_VERSION as f, isPersonalTeam as ft, betterFetch as g, isTaskEntry as gt, addTeamMember as h, isSafeUrlScheme as ht, BLOB_CAP as i, tryDeleteLoop as in, getRun as it, daemonNeedsUpdate as j, listTeamsForUser as jt, createMachine as k, listRunsBefore as kt, CODING_AGENTS as l, validateSteerInstruction as ln, isDevelopment as lt, ValidationError$1 as m, isRequestLike as mt, APIError$1 as n, teamIdForUser as nn, getOrigin as nt, BetterCallError as o, updateMachine as on, getTeamMember as ot, SYNC_BODY_CAP as p, isProduction as pt, getBooleanEnvVar as q, renameTeam as qt, BASE_ERROR_CODES as r, toKebabCase as rn, getProtocol as rt, CHANNELS as s, userByEmail as sn, hasPendingRun as st, APIError as t, stopLoop as tn, getMachine as tt, ENV as u, wildcardMatch as un, isDynamicBaseURLConfig as ut, canEvolve as v, isTeamMember as vt, countRuns as w, listLoops as wt, coerceUi as x, listArtifactsWithMeta as xt, capitalizeFirstLetter as y, isTest as yt, ensureServer as z, normalizeProviderSetting as zt };
@@ -1,2 +1,2 @@
1
- import { G as getArtifactSync, Y as getCliGateway, Z as getGateway } from "./boot-akwC2sQg.mjs";
1
+ import { G as getArtifactSync, Y as getCliGateway, Z as getGateway } from "./boot-3BNKujyp.mjs";
2
2
  export { getArtifactSync, getCliGateway, getGateway };
@@ -1,6 +1,6 @@
1
- import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-Sie6sQHF.mjs";
1
+ import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-30Z4lV1w.mjs";
2
2
  import { n as DEFAULT_MIGRATION_TABLE, t as DEFAULT_MIGRATION_LOCK_TABLE } from "./kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/bun-sqlite-dialect-BW9W1_Ps-CLY8cORt.js
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/bun-sqlite-dialect-BW9W1_Ps-_7tfuNRi.js
4
4
  var BunSqliteAdapter = class {
5
5
  get supportsCreateIfNotExists() {
6
6
  return true;
@@ -1,6 +1,6 @@
1
- import { a as SqliteQueryCompiler, i as SqliteAdapter } from "./auth-Sie6sQHF.mjs";
1
+ import { a as SqliteQueryCompiler, i as SqliteAdapter } from "./auth-30Z4lV1w.mjs";
2
2
  import { n as DEFAULT_MIGRATION_TABLE, t as DEFAULT_MIGRATION_LOCK_TABLE } from "./kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/d1-sqlite-dialect-BLC8LXE6-CRsXQNRe.js
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/d1-sqlite-dialect-BLC8LXE6-ucDUbeBk.js
4
4
  var D1SqliteAdapter = class extends SqliteAdapter {};
5
5
  var D1SqliteDriver = class {
6
6
  #config;
@@ -0,0 +1,2 @@
1
+ import { N as db } from "./boot-3BNKujyp.mjs";
2
+ export { db };
@@ -1,5 +1,5 @@
1
- import { _ as logger, o as createAdapterFactory } from "./factory-CDwHL_zY.mjs";
2
- //#region node_modules/.nitro/vite/services/ssr/assets/dist-Cc_x6bBb.js
1
+ import { _ as logger, o as createAdapterFactory } from "./factory-CWWwV7XZ.mjs";
2
+ //#region node_modules/.nitro/vite/services/ssr/assets/dist-Cd6nlLlO.js
3
3
  /**
4
4
  * Case-insensitive in-memory comparison helpers.
5
5
  * Used when evaluating where clauses in the memory adapter.
@@ -1,5 +1,5 @@
1
- import { V as env, X as getEnvVar, a as BetterAuthError } from "./boot-akwC2sQg.mjs";
2
- //#region node_modules/.nitro/vite/services/ssr/assets/factory-CDwHL_zY.js
1
+ import { V as env, X as getEnvVar, a as BetterAuthError } from "./boot-3BNKujyp.mjs";
2
+ //#region node_modules/.nitro/vite/services/ssr/assets/factory-CWWwV7XZ.js
3
3
  var __defProp = Object.defineProperty;
4
4
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
5
5
  var __exportAll = (all, no_symbols) => {
@@ -1,9 +1,9 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
2
  import { c as getAuthState } from "./loopApi-8_KgBapr.mjs";
3
- import { a as authClient } from "./LoopPlaybook-uq_sFfgU.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-BE_QUAVb.js
5
- var $$splitErrorComponentImporter = () => import("./invite._token-BlbVjz-o.mjs");
6
- var $$splitComponentImporter = () => import("./invite._token-C7GjrJxr.mjs");
3
+ import { a as authClient } from "./LoopPlaybook-DC7QVvPY.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-BKlz0R2f.js
5
+ var $$splitErrorComponentImporter = () => import("./invite._token-CWl6kipD.mjs");
6
+ var $$splitComponentImporter = () => import("./invite._token-SdWXemIc.mjs");
7
7
  /**
8
8
  * Invite-link redeem (`/invite/<token>`, design §4 option B). The recipient opens
9
9
  * the link the owner shared; if signed out (under the gate) they hit the normal