@kky42/pievo-server 2.4.14 → 4.1.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 (95) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/MarkdownView-BuFKr9Jg.js +66 -0
  3. package/.output/public/assets/{actionUi-5PtES4q0.js → actionUi-BZrLpgHT.js} +1 -1
  4. package/.output/public/assets/app-x1CeeY7N.css +2 -0
  5. package/.output/public/assets/index-D0FIKiiW.js +10 -0
  6. package/.output/public/assets/loops._loopId-DTkIz4C0.js +2 -0
  7. package/.output/public/assets/loops._loopId_.runs._runId-CsV2Ih4Z.js +3 -0
  8. package/.output/public/assets/preload-helper-BSxGu4d0.js +3 -0
  9. package/.output/public/assets/{routes-Dm_3J2aV.js → routes-BIOJZsig.js} +1 -1
  10. package/.output/public/assets/routes-m4Z90DTR.js +1 -0
  11. package/.output/server/_chunks/ssr-renderer.mjs +1 -1
  12. package/.output/server/_libs/{drizzle-orm+postgres.mjs → drizzle-orm.mjs} +93 -2218
  13. package/.output/server/_ssr/{MachinesModal-BaEtzycr.mjs → MachinesModal-CLBZxZkq.mjs} +47 -47
  14. package/.output/server/_ssr/MarkdownView-D1J7ImYF.mjs +70 -0
  15. package/.output/server/_ssr/{actionUi-5HOCZnom.mjs → actionUi-DE-Pb2tv.mjs} +1 -2
  16. package/.output/server/_ssr/artifactFiles-B0NPRDOR.mjs +52 -0
  17. package/.output/server/_ssr/{artifactKind-DwDr8IYc.mjs → artifactKind-a2oxT2wQ.mjs} +4 -10
  18. package/.output/server/_ssr/{boot-C472kLwY.mjs → boot-DmpKtb0A.mjs} +2659 -890
  19. package/.output/server/_ssr/lifecycleUi-DEjM8Etm.mjs +106 -0
  20. package/.output/server/_ssr/{loopApi-DT751TJA.mjs → loopApi-DK1lQPrx.mjs} +53 -69
  21. package/.output/server/_ssr/{loopProjection-qaD2I48a.mjs → loopProjection-DdFivf7-.mjs} +6 -24
  22. package/.output/server/_ssr/{loops._loopId-CXgw2Rz1.mjs → loops._loopId-DVCvGSEc.mjs} +36 -116
  23. package/.output/server/_ssr/{loops._loopId_.runs._runId-SASSqOfy.mjs → loops._loopId_.runs._runId-BXbTfLlC.mjs} +35 -39
  24. package/.output/server/_ssr/{loops._loopId_.runs._runId-Dk94Z0Jq.mjs → loops._loopId_.runs._runId-Dr6E-FA5.mjs} +3 -8
  25. package/.output/server/_ssr/{machineFns-BSrIgn3f.mjs → machineFns-DLRHgDdS.mjs} +13 -50
  26. package/.output/server/_ssr/networkAccess-CIlK3ION.mjs +30 -0
  27. package/.output/server/_ssr/router-BhHsTGqu.mjs +355 -0
  28. package/.output/server/_ssr/routes-CCallyCT.mjs +12 -0
  29. package/.output/server/_ssr/{routes-Cr-9yDEH.mjs → routes-CL2Kef-Q.mjs} +91 -50
  30. package/.output/server/_ssr/{routes-DRBS4Zi4.mjs → routes-ngpX7h8D.mjs} +2 -4
  31. package/.output/server/_ssr/ssr.mjs +25 -34
  32. package/.output/server/_ssr/start-B5_9Z5W-.mjs +35 -0
  33. package/.output/server/{_tanstack-start-manifest_v-DxLIQ0cc.mjs → _tanstack-start-manifest_v-BPiJ4yWT.mjs} +9 -15
  34. package/.output/server/drizzle/0000_baseline.sql +6 -97
  35. package/.output/server/drizzle/0001_loop_files.sql +9 -0
  36. package/.output/server/drizzle/meta/_journal.json +3 -17
  37. package/.output/server/index.mjs +50 -50
  38. package/drizzle/0000_baseline.sql +6 -97
  39. package/drizzle/0001_loop_files.sql +9 -0
  40. package/drizzle/meta/_journal.json +3 -17
  41. package/package.json +4 -8
  42. package/scripts/pievo-server.mjs +49 -47
  43. package/scripts/server-cli-lib.mjs +21 -12
  44. package/scripts/server-network.mjs +139 -0
  45. package/.output/public/assets/SignIn-CIFwnZtF.js +0 -1
  46. package/.output/public/assets/app-DvHMhs7S.css +0 -2
  47. package/.output/public/assets/index-CRX2pu0W.js +0 -10
  48. package/.output/public/assets/loops._loopId-BsuV-Rmf.js +0 -67
  49. package/.output/public/assets/loops._loopId_.runs._runId-DpK_fzmZ.js +0 -3
  50. package/.output/public/assets/preload-helper-sAZOZb3G.js +0 -5
  51. package/.output/public/assets/routes-DxF_s3cD.js +0 -1
  52. package/.output/server/_libs/@aws-crypto/crc32+[...].mjs +0 -419
  53. package/.output/server/_libs/@aws-sdk/checksums+[...].mjs +0 -10732
  54. package/.output/server/_libs/@aws-sdk/client-s3+[...].mjs +0 -9475
  55. package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +0 -137
  56. package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +0 -440
  57. package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +0 -62
  58. package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +0 -818
  59. package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +0 -59
  60. package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +0 -342
  61. package/.output/server/_libs/aws-crypto__crc32c.mjs +0 -314
  62. package/.output/server/_libs/aws-sdk__nested-clients.mjs +0 -2671
  63. package/.output/server/_ssr/SignIn-sHQaBQJC.mjs +0 -53
  64. package/.output/server/_ssr/artifactFiles-DO43wwXA.mjs +0 -60
  65. package/.output/server/_ssr/artifacts-Cd7Qx3Qp.mjs +0 -2
  66. package/.output/server/_ssr/auth-0AamrwHo.mjs +0 -38355
  67. package/.output/server/_ssr/auth-client-lSMb_Idt.mjs +0 -1070
  68. package/.output/server/_ssr/bun-sqlite-dialect-BW9W1_Ps-DLIXocA0.mjs +0 -162
  69. package/.output/server/_ssr/core-RrmWoKne.mjs +0 -5
  70. package/.output/server/_ssr/d1-sqlite-dialect-BLC8LXE6-BoFMIPr_.mjs +0 -112
  71. package/.output/server/_ssr/db-BzvMQ2kx.mjs +0 -2
  72. package/.output/server/_ssr/dist-ClzqkwxD.mjs +0 -342
  73. package/.output/server/_ssr/factory-ixUjZqJn.mjs +0 -6903
  74. package/.output/server/_ssr/kysely-adapter-DkZbmKgV.mjs +0 -2
  75. package/.output/server/_ssr/kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs +0 -19
  76. package/.output/server/_ssr/logger-DDjsYB2X.mjs +0 -2
  77. package/.output/server/_ssr/loopTags-CXx5UdGf.mjs +0 -3356
  78. package/.output/server/_ssr/node-sqlite-dialect-BbUqnnYv.mjs +0 -162
  79. package/.output/server/_ssr/router-BlLlhfJe.mjs +0 -543
  80. package/.output/server/_ssr/routes-DTBltabU.mjs +0 -27
  81. package/.output/server/_ssr/start-4ifArtKx.mjs +0 -4
  82. package/.output/server/_ssr/store-vDZ9INSa.mjs +0 -2
  83. package/.output/server/_ssr/tokens-BHiCElYD.mjs +0 -2
  84. package/.output/server/drizzle/0001_add_pi_agent.sql +0 -9
  85. package/.output/server/drizzle/0002_remove_teams.sql +0 -15
  86. package/.output/server/drizzle/0003_add_loop_tags.sql +0 -5
  87. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  88. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  89. package/.output/server/node_modules/tslib/package.json +0 -47
  90. package/.output/server/node_modules/tslib/tslib.js +0 -484
  91. package/.output/server/package.json +0 -9
  92. package/drizzle/0001_add_pi_agent.sql +0 -9
  93. package/drizzle/0002_remove_teams.sql +0 -15
  94. package/drizzle/0003_add_loop_tags.sql +0 -5
  95. package/scripts/prestart.mjs +0 -66
@@ -1,26 +1,21 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
- import { Ft as machinePresence, pt as isOutdated } from "./loopTags-CXx5UdGf.mjs";
2
+ import { E as isOutdated, F as machinePresence } from "./boot-DmpKtb0A.mjs";
3
3
  import { a as DialogClose, c as TooltipPopup, d as TooltipTrigger, f as TooltipRoot, g as require_react, h as require_jsx_runtime, i as DialogPopup, l as TooltipPositioner, n as DialogRoot, o as DialogBackdrop, r as DialogPortal, t as DialogTitle, u as TooltipPortal } from "../_libs/@base-ui/react+[...].mjs";
4
- import { n as createServerFn } from "./ssr.mjs";
5
- import { g as lifecyclePresentation, o as createSsrRpc, p as getConfig, s as daemonStopSupport } from "./auth-client-lSMb_Idt.mjs";
6
- import { C as lastRunOf, D as scheduleText, N as useHydrated, O as sectionHeadCls, S as labelCls, T as runPulseAnim, _ as fmt, c as btn, g as dur, h as dotOpacity, j as until, l as btnDanger, m as dotLabel, n as ErrorBanner, o as Pill, p as dotColor, t as ConfirmBar, u as btnPrimary, v as fnum, w as rel, x as inputCls } from "./actionUi-5HOCZnom.mjs";
7
- //#region node_modules/.nitro/vite/services/ssr/assets/MachinesModal-BaEtzycr.js
4
+ import { r as createServerFn } from "./ssr.mjs";
5
+ import { c as getConfig, d as lifecyclePresentation, n as createSsrRpc, r as daemonStopSupport } from "./lifecycleUi-DEjM8Etm.mjs";
6
+ import { C as lastRunOf, D as scheduleText, N as useHydrated, O as sectionHeadCls, S as labelCls, T as runPulseAnim, _ as fmt, c as btn, g as dur, h as dotOpacity, j as until, l as btnDanger, m as dotLabel, n as ErrorBanner, o as Pill, p as dotColor, t as ConfirmBar, u as btnPrimary, v as fnum, w as rel, x as inputCls } from "./actionUi-DE-Pb2tv.mjs";
7
+ //#region node_modules/.nitro/vite/services/ssr/assets/MachinesModal-CLBZxZkq.js
8
8
  var import_react = /* @__PURE__ */ __toESM(require_react());
9
9
  var import_jsx_runtime = require_jsx_runtime();
10
10
  /**
11
- * Machine-management server functions. In auth mode, the signed-in user is the
12
- * sole human authorization boundary. Open mode intentionally shares all machine
13
- * administration, including reconnect tokens.
11
+ * Machine-management server functions. Pievo is single-user: anyone who can
12
+ * reach the dashboard administers every machine, including reconnect tokens.
14
13
  */
15
- /** Missing and out-of-scope machines both resolve to undefined. */
16
14
  var listMachines = createServerFn({ method: "GET" }).handler(createSsrRpc("aa46310016bb8a58b273a648ffd498c87f1f450d12827e30110a3b83ba6a27d9"));
17
15
  var createMachine = createServerFn({ method: "POST" }).handler(createSsrRpc("ed679b4e1e05e903a5d4ba4a70d9b9d883991ab22ed59b4d2d69078941818415"));
18
16
  var machineStatus = createServerFn({ method: "GET" }).validator((id) => id).handler(createSsrRpc("169566e7637a22599b4eb32ee3775574e99677406922bbef7482a102036c33dd"));
19
17
  var finalizeMachine = createServerFn({ method: "POST" }).validator((data) => data).handler(createSsrRpc("27d7eba0b6a2257949392fdd56057275a5c5366484ae01faf3b5897a225ecd83"));
20
- /**
21
- * Delete server-owned machine data without touching local project files. The
22
- * store rechecks ownership under the deletion lock in auth mode.
23
- */
18
+ /** Delete server-owned machine data without touching local project files. */
24
19
  var deleteMachine = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("a6384dc7154d9930422d29396f5de64b3ac69c62ad3824bc4a22d745fc07b293"));
25
20
  /** Merge two chronological (oldest-first) run lists, dedup by id (the first
26
21
  * occurrence wins, so pass the fresher list first), re-sorted by ts ascending.
@@ -345,12 +340,24 @@ function daemonConnectCommand(origin, token, cli, customCli) {
345
340
  const start = `${cli} daemon connect --server-url ${origin} --connect-key ${token}`;
346
341
  return customCli ? start : `npm install -g @kky42/pievo@latest && ${start}`;
347
342
  }
343
+ /** The server URL other devices should use. A dashboard opened on the server
344
+ * itself sees a loopback origin, which no other device can reach, so prefer the
345
+ * launcher-published network URL there. */
346
+ function connectServerUrl(origin, publicUrl) {
347
+ if (!publicUrl) return origin;
348
+ try {
349
+ const host = new URL(origin).hostname;
350
+ return host === "localhost" || host === "[::1]" || host.startsWith("127.") ? publicUrl : origin;
351
+ } catch {
352
+ return publicUrl;
353
+ }
354
+ }
348
355
  function daemonUpgradeCommand(cli, customCli) {
349
356
  const restart = `${cli} daemon restart`;
350
357
  return customCli ? restart : `npm install -g @kky42/pievo@latest && ${restart}`;
351
358
  }
352
- function connectCmd(token, cli, customCli) {
353
- return daemonConnectCommand(typeof window !== "undefined" ? window.location.origin : "http://127.0.0.1:3000", token, cli, customCli);
359
+ function connectCmd(token, config) {
360
+ return daemonConnectCommand(connectServerUrl(typeof window !== "undefined" ? window.location.origin : "http://127.0.0.1:3000", config.publicUrl), token, config.pievoCli, config.customCli);
354
361
  }
355
362
  function CopyButton({ text }) {
356
363
  const [done, setDone] = (0, import_react.useState)(false);
@@ -364,6 +371,19 @@ function CopyButton({ text }) {
364
371
  children: done ? "Copied ✓" : "Copy"
365
372
  });
366
373
  }
374
+ function UpgradeCommand({ cliConfig, configErr }) {
375
+ const command = cliConfig ? daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli) : null;
376
+ return command ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
377
+ className: "flex items-start gap-2",
378
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
379
+ className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
380
+ children: command
381
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: command })]
382
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
383
+ className: "text-label text-secondary",
384
+ children: configErr ? "Could not load the upgrade command. Close and try again." : "Loading upgrade command…"
385
+ });
386
+ }
367
387
  function machineOrder(a, b) {
368
388
  return a.name.localeCompare(b.name, void 0, {
369
389
  numeric: true,
@@ -442,10 +462,6 @@ function MachinesModal({ open, onClose }) {
442
462
  setDelErr(null);
443
463
  try {
444
464
  const r = await createMachine();
445
- if ("error" in r) {
446
- setDelErr(r.error);
447
- return;
448
- }
449
465
  setStatus(null);
450
466
  setName("");
451
467
  setPending(r);
@@ -499,8 +515,8 @@ function MachinesModal({ open, onClose }) {
499
515
  className: "mt-2 flex items-start gap-2",
500
516
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
501
517
  className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-4 font-mono text-label leading-relaxed text-paper",
502
- children: connectCmd(pending.token, cliConfig.pievoCli, cliConfig.customCli)
503
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(pending.token, cliConfig.pievoCli, cliConfig.customCli) })]
518
+ children: connectCmd(pending.token, cliConfig)
519
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(pending.token, cliConfig) })]
504
520
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
505
521
  className: "mt-2 text-body text-secondary",
506
522
  children: configErr ? "Could not load the connection command. Close and try again." : "Loading connection command…"
@@ -619,7 +635,7 @@ function MachinesModal({ open, onClose }) {
619
635
  }),
620
636
  confirmDelete === m.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfirmBar, {
621
637
  prompt: `Delete ${m.name} and ${m.loopCount} loop${m.loopCount === 1 ? "" : "s"}?`,
622
- note: `This permanently deletes the machine, ${m.loopCount} loop${m.loopCount === 1 ? "" : "s"}, and their server history and artifact metadata. Local project files are not deleted, but an unreachable local agent may continue running.`,
638
+ note: `This permanently deletes the machine, ${m.loopCount} loop${m.loopCount === 1 ? "" : "s"}, and their server history, memory, and artifacts. Local project files are not deleted, but an unreachable local agent may continue running.`,
623
639
  cta: "Delete machine",
624
640
  danger: true,
625
641
  busy: deleting,
@@ -638,10 +654,6 @@ function MachinesModal({ open, onClose }) {
638
654
  className: "text-label text-accent",
639
655
  children: "Daemon upgrade required to stop a running process"
640
656
  }),
641
- !m.online && !m.token && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
642
- className: "text-label text-secondary",
643
- children: "Reconnect command available from the machine owner's account."
644
- }),
645
657
  !m.online && m.token && !cliConfig && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
646
658
  className: "text-label text-secondary",
647
659
  children: configErr ? "Could not load the reconnect command. Close and try again." : "Loading reconnect command…"
@@ -653,8 +665,8 @@ function MachinesModal({ open, onClose }) {
653
665
  className: "mt-2 flex items-start gap-2",
654
666
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
655
667
  className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
656
- children: connectCmd(m.token, cliConfig.pievoCli, cliConfig.customCli)
657
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(m.token, cliConfig.pievoCli, cliConfig.customCli) })]
668
+ children: connectCmd(m.token, cliConfig)
669
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(m.token, cliConfig) })]
658
670
  })] }),
659
671
  m.needsUpdate && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
660
672
  className: "flex flex-col gap-1.5 rounded-control border border-warn/40 bg-warn/10 p-3",
@@ -672,15 +684,9 @@ function MachinesModal({ open, onClose }) {
672
684
  m.requiredDaemonVersion
673
685
  ]
674
686
  }),
675
- cliConfig ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
676
- className: "flex items-start gap-2",
677
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
678
- className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
679
- children: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli)
680
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli) })]
681
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
682
- className: "text-label text-secondary",
683
- children: configErr ? "Could not load the upgrade command. Close and try again." : "Loading upgrade command…"
687
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UpgradeCommand, {
688
+ cliConfig,
689
+ configErr
684
690
  })
685
691
  ]
686
692
  }),
@@ -695,15 +701,9 @@ function MachinesModal({ open, onClose }) {
695
701
  m.latestDaemonVersion,
696
702
  ")"
697
703
  ]
698
- }), cliConfig ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
699
- className: "flex items-start gap-2",
700
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
701
- className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
702
- children: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli)
703
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli) })]
704
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
705
- className: "text-label text-secondary",
706
- children: configErr ? "Could not load the upgrade command. Close and try again." : "Loading upgrade command…"
704
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UpgradeCommand, {
705
+ cliConfig,
706
+ configErr
707
707
  })]
708
708
  })
709
709
  ]
@@ -723,4 +723,4 @@ function MachinesModal({ open, onClose }) {
723
723
  });
724
724
  }
725
725
  //#endregion
726
- export { Timeline as a, mergeRuns as c, ModalHead as i, MachinesModal as n, daemonConnectCommand as o, Modal as r, listMachines as s, LoopOverview as t };
726
+ export { Timeline as a, listMachines as c, ModalHead as i, mergeRuns as l, MachinesModal as n, connectServerUrl as o, Modal as r, daemonConnectCommand as s, LoopOverview as t };
@@ -0,0 +1,70 @@
1
+ import { o as __toESM } from "../_runtime.mjs";
2
+ import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
+ import { t as purify } from "../_libs/dompurify.mjs";
4
+ import { t as g } from "../_libs/marked.mjs";
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/MarkdownView-D1J7ImYF.js
6
+ var import_react = /* @__PURE__ */ __toESM(require_react());
7
+ var import_jsx_runtime = require_jsx_runtime();
8
+ /**
9
+ * Shared markdown → sanitized HTML pipeline: marked (GFM) → DOMPurify (an
10
+ * allowlisted prose subset, NO script/handlers). ONE sanitizer config for every
11
+ * loop-file markdown surface so the allowlist cannot drift between viewers.
12
+ * Render the output under
13
+ * the `.artifact-markdown` styles.
14
+ */
15
+ var MD_SANITIZE = {
16
+ ALLOWED_TAGS: [
17
+ "h1",
18
+ "h2",
19
+ "h3",
20
+ "h4",
21
+ "h5",
22
+ "h6",
23
+ "p",
24
+ "br",
25
+ "hr",
26
+ "strong",
27
+ "b",
28
+ "em",
29
+ "i",
30
+ "del",
31
+ "s",
32
+ "code",
33
+ "pre",
34
+ "blockquote",
35
+ "ul",
36
+ "ol",
37
+ "li",
38
+ "a",
39
+ "span",
40
+ "table",
41
+ "thead",
42
+ "tbody",
43
+ "tr",
44
+ "th",
45
+ "td",
46
+ "img"
47
+ ],
48
+ ALLOWED_ATTR: [
49
+ "href",
50
+ "title",
51
+ "target",
52
+ "rel",
53
+ "src",
54
+ "alt"
55
+ ]
56
+ };
57
+ function renderMarkdown(content) {
58
+ return purify.sanitize(g.parse(content, {
59
+ async: false,
60
+ gfm: true
61
+ }), MD_SANITIZE);
62
+ }
63
+ function MarkdownView({ content }) {
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
65
+ className: "artifact-markdown px-5 py-4",
66
+ dangerouslySetInnerHTML: { __html: (0, import_react.useMemo)(() => renderMarkdown(content), [content]) }
67
+ });
68
+ }
69
+ //#endregion
70
+ export { MarkdownView as t };
@@ -1,6 +1,6 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-5HOCZnom.js
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-DE-Pb2tv.js
4
4
  var import_react = /* @__PURE__ */ __toESM(require_react());
5
5
  var import_jsx_runtime = require_jsx_runtime();
6
6
  var fmt = (t) => t ? new Date(t).toLocaleString() : "—";
@@ -169,7 +169,6 @@ var btn = `${btnBase} border border-wire bg-surface text-primary hover:bg-raised
169
169
  var btnPrimary = `${btnBase} border border-display bg-display text-paper hover:opacity-85`;
170
170
  var btnDanger = `${btnBase} border border-transparent bg-rubik-red text-white hover:opacity-85`;
171
171
  var btnSm = `inline-flex shrink-0 cursor-pointer items-center gap-1 rounded-full border border-wire bg-surface px-3 py-1 text-label font-medium text-primary transition-colors duration-150 hover:bg-raised disabled:cursor-default disabled:opacity-40 ${focusRing}`;
172
- `${focusRing}`;
173
172
  var btnQuiet = "inline-flex cursor-pointer items-center gap-1.5 border-none bg-transparent p-0 text-meta font-medium text-secondary transition-colors hover:text-display";
174
173
  var sectionHeadCls = "text-label font-semibold text-secondary";
175
174
  var labelCls = "mb-1.5 mt-3 block text-label font-medium text-secondary";
@@ -0,0 +1,52 @@
1
+ import { D as listArtifacts, b as getArtifactFile, c as getLoopFiles } from "./boot-DmpKtb0A.mjs";
2
+ import { n as toArtifactSummary } from "./loopProjection-DdFivf7-.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/artifactFiles-B0NPRDOR.js
4
+ /**
5
+ * Server-side reads over a loop's current files (MEMORY.md + artifacts). Pure helpers
6
+ * (no request/session context) so they're shared by the lazy server fns
7
+ * (`getArtifacts` / `getArtifact` in loopApi) AND the download route, and are
8
+ * directly unit-testable against an injected blob store.
9
+ *
10
+ * The bytes live in the gateway's local BlobStore; here we only read them — never write — so the feature is strictly read-only and
11
+ * the server's zero-exec invariant holds (it decodes text, never interprets it).
12
+ */
13
+ async function listLoopArtifacts(loopId) {
14
+ return (await listArtifacts(loopId)).map(toArtifactSummary);
15
+ }
16
+ /**
17
+ * One file's content for inline display: decoded text for a text file, or a
18
+ * binary/oversize marker (the UI then offers the download route). Returns an
19
+ * error marker for an unknown/tombstoned name or a row whose blob bytes are
20
+ * absent — never throws.
21
+ */
22
+ async function readLoopArtifact(loopId, rawPath) {
23
+ const row = await getArtifactFile(loopId, rawPath);
24
+ if (!row || row.deleted) return { error: "file not found" };
25
+ if (row.binary || row.oversize) return {
26
+ binary: true,
27
+ size: row.size ?? null,
28
+ oversize: row.oversize
29
+ };
30
+ if (!row.hash) return { error: "file has no stored version" };
31
+ const bytes = await (await getLoopFiles()).readBlob(row.hash);
32
+ if (!bytes) return { error: "file not found" };
33
+ return { text: bytes.toString("utf8") };
34
+ }
35
+ /**
36
+ * Resolve a loop file name to its stored bytes for the download route. Names are
37
+ * matched exactly against stored rows; tombstoned/absent → 404. The bytes stream straight from the BlobStore.
38
+ */
39
+ async function readLoopArtifactBytes(loopId, rawPath) {
40
+ const row = await getArtifactFile(loopId, rawPath);
41
+ if (!row || row.deleted || !row.hash) return { status: 404 };
42
+ const bytes = await (await getLoopFiles()).readBlob(row.hash);
43
+ if (!bytes) return { status: 404 };
44
+ return {
45
+ status: 200,
46
+ bytes,
47
+ binary: row.binary,
48
+ filename: rawPath
49
+ };
50
+ }
51
+ //#endregion
52
+ export { listLoopArtifacts, readLoopArtifact, readLoopArtifactBytes };
@@ -1,19 +1,13 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
- import { f as getAuthState } from "./auth-client-lSMb_Idt.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/artifactKind-DwDr8IYc.js
4
- var $$splitComponentImporter = () => import("./loops._loopId-CXgw2Rz1.mjs");
2
+ //#region node_modules/.nitro/vite/services/ssr/assets/artifactKind-a2oxT2wQ.js
3
+ var $$splitComponentImporter = () => import("./loops._loopId-DVCvGSEc.mjs");
5
4
  /**
6
5
  * Loop detail page — `/loops/$loopId`: a loop header and action toolbar, the
7
- * exact artifact Files panel, and the runs timeline. The view owns its own
8
- * data + self-poll (ssr:false so the session cookie rides along with its fetches,
9
- * like the dashboard loader). Run rows link on to `/loops/$loopId/runs/$runId`.
10
- *
11
- * Auth-gated exactly like the dashboard (`/`): Better Auth's session hook keeps a
12
- * logged-out or expired deep link from mounting the ownership-scoped data view.
6
+ * loop Files panel, and the runs timeline. The view owns its own data + self-poll.
7
+ * Run rows link on to `/loops/$loopId/runs/$runId`.
13
8
  */
14
9
  var Route = createFileRoute("/loops/$loopId")({
15
10
  ssr: false,
16
- loader: async () => ({ auth: await getAuthState() }),
17
11
  component: lazyRouteComponent($$splitComponentImporter, "component")
18
12
  });
19
13
  /** Extension → MIME for the image types we serve inline. This is an ALLOWLIST: