@kky42/pievo-server 1.0.0 → 1.0.1

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 (96) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{LoopView-B4H9QibC.js → LoopView-d0XYkzpx.js} +3 -3
  3. package/.output/public/assets/Modal-D_od-AuP.js +1 -0
  4. package/.output/public/assets/{SignIn-SHuRRyOv.js → SignIn-CbMeIAJZ.js} +1 -1
  5. package/.output/public/assets/app-BKySt9Ta.css +2 -0
  6. package/.output/public/assets/{artifactView-DFuubXLJ.js → artifactView-DekEs5ME.js} +1 -1
  7. package/.output/public/assets/index-C4UaIr-9.js +12 -0
  8. package/.output/public/assets/{invite._token-T8oo4Qtw.js → invite._token-CnyCmLfD.js} +1 -1
  9. package/.output/public/assets/{lifecycleUi-DKkChdnU.js → lifecycleUi-DGVOf5yS.js} +1 -1
  10. package/.output/public/assets/{loopApi-BM2nj71x.js → loopApi-5s2-kCnu.js} +1 -1
  11. package/.output/public/assets/loops._loopId-DdWM2f1F.js +5 -0
  12. package/.output/public/assets/{loops._loopId_.runs._runId-_CflHV38.js → loops._loopId_.runs._runId-DTwSFHkl.js} +2 -2
  13. package/.output/public/assets/notifyFns-b_jCi5XK.js +1 -0
  14. package/.output/public/assets/{preload-helper-CKUiEq3b.js → preload-helper-ycaoAemE.js} +1 -1
  15. package/.output/public/assets/{routes-B9tgli5f.js → routes-G3WYRyPN.js} +1 -1
  16. package/.output/public/assets/{t._teamId-Bm21mngW.js → t._teamId-CGv7Oq6A.js} +1 -1
  17. package/.output/server/_libs/@base-ui/react+[...].mjs +23 -2375
  18. package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
  19. package/.output/server/_libs/html-react-parser+[...].mjs +1 -1
  20. package/.output/server/_libs/react-redux+[...].mjs +1 -1
  21. package/.output/server/_libs/recharts+victory-vendor.mjs +1 -1
  22. package/.output/server/_libs/uiw__react-codemirror.mjs +1 -1
  23. package/.output/server/_ssr/CodeField-tm4rr6G3.mjs +1 -1
  24. package/.output/server/_ssr/{DashboardView-CC7htv28.mjs → DashboardView-CmDqjCiq.mjs} +45 -35
  25. package/.output/server/_ssr/{LoopPlaybook-BXH8mhiX.mjs → LoopPlaybook-BBn-xXpG.mjs} +3 -3
  26. package/.output/server/_ssr/{LoopView-DCugEbHx.mjs → LoopView-DdyJYOCY.mjs} +5 -5
  27. package/.output/server/_ssr/Modal-DpKZHLZK.mjs +1 -1
  28. package/.output/server/_ssr/{SignIn-dTndU6Hw.mjs → SignIn-RJN_0GFZ.mjs} +3 -3
  29. package/.output/server/_ssr/actionUi-CZbEixbf.mjs +1 -1
  30. package/.output/server/_ssr/{adapters-BS8XosjF.mjs → adapters-CJUhP66K.mjs} +9 -3
  31. package/.output/server/_ssr/{artifactFiles-Cagtj7J0.mjs → artifactFiles-zP43a-_v.mjs} +3 -3
  32. package/.output/server/_ssr/{artifactView-DS4O22wl.mjs → artifactView-CYV1r48i.mjs} +3 -3
  33. package/.output/server/_ssr/artifacts-CwCDal_d.mjs +2 -0
  34. package/.output/server/_ssr/{auth-DY1DuYZd.mjs → auth-D2SlCxwE.mjs} +9 -9
  35. package/.output/server/_ssr/{boot-CMHTxQpJ.mjs → boot-BHTcCXzm.mjs} +1 -1
  36. package/.output/server/_ssr/{boot-BbtG0ImW.mjs → boot-aI3l2EYT.mjs} +494 -107
  37. package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CU1Spd6z.mjs → bun-sqlite-dialect-BW9W1_Ps-B-3PhI3u.mjs} +2 -2
  38. package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-DfG7tB8s.mjs → d1-sqlite-dialect-BLC8LXE6-Dm_NrETM.mjs} +2 -2
  39. package/.output/server/_ssr/db-7gZ8_zkc.mjs +2 -0
  40. package/.output/server/_ssr/{dist-BIxFFVZg.mjs → dist-DW3TO9NM.mjs} +2 -2
  41. package/.output/server/_ssr/{factory-Blq0DYfT.mjs → factory-Voe90MEY.mjs} +2 -2
  42. package/.output/server/_ssr/{invite._token-NewFt27g.mjs → invite._token-CeD9PCvh.mjs} +6 -6
  43. package/.output/server/_ssr/{invite._token-BRCo9LGB.mjs → invite._token-D80GP0-u.mjs} +4 -4
  44. package/.output/server/_ssr/invite._token-DJxGLILJ.mjs +1 -1
  45. package/.output/server/_ssr/{kysely-adapter-D3XTe64J.mjs → kysely-adapter-DSLWmYjO.mjs} +1 -1
  46. package/.output/server/_ssr/{lifecycleUi-C9lg1r3r.mjs → lifecycleUi-BhRsBvJ7.mjs} +4 -4
  47. package/.output/server/_ssr/logger-Dbz2vUU-.mjs +2 -0
  48. package/.output/server/_ssr/{loopApi-Cxe8WyOB.mjs → loopApi-BfMnXaKT.mjs} +7 -7
  49. package/.output/server/_ssr/{loopApi-BtfkZQYK.mjs → loopApi-ByX_X17-.mjs} +31 -14
  50. package/.output/server/_ssr/{loops._loopId-DhnArGdL.mjs → loops._loopId-BODmoHPu.mjs} +236 -370
  51. package/.output/server/_ssr/{loops._loopId-7NQJPB9W.mjs → loops._loopId-u8Dr2J5f.mjs} +4 -4
  52. package/.output/server/_ssr/{loops._loopId_.runs._runId-Dip5Xk-q.mjs → loops._loopId_.runs._runId-DaKJdso2.mjs} +48 -6
  53. package/.output/server/_ssr/{loops._loopId_.runs._runId-Bvuo2nki.mjs → loops._loopId_.runs._runId-kGL-CMG6.mjs} +4 -4
  54. package/.output/server/_ssr/{machineFns-Dvr5ICUy.mjs → machineFns-MMSoHs7N.mjs} +3 -3
  55. package/.output/server/_ssr/{node-sqlite-dialect-DhyOpJTX.mjs → node-sqlite-dialect-Y22MTyEv.mjs} +2 -2
  56. package/.output/server/_ssr/{notifyFns-BcMRY5kP.mjs → notifyFns-Bmqhlrkc.mjs} +3 -3
  57. package/.output/server/_ssr/{notifyFns-Q458pZmE.mjs → notifyFns-CdrijMGW.mjs} +5 -5
  58. package/.output/server/_ssr/{router-J8KZ30xw.mjs → router-CdxedJtm.mjs} +30 -30
  59. package/.output/server/_ssr/routes-Bcs4T1ox.mjs +1 -1
  60. package/.output/server/_ssr/{routes-D4am3Zff.mjs → routes-Bhay1OjL.mjs} +6 -6
  61. package/.output/server/_ssr/{routes-BoGrcf-b.mjs → routes-ROFun1nJ.mjs} +5 -5
  62. package/.output/server/_ssr/{runDiff-CpEFqo7G.mjs → runDiff-DWwt7qXb.mjs} +2 -2
  63. package/.output/server/_ssr/ssr.mjs +49 -49
  64. package/.output/server/_ssr/store-D75hcTob.mjs +2 -0
  65. package/.output/server/_ssr/{t._teamId-DR-hQK7o.mjs → t._teamId-CGba9PRq.mjs} +5 -5
  66. package/.output/server/_ssr/{t._teamId-CeUhzgzT.mjs → t._teamId-DTKU7GOp.mjs} +6 -6
  67. package/.output/server/_ssr/t._teamId-Dy_McbRt.mjs +1 -1
  68. package/.output/server/_ssr/{teamFns-BIDnsg2A.mjs → teamFns-BMDqynoT.mjs} +3 -3
  69. package/.output/server/_ssr/{teamFns-DA4ovI5g.mjs → teamFns-D4I-0dEB.mjs} +2 -2
  70. package/.output/server/_ssr/tokens-BHjz7Lvx.mjs +2 -0
  71. package/.output/server/_ssr/ui-Dej2qjuS.mjs +1 -1
  72. package/.output/server/{_tanstack-start-manifest_v-CVS6c7re.mjs → _tanstack-start-manifest_v-BwejIUux.mjs} +21 -21
  73. package/.output/server/drizzle/0009_ordinary_electro.sql +1 -0
  74. package/.output/server/drizzle/0010_workable_rage.sql +14 -0
  75. package/.output/server/drizzle/meta/0009_snapshot.json +1793 -0
  76. package/.output/server/drizzle/meta/0010_snapshot.json +1891 -0
  77. package/.output/server/drizzle/meta/_journal.json +14 -0
  78. package/.output/server/index.mjs +102 -102
  79. package/drizzle/0009_ordinary_electro.sql +1 -0
  80. package/drizzle/0010_workable_rage.sql +14 -0
  81. package/drizzle/meta/0009_snapshot.json +1793 -0
  82. package/drizzle/meta/0010_snapshot.json +1891 -0
  83. package/drizzle/meta/_journal.json +14 -0
  84. package/package.json +1 -1
  85. package/scripts/pievo-server.mjs +5 -0
  86. package/scripts/server-cli-lib.mjs +2 -0
  87. package/.output/public/assets/Modal-D33gNSgx.js +0 -1
  88. package/.output/public/assets/app-DElSo_jy.css +0 -2
  89. package/.output/public/assets/index-DfpTWRSz.js +0 -12
  90. package/.output/public/assets/loops._loopId-B19Jw7jC.js +0 -5
  91. package/.output/public/assets/notifyFns-DCubjpRy.js +0 -1
  92. package/.output/server/_ssr/artifacts-DngKyW2u.mjs +0 -2
  93. package/.output/server/_ssr/db-DWAuZq1o.mjs +0 -2
  94. package/.output/server/_ssr/logger-Dw82jNjH.mjs +0 -2
  95. package/.output/server/_ssr/store-b3JcQ08F.mjs +0 -2
  96. package/.output/server/_ssr/tokens-ytd60FUt.mjs +0 -2
@@ -1,18 +1,18 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
- import { C as require_jsx_runtime, S as require_react, a as MenuPortal, i as MenuPositioner, n as MenuTrigger, o as MenuPopup, r as MenuRoot, s as MenuItem, t as Separator } from "../_libs/@base-ui/react+[...].mjs";
3
- import { c as CODING_AGENTS, ft as isTaskEntry, h as buildFileEntries } from "./boot-BbtG0ImW.mjs";
2
+ import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
+ import { c as CODING_AGENTS, ft as isTaskEntry, h as buildFileEntries } from "./boot-aI3l2EYT.mjs";
4
4
  import { A as selectCls, C as labelCls, E as rel, M as until, O as runPulseStyle, S as isCompleted, _ as fmt, b as inputCls, c as btnDanger, d as btnQuiet, g as dur, h as dotLabel, i as Pre, j as tsShort, k as sectionHeadCls, l as btnPrimary, m as dotColor, n as Loading, o as btn, p as cronText, r as Pill, s as btnCost, t as ErrorBanner, x as isClosed, y as humanBytes } from "./ui-Dej2qjuS.mjs";
5
5
  import { d as useNavigate, u as Link } from "../_libs/@tanstack/react-router+[...].mjs";
6
- import { C as startJob, S as runJob, _ as loadOlderRuns, a as evolveJob, b as pauseJob, c as getArtifacts, f as getJobDetail, i as deleteJob, o as forceDeleteJob, w as stopJob, x as requestEdit, y as patchJob } from "./loopApi-Cxe8WyOB.mjs";
7
- import { n as TaskFileView, r as ViewerHead, t as ArtifactBody } from "./artifactView-DS4O22wl.mjs";
8
- import { i as useFlash, n as FlashLine, r as LoadErrorCard, t as ConfirmBar } from "./actionUi-CZbEixbf.mjs";
9
- import { s as useSession } from "./LoopPlaybook-BXH8mhiX.mjs";
6
+ import { C as stopJob, S as startJob, a as evolveJob, b as requestEdit, d as getJobDetail, g as loadOlderRuns, i as deleteJob, s as getArtifacts, v as patchJob, x as runJob, y as pauseJob } from "./loopApi-BfMnXaKT.mjs";
7
+ import { n as TaskFileView, r as ViewerHead, t as ArtifactBody } from "./artifactView-CYV1r48i.mjs";
8
+ import { s as useSession } from "./LoopPlaybook-BBn-xXpG.mjs";
10
9
  import { t as setActiveTeamCookie } from "./teamCookie-B7hLOIie.mjs";
11
- import { t as SignIn } from "./SignIn-dTndU6Hw.mjs";
12
- import { i as lifecycleDisplay, n as daemonStopSupport, r as deriveLoopLifecycle, t as DAEMON_UPGRADE_REQUIRED } from "./lifecycleUi-C9lg1r3r.mjs";
13
- import { a as listChannels, n as Timeline, s as mergeRuns, t as MachinesModal } from "./notifyFns-Q458pZmE.mjs";
14
- import { t as Route } from "./loops._loopId-7NQJPB9W.mjs";
15
- //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-DhnArGdL.js
10
+ import { t as SignIn } from "./SignIn-RJN_0GFZ.mjs";
11
+ import { i as useFlash, n as FlashLine, r as LoadErrorCard, t as ConfirmBar } from "./actionUi-CZbEixbf.mjs";
12
+ import { i as lifecycleDisplay, n as daemonStopSupport, r as deriveLoopLifecycle, t as DAEMON_UPGRADE_REQUIRED } from "./lifecycleUi-BhRsBvJ7.mjs";
13
+ import { a as listChannels, n as Timeline, s as mergeRuns, t as MachinesModal } from "./notifyFns-CdrijMGW.mjs";
14
+ import { t as Route } from "./loops._loopId-u8Dr2J5f.mjs";
15
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-BODmoHPu.js
16
16
  var import_react = /* @__PURE__ */ __toESM(require_react());
17
17
  var import_jsx_runtime = require_jsx_runtime();
18
18
  /**
@@ -187,16 +187,17 @@ function ArtifactEntryView({ loopId, file }) {
187
187
  /**
188
188
  * Build the exec slice of a manual form save.
189
189
  *
190
- * Always emits so model / allowControl ride with Save even when workdir is
191
- * empty (common for taskFile/workflow-only loops). Empty strings stay defined
192
- * so patchJob can clear stored model/workdir via `trim() || null` - do not
193
- * coerce cleared fields to `undefined` or gate the whole object on workdir.
190
+ * Always emits so model / reasoningEffort / allowControl ride with Save even
191
+ * when workdir is empty (common for taskFile/workflow-only loops). Empty strings
192
+ * stay defined so patchJob can clear stored execution settings via `trim() || null` -
193
+ * do not coerce cleared fields to `undefined` or gate the whole object on workdir.
194
194
  */
195
195
  function buildFormExec(f) {
196
196
  return {
197
197
  executor: "claude",
198
198
  workdir: f.workdir.trim(),
199
199
  model: f.model.trim(),
200
+ reasoningEffort: f.reasoningEffort.trim(),
200
201
  allowControl: f.allowControl
201
202
  };
202
203
  }
@@ -217,6 +218,7 @@ function initState(initial) {
217
218
  agent: initial?.agent ?? "claude-code",
218
219
  workdir: e?.workdir ?? "",
219
220
  model: e?.model ?? "",
221
+ reasoningEffort: e?.reasoningEffort ?? "",
220
222
  allowControl: !!e?.allowControl
221
223
  };
222
224
  }
@@ -229,14 +231,17 @@ var AGENT_LABEL$1 = {
229
231
  codex: "Codex"
230
232
  };
231
233
  function TextField({ label, value, onChange, mono, ph, hint }) {
234
+ const id = (0, import_react.useId)();
232
235
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
233
236
  className: "min-w-0",
234
237
  children: [
235
238
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
239
+ htmlFor: id,
236
240
  className: labelCls,
237
241
  children: label
238
242
  }),
239
243
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
244
+ id,
240
245
  type: "text",
241
246
  className: mono ? `${inputCls} font-mono` : inputCls,
242
247
  value,
@@ -451,7 +456,15 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial, channel
451
456
  label: "Model",
452
457
  value: f.model,
453
458
  onChange: (v) => set("model", v),
454
- hint: "Optional - the daemon default when empty."
459
+ ph: "default",
460
+ hint: "Optional arbitrary model id. Empty uses the coding-agent CLI default."
461
+ }),
462
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextField, {
463
+ label: "Reasoning effort",
464
+ value: f.reasoningEffort,
465
+ onChange: (v) => set("reasoningEffort", v),
466
+ ph: "default",
467
+ hint: "Optional arbitrary effort value. Empty uses the coding-agent CLI default."
455
468
  }),
456
469
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
457
470
  className: "mt-4 flex cursor-pointer items-center gap-2 text-body text-primary",
@@ -567,7 +580,7 @@ var EDIT_SEEDS = [
567
580
  seed: "Give this loop a goal, and finish it once the goal is met: "
568
581
  }
569
582
  ];
570
- var LoopView = (0, import_react.lazy)(() => import("./LoopView-DCugEbHx.mjs").then((m) => ({ default: m.LoopView })));
583
+ var LoopView = (0, import_react.lazy)(() => import("./LoopView-DdyJYOCY.mjs").then((m) => ({ default: m.LoopView })));
571
584
  /**
572
585
  * Loop detail PAGE body (`/loops/$loopId`) — the redesign of the former modal.
573
586
  * One scrolling page: a loop header (name / status / schedule / agent / machine +
@@ -576,14 +589,13 @@ var LoopView = (0, import_react.lazy)(() => import("./LoopView-DCugEbHx.mjs").th
576
589
  * the Runs timeline (a strip + a clickable list, each run linking to its own
577
590
  * detail route). Self-polls while open (fast while a run is live).
578
591
  *
579
- * Editing (2026-07 redesign): the primary path is an INLINE composer in the
580
- * header footer (same slot as the Push settings) - the page stays visible, so
592
+ * Editing (2026-07 redesign): the primary path is an INLINE composer below the
593
+ * always-visible action toolbar - the page stays visible, so
581
594
  * the owner describes the change while looking at the spec/dashboard it applies
582
595
  * to. Dispatch swaps the composer for a live status card under the header
583
596
  * (queued → applying → settled with report + files + a link to
584
597
  * the edit run); the page keeps polling, so the applied change surfaces around
585
- * the card. Only the manual field form (the raw-settings fallback) remains a
586
- * full-page takeover.
598
+ * the card. Settings remains a full-page field-form takeover.
587
599
  */
588
600
  function LoopDetailView({ id }) {
589
601
  const navigate = useNavigate();
@@ -598,11 +610,9 @@ function LoopDetailView({ id }) {
598
610
  const [editDispatched, setEditDispatched] = (0, import_react.useState)(false);
599
611
  const [editRunId, setEditRunId] = (0, import_react.useState)(null);
600
612
  const editBoxRef = (0, import_react.useRef)(null);
601
- const [pushOpen, setPushOpen] = (0, import_react.useState)(false);
602
- const [pushSaved, setPushSaved] = (0, import_react.useState)(false);
603
613
  const [machinesOpen, setMachinesOpen] = (0, import_react.useState)(false);
604
614
  const [pending, setPending] = (0, import_react.useState)(null);
605
- const [confirming, setConfirming] = (0, import_react.useState)(null);
615
+ const [confirmingDelete, setConfirmingDelete] = (0, import_react.useState)(false);
606
616
  const [flash, setFlash] = useFlash();
607
617
  const formRef = (0, import_react.useRef)(null);
608
618
  const deletingRef = (0, import_react.useRef)(false);
@@ -626,7 +636,7 @@ function LoopDetailView({ id }) {
626
636
  setPromptCopied(false);
627
637
  setEditDispatched(false);
628
638
  setEditRunId(null);
629
- setPushOpen(false);
639
+ setConfirmingDelete(false);
630
640
  setOlder([]);
631
641
  load();
632
642
  listChannels().then(setChannels).catch(() => {});
@@ -641,25 +651,15 @@ function LoopDetailView({ id }) {
641
651
  running,
642
652
  load
643
653
  ]);
644
- (0, import_react.useEffect)(() => {
645
- if (!pushSaved) return;
646
- const t = setTimeout(() => setPushSaved(false), 1800);
647
- return () => clearTimeout(t);
648
- }, [pushSaved]);
649
654
  async function refreshAll() {
650
655
  await load();
651
656
  }
652
- function onRun() {
653
- if (detail?.job.exec) setConfirming("run");
654
- else doRun();
655
- }
656
657
  async function doRun() {
657
658
  setActionErr(null);
658
659
  setPending("run");
659
660
  try {
660
661
  const r = await runJob({ data: id });
661
662
  if (r?.error) return setActionErr(`Run failed: ${r.error}`);
662
- setConfirming(null);
663
663
  setFlash({
664
664
  label: r.coalesced ? "Already queued" : "Queued",
665
665
  hold: 4e3
@@ -675,7 +675,6 @@ function LoopDetailView({ id }) {
675
675
  try {
676
676
  const r = await evolveJob({ data: id });
677
677
  if (r?.error) return setActionErr(`Evolve failed: ${r.error}`);
678
- setConfirming(null);
679
678
  setFlash({
680
679
  label: r.coalesced ? "Evolve already queued" : "Evolve queued",
681
680
  hold: 4e3
@@ -689,12 +688,12 @@ function LoopDetailView({ id }) {
689
688
  setActionErr(null);
690
689
  setPending("lifecycle");
691
690
  try {
692
- const r = action === "pause" ? await pauseJob({ data: id }) : action === "start" ? await startJob({ data: id }) : action === "stop" ? await stopJob({ data: id }) : action === "delete" ? await deleteJob({ data: id }) : await forceDeleteJob({ data: {
691
+ const r = action === "pause" ? await pauseJob({ data: id }) : action === "start" ? await startJob({ data: id }) : action === "stop" ? await stopJob({ data: id }) : action === "reopen" ? await patchJob({ data: {
693
692
  id,
694
- confirmation: "delete-server-data-anyway"
695
- } });
696
- if (r.error) return setActionErr(`${action === "force-delete" ? "Force delete" : action[0].toUpperCase() + action.slice(1)} failed: ${r.error}`);
697
- setConfirming(null);
693
+ patch: { enabled: true }
694
+ } }) : await deleteJob({ data: id });
695
+ if (r.error) return setActionErr(`${action[0].toUpperCase() + action.slice(1)} failed: ${r.error}`);
696
+ setConfirmingDelete(false);
698
697
  if (r.deleted) {
699
698
  deletingRef.current = false;
700
699
  navigate({ to: "/" });
@@ -702,21 +701,11 @@ function LoopDetailView({ id }) {
702
701
  }
703
702
  if (action === "delete") deletingRef.current = true;
704
703
  await refreshAll();
705
- setFlash({ label: action === "start" ? "Started" : action === "pause" ? "Paused" : action === "stop" ? "Stop requested" : "Deleting" });
704
+ setFlash({ label: action === "start" ? "Started" : action === "reopen" ? "Reopened" : action === "pause" ? "Paused" : action === "stop" ? "Stop requested" : "Deleting" });
706
705
  } finally {
707
706
  setPending(null);
708
707
  }
709
708
  }
710
- async function setPush(patch) {
711
- setActionErr(null);
712
- const r = await patchJob({ data: {
713
- id,
714
- patch
715
- } });
716
- if (r.error) return setActionErr(`Save failed: ${r.error}`);
717
- await refreshAll();
718
- setPushSaved(true);
719
- }
720
709
  async function onSave() {
721
710
  const payload = formRef.current?.read();
722
711
  if (!payload) return;
@@ -755,14 +744,6 @@ function LoopDetailView({ id }) {
755
744
  setPending(null);
756
745
  }
757
746
  }
758
- function onConfirm() {
759
- if (confirming === "run") doRun();
760
- else if (confirming === "evolve") doEvolve();
761
- else if (confirming === "pause") doLifecycle("pause");
762
- else if (confirming === "stop") doLifecycle("stop");
763
- else if (confirming === "delete") doLifecycle("delete");
764
- else if (confirming === "force-delete") doLifecycle("force-delete");
765
- }
766
747
  const backLink = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
767
748
  to: "/",
768
749
  className: "inline-flex items-center gap-1.5 text-meta font-medium text-secondary transition-colors hover:text-display",
@@ -815,41 +796,6 @@ function LoopDetailView({ id }) {
815
796
  setActionErr("Could not copy the prompt - try again or copy it manually.");
816
797
  }
817
798
  };
818
- const CONFIRM = {
819
- run: {
820
- q: "Run one real cycle now?",
821
- note: `Spawns the coding agent (${AGENT_LABEL[job.agent ?? "claude-code"] ?? job.agent ?? "Claude Code"}).`,
822
- cta: "Run once",
823
- danger: false
824
- },
825
- evolve: {
826
- q: "Trigger an evolution pass now?",
827
- note: "Re-authors the dashboard / tightens the gate from real run data.",
828
- cta: "Evolve",
829
- danger: false
830
- },
831
- pause: {
832
- q: "Pause future runs? The current run will continue.",
833
- cta: "Pause",
834
- danger: false
835
- },
836
- stop: {
837
- q: "Pause this loop, cancel queued work, and stop the current run if it is still running?",
838
- cta: "Stop",
839
- danger: true
840
- },
841
- delete: {
842
- q: "Stop this loop and delete its Pievo history and synced artifacts? Local project files are not deleted.",
843
- cta: "Delete",
844
- danger: true
845
- },
846
- "force-delete": {
847
- q: "Delete server data anyway",
848
- note: "The machine is unreachable. Its local process may still be running. This removes Pievo authority and server data only.",
849
- cta: "Delete server data anyway",
850
- danger: true
851
- }
852
- };
853
799
  const flashLine = flash && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
854
800
  className: "mb-2.5",
855
801
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlashLine, {
@@ -858,296 +804,192 @@ function LoopDetailView({ id }) {
858
804
  onUndo: flash.undo
859
805
  })
860
806
  });
861
- const c = confirming && CONFIRM[confirming];
862
- const confirmLocked = busy;
863
- const pushSelectCls = "lp-select cursor-pointer rounded-control border border-wire bg-surface py-1.5 pl-2.5 text-meta text-primary outline-none transition-colors hover:border-display focus:border-display disabled:cursor-default disabled:opacity-40";
864
- const menuItem = "flex w-full cursor-pointer select-none items-center px-3.5 py-2 text-body text-primary outline-none transition-colors data-[highlighted]:bg-raised data-[disabled]:cursor-default data-[disabled]:opacity-40";
865
- const menuItemDanger = "flex w-full cursor-pointer select-none items-center px-3.5 py-2 text-body text-accent outline-none transition-colors data-[highlighted]:bg-accent-soft data-[disabled]:cursor-default data-[disabled]:opacity-40";
866
- const actionBar = c ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfirmBar, {
867
- prompt: c.q,
868
- note: "note" in c ? c.note : void 0,
869
- cta: c.cta,
870
- danger: c.danger,
871
- busy: confirmLocked,
872
- onConfirm,
873
- onCancel: () => setConfirming(null)
874
- }, confirming) : lifecycle === "deleting" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
875
- className: "flex flex-wrap items-center gap-3 rounded-md border border-wire bg-raised px-4 py-3",
876
- children: [
877
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
878
- className: "text-body font-medium text-display",
879
- children: lifecycleText
880
- }),
881
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
882
- className: "text-meta text-secondary",
883
- children: "Server deletion is waiting for execution authority to end."
884
- }),
885
- !online && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
886
- type: "button",
887
- className: btnDanger,
888
- onClick: () => setConfirming("force-delete"),
889
- disabled: busy,
890
- children: "Delete server data anyway"
891
- })
892
- ]
893
- }) : editVia ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
894
- onKeyDown: (e) => {
895
- if (e.key === "Escape" && pending !== "edit") {
896
- e.stopPropagation();
897
- setEditVia(false);
898
- }
899
- },
807
+ const deleting = lifecycle === "deleting";
808
+ const paused = !s.enabled && !completed && !deleting;
809
+ const active = s.enabled && !completed && !deleting;
810
+ const actionDisabled = busy || deleting;
811
+ const canRunWork = active || paused;
812
+ const canStop = canRunWork && !!s.running && protocolSupport.supported;
813
+ const stopTitle = s.running && !protocolSupport.supported ? DAEMON_UPGRADE_REQUIRED : !s.running ? "No run is currently running" : void 0;
814
+ const actionBar = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
815
+ className: "min-w-0",
900
816
  children: [
901
817
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
902
- className: "flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",
903
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
904
- className: "text-body font-medium text-display",
905
- children: "Edit with your coding agent"
906
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
907
- className: "text-meta text-secondary",
908
- children: [
909
- "One agent pass on ",
910
- onMachine,
911
- " · spends credits"
912
- ]
913
- })]
914
- }),
915
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
916
- ref: editBoxRef,
917
- autoFocus: true,
918
- value: editInstruction,
919
- onChange: (e) => setEditInstruction(e.target.value),
920
- onKeyDown: (e) => {
921
- if ((e.metaKey || e.ctrlKey) && e.key === "Enter" && editInstruction.trim() && pending !== "edit") onRequestEdit();
922
- },
923
- rows: 3,
924
- placeholder: "e.g. run at 9am on weekdays instead, and also check coffee stock",
925
- className: "mt-3 w-full resize-y rounded-control border border-wire bg-raised p-3 font-mono text-label leading-relaxed text-primary outline-none transition-shadow placeholder:text-disabled focus:border-transparent focus:shadow-focus"
926
- }),
927
- !editInstruction.trim() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
928
- className: "mt-2 flex flex-wrap gap-1.5",
929
- children: EDIT_SEEDS.map((sd) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
930
- type: "button",
931
- onClick: () => {
932
- setEditInstruction(sd.seed);
933
- editBoxRef.current?.focus();
934
- },
935
- className: "cursor-pointer rounded-full border border-wire bg-surface px-3 py-1 text-label font-medium text-secondary transition-colors hover:bg-raised hover:text-display",
936
- children: sd.label
937
- }, sd.label))
938
- }),
939
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
940
- className: "mt-3.5 flex flex-wrap items-center gap-x-2.5 gap-y-2",
818
+ className: "flex min-w-0 flex-wrap items-center gap-2",
941
819
  children: [
942
820
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
943
- className: btnCost,
944
- disabled: pending === "edit" || !editInstruction.trim(),
945
- title: offlineHint,
946
- onClick: () => void onRequestEdit(),
947
- children: pending === "edit" ? "Dispatching…" : "Dispatch to your coding agent"
821
+ className: btnPrimary,
822
+ disabled: actionDisabled || !canRunWork,
823
+ onClick: () => void doRun(),
824
+ title: !canRunWork ? "Unavailable for a completed or deleting loop" : offlineHint ?? (job.exec ? "Spends credits" : void 0),
825
+ "aria-label": job.exec ? "Run once - spends credits" : "Run once",
826
+ children: pending === "run" ? "Queuing…" : "Run once"
948
827
  }),
949
828
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
950
- type: "button",
951
829
  className: btn,
952
- disabled: pending === "edit",
953
- onClick: () => void copyEditPrompt(),
954
- children: promptCopied ? "✓ Prompt copied" : "Copy prompt"
830
+ disabled: actionDisabled || !(canRunWork || completed),
831
+ title: "Dispatch or copy a prompt for an owner-requested edit",
832
+ onClick: () => setEditVia(true),
833
+ children: "Agent edit"
955
834
  }),
956
835
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
957
836
  className: btn,
958
- disabled: pending === "edit",
959
- onClick: () => setEditVia(false),
960
- children: "Cancel"
837
+ disabled: actionDisabled || !canRunWork,
838
+ title: !canRunWork ? "Unavailable for a completed or deleting loop" : offlineHint ?? "Spends credits",
839
+ onClick: () => void doEvolve(),
840
+ children: pending === "evolve" ? "Evolving…" : "Evolve once"
961
841
  }),
962
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
963
- className: "hidden text-caption text-disabled sm:inline",
964
- children: "⌘↩ dispatch · esc cancel"
842
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
843
+ className: btn,
844
+ disabled: actionDisabled,
845
+ onClick: () => setEditing(true),
846
+ children: "Settings"
965
847
  }),
966
848
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
967
- type: "button",
968
- onClick: () => {
969
- setEditVia(false);
970
- setEditing(true);
971
- },
972
- className: "ml-auto cursor-pointer border-none bg-transparent p-0 text-label text-secondary underline underline-offset-2 transition-colors hover:text-display",
973
- children: "Manual settings →"
849
+ className: btn,
850
+ disabled: actionDisabled || !paused,
851
+ onClick: () => void doLifecycle("start"),
852
+ children: "Start"
853
+ }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
855
+ className: btn,
856
+ disabled: actionDisabled || !active,
857
+ onClick: () => void doLifecycle("pause"),
858
+ children: "Pause"
859
+ }),
860
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
861
+ className: btnDanger,
862
+ disabled: actionDisabled || !canStop,
863
+ title: stopTitle,
864
+ onClick: () => void doLifecycle("stop"),
865
+ children: "Stop"
866
+ }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
868
+ className: btn,
869
+ disabled: actionDisabled || !completed,
870
+ onClick: () => void doLifecycle("reopen"),
871
+ children: "Reopen"
872
+ }),
873
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
874
+ className: btnDanger,
875
+ disabled: actionDisabled,
876
+ onClick: () => setConfirmingDelete(true),
877
+ children: deleting ? "Deleting…" : "Delete"
974
878
  })
975
879
  ]
976
880
  }),
977
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
978
- className: "mt-2 text-caption leading-snug text-disabled",
979
- children: promptCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
980
- className: "text-secondary",
981
- children: [
982
- "✓ Copied · run your coding agent",
983
- " ",
984
- editDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: ["in ", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
985
- className: "break-all font-mono text-primary",
986
- children: editDir
987
- })] }) : "in the loop’s local directory on this machine",
988
- " ",
989
- "and paste the prompt to adjust the loop yourself."
990
- ]
991
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: "Prefer to adjust it yourself? Copy prompt drops a ready-to-paste prompt for your own coding agent - no dispatch, no credits." })
992
- })
993
- ]
994
- }) : pushOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
995
- className: "flex flex-wrap items-center gap-2.5",
996
- children: [
997
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
998
- className: "text-label font-medium text-secondary",
999
- children: "Push"
1000
- }),
1001
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
1002
- "aria-label": "Notify",
1003
- className: pushSelectCls,
1004
- value: job.notify,
1005
- disabled: busy,
1006
- onChange: (e) => void setPush({ notify: e.target.value }),
1007
- children: [
1008
- "auto",
1009
- "always",
1010
- "never"
1011
- ].map((n) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
1012
- value: n,
1013
- children: n
1014
- }, n))
1015
- }),
1016
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1017
- "aria-hidden": true,
1018
- className: "text-secondary",
1019
- children: "→"
881
+ confirmingDelete && !deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
882
+ className: "mt-3",
883
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfirmBar, {
884
+ prompt: "Stop this loop and delete its server data?",
885
+ note: "This stops the loop and deletes server history and synced artifacts. Local files are not deleted. If the machine is unreachable, server data is still deleted and its local process may continue running.",
886
+ cta: "Delete",
887
+ danger: true,
888
+ busy,
889
+ onConfirm: () => void doLifecycle("delete"),
890
+ onCancel: () => setConfirmingDelete(false)
891
+ })
1020
892
  }),
1021
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
1022
- "aria-label": "Push channel",
1023
- className: pushSelectCls,
1024
- value: job.channelId ?? "",
1025
- disabled: busy,
1026
- onChange: (e) => void setPush({ channelId: e.target.value }),
1027
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
1028
- value: "",
1029
- children: "none (dashboard only)"
1030
- }), channels.map((ch) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
1031
- value: ch.id,
1032
- children: ch.name
1033
- }, ch.id))]
893
+ deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
894
+ className: "mt-3 rounded-md border border-wire bg-raised px-4 py-3 text-meta text-secondary",
895
+ children: "Deleting… graceful stop is waiting for execution authority to end."
1034
896
  }),
1035
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1036
- className: "ml-auto flex items-center gap-2.5",
1037
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1038
- "aria-hidden": true,
1039
- className: `text-[14px] leading-none text-success transition-opacity duration-200 ${pushSaved ? "opacity-100" : "opacity-0"}`,
1040
- children: "✓"
1041
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
1042
- type: "button",
1043
- onClick: () => setPushOpen(false),
1044
- className: btnQuiet,
1045
- children: "Done"
1046
- })]
897
+ editVia && !deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
898
+ className: "mt-4 border-t border-hairline pt-4",
899
+ onKeyDown: (e) => {
900
+ if (e.key === "Escape" && pending !== "edit") {
901
+ e.stopPropagation();
902
+ setEditVia(false);
903
+ }
904
+ },
905
+ children: [
906
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
907
+ className: "flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",
908
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
909
+ className: "text-body font-medium text-display",
910
+ children: "Edit with your coding agent"
911
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
912
+ className: "text-meta text-secondary",
913
+ children: [
914
+ "One agent pass on ",
915
+ onMachine,
916
+ " · spends credits"
917
+ ]
918
+ })]
919
+ }),
920
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
921
+ ref: editBoxRef,
922
+ autoFocus: true,
923
+ value: editInstruction,
924
+ onChange: (e) => setEditInstruction(e.target.value),
925
+ onKeyDown: (e) => {
926
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter" && editInstruction.trim() && pending !== "edit") onRequestEdit();
927
+ },
928
+ rows: 3,
929
+ placeholder: "e.g. run at 9am on weekdays instead, and also check coffee stock",
930
+ className: "mt-3 w-full resize-y rounded-control border border-wire bg-raised p-3 font-mono text-label leading-relaxed text-primary outline-none transition-shadow placeholder:text-disabled focus:border-transparent focus:shadow-focus"
931
+ }),
932
+ !editInstruction.trim() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
933
+ className: "mt-2 flex flex-wrap gap-1.5",
934
+ children: EDIT_SEEDS.map((sd) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
935
+ type: "button",
936
+ onClick: () => {
937
+ setEditInstruction(sd.seed);
938
+ editBoxRef.current?.focus();
939
+ },
940
+ className: "cursor-pointer rounded-full border border-wire bg-surface px-3 py-1 text-label font-medium text-secondary transition-colors hover:bg-raised hover:text-display",
941
+ children: sd.label
942
+ }, sd.label))
943
+ }),
944
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
945
+ className: "mt-3.5 flex flex-wrap items-center gap-x-2.5 gap-y-2",
946
+ children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
948
+ className: btnCost,
949
+ disabled: pending === "edit" || !editInstruction.trim(),
950
+ title: offlineHint,
951
+ onClick: () => void onRequestEdit(),
952
+ children: pending === "edit" ? "Dispatching…" : "Dispatch to your coding agent"
953
+ }),
954
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
955
+ type: "button",
956
+ className: btn,
957
+ disabled: pending === "edit",
958
+ onClick: () => void copyEditPrompt(),
959
+ children: promptCopied ? "✓ Prompt copied" : "Copy prompt"
960
+ }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
962
+ className: btn,
963
+ disabled: pending === "edit",
964
+ onClick: () => setEditVia(false),
965
+ children: "Cancel"
966
+ }),
967
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
968
+ className: "hidden text-caption text-disabled sm:inline",
969
+ children: "⌘↩ dispatch · esc cancel"
970
+ })
971
+ ]
972
+ }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
974
+ className: "mt-2 text-caption leading-snug text-disabled",
975
+ children: promptCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
976
+ className: "text-secondary",
977
+ children: [
978
+ "✓ Copied · run your coding agent",
979
+ " ",
980
+ editDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: ["in ", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
981
+ className: "break-all font-mono text-primary",
982
+ children: editDir
983
+ })] }) : "in the loop’s local directory on this machine",
984
+ " ",
985
+ "and paste the prompt to adjust the loop yourself."
986
+ ]
987
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: "Prefer to adjust it yourself? Copy prompt drops a ready-to-paste prompt for your own coding agent - no dispatch, no credits." })
988
+ })
989
+ ]
1047
990
  })
1048
991
  ]
1049
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1050
- className: "flex flex-wrap items-center gap-2",
1051
- children: [
1052
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
1053
- className: btnPrimary,
1054
- disabled: busy || completed,
1055
- onClick: onRun,
1056
- title: completed ? "Loop completed - only Edit is available until it is reopened" : s.running || s.queued ? "Queues or coalesces one exec follow-up" : offlineHint ?? (job.exec ? "Spends credits" : void 0),
1057
- "aria-label": job.exec ? "Run once - spends credits" : "Run once",
1058
- children: pending === "run" ? "Queuing…" : s.running || s.queued ? "Queue run" : "Run once"
1059
- }),
1060
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
1061
- className: btn,
1062
- disabled: busy,
1063
- title: "Queues an edit; a queued edit is updated with the latest instruction",
1064
- onClick: () => setEditVia(true),
1065
- children: "Edit"
1066
- }),
1067
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(MenuRoot, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuTrigger, {
1068
- className: `${btn} px-2.5`,
1069
- disabled: busy,
1070
- "aria-label": "More actions",
1071
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
1072
- "aria-hidden": true,
1073
- width: "16",
1074
- height: "16",
1075
- viewBox: "0 0 16 16",
1076
- fill: "currentColor",
1077
- children: [
1078
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
1079
- cx: "3",
1080
- cy: "8",
1081
- r: "1.4"
1082
- }),
1083
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
1084
- cx: "8",
1085
- cy: "8",
1086
- r: "1.4"
1087
- }),
1088
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
1089
- cx: "13",
1090
- cy: "8",
1091
- r: "1.4"
1092
- })
1093
- ]
1094
- })
1095
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuPositioner, {
1096
- side: "bottom",
1097
- align: "end",
1098
- sideOffset: 6,
1099
- className: "z-[950]",
1100
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(MenuPopup, {
1101
- className: "glass-strong min-w-[176px] origin-[var(--transform-origin)] rounded-control py-1.5 outline-none transition-[opacity,transform] duration-150 data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
1102
- children: [
1103
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1104
- className: menuItem,
1105
- disabled: busy || completed,
1106
- onClick: () => setConfirming("evolve"),
1107
- title: completed ? "Completed loops only accept manual edits" : offlineHint ?? "Spends credits",
1108
- children: pending === "evolve" ? "Evolving…" : "Evolve now"
1109
- }),
1110
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1111
- className: menuItem,
1112
- onClick: () => setPushOpen(true),
1113
- children: "Push…"
1114
- }),
1115
- completed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1116
- className: menuItem,
1117
- onClick: () => void patchJob({ data: {
1118
- id,
1119
- patch: { enabled: true }
1120
- } }).then(refreshAll),
1121
- children: "Reopen"
1122
- }) : lifecycle === "paused" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1123
- className: menuItem,
1124
- onClick: () => void doLifecycle("start"),
1125
- children: "Start"
1126
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1127
- className: menuItem,
1128
- onClick: () => setConfirming("pause"),
1129
- children: "Pause"
1130
- }),
1131
- !completed && lifecycle !== "stopping" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1132
- className: menuItemDanger,
1133
- disabled: !!s.running && !protocolSupport.supported,
1134
- title: s.running && !protocolSupport.supported ? "Daemon upgrade required to stop a running process. Run `npm install -g @kky42/pievo@latest`, then `pievo daemon restart`." : void 0,
1135
- onClick: () => setConfirming("stop"),
1136
- children: "Stop"
1137
- }),
1138
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Separator, { className: "my-1.5 h-px bg-hairline" }),
1139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuItem, {
1140
- className: menuItemDanger,
1141
- disabled: !!s.running && !protocolSupport.supported,
1142
- title: s.running && !protocolSupport.supported ? DAEMON_UPGRADE_REQUIRED : void 0,
1143
- onClick: () => setConfirming("delete"),
1144
- children: "Delete"
1145
- })
1146
- ]
1147
- })
1148
- }) })] })
1149
- ]
1150
- }) });
992
+ });
1151
993
  const actionErrEl = actionErr && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, {
1152
994
  message: actionErr,
1153
995
  onDismiss: () => setActionErr(null),
@@ -1245,6 +1087,10 @@ function LoopDetailView({ id }) {
1245
1087
  })]
1246
1088
  });
1247
1089
  const agentLabel = AGENT_LABEL[job.agent ?? "claude-code"] ?? job.agent ?? "Claude Code";
1090
+ const modelLabel = job.exec?.model?.trim() || "default";
1091
+ const reasoningEffortLabel = job.exec?.reasoningEffort?.trim() || "default";
1092
+ const newestRun = runs[0];
1093
+ const latestIncidentRun = newestRun?.reportIncident ? newestRun : void 0;
1248
1094
  const metaDot = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1249
1095
  className: "text-wire",
1250
1096
  children: "·"
@@ -1266,7 +1112,7 @@ function LoopDetailView({ id }) {
1266
1112
  className: "text-[28px] font-semibold leading-tight tracking-[-0.015em] text-display",
1267
1113
  children: s.name
1268
1114
  }),
1269
- completed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1115
+ lifecycle === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1270
1116
  tone: "success",
1271
1117
  dot: "green",
1272
1118
  children: "Completed"
@@ -1289,6 +1135,22 @@ function LoopDetailView({ id }) {
1289
1135
  title: "Recorded coding agent",
1290
1136
  children: agentLabel
1291
1137
  }),
1138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1139
+ tone: "outline",
1140
+ title: `Model: ${modelLabel}`,
1141
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
1142
+ className: "max-w-72 truncate",
1143
+ children: ["Model: ", modelLabel]
1144
+ })
1145
+ }),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1147
+ tone: "outline",
1148
+ title: `Reasoning: ${reasoningEffortLabel}`,
1149
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
1150
+ className: "max-w-72 truncate",
1151
+ children: ["Reasoning: ", reasoningEffortLabel]
1152
+ })
1153
+ }),
1292
1154
  crossTeam && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1293
1155
  tone: "outline",
1294
1156
  title: "This loop belongs to another of your teams",
@@ -1339,7 +1201,7 @@ function LoopDetailView({ id }) {
1339
1201
  children: s.goal
1340
1202
  })]
1341
1203
  }),
1342
- completed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1204
+ lifecycle === "completed" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1343
1205
  className: "mt-2 text-body leading-snug text-success",
1344
1206
  children: [
1345
1207
  "Completed",
@@ -1349,6 +1211,10 @@ function LoopDetailView({ id }) {
1349
1211
  children: [" - ", s.completionReason]
1350
1212
  })
1351
1213
  ]
1214
+ }),
1215
+ latestIncidentRun?.reportIncident && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1216
+ className: "mt-2 text-body leading-snug text-secondary",
1217
+ children: latestIncidentRun.outcome === "error" ? "Last run failed · Terminal report rejected" : "Last run telemetry warning · Terminal report rejected"
1352
1218
  })
1353
1219
  ]
1354
1220
  })
@@ -1495,7 +1361,7 @@ function LoopDetailView({ id }) {
1495
1361
  });
1496
1362
  }
1497
1363
  /**
1498
- * Manual-settings page heading. The field form is an in-page mode takeover (NOT
1364
+ * Settings page heading. The field form is an in-page mode takeover (NOT
1499
1365
  * a modal), so this is a plain heading - NOT `ModalHead`, whose Base UI
1500
1366
  * `Dialog.Title`/`Dialog.Close` require a `Dialog.Root` ancestor and throw
1501
1367
  * ("Cannot destructure property 'store' of 'useDialogRootContext(...)'") when
@@ -1514,11 +1380,11 @@ function EditHead({ name, onBack }) {
1514
1380
  }),
1515
1381
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h1", {
1516
1382
  className: "mt-2.5 text-[24px] font-semibold leading-tight tracking-[-0.015em] text-display",
1517
- children: ["Manual settings · ", name]
1383
+ children: ["Settings · ", name]
1518
1384
  }),
1519
1385
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
1520
1386
  className: "mt-1.5 max-w-[640px] text-meta leading-snug text-secondary",
1521
- children: "The raw fields, saved directly - no agent pass, no credits. For schedule or task changes in plain words, use Edit with your coding agent instead."
1387
+ children: "Loop configuration, notifications, and push channel, saved directly - no agent pass or credits. For changes in plain words, use Agent edit instead."
1522
1388
  })
1523
1389
  ] });
1524
1390
  }