@kky42/pievo-server 1.0.0 → 2.0.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 (100) 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-vKFxjMMk.css +2 -0
  6. package/.output/public/assets/{artifactView-DFuubXLJ.js → artifactView-DekEs5ME.js} +1 -1
  7. package/.output/public/assets/index-DSF-1ahT.js +12 -0
  8. package/.output/public/assets/{invite._token-T8oo4Qtw.js → invite._token-Cl9Oarnq.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-B-dYxc9i.js +4 -0
  12. package/.output/public/assets/{loops._loopId_.runs._runId-_CflHV38.js → loops._loopId_.runs._runId-DepMp3Me.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-BB4aDC1D.js} +1 -1
  16. package/.output/public/assets/{t._teamId-Bm21mngW.js → t._teamId-D552b9PT.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 → CodeField-B7oOmmwH.mjs} +4 -4
  24. package/.output/server/_ssr/{DashboardView-CC7htv28.mjs → DashboardView-D3E-zevQ.mjs} +45 -35
  25. package/.output/server/_ssr/{LoopPlaybook-BXH8mhiX.mjs → LoopPlaybook-DJlWGia5.mjs} +3 -3
  26. package/.output/server/_ssr/{LoopView-DCugEbHx.mjs → LoopView-BtMANpb_.mjs} +5 -5
  27. package/.output/server/_ssr/Modal-DpKZHLZK.mjs +1 -1
  28. package/.output/server/_ssr/{SignIn-dTndU6Hw.mjs → SignIn-CjFonm71.mjs} +3 -3
  29. package/.output/server/_ssr/actionUi-CZbEixbf.mjs +1 -1
  30. package/.output/server/_ssr/{adapters-BS8XosjF.mjs → adapters-vbuo_-wD.mjs} +10 -5
  31. package/.output/server/_ssr/{artifactFiles-Cagtj7J0.mjs → artifactFiles-BGod8IWQ.mjs} +3 -3
  32. package/.output/server/_ssr/{artifactView-DS4O22wl.mjs → artifactView-CYV1r48i.mjs} +3 -3
  33. package/.output/server/_ssr/artifacts-CduiDAM2.mjs +2 -0
  34. package/.output/server/_ssr/{auth-DY1DuYZd.mjs → auth-Ca-um-e8.mjs} +9 -9
  35. package/.output/server/_ssr/{boot-CMHTxQpJ.mjs → boot-C0f0HGCw.mjs} +1 -1
  36. package/.output/server/_ssr/{boot-BbtG0ImW.mjs → boot-CkFZynUz.mjs} +533 -294
  37. package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CU1Spd6z.mjs → bun-sqlite-dialect-BW9W1_Ps-CG9VPNj0.mjs} +2 -2
  38. package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-DfG7tB8s.mjs → d1-sqlite-dialect-BLC8LXE6-DBf7xVin.mjs} +2 -2
  39. package/.output/server/_ssr/db-Cs0gnPZZ.mjs +2 -0
  40. package/.output/server/_ssr/{dist-BIxFFVZg.mjs → dist-CwI9FwLx.mjs} +2 -2
  41. package/.output/server/_ssr/{factory-Blq0DYfT.mjs → factory-L3gsmDL7.mjs} +2 -2
  42. package/.output/server/_ssr/{invite._token-NewFt27g.mjs → invite._token-CN2p7Gt3.mjs} +6 -6
  43. package/.output/server/_ssr/invite._token-DJxGLILJ.mjs +1 -1
  44. package/.output/server/_ssr/{invite._token-BRCo9LGB.mjs → invite._token-KLCPnHk-.mjs} +4 -4
  45. package/.output/server/_ssr/{kysely-adapter-D3XTe64J.mjs → kysely-adapter-Czkfz-W-.mjs} +1 -1
  46. package/.output/server/_ssr/{lifecycleUi-C9lg1r3r.mjs → lifecycleUi-BhRsBvJ7.mjs} +4 -4
  47. package/.output/server/_ssr/logger-Cj1GFV_8.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-CVf9RC6s.mjs} +32 -16
  50. package/.output/server/_ssr/{loops._loopId-DhnArGdL.mjs → loops._loopId-CbuhuTAp.mjs} +239 -397
  51. package/.output/server/_ssr/{loops._loopId-7NQJPB9W.mjs → loops._loopId-gNSxIQBe.mjs} +4 -4
  52. package/.output/server/_ssr/{loops._loopId_.runs._runId-Dip5Xk-q.mjs → loops._loopId_.runs._runId-0MahUyHy.mjs} +48 -6
  53. package/.output/server/_ssr/{loops._loopId_.runs._runId-Bvuo2nki.mjs → loops._loopId_.runs._runId-BptlCXat.mjs} +4 -4
  54. package/.output/server/_ssr/{machineFns-Dvr5ICUy.mjs → machineFns-D5rQWyLl.mjs} +3 -3
  55. package/.output/server/_ssr/{node-sqlite-dialect-DhyOpJTX.mjs → node-sqlite-dialect-Dr9_QokR.mjs} +2 -2
  56. package/.output/server/_ssr/{notifyFns-BcMRY5kP.mjs → notifyFns-BobPaLWi.mjs} +3 -3
  57. package/.output/server/_ssr/{notifyFns-Q458pZmE.mjs → notifyFns-c7ZY2TWF.mjs} +5 -5
  58. package/.output/server/_ssr/{router-J8KZ30xw.mjs → router-B8JTBtGd.mjs} +30 -30
  59. package/.output/server/_ssr/{routes-D4am3Zff.mjs → routes-B-MWifFy.mjs} +6 -6
  60. package/.output/server/_ssr/{routes-BoGrcf-b.mjs → routes-BJCWMIzb.mjs} +5 -5
  61. package/.output/server/_ssr/routes-Bcs4T1ox.mjs +1 -1
  62. package/.output/server/_ssr/{runDiff-CpEFqo7G.mjs → runDiff-C0w1D4a3.mjs} +2 -2
  63. package/.output/server/_ssr/ssr.mjs +49 -49
  64. package/.output/server/_ssr/store-LYphMSJ-.mjs +2 -0
  65. package/.output/server/_ssr/t._teamId-Dy_McbRt.mjs +1 -1
  66. package/.output/server/_ssr/{t._teamId-CeUhzgzT.mjs → t._teamId-FYVEIAGw.mjs} +6 -6
  67. package/.output/server/_ssr/{t._teamId-DR-hQK7o.mjs → t._teamId-fw8RfHyI.mjs} +5 -5
  68. package/.output/server/_ssr/{teamFns-DA4ovI5g.mjs → teamFns-D4I-0dEB.mjs} +2 -2
  69. package/.output/server/_ssr/{teamFns-BIDnsg2A.mjs → teamFns-Dz41U7gA.mjs} +3 -3
  70. package/.output/server/_ssr/tokens-3ZFpqsuf.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-C9p30TZH.mjs} +20 -20
  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/0011_steep_marvel_zombies.sql +3 -0
  76. package/.output/server/drizzle/meta/0009_snapshot.json +1793 -0
  77. package/.output/server/drizzle/meta/0010_snapshot.json +1891 -0
  78. package/.output/server/drizzle/meta/0011_snapshot.json +1872 -0
  79. package/.output/server/drizzle/meta/_journal.json +21 -0
  80. package/.output/server/index.mjs +101 -101
  81. package/drizzle/0009_ordinary_electro.sql +1 -0
  82. package/drizzle/0010_workable_rage.sql +14 -0
  83. package/drizzle/0011_steep_marvel_zombies.sql +3 -0
  84. package/drizzle/meta/0009_snapshot.json +1793 -0
  85. package/drizzle/meta/0010_snapshot.json +1891 -0
  86. package/drizzle/meta/0011_snapshot.json +1872 -0
  87. package/drizzle/meta/_journal.json +21 -0
  88. package/package.json +1 -1
  89. package/scripts/pievo-server.mjs +5 -0
  90. package/scripts/server-cli-lib.mjs +2 -0
  91. package/.output/public/assets/Modal-D33gNSgx.js +0 -1
  92. package/.output/public/assets/app-DElSo_jy.css +0 -2
  93. package/.output/public/assets/index-DfpTWRSz.js +0 -12
  94. package/.output/public/assets/loops._loopId-B19Jw7jC.js +0 -5
  95. package/.output/public/assets/notifyFns-DCubjpRy.js +0 -1
  96. package/.output/server/_ssr/artifacts-DngKyW2u.mjs +0 -2
  97. package/.output/server/_ssr/db-DWAuZq1o.mjs +0 -2
  98. package/.output/server/_ssr/logger-Dw82jNjH.mjs +0 -2
  99. package/.output/server/_ssr/store-b3JcQ08F.mjs +0 -2
  100. 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-CkFZynUz.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-DJlWGia5.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-CjFonm71.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-c7ZY2TWF.mjs";
14
+ import { t as Route } from "./loops._loopId-gNSxIQBe.mjs";
15
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-CbuhuTAp.js
16
16
  var import_react = /* @__PURE__ */ __toESM(require_react());
17
17
  var import_jsx_runtime = require_jsx_runtime();
18
18
  /**
@@ -187,20 +187,21 @@ 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. 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
  }
203
- var CodeField = (0, import_react.lazy)(() => import("./CodeField-tm4rr6G3.mjs"));
204
+ var CodeField = (0, import_react.lazy)(() => import("./CodeField-B7oOmmwH.mjs"));
204
205
  function initState(initial) {
205
206
  const e = initial?.exec;
206
207
  return {
@@ -211,12 +212,12 @@ function initState(initial) {
211
212
  taskFile: initial?.taskFile ?? "",
212
213
  notify: initial?.notify ?? "auto",
213
214
  channelId: initial?.channelId ?? "",
214
- workflow: initial?.workflow ?? "",
215
215
  stateSchema: initial?.stateSchema ? JSON.stringify(initial.stateSchema) : "",
216
216
  ui: initial?.ui ?? "",
217
217
  agent: initial?.agent ?? "claude-code",
218
218
  workdir: e?.workdir ?? "",
219
219
  model: e?.model ?? "",
220
+ reasoningEffort: e?.reasoningEffort ?? "",
220
221
  allowControl: !!e?.allowControl
221
222
  };
222
223
  }
@@ -229,14 +230,17 @@ var AGENT_LABEL$1 = {
229
230
  codex: "Codex"
230
231
  };
231
232
  function TextField({ label, value, onChange, mono, ph, hint }) {
233
+ const id = (0, import_react.useId)();
232
234
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
233
235
  className: "min-w-0",
234
236
  children: [
235
237
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
238
+ htmlFor: id,
236
239
  className: labelCls,
237
240
  children: label
238
241
  }),
239
242
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
243
+ id,
240
244
  type: "text",
241
245
  className: mono ? `${inputCls} font-mono` : inputCls,
242
246
  value,
@@ -300,7 +304,6 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial, channel
300
304
  taskFile: f.taskFile.trim(),
301
305
  notify: f.notify,
302
306
  channelId: f.channelId || null,
303
- workflow: f.workflow.trim(),
304
307
  ui: f.ui.trim() || void 0,
305
308
  agent: f.agent,
306
309
  exec: buildFormExec(f),
@@ -445,13 +448,21 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial, channel
445
448
  onChange: (v) => set("workdir", v),
446
449
  mono: true,
447
450
  ph: "/Users/you/Workspace/project",
448
- hint: "Project root on the machine - empty means workflow-only / agent() escalation."
451
+ hint: "Project root on the machine. Empty lets the daemon use a scratch directory."
449
452
  }),
450
453
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextField, {
451
454
  label: "Model",
452
455
  value: f.model,
453
456
  onChange: (v) => set("model", v),
454
- hint: "Optional - the daemon default when empty."
457
+ ph: "default",
458
+ hint: "Optional arbitrary model id. Empty uses the coding-agent CLI default."
459
+ }),
460
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextField, {
461
+ label: "Reasoning effort",
462
+ value: f.reasoningEffort,
463
+ onChange: (v) => set("reasoningEffort", v),
464
+ ph: "default",
465
+ hint: "Optional arbitrary effort value. Empty uses the coding-agent CLI default."
455
466
  }),
456
467
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
457
468
  className: "mt-4 flex cursor-pointer items-center gap-2 text-body text-primary",
@@ -468,29 +479,7 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial, channel
468
479
  children: [
469
480
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
470
481
  title: "Agent-authored content",
471
- hint: "Workflow, metrics and dashboard - usually written by evolve passes; edit by hand here when you know exactly what you want."
472
- }),
473
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
474
- className: labelCls,
475
- children: "Workflow · JavaScript function body"
476
- }),
477
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, {
478
- fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EditorFallback, { minHeight: "180px" }),
479
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeField, {
480
- lang: "js",
481
- value: f.workflow,
482
- onChange: (v) => set("workflow", v),
483
- minHeight: "180px",
484
- placeholder: "const res = await tools.call(\"server.tool\", { ... })\nreturn { message: \"...\", state: { ... } }"
485
- })
486
- }),
487
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
488
- className: hintCls,
489
- children: [
490
- "Deterministic zero-LLM pre-stage; top-level await and return ",
491
- "{message, state}",
492
- " are allowed (optional)."
493
- ]
482
+ hint: "Metrics and dashboard - usually written by evolve passes; edit by hand here when you know exactly what you want."
494
483
  }),
495
484
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
496
485
  className: labelCls,
@@ -567,7 +556,7 @@ var EDIT_SEEDS = [
567
556
  seed: "Give this loop a goal, and finish it once the goal is met: "
568
557
  }
569
558
  ];
570
- var LoopView = (0, import_react.lazy)(() => import("./LoopView-DCugEbHx.mjs").then((m) => ({ default: m.LoopView })));
559
+ var LoopView = (0, import_react.lazy)(() => import("./LoopView-BtMANpb_.mjs").then((m) => ({ default: m.LoopView })));
571
560
  /**
572
561
  * Loop detail PAGE body (`/loops/$loopId`) — the redesign of the former modal.
573
562
  * One scrolling page: a loop header (name / status / schedule / agent / machine +
@@ -576,14 +565,13 @@ var LoopView = (0, import_react.lazy)(() => import("./LoopView-DCugEbHx.mjs").th
576
565
  * the Runs timeline (a strip + a clickable list, each run linking to its own
577
566
  * detail route). Self-polls while open (fast while a run is live).
578
567
  *
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
568
+ * Editing (2026-07 redesign): the primary path is an INLINE composer below the
569
+ * always-visible action toolbar - the page stays visible, so
581
570
  * the owner describes the change while looking at the spec/dashboard it applies
582
571
  * to. Dispatch swaps the composer for a live status card under the header
583
572
  * (queued → applying → settled with report + files + a link to
584
573
  * 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.
574
+ * the card. Settings remains a full-page field-form takeover.
587
575
  */
588
576
  function LoopDetailView({ id }) {
589
577
  const navigate = useNavigate();
@@ -598,11 +586,9 @@ function LoopDetailView({ id }) {
598
586
  const [editDispatched, setEditDispatched] = (0, import_react.useState)(false);
599
587
  const [editRunId, setEditRunId] = (0, import_react.useState)(null);
600
588
  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
589
  const [machinesOpen, setMachinesOpen] = (0, import_react.useState)(false);
604
590
  const [pending, setPending] = (0, import_react.useState)(null);
605
- const [confirming, setConfirming] = (0, import_react.useState)(null);
591
+ const [confirmingDelete, setConfirmingDelete] = (0, import_react.useState)(false);
606
592
  const [flash, setFlash] = useFlash();
607
593
  const formRef = (0, import_react.useRef)(null);
608
594
  const deletingRef = (0, import_react.useRef)(false);
@@ -626,7 +612,7 @@ function LoopDetailView({ id }) {
626
612
  setPromptCopied(false);
627
613
  setEditDispatched(false);
628
614
  setEditRunId(null);
629
- setPushOpen(false);
615
+ setConfirmingDelete(false);
630
616
  setOlder([]);
631
617
  load();
632
618
  listChannels().then(setChannels).catch(() => {});
@@ -641,25 +627,15 @@ function LoopDetailView({ id }) {
641
627
  running,
642
628
  load
643
629
  ]);
644
- (0, import_react.useEffect)(() => {
645
- if (!pushSaved) return;
646
- const t = setTimeout(() => setPushSaved(false), 1800);
647
- return () => clearTimeout(t);
648
- }, [pushSaved]);
649
630
  async function refreshAll() {
650
631
  await load();
651
632
  }
652
- function onRun() {
653
- if (detail?.job.exec) setConfirming("run");
654
- else doRun();
655
- }
656
633
  async function doRun() {
657
634
  setActionErr(null);
658
635
  setPending("run");
659
636
  try {
660
637
  const r = await runJob({ data: id });
661
638
  if (r?.error) return setActionErr(`Run failed: ${r.error}`);
662
- setConfirming(null);
663
639
  setFlash({
664
640
  label: r.coalesced ? "Already queued" : "Queued",
665
641
  hold: 4e3
@@ -675,7 +651,6 @@ function LoopDetailView({ id }) {
675
651
  try {
676
652
  const r = await evolveJob({ data: id });
677
653
  if (r?.error) return setActionErr(`Evolve failed: ${r.error}`);
678
- setConfirming(null);
679
654
  setFlash({
680
655
  label: r.coalesced ? "Evolve already queued" : "Evolve queued",
681
656
  hold: 4e3
@@ -689,12 +664,12 @@ function LoopDetailView({ id }) {
689
664
  setActionErr(null);
690
665
  setPending("lifecycle");
691
666
  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: {
667
+ 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
668
  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);
669
+ patch: { enabled: true }
670
+ } }) : await deleteJob({ data: id });
671
+ if (r.error) return setActionErr(`${action[0].toUpperCase() + action.slice(1)} failed: ${r.error}`);
672
+ setConfirmingDelete(false);
698
673
  if (r.deleted) {
699
674
  deletingRef.current = false;
700
675
  navigate({ to: "/" });
@@ -702,21 +677,11 @@ function LoopDetailView({ id }) {
702
677
  }
703
678
  if (action === "delete") deletingRef.current = true;
704
679
  await refreshAll();
705
- setFlash({ label: action === "start" ? "Started" : action === "pause" ? "Paused" : action === "stop" ? "Stop requested" : "Deleting" });
680
+ setFlash({ label: action === "start" ? "Started" : action === "reopen" ? "Reopened" : action === "pause" ? "Paused" : action === "stop" ? "Stop requested" : "Deleting" });
706
681
  } finally {
707
682
  setPending(null);
708
683
  }
709
684
  }
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
685
  async function onSave() {
721
686
  const payload = formRef.current?.read();
722
687
  if (!payload) return;
@@ -755,14 +720,6 @@ function LoopDetailView({ id }) {
755
720
  setPending(null);
756
721
  }
757
722
  }
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
723
  const backLink = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
767
724
  to: "/",
768
725
  className: "inline-flex items-center gap-1.5 text-meta font-medium text-secondary transition-colors hover:text-display",
@@ -815,41 +772,6 @@ function LoopDetailView({ id }) {
815
772
  setActionErr("Could not copy the prompt - try again or copy it manually.");
816
773
  }
817
774
  };
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
775
  const flashLine = flash && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
854
776
  className: "mb-2.5",
855
777
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlashLine, {
@@ -858,296 +780,192 @@ function LoopDetailView({ id }) {
858
780
  onUndo: flash.undo
859
781
  })
860
782
  });
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
- },
783
+ const deleting = lifecycle === "deleting";
784
+ const paused = !s.enabled && !completed && !deleting;
785
+ const active = s.enabled && !completed && !deleting;
786
+ const actionDisabled = busy || deleting;
787
+ const canRunWork = active || paused;
788
+ const canStop = canRunWork && !!s.running && protocolSupport.supported;
789
+ const stopTitle = s.running && !protocolSupport.supported ? DAEMON_UPGRADE_REQUIRED : !s.running ? "No run is currently running" : void 0;
790
+ const actionBar = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
791
+ className: "min-w-0",
900
792
  children: [
901
793
  /* @__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",
794
+ className: "flex min-w-0 flex-wrap items-center gap-2",
941
795
  children: [
942
796
  /* @__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"
797
+ className: btnPrimary,
798
+ disabled: actionDisabled || !canRunWork,
799
+ onClick: () => void doRun(),
800
+ title: !canRunWork ? "Unavailable for a completed or deleting loop" : offlineHint ?? (job.exec ? "Spends credits" : void 0),
801
+ "aria-label": job.exec ? "Run once - spends credits" : "Run once",
802
+ children: pending === "run" ? "Queuing…" : "Run once"
948
803
  }),
949
804
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
950
- type: "button",
951
805
  className: btn,
952
- disabled: pending === "edit",
953
- onClick: () => void copyEditPrompt(),
954
- children: promptCopied ? "✓ Prompt copied" : "Copy prompt"
806
+ disabled: actionDisabled || !(canRunWork || completed),
807
+ title: "Dispatch or copy a prompt for an owner-requested edit",
808
+ onClick: () => setEditVia(true),
809
+ children: "Agent edit"
955
810
  }),
956
811
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
957
812
  className: btn,
958
- disabled: pending === "edit",
959
- onClick: () => setEditVia(false),
960
- children: "Cancel"
813
+ disabled: actionDisabled || !canRunWork,
814
+ title: !canRunWork ? "Unavailable for a completed or deleting loop" : offlineHint ?? "Spends credits",
815
+ onClick: () => void doEvolve(),
816
+ children: pending === "evolve" ? "Evolving…" : "Evolve once"
961
817
  }),
962
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
963
- className: "hidden text-caption text-disabled sm:inline",
964
- children: "⌘↩ dispatch · esc cancel"
818
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
819
+ className: btn,
820
+ disabled: actionDisabled,
821
+ onClick: () => setEditing(true),
822
+ children: "Settings"
965
823
  }),
966
824
  /* @__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 →"
825
+ className: btn,
826
+ disabled: actionDisabled || !paused,
827
+ onClick: () => void doLifecycle("start"),
828
+ children: "Start"
829
+ }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
831
+ className: btn,
832
+ disabled: actionDisabled || !active,
833
+ onClick: () => void doLifecycle("pause"),
834
+ children: "Pause"
835
+ }),
836
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
837
+ className: btnDanger,
838
+ disabled: actionDisabled || !canStop,
839
+ title: stopTitle,
840
+ onClick: () => void doLifecycle("stop"),
841
+ children: "Stop"
842
+ }),
843
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
844
+ className: btn,
845
+ disabled: actionDisabled || !completed,
846
+ onClick: () => void doLifecycle("reopen"),
847
+ children: "Reopen"
848
+ }),
849
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
850
+ className: btnDanger,
851
+ disabled: actionDisabled,
852
+ onClick: () => setConfirmingDelete(true),
853
+ children: deleting ? "Deleting…" : "Delete"
974
854
  })
975
855
  ]
976
856
  }),
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: "→"
857
+ confirmingDelete && !deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
858
+ className: "mt-3",
859
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfirmBar, {
860
+ prompt: "Stop this loop and delete its server data?",
861
+ 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.",
862
+ cta: "Delete",
863
+ danger: true,
864
+ busy,
865
+ onConfirm: () => void doLifecycle("delete"),
866
+ onCancel: () => setConfirmingDelete(false)
867
+ })
1020
868
  }),
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))]
869
+ deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
870
+ className: "mt-3 rounded-md border border-wire bg-raised px-4 py-3 text-meta text-secondary",
871
+ children: "Deleting… graceful stop is waiting for execution authority to end."
1034
872
  }),
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
- })]
873
+ editVia && !deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
874
+ className: "mt-4 border-t border-hairline pt-4",
875
+ onKeyDown: (e) => {
876
+ if (e.key === "Escape" && pending !== "edit") {
877
+ e.stopPropagation();
878
+ setEditVia(false);
879
+ }
880
+ },
881
+ children: [
882
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
883
+ className: "flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",
884
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
885
+ className: "text-body font-medium text-display",
886
+ children: "Edit with your coding agent"
887
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
888
+ className: "text-meta text-secondary",
889
+ children: [
890
+ "One agent pass on ",
891
+ onMachine,
892
+ " · spends credits"
893
+ ]
894
+ })]
895
+ }),
896
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
897
+ ref: editBoxRef,
898
+ autoFocus: true,
899
+ value: editInstruction,
900
+ onChange: (e) => setEditInstruction(e.target.value),
901
+ onKeyDown: (e) => {
902
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter" && editInstruction.trim() && pending !== "edit") onRequestEdit();
903
+ },
904
+ rows: 3,
905
+ placeholder: "e.g. run at 9am on weekdays instead, and also check coffee stock",
906
+ 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"
907
+ }),
908
+ !editInstruction.trim() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
909
+ className: "mt-2 flex flex-wrap gap-1.5",
910
+ children: EDIT_SEEDS.map((sd) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
911
+ type: "button",
912
+ onClick: () => {
913
+ setEditInstruction(sd.seed);
914
+ editBoxRef.current?.focus();
915
+ },
916
+ 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",
917
+ children: sd.label
918
+ }, sd.label))
919
+ }),
920
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
921
+ className: "mt-3.5 flex flex-wrap items-center gap-x-2.5 gap-y-2",
922
+ children: [
923
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
924
+ className: btnCost,
925
+ disabled: pending === "edit" || !editInstruction.trim(),
926
+ title: offlineHint,
927
+ onClick: () => void onRequestEdit(),
928
+ children: pending === "edit" ? "Dispatching…" : "Dispatch to your coding agent"
929
+ }),
930
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
931
+ type: "button",
932
+ className: btn,
933
+ disabled: pending === "edit",
934
+ onClick: () => void copyEditPrompt(),
935
+ children: promptCopied ? "✓ Prompt copied" : "Copy prompt"
936
+ }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
938
+ className: btn,
939
+ disabled: pending === "edit",
940
+ onClick: () => setEditVia(false),
941
+ children: "Cancel"
942
+ }),
943
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
944
+ className: "hidden text-caption text-disabled sm:inline",
945
+ children: "⌘↩ dispatch · esc cancel"
946
+ })
947
+ ]
948
+ }),
949
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
950
+ className: "mt-2 text-caption leading-snug text-disabled",
951
+ children: promptCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
952
+ className: "text-secondary",
953
+ children: [
954
+ "✓ Copied · run your coding agent",
955
+ " ",
956
+ editDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: ["in ", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
957
+ className: "break-all font-mono text-primary",
958
+ children: editDir
959
+ })] }) : "in the loop’s local directory on this machine",
960
+ " ",
961
+ "and paste the prompt to adjust the loop yourself."
962
+ ]
963
+ }) : /* @__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." })
964
+ })
965
+ ]
1047
966
  })
1048
967
  ]
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
- }) });
968
+ });
1151
969
  const actionErrEl = actionErr && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, {
1152
970
  message: actionErr,
1153
971
  onDismiss: () => setActionErr(null),
@@ -1245,6 +1063,10 @@ function LoopDetailView({ id }) {
1245
1063
  })]
1246
1064
  });
1247
1065
  const agentLabel = AGENT_LABEL[job.agent ?? "claude-code"] ?? job.agent ?? "Claude Code";
1066
+ const modelLabel = job.exec?.model?.trim() || "default";
1067
+ const reasoningEffortLabel = job.exec?.reasoningEffort?.trim() || "default";
1068
+ const newestRun = runs[0];
1069
+ const latestIncidentRun = newestRun?.reportIncident ? newestRun : void 0;
1248
1070
  const metaDot = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1249
1071
  className: "text-wire",
1250
1072
  children: "·"
@@ -1266,7 +1088,7 @@ function LoopDetailView({ id }) {
1266
1088
  className: "text-[28px] font-semibold leading-tight tracking-[-0.015em] text-display",
1267
1089
  children: s.name
1268
1090
  }),
1269
- completed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1091
+ lifecycle === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1270
1092
  tone: "success",
1271
1093
  dot: "green",
1272
1094
  children: "Completed"
@@ -1289,6 +1111,22 @@ function LoopDetailView({ id }) {
1289
1111
  title: "Recorded coding agent",
1290
1112
  children: agentLabel
1291
1113
  }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1115
+ tone: "outline",
1116
+ title: `Model: ${modelLabel}`,
1117
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
1118
+ className: "max-w-72 truncate",
1119
+ children: ["Model: ", modelLabel]
1120
+ })
1121
+ }),
1122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1123
+ tone: "outline",
1124
+ title: `Reasoning: ${reasoningEffortLabel}`,
1125
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
1126
+ className: "max-w-72 truncate",
1127
+ children: ["Reasoning: ", reasoningEffortLabel]
1128
+ })
1129
+ }),
1292
1130
  crossTeam && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
1293
1131
  tone: "outline",
1294
1132
  title: "This loop belongs to another of your teams",
@@ -1339,7 +1177,7 @@ function LoopDetailView({ id }) {
1339
1177
  children: s.goal
1340
1178
  })]
1341
1179
  }),
1342
- completed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1180
+ lifecycle === "completed" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1343
1181
  className: "mt-2 text-body leading-snug text-success",
1344
1182
  children: [
1345
1183
  "Completed",
@@ -1349,6 +1187,10 @@ function LoopDetailView({ id }) {
1349
1187
  children: [" - ", s.completionReason]
1350
1188
  })
1351
1189
  ]
1190
+ }),
1191
+ latestIncidentRun?.reportIncident && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1192
+ className: "mt-2 text-body leading-snug text-secondary",
1193
+ children: latestIncidentRun.outcome === "error" ? "Last run failed · Terminal report rejected" : "Last run telemetry warning · Terminal report rejected"
1352
1194
  })
1353
1195
  ]
1354
1196
  })
@@ -1495,7 +1337,7 @@ function LoopDetailView({ id }) {
1495
1337
  });
1496
1338
  }
1497
1339
  /**
1498
- * Manual-settings page heading. The field form is an in-page mode takeover (NOT
1340
+ * Settings page heading. The field form is an in-page mode takeover (NOT
1499
1341
  * a modal), so this is a plain heading - NOT `ModalHead`, whose Base UI
1500
1342
  * `Dialog.Title`/`Dialog.Close` require a `Dialog.Root` ancestor and throw
1501
1343
  * ("Cannot destructure property 'store' of 'useDialogRootContext(...)'") when
@@ -1514,11 +1356,11 @@ function EditHead({ name, onBack }) {
1514
1356
  }),
1515
1357
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h1", {
1516
1358
  className: "mt-2.5 text-[24px] font-semibold leading-tight tracking-[-0.015em] text-display",
1517
- children: ["Manual settings · ", name]
1359
+ children: ["Settings · ", name]
1518
1360
  }),
1519
1361
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
1520
1362
  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."
1363
+ children: "Loop configuration, notifications, and push channel, saved directly - no agent pass or credits. For changes in plain words, use Agent edit instead."
1522
1364
  })
1523
1365
  ] });
1524
1366
  }