@edspencer/paddock 0.70.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/package.json +2 -2
  2. package/packages/server/dist/background-live.d.ts +40 -8
  3. package/packages/server/dist/background-live.js +79 -1
  4. package/packages/server/dist/cli/args.d.ts +11 -3
  5. package/packages/server/dist/cli/args.js +33 -7
  6. package/packages/server/dist/cli/service/index.js +12 -1
  7. package/packages/server/dist/git.d.ts +63 -8
  8. package/packages/server/dist/git.js +100 -20
  9. package/packages/server/dist/herdctl-jobs.d.ts +30 -4
  10. package/packages/server/dist/herdctl-jobs.js +35 -8
  11. package/packages/server/dist/herdctl.d.ts +49 -0
  12. package/packages/server/dist/herdctl.js +42 -0
  13. package/packages/server/dist/project-files.d.ts +18 -7
  14. package/packages/server/dist/project-files.js +38 -34
  15. package/packages/server/dist/projects.d.ts +1 -1
  16. package/packages/server/dist/projects.js +14 -7
  17. package/packages/server/dist/routes/chats.js +7 -7
  18. package/packages/server/dist/routes/discover.js +1 -1
  19. package/packages/server/dist/routes/git.d.ts +2 -2
  20. package/packages/server/dist/routes/git.js +133 -1
  21. package/packages/server/dist/ws-protocol.d.ts +89 -3
  22. package/packages/server/dist/ws-protocol.js +9 -0
  23. package/packages/server/dist/ws.js +38 -0
  24. package/packages/server/package.json +1 -1
  25. package/packages/web/dist/assets/{Chip-C8a-t439.js → Chip-5S5MAayn.js} +1 -1
  26. package/packages/web/dist/assets/DiscoverPage-CEzcRO7X.js +2 -0
  27. package/packages/web/dist/assets/DiscoverView-CArICIRO.js +2 -0
  28. package/packages/web/dist/assets/InstanceConfigPage-CKjJsaGZ.js +2 -0
  29. package/packages/web/dist/assets/{MarkdownRenderer-DCj_ZwVG.js → MarkdownRenderer-BOrDawoY.js} +1 -1
  30. package/packages/web/dist/assets/{ProjectMenu-B7dGZSFB.js → ProjectMenu-B_8NYWZr.js} +1 -1
  31. package/packages/web/dist/assets/{ProjectRedirect-bstvMvM9.js → ProjectRedirect-xFWTlADS.js} +1 -1
  32. package/packages/web/dist/assets/ProjectView-polknqZw.js +13 -0
  33. package/packages/web/dist/assets/{ProjectsGrid-DKvySDUQ.js → ProjectsGrid-BF65wTqN.js} +1 -1
  34. package/packages/web/dist/assets/{RootHome-CD_37qb-.js → RootHome-32k1iDh4.js} +1 -1
  35. package/packages/web/dist/assets/{Surfaces-1dBayrsj.js → Surfaces-DCm19ZAD.js} +1 -1
  36. package/packages/web/dist/assets/{arc-BJPb3ViJ.js → arc-7GXE70CZ.js} +1 -1
  37. package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-PkLOC5wV.js → architectureDiagram-3BPJPVTR-CAEj_lAw.js} +1 -1
  38. package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-IPduhNH-.js → blockDiagram-GPEHLZMM-wNLONvdQ.js} +1 -1
  39. package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-dKTYV1Vq.js → c4Diagram-AAUBKEIU-Cf7MUqJz.js} +1 -1
  40. package/packages/web/dist/assets/channel-U0NZSTs2.js +2 -0
  41. package/packages/web/dist/assets/{chunk-2J33WTMH-B5C6geyg.js → chunk-2J33WTMH-W18BVHtE.js} +1 -1
  42. package/packages/web/dist/assets/{chunk-4BX2VUAB-1BRhFRhF.js → chunk-4BX2VUAB-DDJQi9KC.js} +1 -1
  43. package/packages/web/dist/assets/{chunk-55IACEB6-DNv-sTiI.js → chunk-55IACEB6-L5afa49k.js} +1 -1
  44. package/packages/web/dist/assets/{chunk-727SXJPM-CWezuVkx.js → chunk-727SXJPM-Bb0Sw8oK.js} +1 -1
  45. package/packages/web/dist/assets/{chunk-AQP2D5EJ-Bt4yEQnu.js → chunk-AQP2D5EJ-DRrKTv1K.js} +1 -1
  46. package/packages/web/dist/assets/{chunk-FMBD7UC4-lb_8q4JY.js → chunk-FMBD7UC4-CIsdDBaT.js} +1 -1
  47. package/packages/web/dist/assets/{chunk-ND2GUHAM-DOwgGlQ_.js → chunk-ND2GUHAM-DN5ua8KT.js} +1 -1
  48. package/packages/web/dist/assets/{chunk-QZHKN3VN-BanKpY4q.js → chunk-QZHKN3VN-DE1WNShj.js} +1 -1
  49. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-D1QjNKTc.js +2 -0
  50. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-D1QjNKTc.js +2 -0
  51. package/packages/web/dist/assets/{core-CAsyoNAa.js → core-DadwNpE4.js} +1 -1
  52. package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-sVaVkwMI.js → cose-bilkent-S5V4N54A-2FTPTDA6.js} +1 -1
  53. package/packages/web/dist/assets/{dagre-BM42HDAG-C9pKHSMo.js → dagre-BM42HDAG-eJ7MdaEX.js} +1 -1
  54. package/packages/web/dist/assets/{diagram-2AECGRRQ-CHdrmCfX.js → diagram-2AECGRRQ-D8MZTSkB.js} +1 -1
  55. package/packages/web/dist/assets/{diagram-5GNKFQAL-4UTa2Dfa.js → diagram-5GNKFQAL-DVXF3Z-H.js} +1 -1
  56. package/packages/web/dist/assets/{diagram-KO2AKTUF-NidpfVwW.js → diagram-KO2AKTUF-DoXfbQ0i.js} +1 -1
  57. package/packages/web/dist/assets/{diagram-LMA3HP47-ictQj03T.js → diagram-LMA3HP47-CRW0fiqv.js} +1 -1
  58. package/packages/web/dist/assets/{diagram-OG6HWLK6-B7dTLMHC.js → diagram-OG6HWLK6-DfhYXDqr.js} +1 -1
  59. package/packages/web/dist/assets/{erDiagram-TEJ5UH35-C2QYYzJ8.js → erDiagram-TEJ5UH35-HG0QTHgA.js} +1 -1
  60. package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-D2rcjSZ9.js → flowDiagram-I6XJVG4X-ChVekwUy.js} +1 -1
  61. package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-BQcXTYzg.js → ganttDiagram-6RSMTGT7-CeA-6Z-T.js} +1 -1
  62. package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-DwB2Vqxa.js → gitGraphDiagram-PVQCEYII-ew2oouNN.js} +1 -1
  63. package/packages/web/dist/assets/{index-BeuEs7dL.js → index-CbqaEg2j.js} +14 -14
  64. package/packages/web/dist/assets/index-tvJIh4A9.css +1 -0
  65. package/packages/web/dist/assets/{infoDiagram-5YYISTIA-BoK4Mawg.js → infoDiagram-5YYISTIA-BY9NYdld.js} +1 -1
  66. package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DPP9svhg.js → ishikawaDiagram-YF4QCWOH-CgbdrGBm.js} +1 -1
  67. package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-TrggodYk.js → journeyDiagram-JHISSGLW-BepLFtbU.js} +1 -1
  68. package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-Bh69hRSR.js → kanban-definition-UN3LZRKU-JHMJYGJu.js} +1 -1
  69. package/packages/web/dist/assets/{linear-C1iYMpBz.js → linear-Ccw8eVgC.js} +1 -1
  70. package/packages/web/dist/assets/{mermaid.core-BZDABcuq.js → mermaid.core-lHjASk7x.js} +4 -4
  71. package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-DTJON3dS.js → mindmap-definition-RKZ34NQL-Bi5Iq2M4.js} +1 -1
  72. package/packages/web/dist/assets/{pieDiagram-4H26LBE5-BxtFV74I.js → pieDiagram-4H26LBE5-rZuB_P1J.js} +1 -1
  73. package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-D2Ar8kmO.js → quadrantDiagram-W4KKPZXB-BuStI37i.js} +1 -1
  74. package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-DiLSfeSQ.js → requirementDiagram-4Y6WPE33-BFElQKEX.js} +1 -1
  75. package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-D_CRQc7j.js → sankeyDiagram-5OEKKPKP-tzdQCr91.js} +1 -1
  76. package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-DjtfcRNV.js → sequenceDiagram-3UESZ5HK-j1koqb6Q.js} +1 -1
  77. package/packages/web/dist/assets/{stateDiagram-AJRCARHV-CzEtmYLV.js → stateDiagram-AJRCARHV-B-dUkvgq.js} +1 -1
  78. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-b1ksIBrs.js +2 -0
  79. package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-DXKspEG3.js → timeline-definition-PNZ67QCA-BWyq6u64.js} +1 -1
  80. package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-B_tXRMHH.js → vennDiagram-CIIHVFJN-B0CRl3xN.js} +1 -1
  81. package/packages/web/dist/assets/{wardley-L42UT6IY-DNaNoaJm.js → wardley-L42UT6IY-C45bBEPS.js} +1 -1
  82. package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-BuVDpC8s.js → wardleyDiagram-YWT4CUSO-DT50TWrW.js} +1 -1
  83. package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-Cqtew2PA.js → xychartDiagram-2RQKCTM6-C8iBuFGD.js} +1 -1
  84. package/packages/web/dist/index.html +2 -2
  85. package/packages/web/dist/sw.js +1 -1
  86. package/packages/web/dist/assets/DiscoverPage-C1khyCvD.js +0 -2
  87. package/packages/web/dist/assets/DiscoverView-DS_Z9xKH.js +0 -2
  88. package/packages/web/dist/assets/InstanceConfigPage-B1ei1FDo.js +0 -2
  89. package/packages/web/dist/assets/ProjectView-iuiUIoIl.js +0 -13
  90. package/packages/web/dist/assets/channel-BhrgMiqg.js +0 -2
  91. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-Ho1IMdjg.js +0 -2
  92. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-Ho1IMdjg.js +0 -2
  93. package/packages/web/dist/assets/index-BNzTD4hA.css +0 -1
  94. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-pM8fIOir.js +0 -2
@@ -159,6 +159,59 @@ export interface ChatCancelMessage {
159
159
  jobId: string;
160
160
  };
161
161
  }
162
+ /**
163
+ * Stop ONE piece of background work, leaving the session and everything else it
164
+ * is running alone (issue #848).
165
+ *
166
+ * The finer-grained sibling of `chat:cancel`: that ends the model turn (or, in
167
+ * the background phase, reaps the whole session), this ends a single background
168
+ * shell / sub-agent / monitor. Keyed on the SESSION id rather than a job or turn
169
+ * id because background work outlives the turn that started it — which is
170
+ * exactly the phase in which the running-work bar matters.
171
+ *
172
+ * `taskId` is the SDK's own `task_id`, carried to the client on
173
+ * `chat:background` as {@link LiveBackgroundTaskWire.id}.
174
+ *
175
+ * Answered by exactly one {@link ChatStopTaskResultMessage}, to the asking
176
+ * socket. It does NOT remove the row: the SDK emits its own terminal
177
+ * `task_notification`, which arrives as an ordinary `chat:background` update.
178
+ */
179
+ export interface ChatStopTaskMessage {
180
+ type: "chat:stop_task";
181
+ payload: {
182
+ sessionId: string;
183
+ taskId: string;
184
+ };
185
+ }
186
+ /**
187
+ * The answer to one {@link ChatStopTaskMessage} — three outcomes, only one of
188
+ * which is a failure:
189
+ *
190
+ * - `stopping` — accepted. The row stays, held at `stopping…`, until the SDK's
191
+ * terminal notification evicts it. Also the idempotent case: a click that
192
+ * raced a natural completion lands here.
193
+ * - `gone` — no live session. NOT an error; the work died with the session, so
194
+ * the intent is already satisfied. The server has already dropped the task
195
+ * from the registry (nothing is left to notify), so a `chat:background`
196
+ * update without it accompanies this.
197
+ * - `error` — the stop did not happen and the task is STILL RUNNING. Notably a
198
+ * `monitor_mcp` task, which the CLI cannot kill. `message` is for display.
199
+ *
200
+ * Unicast, not broadcast: it answers one socket's request, and a second viewer
201
+ * of the same chat should not be shown an error for a click it did not make.
202
+ * Both viewers still agree on the outcome, because the row's actual removal
203
+ * travels on the broadcast `chat:background` frame.
204
+ */
205
+ export interface ChatStopTaskResultMessage {
206
+ type: "chat:stop_task_result";
207
+ payload: {
208
+ sessionId: string;
209
+ taskId: string;
210
+ outcome: "stopping" | "gone" | "error";
211
+ /** Present only on `error`. */
212
+ message?: string;
213
+ };
214
+ }
162
215
  /**
163
216
  * Run a slash command (e.g. `/compact`) in the current chat.
164
217
  *
@@ -276,7 +329,7 @@ export interface ChatContinueMessage {
276
329
  export interface PingMessage {
277
330
  type: "ping";
278
331
  }
279
- export type ClientMessage = ChatSendMessage | ChatCommandMessage | ChatCancelMessage | ChatSubscribeMessage | ChatSetQueueMessage | ChatContinueMessage | PingMessage;
332
+ export type ClientMessage = ChatSendMessage | ChatCommandMessage | ChatCancelMessage | ChatStopTaskMessage | ChatSubscribeMessage | ChatSetQueueMessage | ChatContinueMessage | PingMessage;
280
333
  export interface Routing {
281
334
  projectSlug: string;
282
335
  sessionId: string | null;
@@ -561,8 +614,18 @@ export interface ChatKilledTaskMessage {
561
614
  */
562
615
  export interface LiveBackgroundTaskWire {
563
616
  id: string;
564
- /** `shell` | `subagent` | `monitor` | `workflow`, or a raw discriminant we do not know. */
617
+ /**
618
+ * The RAW SDK discriminant — `local_bash`, `local_agent`, `monitor_mcp`, … —
619
+ * carried verbatim so an unexpected kind is diagnosable from the wire (#846).
620
+ * Render from {@link role} instead.
621
+ */
565
622
  type: string;
623
+ /**
624
+ * Rendering role derived from {@link type} by the registry: `shell` |
625
+ * `subagent` | `monitor` | `workflow` | `task`, falling back to the raw
626
+ * discriminant for a kind the server does not know about yet.
627
+ */
628
+ role: string;
566
629
  description: string;
567
630
  startedAt: number;
568
631
  toolUseId?: string;
@@ -574,6 +637,29 @@ export interface LiveBackgroundTaskWire {
574
637
  lastToolName?: string;
575
638
  toolUses?: number;
576
639
  skipTranscript?: boolean;
640
+ /**
641
+ * May this task be stopped via `chat:stop_task` (#848)? Resolved on the
642
+ * server from the raw {@link type}, and sent rather than left to the client
643
+ * for two reasons — note that neither is "the client could not tell", since
644
+ * #846 does carry the raw discriminant here:
645
+ *
646
+ * 1. It is a fact about the RUNTIME'S capability, not about rendering. The
647
+ * server owns which task types the CLI has a kill strategy for; a second
648
+ * copy of that denylist in the client is a second place to forget when
649
+ * the SDK gains one.
650
+ * 2. #846 made {@link role} the thing clients render and {@link type} a
651
+ * diagnostic. Having the client branch on `type` for this one decision
652
+ * would re-couple its rendering to the discriminant #846 just abstracted
653
+ * away — and `role` alone genuinely is not enough, because `monitor_ws`
654
+ * and `monitor_mcp` share the `monitor` role and only one is killable.
655
+ *
656
+ * REQUIRED on the wire, like {@link role}: the server always resolves it, and
657
+ * leaving it optional here would let a future producer omit it and still
658
+ * typecheck — at which point clients read absent as "stoppable" and hand a
659
+ * `monitor_mcp` row a button that can only ever fail. The tolerance for an
660
+ * older server belongs on the CLIENT's copy of this type, and lives there.
661
+ */
662
+ stoppable: boolean;
577
663
  }
578
664
  /**
579
665
  * A session's live background work (#604) — the tasks still running after the
@@ -616,6 +702,6 @@ export interface ChatNoticeMessage {
616
702
  export interface PongMessage {
617
703
  type: "pong";
618
704
  }
619
- export type ServerMessage = ChatResponseMessage | ChatToolCallMessage | ChatToolStartMessage | ChatMessageBoundaryMessage | ChatCompleteMessage | ChatErrorMessage | ChatResyncMessage | ChatActiveMessage | ChatQueuedFlushedMessage | ChatQueuedStateMessage | ChatQueuedReturnedMessage | ChatKilledTaskMessage | ChatBackgroundMessage | ChatNoticeMessage | PongMessage;
705
+ export type ServerMessage = ChatResponseMessage | ChatToolCallMessage | ChatToolStartMessage | ChatMessageBoundaryMessage | ChatCompleteMessage | ChatErrorMessage | ChatResyncMessage | ChatActiveMessage | ChatQueuedFlushedMessage | ChatQueuedStateMessage | ChatQueuedReturnedMessage | ChatKilledTaskMessage | ChatBackgroundMessage | ChatStopTaskResultMessage | ChatNoticeMessage | PongMessage;
620
706
  export declare function isClientMessage(data: unknown): data is ClientMessage;
621
707
  export {};
@@ -198,6 +198,15 @@ export function isClientMessage(data) {
198
198
  const p = m.payload;
199
199
  return !!p && typeof p.jobId === "string";
200
200
  }
201
+ if (m.type === "chat:stop_task") {
202
+ const p = m.payload;
203
+ // Both ids must be non-empty: an empty session id would reach the fleet as a
204
+ // lookup miss and report `gone`, quietly telling the user work that is still
205
+ // running has stopped.
206
+ if (!p || typeof p.sessionId !== "string" || p.sessionId.length === 0)
207
+ return false;
208
+ return typeof p.taskId === "string" && p.taskId.length > 0;
209
+ }
201
210
  if (m.type === "chat:send") {
202
211
  const p = m.payload;
203
212
  if (!p || typeof p.message !== "string")
@@ -1500,6 +1500,44 @@ export function makeChatHandler(deps) {
1500
1500
  void deps.herdctl.cancel(parsed.payload.jobId).catch(() => undefined);
1501
1501
  return;
1502
1502
  }
1503
+ if (parsed.type === "chat:stop_task") {
1504
+ // Stop ONE background task (#848). Unlike `chat:cancel` there is no turn
1505
+ // to note and no queue to hand back — this leaves the session, and every
1506
+ // other task in it, running. The row is NOT removed here: on `stopping`
1507
+ // the SDK's own terminal notification does it, which is what keeps the
1508
+ // bar honest if the kill turns out not to land.
1509
+ const { sessionId, taskId } = parsed.payload;
1510
+ void deps.herdctl.stopBackgroundTask(sessionId, taskId).then((res) => {
1511
+ // `gone` means no live session, so nothing will ever notify for this
1512
+ // task — drop it here or the row is stranded at `stopping…` forever.
1513
+ // The level signal stays the authority and puts it back if wrong.
1514
+ if (res.outcome === "gone")
1515
+ background.dropTask(sessionId, taskId);
1516
+ send({
1517
+ type: "chat:stop_task_result",
1518
+ payload: {
1519
+ sessionId,
1520
+ taskId,
1521
+ outcome: res.outcome,
1522
+ ...(res.outcome === "error" ? { message: res.message } : {}),
1523
+ },
1524
+ });
1525
+ },
1526
+ // stopBackgroundTask catches its own rejections; this is belt-and-braces
1527
+ // so a future refactor cannot leave the row held with no answer at all.
1528
+ (err) => {
1529
+ send({
1530
+ type: "chat:stop_task_result",
1531
+ payload: {
1532
+ sessionId,
1533
+ taskId,
1534
+ outcome: "error",
1535
+ message: err instanceof Error ? err.message : String(err),
1536
+ },
1537
+ });
1538
+ });
1539
+ return;
1540
+ }
1503
1541
  if (parsed.type === "chat:subscribe") {
1504
1542
  onSubscribe(parsed);
1505
1543
  return;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paddock/server",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -1,2 +1,2 @@
1
- import{j as r,l as t,r as d}from"./index-BeuEs7dL.js";const u=["w-full rounded-lg border border-edge-strong bg-surface-sunken px-3 py-2 text-sm text-fg","outline-none motion-fast transition-[border-color,box-shadow]","focus:border-accent focus:ring-2 focus:ring-accent/25","disabled:cursor-not-allowed disabled:opacity-60","aria-[invalid=true]:border-danger aria-[invalid=true]:focus:ring-danger/25"].join(" ");function p({className:e,...s}){return r.jsx("input",{className:t(u,e),...s})}function m({className:e,...s}){return r.jsx("textarea",{className:t(u,"resize-y",e),...s})}function h({className:e,...s}){return r.jsx("select",{className:t(u,e),...s})}function j({checked:e,onChange:s,label:a,disabled:n,id:o,className:c}){const i=d.useId(),l=o??i;return r.jsxs("label",{htmlFor:l,className:t("relative inline-block shrink-0 cursor-pointer",c),children:[r.jsx("input",{id:l,type:"checkbox","aria-label":a,className:"peer sr-only",checked:e,disabled:n,onChange:x=>s(x.target.checked)}),r.jsx("span",{className:t("block h-[18px] w-8 rounded-full bg-edge-strong","motion-fast transition-colors","after:absolute after:left-0.5 after:top-0.5 after:h-3.5 after:w-3.5 after:rounded-full","after:bg-surface-raised after:shadow-2xs after:transition-transform after:content-['']","peer-checked:bg-accent-solid peer-checked:after:translate-x-3.5","peer-focus-visible:ring-2 peer-focus-visible:ring-accent/50","peer-disabled:opacity-50")})]})}function w({label:e,description:s,indeterminate:a=!1,className:n,...o}){const c=d.useRef(null);d.useEffect(()=>{c.current&&(c.current.indeterminate=a)},[a]);const i=r.jsx("input",{ref:c,type:"checkbox",...a?{"aria-checked":"mixed"}:{},className:t("h-4 w-4 shrink-0 cursor-pointer rounded border-edge-strong accent-[var(--accent-solid)]","disabled:cursor-not-allowed disabled:opacity-50",e?"mt-0.5":"",n),...o});return e?r.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-sm text-fg",children:[i,r.jsxs("span",{className:"min-w-0",children:[e,s&&r.jsx("span",{className:"block text-xs leading-snug text-fg-muted",children:s})]})]}):i}const f={neutral:"bg-surface-active text-fg-muted",accent:"bg-accent-soft text-accent",success:"bg-success-soft text-success",warn:"bg-warn-soft text-warn",danger:"bg-danger-soft text-danger",info:"bg-info-soft text-info",lineage:"bg-lineage-soft text-lineage"},g={neutral:"bg-fg-subtle",accent:"bg-accent-solid",success:"bg-success-solid",warn:"bg-warn-solid",danger:"bg-danger-solid",info:"bg-info-solid",lineage:"bg-lineage-solid"};function N({tone:e="neutral",shape:s="tag",size:a="md",dot:n=!1,icon:o,title:c,className:i,children:l}){return r.jsxs("span",{title:c,className:t("inline-flex items-center gap-1 font-medium leading-none",s==="pill"?"rounded-full px-2 py-0.5":"rounded-md px-1.5 py-0.5",a==="sm"?"text-3xs":"text-2xs",f[e],i),children:[n&&r.jsx("span",{className:t("h-1.5 w-1.5 shrink-0 rounded-full",g[e])}),o,l]})}function k({tone:e="neutral",pulse:s=!1,className:a}){return r.jsx("span",{className:t("inline-block h-2 w-2 shrink-0 rounded-full",g[e],s&&"animate-pulse",a)})}function y({tone:e="info",icon:s,className:a,children:n}){const o={neutral:"border-edge",accent:"border-accent-edge",success:"border-success-edge",warn:"border-warn-edge",danger:"border-danger-edge",info:"border-info-edge",lineage:"border-lineage-edge"};return r.jsxs("div",{role:e==="danger"?"alert":void 0,className:t("flex items-start gap-2 rounded-lg border px-3 py-2 text-sm",f[e],o[e],a),children:[s&&r.jsx("span",{className:"mt-0.5 shrink-0",children:s}),r.jsx("div",{className:"min-w-0",children:n})]})}export{N as C,p as I,k as S,j as T,y as a,h as b,m as c,w as d};
1
+ import{j as r,l as t,r as d}from"./index-CbqaEg2j.js";const u=["w-full rounded-lg border border-edge-strong bg-surface-sunken px-3 py-2 text-sm text-fg","outline-none motion-fast transition-[border-color,box-shadow]","focus:border-accent focus:ring-2 focus:ring-accent/25","disabled:cursor-not-allowed disabled:opacity-60","aria-[invalid=true]:border-danger aria-[invalid=true]:focus:ring-danger/25"].join(" ");function p({className:e,...s}){return r.jsx("input",{className:t(u,e),...s})}function m({className:e,...s}){return r.jsx("textarea",{className:t(u,"resize-y",e),...s})}function h({className:e,...s}){return r.jsx("select",{className:t(u,e),...s})}function j({checked:e,onChange:s,label:a,disabled:n,id:o,className:c}){const i=d.useId(),l=o??i;return r.jsxs("label",{htmlFor:l,className:t("relative inline-block shrink-0 cursor-pointer",c),children:[r.jsx("input",{id:l,type:"checkbox","aria-label":a,className:"peer sr-only",checked:e,disabled:n,onChange:x=>s(x.target.checked)}),r.jsx("span",{className:t("block h-[18px] w-8 rounded-full bg-edge-strong","motion-fast transition-colors","after:absolute after:left-0.5 after:top-0.5 after:h-3.5 after:w-3.5 after:rounded-full","after:bg-surface-raised after:shadow-2xs after:transition-transform after:content-['']","peer-checked:bg-accent-solid peer-checked:after:translate-x-3.5","peer-focus-visible:ring-2 peer-focus-visible:ring-accent/50","peer-disabled:opacity-50")})]})}function w({label:e,description:s,indeterminate:a=!1,className:n,...o}){const c=d.useRef(null);d.useEffect(()=>{c.current&&(c.current.indeterminate=a)},[a]);const i=r.jsx("input",{ref:c,type:"checkbox",...a?{"aria-checked":"mixed"}:{},className:t("h-4 w-4 shrink-0 cursor-pointer rounded border-edge-strong accent-[var(--accent-solid)]","disabled:cursor-not-allowed disabled:opacity-50",e?"mt-0.5":"",n),...o});return e?r.jsxs("label",{className:"flex cursor-pointer items-start gap-2 text-sm text-fg",children:[i,r.jsxs("span",{className:"min-w-0",children:[e,s&&r.jsx("span",{className:"block text-xs leading-snug text-fg-muted",children:s})]})]}):i}const f={neutral:"bg-surface-active text-fg-muted",accent:"bg-accent-soft text-accent",success:"bg-success-soft text-success",warn:"bg-warn-soft text-warn",danger:"bg-danger-soft text-danger",info:"bg-info-soft text-info",lineage:"bg-lineage-soft text-lineage"},g={neutral:"bg-fg-subtle",accent:"bg-accent-solid",success:"bg-success-solid",warn:"bg-warn-solid",danger:"bg-danger-solid",info:"bg-info-solid",lineage:"bg-lineage-solid"};function N({tone:e="neutral",shape:s="tag",size:a="md",dot:n=!1,icon:o,title:c,className:i,children:l}){return r.jsxs("span",{title:c,className:t("inline-flex items-center gap-1 font-medium leading-none",s==="pill"?"rounded-full px-2 py-0.5":"rounded-md px-1.5 py-0.5",a==="sm"?"text-3xs":"text-2xs",f[e],i),children:[n&&r.jsx("span",{className:t("h-1.5 w-1.5 shrink-0 rounded-full",g[e])}),o,l]})}function k({tone:e="neutral",pulse:s=!1,className:a}){return r.jsx("span",{className:t("inline-block h-2 w-2 shrink-0 rounded-full",g[e],s&&"animate-pulse",a)})}function y({tone:e="info",icon:s,className:a,children:n}){const o={neutral:"border-edge",accent:"border-accent-edge",success:"border-success-edge",warn:"border-warn-edge",danger:"border-danger-edge",info:"border-info-edge",lineage:"border-lineage-edge"};return r.jsxs("div",{role:e==="danger"?"alert":void 0,className:t("flex items-start gap-2 rounded-lg border px-3 py-2 text-sm",f[e],o[e],a),children:[s&&r.jsx("span",{className:"mt-0.5 shrink-0",children:s}),r.jsx("div",{className:"min-w-0",children:n})]})}export{N as C,p as I,k as S,j as T,y as a,h as b,m as c,w as d};
2
2
 
@@ -0,0 +1,2 @@
1
+ import{j as r}from"./index-CbqaEg2j.js";import{D as o}from"./DiscoverView-CArICIRO.js";import"./Surfaces-DCm19ZAD.js";import"./Chip-5S5MAayn.js";function s(){return r.jsx(o,{})}export{s as DiscoverPage};
2
+
@@ -0,0 +1,2 @@
1
+ import{a as ne,u as re,H as ae,r as l,b as A,j as s,M as oe,E as ie,D as Q,J as U,K as de,l as F,O as ce,h as le}from"./index-CbqaEg2j.js";import{E as D,B as O,C as he}from"./Surfaces-DCm19ZAD.js";import{a as W,d as M,C as P,T as K}from"./Chip-5S5MAayn.js";function ue(e){const t={};for(const r of e)t[r.path]={checked:!0,expanded:!1,loading:!1,error:null};return t}function pe(e){if(!e.sessions||!e.selected)return e.checked?"on":"off";const t=e.sessions.sessions.length,r=e.selected.size;return t===0||r===0?"off":r===t?"on":"mixed"}function C(e,t){return e.sessions&&e.selected?e.selected.size:e.checked?t.sessionCount:0}function me(e,t){return t.reduce((r,a)=>r+C(e[a.path]??R(),a),0)}function xe(e,t){return t.filter(r=>C(e[r.path]??R(),r)>0)}function ge(e,t,r){const a=e[t];if(!a)return e;const n={...a,checked:r};return a.sessions&&(n.selected=r?new Set(a.sessions.sessions.map(c=>c.sessionId)):new Set),{...e,[t]:n}}function fe(e,t,r){const a=e[t];if(!a||!a.sessions)return e;const n=new Set(a.selected??[]);return n.delete(r)||n.add(r),{...e,[t]:{...a,selected:n,checked:n.size>0}}}function je(e,t,r){const a=e[t];if(!a)return e;const n=a.checked?new Set(r.sessions.map(c=>c.sessionId)):new Set;return{...e,[t]:{...a,sessions:r,selected:n,loading:!1,error:null}}}function T(e,t,r){const a=e[t];return a?{...e,[t]:{...a,...r}}:e}function be(e,t){const r=e??R();return C(r,t)===0?null:r.sessions&&r.selected?{sessionIds:[...r.selected]}:{}}function R(){return{checked:!1,expanded:!1,loading:!1,error:null}}function ye(e){return e.error!==void 0?e.stage==="create"?"danger":"warn":e.adopted>0?"success":"warn"}async function we(e,t,r){let a;try{a=await e.createProject({name:t.name,slug:t.suggestedSlug,path:t.path,managed:!1})}catch(n){return{stage:"create",adopted:0,skipped:[],error:V(n)}}try{const n=await e.adoptChats(a.slug,{sourceCwd:a.workingDir,...r.sessionIds?{sessionIds:r.sessionIds}:{}});return{project:a,adopted:n.adopted.length,skipped:n.skipped}}catch(n){return{stage:"import",project:a,adopted:0,skipped:[],error:V(n)}}}async function Ne(e,t,r){const a=[];for(const n of t){r(n.candidate.path,"running");const c=await we(e,n.candidate,n.plan);a.push(c),r(n.candidate.path,"done",c)}return a}const ve={sidechain:"sub-agent transcript","already-adopted":"already adopted","destination-exists":"a chat with that id already exists here","attributed-to-run":"belongs to a Paddock run",unreadable:"transcript unreadable","placement-failed":"copy failed","record-failed":"could not be recorded"};function J(e){if(e.length===0)return"";const t=[...new Set(e.map(r=>ve[r.reason]??r.reason))];return`${e.length} skipped (${t.join(", ")})`}function ke(e,t){var h;if(e.stage==="create")return`Couldn't create the project: ${e.error}`;const r=((h=e.project)==null?void 0:h.slug)??t.suggestedSlug;if(e.stage==="import")return`Project “${r}” was created, but importing its chats failed: ${e.error}. It is there and empty — you can import them from the project itself.`;if(e.adopted===0){const m=J(e.skipped);return t.recordedPath!==void 0?`Project “${r}” was created but no chats came with it. Its transcripts record ${t.recordedPath}, a different spelling of ${t.path}, and an import matches on the exact path.`:m?`Project “${r}” was created but no chats came with it — ${m}.`:`Project “${r}” was created but no chats came with it.`}const a=e.adopted,n=J(e.skipped),c=`Adopted ${a} chat${a===1?"":"s"} into “${r}”`;return n?`${c} — ${n}.`:`${c}.`}function V(e){return e instanceof Error?e.message:String(e)}function Re({firstRun:e=!1,onLeave:t}){const r=ne(),{refresh:a}=re(),n=ae(),[c,h]=l.useState(!1),[m,d]=l.useState(!1),[x,$]=l.useState(null),[f,u]=l.useState(null),[v,I]=l.useState(!0),[j,w]=l.useState({}),[k,z]=l.useState(!1),[X,H]=l.useState({}),[E,B]=l.useState({}),[S,Y]=l.useState(!1);l.useEffect(()=>{let o=!0;return I(!0),u(null),A.discover({includeNonGit:c,includeOutsideHome:m}).then(i=>{o&&($(i),w(ue(i.candidates)),I(!1))}).catch(i=>{o&&(u(i instanceof Error?i.message:"Discovery failed"),I(!1))}),()=>{o=!1}},[c,m]);const y=(x==null?void 0:x.candidates)??[],G=l.useMemo(()=>me(j,y),[j,y]),b=l.useMemo(()=>xe(j,y),[j,y]),Z=l.useCallback(o=>{w(p=>{const g=p[o.path];if(!g)return p;const N=T(p,o.path,{expanded:!g.expanded});return g.expanded||g.sessions||g.loading?N:T(N,o.path,{loading:!0,error:null})});const i=j[o.path];!i||i.expanded||i.sessions||i.loading||A.discoverSessions(o.path).then(p=>w(g=>je(g,o.path,p))).catch(p=>w(g=>T(g,o.path,{loading:!1,error:p instanceof Error?p.message:"Could not read this directory's sessions"})))},[j]),L=l.useCallback(async()=>{if(k)return;z(!0),H(Object.fromEntries(b.map(i=>[i.path,"pending"]))),B({});const o=b.map(i=>({candidate:i,plan:be(j[i.path],i)??{}}));await Ne(A,o,(i,p,g)=>{H(N=>({...N,[i]:p})),g&&B(N=>({...N,[i]:g}))}),z(!1),Y(!0),await a()},[b,j,k,a]),ee=l.useCallback(async()=>{await a(),t==null||t(),r("/")},[r,a,t]),se=Object.values(E).reduce((o,i)=>o+i.adopted,0),te=Object.values(E).filter(o=>o.project).length;return s.jsxs("div",{className:"flex h-full min-h-0 flex-col",children:[s.jsxs("header",{className:"pt-safe flex items-center gap-2 border-b border-edge px-3 pb-2.5 sm:px-6 lg:py-4",children:[s.jsx("button",{type:"button",onClick:()=>n==null?void 0:n.openNav(),"aria-label":"Open menu",className:"btn-subtle -ml-1 shrink-0 px-2 py-1.5 lg:hidden",children:s.jsx(oe,{width:20,height:20})}),s.jsx(ie,{width:18,height:18,className:"shrink-0 text-fg-subtle"}),s.jsx("h1",{className:"text-md font-semibold tracking-tight",children:"Discover"})]}),s.jsx("div",{className:"flex-1 overflow-y-auto overscroll-contain",children:s.jsxs("div",{className:"mx-auto max-w-3xl px-6 py-6",children:[s.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:e?"Nothing here yet — but you have probably already been using Claude Code in a terminal. These directories have history Paddock can bring in as projects.":"Directories on this machine with existing Claude Code history. Adopting one links it as a project and brings its conversations in; your own history is never moved or deleted."}),S&&s.jsx(Ie,{imported:se,projects:te,onGetStarted:ee}),f!==null&&s.jsx(W,{tone:"danger",icon:s.jsx(Q,{width:16,height:16}),children:f}),v&&s.jsx(Ee,{}),!v&&f===null&&x!==null&&s.jsxs(s.Fragment,{children:[x.scanned===0?s.jsx($e,{claudeHome:x.claudeHome}):y.length===0?s.jsx(D,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:"Nothing left to adopt",body:"Every directory with Claude Code history on this machine is already a project, or was filtered out."}):s.jsx("ul",{className:"space-y-2",children:y.map(o=>s.jsx(Se,{candidate:o,row:j[o.path],status:X[o.path],outcome:E[o.path],locked:k||S,onToggleRow:i=>w(p=>ge(p,o.path,i)),onToggleSession:i=>w(p=>fe(p,o.path,i)),onToggleExpanded:()=>Z(o)},o.path))}),!S&&s.jsx(Ce,{result:x,includeNonGit:c,includeOutsideHome:m,disabled:k,onIncludeNonGit:h,onIncludeOutsideHome:d}),y.length>0&&!S&&s.jsxs("div",{className:"mt-5 flex items-center justify-between gap-3 border-t border-edge pt-4",children:[s.jsxs("span",{className:"text-sm text-fg-muted",children:[G," conversation",G===1?"":"s"," from ",b.length," director",b.length===1?"y":"ies"]}),s.jsxs(O,{variant:"primary",onClick:()=>void L(),disabled:b.length===0,loading:k,loadingLabel:"Adopting…",children:["Adopt ",b.length," project",b.length===1?"":"s"]})]})]})]})})]})}function Se({candidate:e,row:t,status:r,outcome:a,locked:n,onToggleRow:c,onToggleSession:h,onToggleExpanded:m}){const d=t??{checked:!1,expanded:!1,loading:!1,error:null},x=pe(d),$=C(d,e),f=a?ye(a):null;return s.jsx("li",{children:s.jsxs(he,{flush:!0,className:F("overflow-hidden",f==="success"&&"border-success-edge bg-success-soft",f==="warn"&&"border-warn-edge bg-warn-soft",f==="danger"&&"border-danger-edge bg-danger-soft",r==="running"&&"border-accent-edge"),"data-testid":`discover-row-${e.suggestedSlug}`,"data-tone":f??void 0,children:[s.jsxs("div",{className:"flex items-start gap-3 px-3 py-2.5",children:[s.jsx(M,{className:"mt-1",checked:x==="on",indeterminate:x==="mixed",disabled:n,"aria-label":`Adopt ${e.path}`,onChange:u=>c(u.target.checked)}),s.jsxs("div",{className:"min-w-0 flex-1",children:[s.jsx("code",{className:"block break-all text-sm text-fg",children:e.path}),s.jsxs("div",{className:"mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-fg-muted",children:[s.jsxs("span",{className:"tabular",children:[e.sessionCount," conversation",e.sessionCount===1?"":"s"]}),e.filteredCount>0&&s.jsxs("span",{className:"tabular",title:"Empty, slash-command-only or sweeper transcripts, withheld as noise",children:["· ",e.filteredCount," filtered out"]}),e.lastSessionAt!==void 0&&s.jsxs("span",{className:"tabular",children:["· last ",q(e.lastSessionAt)]}),e.gitRemote!==void 0&&s.jsx(P,{tone:"lineage",size:"sm",children:e.gitRemote}),!e.hasGit&&s.jsx(P,{tone:"neutral",size:"sm",children:"no git"}),!e.insideHome&&s.jsx(P,{tone:"neutral",size:"sm",children:"outside home"})]}),e.recordedPath!==void 0&&s.jsx(W,{tone:"warn",className:"mt-2",icon:s.jsx(Q,{width:14,height:14}),children:s.jsxs("span",{className:"text-xs",children:["These transcripts record"," ",s.jsx("code",{className:"break-all",children:e.recordedPath})," — a different spelling of this path. The import matches on the exact path, so it may bring nothing in."]})}),a&&s.jsx("p",{className:F("mt-2 text-xs",f==="success"&&"text-success",f==="warn"&&"text-warn",f==="danger"&&"text-danger"),children:ke(a,e)}),r==="running"&&!a&&s.jsx("p",{className:"mt-2 text-xs text-fg-muted",children:"Adopting…"})]}),s.jsxs("span",{className:"flex shrink-0 items-center gap-1",children:[s.jsx("span",{className:"tabular text-xs text-fg-subtle",children:$}),s.jsx(O,{size:"icon-sm",variant:"subtle","aria-label":d.expanded?"Hide conversations":"Show conversations","aria-expanded":d.expanded,onClick:m,children:d.expanded?s.jsx(ce,{width:14,height:14}):s.jsx(le,{width:14,height:14})})]})]}),d.expanded&&s.jsxs("div",{className:"border-t border-edge px-3 py-2",children:[d.loading&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Reading transcripts…"}),d.error!==null&&s.jsx("p",{className:"py-2 text-xs text-danger",children:d.error}),d.sessions&&d.sessions.sessions.length===0&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Nothing to adopt here any more — it may have been adopted since the scan."}),d.sessions&&d.sessions.sessions.length>0&&s.jsx("ul",{className:"space-y-1",children:d.sessions.sessions.map(u=>{var v;return s.jsx("li",{children:s.jsxs("label",{className:"flex cursor-pointer items-start gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-surface-hover",children:[s.jsx(M,{checked:((v=d.selected)==null?void 0:v.has(u.sessionId))??!1,disabled:n,"aria-label":_(u),onChange:()=>h(u.sessionId)}),s.jsxs("span",{className:"min-w-0 flex-1",children:[s.jsx("span",{className:"block truncate text-xs text-fg",children:_(u)}),s.jsxs("span",{className:"tabular mt-0.5 block text-3xs text-fg-muted",children:[q(u.mtime)," · ",Pe(u.sizeBytes)]})]})]})},u.sessionId)})}),d.sessions&&d.sessions.filtered.length>0&&s.jsxs("p",{className:"mt-2 px-2 text-3xs text-fg-subtle",children:[d.sessions.filtered.length," more withheld as noise (",[...new Set(d.sessions.filtered.map(u=>u.reason))].join(", "),")."]})]})]})})}function Ce({result:e,includeNonGit:t,includeOutsideHome:r,disabled:a,onIncludeNonGit:n,onIncludeOutsideHome:c}){const h=e.excluded["no-git"]??0,m=e.excluded["outside-home"]??0,d=h>0||t,x=m>0||r;return e.scanned===0?null:s.jsxs("div",{className:"mt-5 space-y-2 border-t border-edge pt-4",children:[s.jsx("p",{className:"text-xs text-fg-muted",children:Ae(e)}),d&&s.jsxs("div",{className:"flex items-center gap-2 text-xs text-fg-muted",children:[s.jsx(K,{checked:t,disabled:a,onChange:n,label:"Also offer directories without a git repository"}),s.jsxs("span",{children:["Also offer directories without a git repository",h>0&&` (${h} hidden)`]})]}),x&&s.jsxs("div",{className:"flex items-center gap-2 text-xs text-fg-muted",children:[s.jsx(K,{checked:r,disabled:a,onChange:c,label:"Also offer directories outside your home directory"}),s.jsxs("span",{children:["Also offer directories outside ",s.jsx("code",{children:e.homeDir}),m>0&&` (${m} hidden)`]})]})]})}function $e({claudeHome:e}){return s.jsx(D,{variant:"panel",icon:s.jsx(de,{width:22,height:22}),title:"No Claude Code history on this machine",body:s.jsxs(s.Fragment,{children:["Nothing has been recorded under ",s.jsx("code",{className:"break-all",children:e}),". That is normal for a container, whose Claude home is its own rather than yours — bind-mount your history there and re-open this page, or import it headlessly with"," ",s.jsx("code",{children:"npm run import-chats"}),"."]})})}function Ie({imported:e,projects:t,onGetStarted:r}){return s.jsx("div",{className:"mb-6",children:s.jsx(D,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:t===0?"Nothing was adopted":`${t} project${t===1?"":"s"}, ${e} conversation${e===1?"":"s"}`,body:t===0?"Every row failed. Each one says why below.":"They are in the sidebar now. Anything that did not land says why below.",action:s.jsx(O,{variant:"primary",onClick:()=>void r(),children:"Get started"})})})}function Ee(){return s.jsx("div",{className:"space-y-2","aria-label":"Scanning",role:"status",children:[0,1,2].map(e=>s.jsx("div",{className:"h-16 animate-pulse rounded-2xl bg-surface-active"},e))})}function Ae(e){const t=[],r=[["temp-root",n=>`${n} in temp directories`],["no-git",n=>`${n} without a git repository`],["outside-home",n=>`${n} outside your home directory`],["already-managed",n=>`${n} already a project`],["no-sessions",n=>`${n} with nothing to adopt`],["no-recorded-cwd",n=>`${n} with no recorded directory`],["missing",n=>`${n} no longer on disk`],["home-root",n=>`${n} your home directory itself`],["system-path",n=>`${n} system directories`],["paddock-internal",n=>`${n} inside Paddock's own data`]];for(const[n,c]of r){const h=e.excluded[n];h!==void 0&&h>0&&t.push(c(h))}const a=`${e.scanned} transcript folder${e.scanned===1?"":"s"} scanned`;return t.length===0?`${a}.`:`${a}; skipped ${t.join(", ")}.`}function _(e){var a,n;const t=(a=e.autoName)==null?void 0:a.trim();if(t!==void 0&&t!=="")return t;const r=(n=e.preview)==null?void 0:n.trim();return r!==void 0&&r!==""?r:e.sessionId}function q(e){const t=new Date(e);return Number.isNaN(t.getTime())?"unknown date":t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}function Pe(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} kB`:`${(e/(1024*1024)).toFixed(1)} MB`}export{Re as D};
2
+
@@ -0,0 +1,2 @@
1
+ import{r as u,n as W,s as Z,A as ee,p as pe,j as e,q as ae,l as b,t as ie,v as be,w as je,x as le,y as ve,z as ye,b as O,D as oe,E as we,X as Ne,F as ke,G as Ce,H as Se,M as Ae,I as Ee}from"./index-CbqaEg2j.js";import{B as A,S as te}from"./Surfaces-DCm19ZAD.js";import{C as ce,S as L,I as B,a as Re,T as $e,b as Me,c as Pe}from"./Chip-5S5MAayn.js";const Ie=Array.from({length:72},(t,n)=>n*5),S=[...ie].sort((t,n)=>t.hue-n.hue),z=(t,n)=>Math.min(Math.abs(t-n),360-Math.abs(t-n));function ne(t){const n=S.reduce((a,s)=>z(s.hue,t)<z(a.hue,t)?s:a);if(z(n.hue,t)<=8)return n.name;const r=S.find(a=>a.hue>t)??S[0];return`between ${S[(S.indexOf(r)-1+S.length)%S.length].name} and ${r.name}`}function Fe({theme:t,dark:n,hue:r,className:c}){const a=u.useRef(null);return u.useLayoutEffect(()=>{const s=a.current;s&&(r===null?je(s):le(r,s))},[t,n,r]),e.jsx("div",{ref:a,"data-theme":t,className:b("overflow-hidden rounded-lg border border-edge",n&&"dark",c),children:e.jsxs("div",{className:"flex h-full items-center gap-2 bg-surface p-2",children:[e.jsxs("div",{className:"flex-1 rounded-md border border-edge-subtle bg-surface-raised p-1.5",children:[e.jsx("div",{className:"h-1 w-4/5 rounded-full bg-fg"}),e.jsx("div",{className:"mt-1 h-1 w-3/5 rounded-full bg-fg-subtle"})]}),e.jsx("div",{className:"grid h-6 w-6 shrink-0 place-items-center rounded-md bg-accent-solid",children:e.jsx("div",{className:"h-1 w-3 rounded-full bg-accent-fg"})})]})})}function Te({hexes:t,hue:n,active:r,onCommit:c}){const a=u.useRef(null),s=u.useRef(null),d=u.useRef(null),x=u.useRef(0),h=u.useRef(null),p=u.useRef(!1),g=u.useRef(null),l=u.useMemo(()=>{if(t.length===0)return;const m=t.map((j,y)=>`${j} ${(y/t.length*100).toFixed(2)}%`);return m.push(`${t[0]} 100%`),`linear-gradient(to right, ${m.join(", ")})`},[t]),f=u.useCallback(m=>{s.current&&(s.current.style.left=`${m/360*100}%`),d.current&&(d.current.textContent=ne(m))},[]);u.useEffect(()=>{p.current||f(n)},[n,f]);const N=m=>{var $;const j=($=a.current)==null?void 0:$.getBoundingClientRect();if(!j||j.width===0)return 0;const y=Math.min(1,Math.max(0,(m-j.left)/j.width));return Math.round(y*360)%360},w=u.useCallback(m=>{h.current=m,!x.current&&(x.current=requestAnimationFrame(()=>{x.current=0;const j=h.current;h.current=null,j!==null&&(f(j),le(j,document.documentElement,{context:g.current??void 0,live:!0}))}))},[f]);u.useEffect(()=>()=>cancelAnimationFrame(x.current),[]);const F=m=>{p.current=!1,g.current=null,cancelAnimationFrame(x.current),x.current=0,h.current=null,c(m)};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mt-2 flex items-baseline justify-between gap-2",children:[e.jsx("span",{className:"text-3xs text-fg-subtle",children:"Drag along the strip"}),e.jsx("span",{ref:d,className:"text-3xs font-medium text-fg-muted","aria-hidden":!0})]}),e.jsx("div",{ref:a,role:"slider",tabIndex:0,"aria-label":"Accent colour","aria-valuemin":0,"aria-valuemax":359,"aria-valuenow":n,"aria-valuetext":r?ne(n):"the theme’s own colour",onPointerDown:m=>{m.currentTarget.setPointerCapture(m.pointerId),p.current=!0,g.current=ve(),w(N(m.clientX))},onPointerMove:m=>{p.current&&w(N(m.clientX))},onPointerUp:m=>{p.current&&F(N(m.clientX))},onPointerCancel:()=>{p.current&&F(n)},onKeyDown:m=>{const j=m.key==="PageUp"||m.key==="PageDown"?15:m.shiftKey?10:2;let y=null;m.key==="ArrowLeft"||m.key==="ArrowDown"||m.key==="PageDown"?y=(n-j+360)%360:m.key==="ArrowRight"||m.key==="ArrowUp"||m.key==="PageUp"?y=(n+j)%360:m.key==="Home"?y=0:m.key==="End"&&(y=359),y!==null&&(m.preventDefault(),c(y))},style:{backgroundImage:l,touchAction:"none"},className:b("relative mt-1 h-8 cursor-pointer rounded-lg border border-edge shadow-xs select-none","focus-visible:focus-ring"),children:e.jsx("div",{ref:s,"aria-hidden":!0,style:{left:`${n/360*100}%`},className:b("pointer-events-none absolute top-1/2 h-[calc(100%+6px)] w-1.5 -translate-x-1/2 -translate-y-1/2 rounded-full","border border-fg bg-surface-raised shadow-sm",!r&&"opacity-0")})})]})}function Oe({className:t}){const[n,r]=u.useState(W),[c,a]=u.useState(null),s=typeof document<"u"&&document.documentElement.classList.contains("dark"),d=u.useRef(n),x=u.useCallback(l=>{const f={...d.current,...l};d.current=f,r(f),a(Z(f))},[]);u.useEffect(()=>{const l=f=>a(f.detail);return window.addEventListener(ee,l),a(Z(W())),()=>window.removeEventListener(ee,l)},[]);const h=u.useMemo(()=>pe(Ie),[n.theme,s,c==null?void 0:c.mode]),p=(c==null?void 0:c.hue)??0,g=n.hue!==null;return e.jsxs("div",{className:b("space-y-5",t),children:[e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Theme"}),e.jsx("div",{className:b("mt-2 grid gap-2","grid-cols-2 sm:grid-cols-4"),children:ae.map(l=>{const f=n.theme===l.id;return e.jsxs("button",{type:"button","aria-pressed":f,title:`${l.label} — ${l.blurb}`,onClick:()=>x({theme:l.id}),className:b("motion-fast rounded-xl border text-left transition-[border-color,box-shadow]","focus-visible:focus-ring","p-1.5",f?"border-accent-edge bg-accent-soft shadow-xs":"border-edge bg-surface-raised hover:border-edge-strong"),children:[e.jsx(Fe,{theme:l.id,dark:s,hue:n.hue,className:"h-10"}),e.jsxs("div",{className:"mt-1.5 min-w-0 px-0.5 pb-0.5",children:[e.jsx("span",{className:"block truncate text-xs font-semibold text-fg",children:l.label}),e.jsx("span",{className:"mt-0.5 line-clamp-2 text-3xs leading-snug text-fg-muted",children:l.blurb})]})]},l.id)})})]}),e.jsxs("div",{className:b("grid gap-5 lg:grid-cols-[minmax(0,1fr)_15rem] lg:items-start"),children:[e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Accent colour"}),e.jsx("p",{className:"mt-1 text-3xs leading-snug text-fg-subtle",children:"Pick any colour. The theme adjusts it so buttons and labels stay readable in both light and dark."}),e.jsx(Te,{hexes:h,hue:p,active:g,onCommit:l=>x({hue:l})}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-1",children:[e.jsx("button",{type:"button",onClick:()=>x({hue:null}),"aria-pressed":!g,className:b("motion-fast rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",g?"border-edge text-fg-muted hover:border-edge-strong hover:text-fg":"border-accent-edge bg-accent-soft text-accent"),children:"Theme’s own"}),ie.map(l=>{const f=g&&Math.abs(p-l.hue)<2.5;return e.jsxs("button",{type:"button","aria-pressed":f,onClick:()=>x({hue:l.hue}),className:b("motion-fast inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",f?"border-edge-strong bg-surface-active text-fg":"border-edge text-fg-muted hover:border-edge-strong hover:text-fg"),children:[e.jsx("span",{"aria-hidden":!0,className:"h-2.5 w-2.5 rounded-full",style:{backgroundColor:h[Math.round(l.hue/5)%h.length]}}),l.name]},l.name)})]})]}),e.jsxs("fieldset",{children:[e.jsx("legend",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Tint the background"}),e.jsx("p",{className:"mt-1 text-3xs leading-snug text-fg-subtle",children:"Colours the whole page a little, not just the buttons. Useful for telling two Paddock instances apart at a glance."}),e.jsx("div",{className:"mt-2 inline-flex rounded-lg border border-edge p-0.5",children:be.map(l=>e.jsx("button",{type:"button","aria-pressed":n.tint===l.level,onClick:()=>x({tint:l.level}),className:b("motion-fast rounded-md px-2.5 py-1 text-3xs transition-colors","focus-visible:focus-ring",n.tint===l.level?"bg-surface-active font-medium text-fg":"text-fg-muted hover:text-fg"),children:l.label},l.level))})]})]}),e.jsx(Le,{})]})}function Le(){return e.jsxs("div",{children:[e.jsx("p",{className:"text-2xs font-semibold uppercase tracking-wide text-fg-muted",children:"Preview"}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2 rounded-xl border border-edge bg-surface p-3",children:[e.jsx(A,{variant:"primary",size:"sm",children:"Send"}),e.jsx(A,{variant:"ghost",size:"sm",children:"Cancel"}),e.jsx(A,{variant:"link",size:"sm",children:"A link"}),e.jsx("span",{className:"inline-flex items-center gap-1 rounded-md border border-accent-edge bg-accent-soft px-1.5 py-0.5 text-2xs font-medium text-accent",children:"accent chip"}),e.jsx(ce,{tone:"accent",shape:"pill",dot:!0,children:"running"}),e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-2xs text-fg-subtle",children:[e.jsx("span",{className:"h-4 w-4 rounded-md border border-edge bg-accent-solid-hover","aria-hidden":!0}),"hovered"]}),e.jsxs("span",{className:"ml-auto inline-flex items-center gap-1.5",children:[e.jsx(L,{tone:"success"}),e.jsx(L,{tone:"warn"}),e.jsx(L,{tone:"danger"}),e.jsx(L,{tone:"info"}),e.jsx("span",{className:"text-2xs text-fg-subtle",children:"status hues (theme’s, not yours)"})]})]})]})}const _="mx-auto w-full max-w-4xl",De="sm:w-64";function Ve(){const[t,n]=u.useState(null),[r,c]=u.useState(!0),[a,s]=u.useState(null),[d,x]=u.useState({}),[h,p]=u.useState(!1),[g,l]=u.useState(null),[f,N]=u.useState(!1),[w,F]=u.useState(""),[m,j]=u.useState(!1),[y,$]=u.useState(null),K=u.useRef(null),de=ye("(min-width: 1024px)");u.useEffect(()=>{let i=!0;return c(!0),O.getInstanceConfig().then(o=>{i&&(n(o),s(null))}).catch(o=>i&&s(o instanceof Error?o.message:String(o))).finally(()=>i&&c(!1)),()=>{i=!1}},[]);const ue=(i,o)=>{N(!1),l(null),x(v=>({...v,[i]:o}))},me=i=>se(i,d),U=u.useMemo(()=>t?t.groups.flatMap(i=>i.fields):[],[t]),k=u.useMemo(()=>U.filter(i=>i.editable&&!i.envOverridden).filter(i=>Object.prototype.hasOwnProperty.call(d,i.key)).filter(i=>!re(d[i.key],q(i))).map(i=>i.key),[U,d]),X=u.useMemo(()=>new Set(k),[k]),C=u.useMemo(()=>{if(!t)return[];const i=w.trim().toLowerCase(),o=[];for(const v of t.groups){const P=i!==""&&v.label.toLowerCase().includes(i),I=v.fields.filter(E=>{const T=se(E,d);return m&&re(T,E.default)?!1:i===""||P?!0:Ye(E).includes(i)});I.length>0&&o.push({...v,fields:I})}return o},[t,w,m,d]),J=C.reduce((i,o)=>i+o.fields.length,0),xe=w.trim()!==""||m,H=!m&&(w.trim()===""||We.includes(w.trim().toLowerCase())),M=u.useMemo(()=>H?[V,...C]:C,[H,C]),he=C.some(i=>i.fields.some(o=>o.envOverridden)),Y=Qe(C,X);u.useEffect(()=>{const i=K.current;if(!i||M.length===0)return;const o=M.map(P=>P.id),v=()=>{const P=i.getBoundingClientRect().top;let I=o[0];for(const E of o){const T=document.getElementById(D(E));if(T)if(T.getBoundingClientRect().top-P<=80)I=E;else break}$(I)};return v(),i.addEventListener("scroll",v,{passive:!0}),()=>i.removeEventListener("scroll",v)},[M]);const Q=i=>{var v;const o=document.getElementById(D(i));(v=o==null?void 0:o.scrollIntoView)==null||v.call(o,{behavior:"smooth",block:"start"}),$(i)},fe=async()=>{if(k.length===0||!t)return;const i={};for(const o of k)i[o]=d[o];p(!0),l(null);try{await O.updateInstanceConfig(i,t.configVersion);const o=await O.getInstanceConfig();n(o),x({}),N(!0)}catch(o){if(o instanceof Ce&&o.status===409)try{n(await O.getInstanceConfig())}catch{}l(o instanceof Error?o.message:String(o))}finally{p(!1)}},ge=()=>{x({}),l(null),N(!1)};return e.jsxs("div",{className:"flex min-h-0 flex-1",children:[t&&e.jsx(Be,{groups:M,active:y,onJump:Q,dirtyCount:Y}),e.jsxs("div",{className:"flex min-h-0 min-w-0 flex-1 flex-col",children:[t&&e.jsx("div",{className:"border-b border-edge px-4 py-2.5 sm:px-6",children:e.jsxs("div",{className:_,children:[e.jsx(He,{query:w,onQuery:F,modifiedOnly:m,onModifiedOnly:j,visibleCount:J,totalCount:U.length,filtering:xe,autoFocus:de}),e.jsx(Ue,{groups:M,active:y,onJump:Q,dirtyCount:Y})]})}),e.jsx("div",{ref:K,className:"min-h-0 flex-1 overflow-y-auto px-4 py-5 sm:px-6",children:e.jsxs("div",{className:_,children:[H&&e.jsx("div",{className:"mb-8 border-b border-edge pb-7",children:e.jsx(te,{id:D(V.id),title:V.label,description:V.description,variant:"rule",first:!0,children:e.jsx(Oe,{})})}),e.jsx(ze,{saved:f,configPath:t==null?void 0:t.configPath,restartRequired:(t==null?void 0:t.restartRequired)??!1,fileError:t==null?void 0:t.configFileError}),r&&e.jsx("p",{className:"text-sm text-fg-muted",children:"Loading…"}),a&&e.jsxs("p",{className:"text-sm text-danger",role:"alert",children:["Failed to load settings: ",a]}),t&&he&&e.jsx(_e,{}),t&&J===0&&e.jsxs("p",{className:"py-8 text-center text-sm text-fg-muted",children:["No settings match"," ",w.trim()?e.jsxs(e.Fragment,{children:["“",e.jsx("span",{className:"font-medium",children:w.trim()}),"”"]}):"this filter","."]}),C.map(i=>e.jsx(te,{id:D(i.id),title:i.label,description:i.description,variant:"card",flush:!0,children:e.jsx("div",{className:"divide-y divide-edge-subtle",children:i.fields.map(o=>e.jsx(Ge,{field:o,value:me(o),dirty:X.has(o.key),onChange:v=>ue(o.key,v)},o.key))})},i.id))]})}),t&&e.jsx("footer",{className:"border-t border-edge px-4 py-3 sm:px-6",children:e.jsxs("div",{className:`${_} flex items-center gap-3`,children:[g&&e.jsxs("span",{className:"flex min-w-0 items-center gap-1.5 text-sm text-danger",role:"alert",children:[e.jsx(oe,{width:14,height:14,className:"shrink-0"}),e.jsx("span",{className:"truncate",children:g})]}),e.jsx("span",{className:"ml-auto shrink-0 text-xs tabular text-fg-subtle",children:k.length>0?`${k.length} unsaved change${k.length===1?"":"s"}`:"No changes"}),e.jsx(A,{variant:"subtle",onClick:ge,disabled:k.length===0||h,children:"Reset"}),e.jsx(A,{variant:"primary",onClick:fe,disabled:k.length===0,loading:h,loadingLabel:"Saving…",children:"Save changes"})]})})]})]})}function Be({groups:t,active:n,onJump:r,dirtyCount:c}){return e.jsx("nav",{"aria-label":"Config sections",className:"hidden w-52 shrink-0 overflow-y-auto border-r border-edge px-2 py-4 lg:block",children:e.jsx("ul",{className:"space-y-0.5",children:t.map(a=>{const s=a.id===n,d=c[a.id]??0;return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>r(a.id),"aria-current":s?"true":void 0,className:b("motion-fast flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm transition-colors",s?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[e.jsx("span",{className:"min-w-0 flex-1 truncate",children:a.label}),d>0&&e.jsx("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full bg-accent-solid","aria-label":`${d} unsaved`}),a.fields.length>0&&e.jsx("span",{className:"shrink-0 text-2xs tabular text-fg-subtle",children:a.fields.length})]})},a.id)})})})}function Ue({groups:t,active:n,onJump:r,dirtyCount:c}){return t.length===0?null:e.jsx("nav",{"aria-label":"Config sections",className:"-mx-1 mt-2 flex gap-1 overflow-x-auto px-1 pb-0.5 lg:hidden",children:t.map(a=>{const s=a.id===n,d=c[a.id]??0;return e.jsxs("button",{type:"button",onClick:()=>r(a.id),"aria-current":s?"true":void 0,className:b("motion-fast flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors",s?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[a.label,d>0&&e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent-solid","aria-label":`${d} unsaved`})]},a.id)})})}function He({query:t,onQuery:n,modifiedOnly:r,onModifiedOnly:c,visibleCount:a,totalCount:s,filtering:d,autoFocus:x}){return e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:"relative min-w-0 flex-1 sm:max-w-sm",children:[e.jsx(we,{width:14,height:14,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-fg-subtle"}),e.jsx(B,{type:"search","aria-label":"Search settings",placeholder:"Search settings, keys, env vars…",className:"h-8 py-0 pl-8 pr-7 [&::-webkit-search-cancel-button]:appearance-none",value:t,autoFocus:x,onChange:h=>n(h.target.value),onKeyDown:h=>{h.key==="Escape"&&t!==""&&(h.preventDefault(),n(""))}}),t!==""&&e.jsx("button",{type:"button","aria-label":"Clear search",onClick:()=>n(""),className:"absolute right-2 top-1/2 -translate-y-1/2 text-fg-subtle hover:text-fg",children:e.jsx(Ne,{width:13,height:13})})]}),e.jsx("button",{type:"button","aria-pressed":r,onClick:()=>c(!r),className:b("motion-fast shrink-0 rounded-md border px-2.5 py-1 text-xs transition-colors",r?"border-accent-edge bg-accent-soft text-accent":"border-edge text-fg-muted hover:text-fg"),children:"Modified only"}),e.jsx("span",{className:"shrink-0 text-xs tabular text-fg-subtle",children:d?`${a} of ${s}`:`${s} settings`})]})}function ze({saved:t,configPath:n,restartRequired:r,fileError:c}){const a=c?"danger":t?"success":"warn";return e.jsx(Re,{tone:a,className:"mb-5 leading-snug",icon:a==="success"?e.jsx(ke,{width:15,height:15}):e.jsx(oe,{width:15,height:15}),children:e.jsx("span",{role:"status",children:c?e.jsxs(e.Fragment,{children:[e.jsxs("strong",{children:["Could not read ",G(n),"."]})," ",c," — the values below are the running instance's; what a restart would load is unknown until the file parses."]}):t?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved to disk."})," These changes take effect only after the server restarts."]}):r?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Restart pending."})," ",e.jsx("code",{className:"font-mono text-xs",children:G(n)})," holds changes the running instance has not picked up — the fields below marked"," ",e.jsx(R,{tone:"warn",children:"restart"})," differ from what is in force right now."]}):e.jsxs(e.Fragment,{children:["Changes here are written to"," ",e.jsx("code",{className:"font-mono text-xs",children:G(n)})," and take effect only after the server restarts — the running instance keeps its current config until then."]})})})}function _e(){return e.jsxs("p",{className:"mb-5 text-xs leading-snug text-fg-muted",children:["Settings marked ",e.jsx(R,{tone:"neutral",children:"env"})," are overridden by an environment variable, which wins over this file — edit that variable (and restart) to change them."]})}function Ge({field:t,value:n,dirty:r,onChange:c}){const a=!t.editable||t.envOverridden,s=`cfg-${t.key}`,d=t.help?`${s}-help`:void 0,x=t.type==="boolean",h=u.useMemo(()=>Je(t,q(t)),[t]),p=x&&!a,g=!t.help&&!t.envOverridden&&!t.pendingRestart,l=g?"items-center":"items-start",f=g?"sm:items-center":"sm:items-start",N=a?e.jsx(Xe,{field:t,value:n}):x?e.jsx($e,{id:s,checked:!!n,onChange:c,label:t.label}):e.jsx(Ke,{field:t,value:n,onChange:c,inputId:s,describedBy:d});return e.jsxs("div",{className:"relative px-4 py-3",children:[r&&e.jsx("span",{"aria-hidden":!0,className:"absolute inset-y-2 left-0 w-0.5 rounded-full bg-accent-solid"}),e.jsxs("div",{className:b(h?"":p?`flex gap-4 ${l}`:`sm:flex sm:gap-6 ${f}`),children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("label",{htmlFor:a?void 0:s,className:"text-sm font-medium text-fg",children:t.label}),t.sensitive&&e.jsx(R,{tone:"warn",children:"sensitive"}),t.envOverridden&&e.jsx(R,{tone:"neutral",title:`Overridden by environment variable ${t.envVar} — edit that env var (and restart) to change it.`,children:"env"}),!t.editable&&!t.envOverridden&&e.jsx(R,{tone:"neutral",children:"read-only"}),t.pendingRestart&&e.jsx(R,{tone:"warn",title:"The config file and the running instance disagree on this field — restart to apply.",children:"restart"})]}),t.help&&e.jsx("p",{id:d,className:"mt-0.5 text-xs leading-snug text-fg-muted",children:t.help}),t.envOverridden&&e.jsx("p",{className:"mt-1 truncate font-mono text-2xs text-fg-subtle",children:t.envVar}),t.pendingRestart&&e.jsxs("p",{className:"mt-1 text-2xs leading-snug text-warn",children:["In force now: ",e.jsx("span",{className:"font-mono",children:qe(t.value)})]})]}),e.jsx("div",{className:b(h?"mt-2":p?"flex shrink-0 justify-end":`mt-2 sm:mt-0 sm:shrink-0 ${De}`),children:N})]})]})}function qe(t){if(t==null||t==="")return"(not set)";const r=(Array.isArray(t)?t.join(", "):String(t)).replace(/\s+/g," ").trim();return r.length>60?`${r.slice(0,60)}…`:r}function R({children:t,tone:n,title:r}){return e.jsx(ce,{tone:n,size:"sm",title:r,className:"uppercase tracking-wide",children:t})}function Ke({field:t,value:n,onChange:r,inputId:c,describedBy:a}){if(t.type==="enum")return e.jsx(Me,{id:c,"aria-describedby":a,value:String(n??""),onChange:s=>r(s.target.value),children:(t.enumValues??[]).map(s=>e.jsx("option",{value:s,children:s},s))});if(t.type==="number")return e.jsx(B,{id:c,type:"number","aria-describedby":a,className:"tabular",value:n==null?"":String(n),placeholder:t.default===null?"default":String(t.default),onChange:s=>r(s.target.value===""?null:Number(s.target.value))});if(t.type==="text"){const s=n==null||n===t.default,d=n==null?String(t.default??""):String(n),x=typeof t.default=="string"&&!s;return e.jsxs("div",{children:[e.jsx(Pe,{id:c,"aria-describedby":a,className:"min-h-[7rem] font-mono text-xs leading-relaxed",rows:6,spellCheck:!1,value:d,onChange:h=>r(h.target.value)}),e.jsxs("div",{className:"mt-1 flex items-center justify-between gap-3 text-xs text-fg-muted",children:[e.jsx("span",{children:s?"Using the built-in default.":n===""?"Empty — nothing will be appended.":`${d.length.toLocaleString()} characters.`}),x&&e.jsx(A,{variant:"link",size:"sm",className:"shrink-0",onClick:()=>r(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const s=Array.isArray(t.default)?t.default.map(String):null,d=Array.isArray(n)?n.map(String):null,x=d===null||s!==null&&d.length===s.length&&d.every((g,l)=>g===s[l]),h=d!==null?d.join(", "):(s==null?void 0:s.join(", "))??"",p=s!==null&&!x;return e.jsxs("div",{children:[e.jsx(B,{id:c,type:"text","aria-describedby":a,value:h,placeholder:(s==null?void 0:s.join(", "))??"",onChange:g=>r(g.target.value.split(",").map(l=>l.trim()).filter(Boolean))}),e.jsxs("div",{className:"mt-1 flex items-center justify-between gap-3 text-xs text-fg-muted",children:[e.jsx("span",{children:x?"Using the built-in default.":d!==null&&d.length===0?"Empty — none offered.":`${(d==null?void 0:d.length)??0} in the list.`}),p&&e.jsx(A,{variant:"link",size:"sm",className:"shrink-0",onClick:()=>r(null),children:"Restore default"})]})]})}return e.jsx(B,{id:c,type:"text","aria-describedby":a,value:n==null?"":String(n),placeholder:t.default===null?"":String(t.default),onChange:s=>r(s.target.value)})}function Xe({field:t,value:n}){const r="rounded-lg bg-surface-sunken px-3 py-2 font-mono text-xs text-fg-muted";return t.type==="boolean"?e.jsx("div",{className:r,children:n?"true":"false"}):n==null||n===""?e.jsx("div",{className:r,children:e.jsx("span",{className:"italic text-fg-subtle",children:t.type==="text"&&n===""?"(empty — nothing appended)":"(not set)"})}):t.type==="text"?e.jsx("div",{className:b(r,"max-h-40 overflow-y-auto whitespace-pre-wrap leading-relaxed"),children:String(n)}):e.jsx("div",{className:b(r,"break-all"),children:Array.isArray(n)?n.join(", "):String(n)})}function Je(t,n){return t.type==="text"||t.type==="string-list"?!0:(Array.isArray(n)?n.join(", "):n==null?"":String(n)).length>38}function Ye(t){return[t.label,t.key,t.help,t.envVar,...t.enumValues??[]].filter(Boolean).join(" ").toLowerCase()}function Qe(t,n){const r={};for(const c of t)r[c.id]=c.fields.filter(a=>n.has(a.key)).length;return r}const D=t=>`cfg-section-${t}`,V={id:"appearance",label:"Appearance",description:"Theme and accent colour for this browser. Applies immediately — no save, no restart.",fields:[]},We=["appearance theme themes colour color accent tint dark light font",...ae.map(t=>t.id)].join(" ");function q(t){return t.pendingValue===void 0?t.value:t.pendingValue}function se(t,n){return Object.prototype.hasOwnProperty.call(n,t.key)?n[t.key]:q(t)}function re(t,n){return Array.isArray(t)&&Array.isArray(n)?t.length===n.length&&t.every((r,c)=>r===n[c]):t===n}function G(t){if(!t)return"paddock.config.yaml";const n=t.split("/");return n[n.length-1]||t}function nt(){const t=Se(),n=(t==null?void 0:t.openNav)??(()=>{});return e.jsxs("div",{className:"flex h-full min-h-0 flex-col",children:[e.jsxs("header",{className:"pt-safe flex items-center gap-2 border-b border-edge px-3 pb-2.5 sm:px-6 lg:py-4",children:[e.jsx("button",{type:"button",onClick:n,"aria-label":"Open menu",className:"btn-subtle -ml-1 shrink-0 px-2 py-1.5 lg:hidden",children:e.jsx(Ae,{width:20,height:20})}),e.jsx(Ee,{width:18,height:18,className:"shrink-0 text-fg-subtle"}),e.jsx("h1",{className:"text-md font-semibold tracking-tight",children:"Config"})]}),e.jsx(Ve,{})]})}export{nt as InstanceConfigPage};
2
+