@edspencer/paddock 0.68.1 → 0.70.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.
- package/package.json +1 -1
- package/packages/server/dist/agent-errors.js +7 -1
- package/packages/server/dist/background-live.d.ts +124 -0
- package/packages/server/dist/background-live.js +226 -0
- package/packages/server/dist/cli/paddock.js +12 -7
- package/packages/server/dist/config.d.ts +7 -5
- package/packages/server/dist/config.js +0 -1
- package/packages/server/dist/instance-config.js +1 -2
- package/packages/server/dist/recovery-config.d.ts +0 -6
- package/packages/server/dist/recovery-config.js +0 -4
- package/packages/server/dist/ws-protocol.d.ts +61 -1
- package/packages/server/dist/ws-turn.d.ts +2 -0
- package/packages/server/dist/ws-turn.js +17 -1
- package/packages/server/dist/ws.js +72 -13
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/{Chip-NMeHUE94.js → Chip-C8a-t439.js} +1 -1
- package/packages/web/dist/assets/DiscoverPage-C1khyCvD.js +2 -0
- package/packages/web/dist/assets/{DiscoverView-Bt4FUTjB.js → DiscoverView-DS_Z9xKH.js} +1 -1
- package/packages/web/dist/assets/{InstanceConfigPage-DIQJtIYC.js → InstanceConfigPage-B1ei1FDo.js} +1 -1
- package/packages/web/dist/assets/{MarkdownRenderer-BVMZB_mP.js → MarkdownRenderer-DCj_ZwVG.js} +1 -1
- package/packages/web/dist/assets/{ProjectMenu-D9Nsqjxy.js → ProjectMenu-B7dGZSFB.js} +1 -1
- package/packages/web/dist/assets/{ProjectRedirect-B8rJ9qqe.js → ProjectRedirect-bstvMvM9.js} +1 -1
- package/packages/web/dist/assets/ProjectView-iuiUIoIl.js +13 -0
- package/packages/web/dist/assets/{ProjectsGrid-CDqvd4bj.js → ProjectsGrid-DKvySDUQ.js} +1 -1
- package/packages/web/dist/assets/{RootHome-CmiJG9wb.js → RootHome-CD_37qb-.js} +1 -1
- package/packages/web/dist/assets/{Surfaces-c410wTbw.js → Surfaces-1dBayrsj.js} +1 -1
- package/packages/web/dist/assets/{arc-DN2jEPE9.js → arc-BJPb3ViJ.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-BLMFd81z.js → architectureDiagram-3BPJPVTR-PkLOC5wV.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-BweEECqE.js → blockDiagram-GPEHLZMM-IPduhNH-.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-DpN_9YFO.js → c4Diagram-AAUBKEIU-dKTYV1Vq.js} +1 -1
- package/packages/web/dist/assets/channel-BhrgMiqg.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-BxWEBoli.js → chunk-2J33WTMH-B5C6geyg.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-C5nkcPRR.js → chunk-4BX2VUAB-1BRhFRhF.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-B8P3CNX8.js → chunk-55IACEB6-DNv-sTiI.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-D3yuzl-m.js → chunk-727SXJPM-CWezuVkx.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-CzWxcEIw.js → chunk-AQP2D5EJ-Bt4yEQnu.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-CCB91otB.js → chunk-FMBD7UC4-lb_8q4JY.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-BymMfuY4.js → chunk-ND2GUHAM-DOwgGlQ_.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-CezHuNcf.js → chunk-QZHKN3VN-BanKpY4q.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-Ho1IMdjg.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-Ho1IMdjg.js +2 -0
- package/packages/web/dist/assets/{core-LjceHm3Z.js → core-CAsyoNAa.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-BWhmWR_V.js → cose-bilkent-S5V4N54A-sVaVkwMI.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-BTXWnJYV.js → dagre-BM42HDAG-C9pKHSMo.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-BY2LZdf0.js → diagram-2AECGRRQ-CHdrmCfX.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-BZ78Imy8.js → diagram-5GNKFQAL-4UTa2Dfa.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-BV4Ax_0D.js → diagram-KO2AKTUF-NidpfVwW.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-1kcTal-d.js → diagram-LMA3HP47-ictQj03T.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-CX3RfHlO.js → diagram-OG6HWLK6-B7dTLMHC.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-BBS46D95.js → erDiagram-TEJ5UH35-C2QYYzJ8.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-CpPHahLZ.js → flowDiagram-I6XJVG4X-D2rcjSZ9.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-CxL_QCuL.js → ganttDiagram-6RSMTGT7-BQcXTYzg.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-BeTkPHaG.js → gitGraphDiagram-PVQCEYII-DwB2Vqxa.js} +1 -1
- package/packages/web/dist/assets/index-BNzTD4hA.css +1 -0
- package/packages/web/dist/assets/{index-DjhUG9sA.js → index-BeuEs7dL.js} +14 -14
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-CiMnl36I.js → infoDiagram-5YYISTIA-BoK4Mawg.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-CjASKQeF.js → ishikawaDiagram-YF4QCWOH-DPP9svhg.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-BZzehSqh.js → journeyDiagram-JHISSGLW-TrggodYk.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-Cn-l0UIy.js → kanban-definition-UN3LZRKU-Bh69hRSR.js} +1 -1
- package/packages/web/dist/assets/{linear-DyELsH8s.js → linear-C1iYMpBz.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-C1adXzqy.js → mermaid.core-BZDABcuq.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-DP6iSaA_.js → mindmap-definition-RKZ34NQL-DTJON3dS.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-DHpN8Fse.js → pieDiagram-4H26LBE5-BxtFV74I.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-DAfc21Kd.js → quadrantDiagram-W4KKPZXB-D2Ar8kmO.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-X3FfIiGh.js → requirementDiagram-4Y6WPE33-DiLSfeSQ.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-Ch319LBM.js → sankeyDiagram-5OEKKPKP-D_CRQc7j.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-CAyajDJc.js → sequenceDiagram-3UESZ5HK-DjtfcRNV.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-C1G4309_.js → stateDiagram-AJRCARHV-CzEtmYLV.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-pM8fIOir.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-Bj5ihSj4.js → timeline-definition-PNZ67QCA-DXKspEG3.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-WIZuVHvV.js → vennDiagram-CIIHVFJN-B_tXRMHH.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-CwRQf2fI.js → wardley-L42UT6IY-DNaNoaJm.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-Bug_Zcav.js → wardleyDiagram-YWT4CUSO-BuVDpC8s.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-Cw5xgfwo.js → xychartDiagram-2RQKCTM6-Cqtew2PA.js} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/sw.js +1 -1
- package/packages/web/dist/assets/DiscoverPage-LY0CRBVz.js +0 -2
- package/packages/web/dist/assets/ProjectView-D-21ULHU.js +0 -13
- package/packages/web/dist/assets/channel-B_SiD-tA.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-Detq0lSJ.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-Detq0lSJ.js +0 -2
- package/packages/web/dist/assets/index-DYccdR9x.css +0 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-C0-BEM28.js +0 -2
|
@@ -57,6 +57,7 @@ import { keeperAgentName, keeperSlugFromAgent, } from "./herdctl.js";
|
|
|
57
57
|
import { consumeResumedTurn } from "./resume-drain.js";
|
|
58
58
|
import { isKnownModel, getContextLimit, DEFAULT_MODEL, isKnownDriveMode, } from "./models.js";
|
|
59
59
|
import { SessionHub } from "./session-hub.js";
|
|
60
|
+
import { BackgroundRegistry } from "./background-live.js";
|
|
60
61
|
import { hasQueuedContent, partsOf, } from "./queued-message.js";
|
|
61
62
|
import { resolveAttachmentsConfig } from "./attachments-config.js";
|
|
62
63
|
import { wrapAttachments, inferAttachmentKind } from "./attachments-hint.js";
|
|
@@ -208,18 +209,13 @@ export function makeChatHandler(deps) {
|
|
|
208
209
|
// broadcast to all clients — powering the per-chat sidebar streaming dots that
|
|
209
210
|
// must update even for chats whose pane isn't mounted (issue #53).
|
|
210
211
|
const clients = new Set();
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
startedAt: info.startedAt,
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
hub.onActive = (info) => {
|
|
222
|
-
const data = JSON.stringify(activeFrame(info));
|
|
212
|
+
/**
|
|
213
|
+
* Live background work per session (#604). Owned here because this is the
|
|
214
|
+
* layer that can broadcast; fed by the turn engine from both message lanes.
|
|
215
|
+
*/
|
|
216
|
+
const background = new BackgroundRegistry();
|
|
217
|
+
const broadcast = (frame) => {
|
|
218
|
+
const data = JSON.stringify(frame);
|
|
223
219
|
for (const c of clients) {
|
|
224
220
|
if (c.readyState === c.OPEN) {
|
|
225
221
|
try {
|
|
@@ -231,6 +227,57 @@ export function makeChatHandler(deps) {
|
|
|
231
227
|
}
|
|
232
228
|
}
|
|
233
229
|
};
|
|
230
|
+
/**
|
|
231
|
+
* #604: a session is busy while it holds background work, even though the
|
|
232
|
+
* turn that launched it has returned. `SessionHub` tracks one turn and cannot
|
|
233
|
+
* know this, so the join happens here — the only place that sees both. Every
|
|
234
|
+
* consumer of `chat:active.running` (sidebar dots, the Home in-flight badge,
|
|
235
|
+
* the running-only filter, the client's own `streaming` gate) then reads the
|
|
236
|
+
* truth instead of "the primary turn ended".
|
|
237
|
+
*/
|
|
238
|
+
const activeFrame = (info) => ({
|
|
239
|
+
type: "chat:active",
|
|
240
|
+
payload: {
|
|
241
|
+
projectSlug: info.projectSlug,
|
|
242
|
+
sessionId: info.sessionId,
|
|
243
|
+
jobId: info.jobId,
|
|
244
|
+
running: info.running || background.isBusy(info.sessionId),
|
|
245
|
+
startedAt: info.startedAt,
|
|
246
|
+
turnRunning: info.running,
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
/**
|
|
250
|
+
* Last `running` we published per session, so a background-set change only
|
|
251
|
+
* re-emits `chat:active` when it actually flips the answer. Without this every
|
|
252
|
+
* task start/stop would broadcast a redundant frame to every socket.
|
|
253
|
+
*/
|
|
254
|
+
const lastPublishedRunning = new Map();
|
|
255
|
+
hub.onActive = (info) => {
|
|
256
|
+
const frame = activeFrame(info);
|
|
257
|
+
lastPublishedRunning.set(info.sessionId, frame.payload.running);
|
|
258
|
+
broadcast(frame);
|
|
259
|
+
};
|
|
260
|
+
background.onChange = (projectSlug, sessionId, tasks) => {
|
|
261
|
+
broadcast({ type: "chat:background", payload: { projectSlug, sessionId, tasks } });
|
|
262
|
+
// The set changing can flip a session between idle and busy while the hub's
|
|
263
|
+
// own turn state is unchanged — that transition is exactly #604.
|
|
264
|
+
const info = hub.activeInfo(sessionId);
|
|
265
|
+
const running = (info?.running ?? false) || tasks.length > 0;
|
|
266
|
+
if (lastPublishedRunning.get(sessionId) === running)
|
|
267
|
+
return;
|
|
268
|
+
lastPublishedRunning.set(sessionId, running);
|
|
269
|
+
broadcast({
|
|
270
|
+
type: "chat:active",
|
|
271
|
+
payload: {
|
|
272
|
+
projectSlug,
|
|
273
|
+
sessionId,
|
|
274
|
+
jobId: info?.jobId ?? null,
|
|
275
|
+
running,
|
|
276
|
+
startedAt: info?.startedAt,
|
|
277
|
+
turnRunning: info?.running ?? false,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
};
|
|
234
281
|
// Drive scheduler-fired session wakes onto the hub (Paddock#111 gap 3). When a
|
|
235
282
|
// keeper scheduled a `ScheduleWakeup` / `/loop`, herdctl reaps the idle session
|
|
236
283
|
// and later resumes it at fire time, handing us the live (managed) session with
|
|
@@ -332,6 +379,8 @@ export function makeChatHandler(deps) {
|
|
|
332
379
|
};
|
|
333
380
|
const onWakeMessage = async (m) => {
|
|
334
381
|
// A sub-agent's nested steps never render top-level ({@link isSidechainMessage}).
|
|
382
|
+
// #604: task lifecycle is session-level — observe before the filter.
|
|
383
|
+
background.observe(slug, m);
|
|
335
384
|
if (isSidechainMessage(m))
|
|
336
385
|
return;
|
|
337
386
|
if (messageProducedReply(m))
|
|
@@ -395,7 +444,7 @@ export function makeChatHandler(deps) {
|
|
|
395
444
|
// wake cache, the shared startAgentTurn engine, and Layer-2/3 recovery. Relocated
|
|
396
445
|
// as one scope so its cross-references stay intact; the socket layer below
|
|
397
446
|
// consumes the returned surface.
|
|
398
|
-
const engine = makeTurnEngine({ deps, hub });
|
|
447
|
+
const engine = makeTurnEngine({ deps, hub, background });
|
|
399
448
|
const { startAgentTurn, wakeInjection, selfMcpCtx, injectRecoveryNudge, recoveryEngine, emitAfterTurn, composePreloadedPrompt, fireTrigger, makeBackgroundTurnSink, } = engine;
|
|
400
449
|
/**
|
|
401
450
|
* Build the chat operations for ONE connection: the handlers behind every
|
|
@@ -942,6 +991,9 @@ export function makeChatHandler(deps) {
|
|
|
942
991
|
// human `chat:send` path, so it is where the duplication was actually
|
|
943
992
|
// seen. Skipping also keeps a sub-agent's context out of the parent's
|
|
944
993
|
// live meter (`foldTurnUsage` below would latch its max — the #398 shape).
|
|
994
|
+
// #604: task lifecycle is session-level, not rendered transcript —
|
|
995
|
+
// observe it before the sidechain filter.
|
|
996
|
+
background.observe(slug, m);
|
|
945
997
|
if (isSidechainMessage(m))
|
|
946
998
|
return;
|
|
947
999
|
// Capture the session id as it arrives mid-stream (the translator
|
|
@@ -1182,6 +1234,9 @@ export function makeChatHandler(deps) {
|
|
|
1182
1234
|
onMessage: async (m) => {
|
|
1183
1235
|
// A slash-command turn can spawn a Task too; its nested steps never
|
|
1184
1236
|
// render top-level ({@link isSidechainMessage}).
|
|
1237
|
+
// #604: task lifecycle is session-level, not rendered transcript —
|
|
1238
|
+
// observe it before the sidechain filter.
|
|
1239
|
+
background.observe(slug, m);
|
|
1185
1240
|
if (isSidechainMessage(m))
|
|
1186
1241
|
return;
|
|
1187
1242
|
if (m.session_id) {
|
|
@@ -1384,6 +1439,10 @@ export function makeChatHandler(deps) {
|
|
|
1384
1439
|
clients.add(socket);
|
|
1385
1440
|
for (const info of hub.runningSessions())
|
|
1386
1441
|
send(activeFrame(info));
|
|
1442
|
+
// #604: and on what background work is in flight, so a remounted pane's
|
|
1443
|
+
// pinned bar is populated from the first paint rather than after a poll.
|
|
1444
|
+
for (const s of background.snapshot())
|
|
1445
|
+
send({ type: "chat:background", payload: { ...s } });
|
|
1387
1446
|
// Heartbeat: browsers auto-answer protocol ping frames with a pong, so a
|
|
1388
1447
|
// client whose TCP has silently died (idle drop, sleep) fails to pong and is
|
|
1389
1448
|
// terminated on the next tick — freeing server resources and letting the
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as r,l as t,r as d}from"./index-
|
|
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};
|
|
2
2
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as ne,u as re,H as ae,r as l,b as P,j as s,M as oe,E as ie,D as Q,J as U,K as ce,l as F,O as de,h as le}from"./index-DjhUG9sA.js";import{E as O,B as R,C as he}from"./Surfaces-c410wTbw.js";import{a as W,d as M,C as T,T as K}from"./Chip-NMeHUE94.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]??z(),a),0)}function xe(e,t){return t.filter(r=>C(e[r.path]??z(),r)>0)}function fe(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(d=>d.sessionId)):new Set),{...e,[t]:n}}function ge(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(d=>d.sessionId)):new Set;return{...e,[t]:{...a,sessions:r,selected:n,loading:!1,error:null}}}function D(e,t,r){const a=e[t];return a?{...e,[t]:{...a,...r}}:e}function be(e,t){const r=e??z();return C(r,t)===0?null:r.sessions&&r.selected?{sessionIds:[...r.selected]}:{}}function z(){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 d=await we(e,n.candidate,n.plan);a.push(d),r(n.candidate.path,"done",d)}return a}const ve={sidechain:"sub-agent transcript","already-adopted":"already imported","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),d=`Imported ${a} chat${a===1?"":"s"} into “${r}”`;return n?`${d} — ${n}.`:`${d}.`}function V(e){return e instanceof Error?e.message:String(e)}function ze({firstRun:e=!1,onLeave:t}){const r=ne(),{refresh:a}=re(),n=ae(),[d,h]=l.useState(!1),[m,c]=l.useState(!1),[x,$]=l.useState(null),[g,u]=l.useState(null),[v,I]=l.useState(!0),[j,w]=l.useState({}),[k,A]=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),P.discover({includeNonGit:d,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}},[d,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 f=p[o.path];if(!f)return p;const N=D(p,o.path,{expanded:!f.expanded});return f.expanded||f.sessions||f.loading?N:D(N,o.path,{loading:!0,error:null})});const i=j[o.path];!i||i.expanded||i.sessions||i.loading||P.discoverSessions(o.path).then(p=>w(f=>je(f,o.path,p))).catch(p=>w(f=>D(f,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;A(!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(P,o,(i,p,f)=>{H(N=>({...N,[i]:p})),f&&B(N=>({...N,[i]:f}))}),A(!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. Importing one links it as a project and copies its conversations in; your own history is never moved or deleted."}),S&&s.jsx(Ie,{imported:se,projects:te,onGetStarted:ee}),g!==null&&s.jsx(W,{tone:"danger",icon:s.jsx(Q,{width:16,height:16}),children:g}),v&&s.jsx(Ee,{}),!v&&g===null&&x!==null&&s.jsxs(s.Fragment,{children:[x.scanned===0?s.jsx($e,{claudeHome:x.claudeHome}):y.length===0?s.jsx(O,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:"Nothing left to import",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=>fe(p,o.path,i)),onToggleSession:i=>w(p=>ge(p,o.path,i)),onToggleExpanded:()=>Z(o)},o.path))}),!S&&s.jsx(Ce,{result:x,includeNonGit:d,includeOutsideHome:m,disabled:k,onIncludeNonGit:h,onIncludeOutsideHome:c}),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(R,{variant:"primary",onClick:()=>void L(),disabled:b.length===0,loading:k,loadingLabel:"Importing…",children:["Import ",b.length," project",b.length===1?"":"s"]})]})]})]})})]})}function Se({candidate:e,row:t,status:r,outcome:a,locked:n,onToggleRow:d,onToggleSession:h,onToggleExpanded:m}){const c=t??{checked:!1,expanded:!1,loading:!1,error:null},x=pe(c),$=C(c,e),g=a?ye(a):null;return s.jsx("li",{children:s.jsxs(he,{flush:!0,className:F("overflow-hidden",g==="success"&&"border-success-edge bg-success-soft",g==="warn"&&"border-warn-edge bg-warn-soft",g==="danger"&&"border-danger-edge bg-danger-soft",r==="running"&&"border-accent-edge"),"data-testid":`discover-row-${e.suggestedSlug}`,"data-tone":g??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":`Import ${e.path}`,onChange:u=>d(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(T,{tone:"lineage",size:"sm",children:e.gitRemote}),!e.hasGit&&s.jsx(T,{tone:"neutral",size:"sm",children:"no git"}),!e.insideHome&&s.jsx(T,{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",g==="success"&&"text-success",g==="warn"&&"text-warn",g==="danger"&&"text-danger"),children:ke(a,e)}),r==="running"&&!a&&s.jsx("p",{className:"mt-2 text-xs text-fg-muted",children:"Importing…"})]}),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(R,{size:"icon-sm",variant:"subtle","aria-label":c.expanded?"Hide conversations":"Show conversations","aria-expanded":c.expanded,onClick:m,children:c.expanded?s.jsx(de,{width:14,height:14}):s.jsx(le,{width:14,height:14})})]})]}),c.expanded&&s.jsxs("div",{className:"border-t border-edge px-3 py-2",children:[c.loading&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Reading transcripts…"}),c.error!==null&&s.jsx("p",{className:"py-2 text-xs text-danger",children:c.error}),c.sessions&&c.sessions.sessions.length===0&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Nothing importable here any more — it may have been imported since the scan."}),c.sessions&&c.sessions.sessions.length>0&&s.jsx("ul",{className:"space-y-1",children:c.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=c.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)," · ",Te(u.sizeBytes)]})]})]})},u.sessionId)})}),c.sessions&&c.sessions.filtered.length>0&&s.jsxs("p",{className:"mt-2 px-2 text-3xs text-fg-subtle",children:[c.sessions.filtered.length," more withheld as noise (",[...new Set(c.sessions.filtered.map(u=>u.reason))].join(", "),")."]})]})]})})}function Ce({result:e,includeNonGit:t,includeOutsideHome:r,disabled:a,onIncludeNonGit:n,onIncludeOutsideHome:d}){const h=e.excluded["no-git"]??0,m=e.excluded["outside-home"]??0,c=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:Pe(e)}),c&&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:d,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(O,{variant:"panel",icon:s.jsx(ce,{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(O,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:t===0?"Nothing was imported":`${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(R,{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 Pe(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 importable`],["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,d]of r){const h=e.excluded[n];h!==void 0&&h>0&&t.push(d(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 Te(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} kB`:`${(e/(1024*1024)).toFixed(1)} MB`}export{ze as D};
|
|
1
|
+
import{a as ne,u as re,H as ae,r as l,b as P,j as s,M as oe,E as ie,D as Q,J as U,K as ce,l as F,O as de,h as le}from"./index-BeuEs7dL.js";import{E as O,B as R,C as he}from"./Surfaces-1dBayrsj.js";import{a as W,d as M,C as T,T as K}from"./Chip-C8a-t439.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]??z(),a),0)}function xe(e,t){return t.filter(r=>C(e[r.path]??z(),r)>0)}function fe(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(d=>d.sessionId)):new Set),{...e,[t]:n}}function ge(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(d=>d.sessionId)):new Set;return{...e,[t]:{...a,sessions:r,selected:n,loading:!1,error:null}}}function D(e,t,r){const a=e[t];return a?{...e,[t]:{...a,...r}}:e}function be(e,t){const r=e??z();return C(r,t)===0?null:r.sessions&&r.selected?{sessionIds:[...r.selected]}:{}}function z(){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 d=await we(e,n.candidate,n.plan);a.push(d),r(n.candidate.path,"done",d)}return a}const ve={sidechain:"sub-agent transcript","already-adopted":"already imported","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),d=`Imported ${a} chat${a===1?"":"s"} into “${r}”`;return n?`${d} — ${n}.`:`${d}.`}function V(e){return e instanceof Error?e.message:String(e)}function ze({firstRun:e=!1,onLeave:t}){const r=ne(),{refresh:a}=re(),n=ae(),[d,h]=l.useState(!1),[m,c]=l.useState(!1),[x,$]=l.useState(null),[g,u]=l.useState(null),[v,I]=l.useState(!0),[j,w]=l.useState({}),[k,A]=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),P.discover({includeNonGit:d,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}},[d,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 f=p[o.path];if(!f)return p;const N=D(p,o.path,{expanded:!f.expanded});return f.expanded||f.sessions||f.loading?N:D(N,o.path,{loading:!0,error:null})});const i=j[o.path];!i||i.expanded||i.sessions||i.loading||P.discoverSessions(o.path).then(p=>w(f=>je(f,o.path,p))).catch(p=>w(f=>D(f,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;A(!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(P,o,(i,p,f)=>{H(N=>({...N,[i]:p})),f&&B(N=>({...N,[i]:f}))}),A(!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. Importing one links it as a project and copies its conversations in; your own history is never moved or deleted."}),S&&s.jsx(Ie,{imported:se,projects:te,onGetStarted:ee}),g!==null&&s.jsx(W,{tone:"danger",icon:s.jsx(Q,{width:16,height:16}),children:g}),v&&s.jsx(Ee,{}),!v&&g===null&&x!==null&&s.jsxs(s.Fragment,{children:[x.scanned===0?s.jsx($e,{claudeHome:x.claudeHome}):y.length===0?s.jsx(O,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:"Nothing left to import",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=>fe(p,o.path,i)),onToggleSession:i=>w(p=>ge(p,o.path,i)),onToggleExpanded:()=>Z(o)},o.path))}),!S&&s.jsx(Ce,{result:x,includeNonGit:d,includeOutsideHome:m,disabled:k,onIncludeNonGit:h,onIncludeOutsideHome:c}),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(R,{variant:"primary",onClick:()=>void L(),disabled:b.length===0,loading:k,loadingLabel:"Importing…",children:["Import ",b.length," project",b.length===1?"":"s"]})]})]})]})})]})}function Se({candidate:e,row:t,status:r,outcome:a,locked:n,onToggleRow:d,onToggleSession:h,onToggleExpanded:m}){const c=t??{checked:!1,expanded:!1,loading:!1,error:null},x=pe(c),$=C(c,e),g=a?ye(a):null;return s.jsx("li",{children:s.jsxs(he,{flush:!0,className:F("overflow-hidden",g==="success"&&"border-success-edge bg-success-soft",g==="warn"&&"border-warn-edge bg-warn-soft",g==="danger"&&"border-danger-edge bg-danger-soft",r==="running"&&"border-accent-edge"),"data-testid":`discover-row-${e.suggestedSlug}`,"data-tone":g??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":`Import ${e.path}`,onChange:u=>d(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(T,{tone:"lineage",size:"sm",children:e.gitRemote}),!e.hasGit&&s.jsx(T,{tone:"neutral",size:"sm",children:"no git"}),!e.insideHome&&s.jsx(T,{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",g==="success"&&"text-success",g==="warn"&&"text-warn",g==="danger"&&"text-danger"),children:ke(a,e)}),r==="running"&&!a&&s.jsx("p",{className:"mt-2 text-xs text-fg-muted",children:"Importing…"})]}),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(R,{size:"icon-sm",variant:"subtle","aria-label":c.expanded?"Hide conversations":"Show conversations","aria-expanded":c.expanded,onClick:m,children:c.expanded?s.jsx(de,{width:14,height:14}):s.jsx(le,{width:14,height:14})})]})]}),c.expanded&&s.jsxs("div",{className:"border-t border-edge px-3 py-2",children:[c.loading&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Reading transcripts…"}),c.error!==null&&s.jsx("p",{className:"py-2 text-xs text-danger",children:c.error}),c.sessions&&c.sessions.sessions.length===0&&s.jsx("p",{className:"py-2 text-xs text-fg-muted",children:"Nothing importable here any more — it may have been imported since the scan."}),c.sessions&&c.sessions.sessions.length>0&&s.jsx("ul",{className:"space-y-1",children:c.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=c.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)," · ",Te(u.sizeBytes)]})]})]})},u.sessionId)})}),c.sessions&&c.sessions.filtered.length>0&&s.jsxs("p",{className:"mt-2 px-2 text-3xs text-fg-subtle",children:[c.sessions.filtered.length," more withheld as noise (",[...new Set(c.sessions.filtered.map(u=>u.reason))].join(", "),")."]})]})]})})}function Ce({result:e,includeNonGit:t,includeOutsideHome:r,disabled:a,onIncludeNonGit:n,onIncludeOutsideHome:d}){const h=e.excluded["no-git"]??0,m=e.excluded["outside-home"]??0,c=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:Pe(e)}),c&&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:d,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(O,{variant:"panel",icon:s.jsx(ce,{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(O,{variant:"panel",icon:s.jsx(U,{width:22,height:22}),title:t===0?"Nothing was imported":`${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(R,{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 Pe(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 importable`],["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,d]of r){const h=e.excluded[n];h!==void 0&&h>0&&t.push(d(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 Te(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} kB`:`${(e/(1024*1024)).toFixed(1)} MB`}export{ze as D};
|
|
2
2
|
|
package/packages/web/dist/assets/{InstanceConfigPage-DIQJtIYC.js → InstanceConfigPage-B1ei1FDo.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as c,n as W,s as Z,A as ee,p as pe,j as e,q as ae,l as g,t as ie,v as be,w as je,x as le,y as ve,z as ye,b as L,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-DjhUG9sA.js";import{B as R,S as te}from"./Surfaces-c410wTbw.js";import{C as ce,S as O,I as B,a as Re,T as Me,b as $e,c as Pe}from"./Chip-NMeHUE94.js";const Ie=Array.from({length:72},(t,n)=>n*5),S=[...ie].sort((t,n)=>t.hue-n.hue),_=(t,n)=>Math.min(Math.abs(t-n),360-Math.abs(t-n));function ne(t){const n=S.reduce((r,a)=>_(a.hue,t)<_(r.hue,t)?a:r);if(_(n.hue,t)<=8)return n.name;const s=S.find(r=>r.hue>t)??S[0];return`between ${S[(S.indexOf(s)-1+S.length)%S.length].name} and ${s.name}`}function Fe({theme:t,dark:n,hue:s,className:o}){const r=c.useRef(null);return c.useLayoutEffect(()=>{const a=r.current;a&&(s===null?je(a):le(s,a))},[t,n,s]),e.jsx("div",{ref:r,"data-theme":t,className:g("overflow-hidden rounded-lg border border-edge",n&&"dark",o),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:s,onCommit:o}){const r=c.useRef(null),a=c.useRef(null),m=c.useRef(null),x=c.useRef(0),h=c.useRef(null),p=c.useRef(!1),j=c.useRef(null),u=c.useMemo(()=>{if(t.length===0)return;const d=t.map((b,y)=>`${b} ${(y/t.length*100).toFixed(2)}%`);return d.push(`${t[0]} 100%`),`linear-gradient(to right, ${d.join(", ")})`},[t]),f=c.useCallback(d=>{a.current&&(a.current.style.left=`${d/360*100}%`),m.current&&(m.current.textContent=ne(d))},[]);c.useEffect(()=>{p.current||f(n)},[n,f]);const N=d=>{var M;const b=(M=r.current)==null?void 0:M.getBoundingClientRect();if(!b||b.width===0)return 0;const y=Math.min(1,Math.max(0,(d-b.left)/b.width));return Math.round(y*360)%360},w=c.useCallback(d=>{h.current=d,!x.current&&(x.current=requestAnimationFrame(()=>{x.current=0;const b=h.current;h.current=null,b!==null&&(f(b),le(b,document.documentElement,{context:j.current??void 0,live:!0}))}))},[f]);c.useEffect(()=>()=>cancelAnimationFrame(x.current),[]);const F=d=>{p.current=!1,j.current=null,cancelAnimationFrame(x.current),x.current=0,h.current=null,o(d)};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:m,className:"text-3xs font-medium text-fg-muted","aria-hidden":!0})]}),e.jsx("div",{ref:r,role:"slider",tabIndex:0,"aria-label":"Accent colour","aria-valuemin":0,"aria-valuemax":359,"aria-valuenow":n,"aria-valuetext":s?ne(n):"the theme’s own colour",onPointerDown:d=>{d.currentTarget.setPointerCapture(d.pointerId),p.current=!0,j.current=ve(),w(N(d.clientX))},onPointerMove:d=>{p.current&&w(N(d.clientX))},onPointerUp:d=>{p.current&&F(N(d.clientX))},onPointerCancel:()=>{p.current&&F(n)},onKeyDown:d=>{const b=d.key==="PageUp"||d.key==="PageDown"?15:d.shiftKey?10:2;let y=null;d.key==="ArrowLeft"||d.key==="ArrowDown"||d.key==="PageDown"?y=(n-b+360)%360:d.key==="ArrowRight"||d.key==="ArrowUp"||d.key==="PageUp"?y=(n+b)%360:d.key==="Home"?y=0:d.key==="End"&&(y=359),y!==null&&(d.preventDefault(),o(y))},style:{backgroundImage:u,touchAction:"none"},className:g("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:a,"aria-hidden":!0,style:{left:`${n/360*100}%`},className:g("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",!s&&"opacity-0")})})]})}function Le({className:t}){const[n,s]=c.useState(W),[o,r]=c.useState(null),a=typeof document<"u"&&document.documentElement.classList.contains("dark"),m=c.useRef(n),x=c.useCallback(u=>{const f={...m.current,...u};m.current=f,s(f),r(Z(f))},[]);c.useEffect(()=>{const u=f=>r(f.detail);return window.addEventListener(ee,u),r(Z(W())),()=>window.removeEventListener(ee,u)},[]);const h=c.useMemo(()=>pe(Ie),[n.theme,a,o==null?void 0:o.mode]),p=(o==null?void 0:o.hue)??0,j=n.hue!==null;return e.jsxs("div",{className:g("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:g("mt-2 grid gap-2","grid-cols-2 sm:grid-cols-4"),children:ae.map(u=>{const f=n.theme===u.id;return e.jsxs("button",{type:"button","aria-pressed":f,title:`${u.label} — ${u.blurb}`,onClick:()=>x({theme:u.id}),className:g("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:u.id,dark:a,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:u.label}),e.jsx("span",{className:"mt-0.5 line-clamp-2 text-3xs leading-snug text-fg-muted",children:u.blurb})]})]},u.id)})})]}),e.jsxs("div",{className:g("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:j,onCommit:u=>x({hue:u})}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-1",children:[e.jsx("button",{type:"button",onClick:()=>x({hue:null}),"aria-pressed":!j,className:g("motion-fast rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",j?"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(u=>{const f=j&&Math.abs(p-u.hue)<2.5;return e.jsxs("button",{type:"button","aria-pressed":f,onClick:()=>x({hue:u.hue}),className:g("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(u.hue/5)%h.length]}}),u.name]},u.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(u=>e.jsx("button",{type:"button","aria-pressed":n.tint===u.level,onClick:()=>x({tint:u.level}),className:g("motion-fast rounded-md px-2.5 py-1 text-3xs transition-colors","focus-visible:focus-ring",n.tint===u.level?"bg-surface-active font-medium text-fg":"text-fg-muted hover:text-fg"),children:u.label},u.level))})]})]}),e.jsx(Oe,{})]})}function Oe(){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(R,{variant:"primary",size:"sm",children:"Send"}),e.jsx(R,{variant:"ghost",size:"sm",children:"Cancel"}),e.jsx(R,{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(O,{tone:"success"}),e.jsx(O,{tone:"warn"}),e.jsx(O,{tone:"danger"}),e.jsx(O,{tone:"info"}),e.jsx("span",{className:"text-2xs text-fg-subtle",children:"status hues (theme’s, not yours)"})]})]})]})}const z="mx-auto w-full max-w-4xl",De="sm:w-64";function Ve(){const[t,n]=c.useState(null),[s,o]=c.useState(!0),[r,a]=c.useState(null),[m,x]=c.useState({}),[h,p]=c.useState(!1),[j,u]=c.useState(null),[f,N]=c.useState(!1),[w,F]=c.useState(""),[d,b]=c.useState(!1),[y,M]=c.useState(null),K=c.useRef(null),de=ye("(min-width: 1024px)");c.useEffect(()=>{let i=!0;return o(!0),L.getInstanceConfig().then(l=>{i&&(n(l),a(null))}).catch(l=>i&&a(l instanceof Error?l.message:String(l))).finally(()=>i&&o(!1)),()=>{i=!1}},[]);const ue=(i,l)=>{N(!1),u(null),x(v=>({...v,[i]:l}))},me=i=>se(i,m),H=c.useMemo(()=>t?t.groups.flatMap(i=>i.fields):[],[t]),k=c.useMemo(()=>H.filter(i=>i.editable&&!i.envOverridden).filter(i=>Object.prototype.hasOwnProperty.call(m,i.key)).filter(i=>!re(m[i.key],q(i))).map(i=>i.key),[H,m]),X=c.useMemo(()=>new Set(k),[k]),C=c.useMemo(()=>{if(!t)return[];const i=w.trim().toLowerCase(),l=[];for(const v of t.groups){const P=i!==""&&v.label.toLowerCase().includes(i),I=v.fields.filter(A=>{const T=se(A,m);return d&&re(T,A.default)?!1:i===""||P?!0:Ye(A).includes(i)});I.length>0&&l.push({...v,fields:I})}return l},[t,w,d,m]),J=C.reduce((i,l)=>i+l.fields.length,0),xe=w.trim()!==""||d,U=!d&&(w.trim()===""||We.includes(w.trim().toLowerCase())),$=c.useMemo(()=>U?[V,...C]:C,[U,C]),he=C.some(i=>i.fields.some(l=>l.envOverridden)),Y=Qe(C,X);c.useEffect(()=>{const i=K.current;if(!i||$.length===0)return;const l=$.map(P=>P.id),v=()=>{const P=i.getBoundingClientRect().top;let I=l[0];for(const A of l){const T=document.getElementById(D(A));if(T)if(T.getBoundingClientRect().top-P<=80)I=A;else break}M(I)};return v(),i.addEventListener("scroll",v,{passive:!0}),()=>i.removeEventListener("scroll",v)},[$]);const Q=i=>{var v;const l=document.getElementById(D(i));(v=l==null?void 0:l.scrollIntoView)==null||v.call(l,{behavior:"smooth",block:"start"}),M(i)},fe=async()=>{if(k.length===0||!t)return;const i={};for(const l of k)i[l]=m[l];p(!0),u(null);try{await L.updateInstanceConfig(i,t.configVersion);const l=await L.getInstanceConfig();n(l),x({}),N(!0)}catch(l){if(l instanceof Ce&&l.status===409)try{n(await L.getInstanceConfig())}catch{}u(l instanceof Error?l.message:String(l))}finally{p(!1)}},ge=()=>{x({}),u(null),N(!1)};return e.jsxs("div",{className:"flex min-h-0 flex-1",children:[t&&e.jsx(Be,{groups:$,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:z,children:[e.jsx(Ue,{query:w,onQuery:F,modifiedOnly:d,onModifiedOnly:b,visibleCount:J,totalCount:H.length,filtering:xe,autoFocus:de}),e.jsx(He,{groups:$,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:z,children:[U&&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(Le,{})})}),e.jsx(_e,{saved:f,configPath:t==null?void 0:t.configPath,restartRequired:(t==null?void 0:t.restartRequired)??!1,fileError:t==null?void 0:t.configFileError}),s&&e.jsx("p",{className:"text-sm text-fg-muted",children:"Loading…"}),r&&e.jsxs("p",{className:"text-sm text-danger",role:"alert",children:["Failed to load settings: ",r]}),t&&he&&e.jsx(ze,{}),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(l=>e.jsx(Ge,{field:l,value:me(l),dirty:X.has(l.key),onChange:v=>ue(l.key,v)},l.key))})},i.id))]})}),t&&e.jsx("footer",{className:"border-t border-edge px-4 py-3 sm:px-6",children:e.jsxs("div",{className:`${z} flex items-center gap-3`,children:[j&&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:j})]}),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(R,{variant:"subtle",onClick:ge,disabled:k.length===0||h,children:"Reset"}),e.jsx(R,{variant:"primary",onClick:fe,disabled:k.length===0,loading:h,loadingLabel:"Saving…",children:"Save changes"})]})})]})]})}function Be({groups:t,active:n,onJump:s,dirtyCount:o}){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(r=>{const a=r.id===n,m=o[r.id]??0;return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:g("motion-fast flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm transition-colors",a?"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:r.label}),m>0&&e.jsx("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full bg-accent-solid","aria-label":`${m} unsaved`}),r.fields.length>0&&e.jsx("span",{className:"shrink-0 text-2xs tabular text-fg-subtle",children:r.fields.length})]})},r.id)})})})}function He({groups:t,active:n,onJump:s,dirtyCount:o}){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(r=>{const a=r.id===n,m=o[r.id]??0;return e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:g("motion-fast flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors",a?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[r.label,m>0&&e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent-solid","aria-label":`${m} unsaved`})]},r.id)})})}function Ue({query:t,onQuery:n,modifiedOnly:s,onModifiedOnly:o,visibleCount:r,totalCount:a,filtering:m,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":s,onClick:()=>o(!s),className:g("motion-fast shrink-0 rounded-md border px-2.5 py-1 text-xs transition-colors",s?"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:m?`${r} of ${a}`:`${a} settings`})]})}function _e({saved:t,configPath:n,restartRequired:s,fileError:o}){const r=o?"danger":t?"success":"warn";return e.jsx(Re,{tone:r,className:"mb-5 leading-snug",icon:r==="success"?e.jsx(ke,{width:15,height:15}):e.jsx(oe,{width:15,height:15}),children:e.jsx("span",{role:"status",children:o?e.jsxs(e.Fragment,{children:[e.jsxs("strong",{children:["Could not read ",G(n),"."]})," ",o," — 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."]}):s?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(E,{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 ze(){return e.jsxs("p",{className:"mb-5 text-xs leading-snug text-fg-muted",children:["Settings marked ",e.jsx(E,{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:s,onChange:o}){const r=!t.editable||t.envOverridden,a=`cfg-${t.key}`,m=t.help?`${a}-help`:void 0,x=t.type==="boolean",h=c.useMemo(()=>Je(t,q(t)),[t]),p=x&&!r,j=!t.help&&!t.envOverridden&&!t.pendingRestart,u=j?"items-center":"items-start",f=j?"sm:items-center":"sm:items-start",N=r?e.jsx(Xe,{field:t,value:n}):x?e.jsx(Me,{id:a,checked:!!n,onChange:o,label:t.label}):e.jsx(Ke,{field:t,value:n,onChange:o,inputId:a,describedBy:m});return e.jsxs("div",{className:"relative px-4 py-3",children:[s&&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:g(h?"":p?`flex gap-4 ${u}`:`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:r?void 0:a,className:"text-sm font-medium text-fg",children:t.label}),t.sensitive&&e.jsx(E,{tone:"warn",children:"sensitive"}),t.envOverridden&&e.jsx(E,{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(E,{tone:"neutral",children:"read-only"}),t.pendingRestart&&e.jsx(E,{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:m,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:g(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 s=(Array.isArray(t)?t.join(", "):String(t)).replace(/\s+/g," ").trim();return s.length>60?`${s.slice(0,60)}…`:s}function E({children:t,tone:n,title:s}){return e.jsx(ce,{tone:n,size:"sm",title:s,className:"uppercase tracking-wide",children:t})}function Ke({field:t,value:n,onChange:s,inputId:o,describedBy:r}){if(t.type==="enum")return e.jsx($e,{id:o,"aria-describedby":r,value:String(n??""),onChange:a=>s(a.target.value),children:(t.enumValues??[]).map(a=>e.jsx("option",{value:a,children:a},a))});if(t.type==="number")return e.jsx(B,{id:o,type:"number","aria-describedby":r,className:"tabular",value:n==null?"":String(n),placeholder:t.default===null?"default":String(t.default),onChange:a=>s(a.target.value===""?null:Number(a.target.value))});if(t.type==="text"){const a=n==null||n===t.default,m=n==null?String(t.default??""):String(n),x=typeof t.default=="string"&&!a;return e.jsxs("div",{children:[e.jsx(Pe,{id:o,"aria-describedby":r,className:"min-h-[7rem] font-mono text-xs leading-relaxed",rows:6,spellCheck:!1,value:m,onChange:h=>s(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:a?"Using the built-in default.":n===""?"Empty — nothing will be appended.":`${m.length.toLocaleString()} characters.`}),x&&e.jsx(R,{variant:"link",size:"sm",className:"shrink-0",onClick:()=>s(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const a=Array.isArray(n)?n.join(", "):String(n??"");return e.jsx(B,{id:o,type:"text","aria-describedby":r,value:a,onChange:m=>s(m.target.value.split(",").map(x=>x.trim()).filter(Boolean))})}return e.jsx(B,{id:o,type:"text","aria-describedby":r,value:n==null?"":String(n),placeholder:t.default===null?"":String(t.default),onChange:a=>s(a.target.value)})}function Xe({field:t,value:n}){const s="rounded-lg bg-surface-sunken px-3 py-2 font-mono text-xs text-fg-muted";return t.type==="boolean"?e.jsx("div",{className:s,children:n?"true":"false"}):n==null||n===""?e.jsx("div",{className:s,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:g(s,"max-h-40 overflow-y-auto whitespace-pre-wrap leading-relaxed"),children:String(n)}):e.jsx("div",{className:g(s,"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 s={};for(const o of t)s[o.id]=o.fields.filter(r=>n.has(r.key)).length;return s}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((s,o)=>s===n[o]):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};
|
|
1
|
+
import{r as c,n as W,s as Z,A as ee,p as pe,j as e,q as ae,l as g,t as ie,v as be,w as je,x as le,y as ve,z as ye,b as L,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-BeuEs7dL.js";import{B as R,S as te}from"./Surfaces-1dBayrsj.js";import{C as ce,S as O,I as B,a as Re,T as Me,b as $e,c as Pe}from"./Chip-C8a-t439.js";const Ie=Array.from({length:72},(t,n)=>n*5),S=[...ie].sort((t,n)=>t.hue-n.hue),_=(t,n)=>Math.min(Math.abs(t-n),360-Math.abs(t-n));function ne(t){const n=S.reduce((r,a)=>_(a.hue,t)<_(r.hue,t)?a:r);if(_(n.hue,t)<=8)return n.name;const s=S.find(r=>r.hue>t)??S[0];return`between ${S[(S.indexOf(s)-1+S.length)%S.length].name} and ${s.name}`}function Fe({theme:t,dark:n,hue:s,className:o}){const r=c.useRef(null);return c.useLayoutEffect(()=>{const a=r.current;a&&(s===null?je(a):le(s,a))},[t,n,s]),e.jsx("div",{ref:r,"data-theme":t,className:g("overflow-hidden rounded-lg border border-edge",n&&"dark",o),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:s,onCommit:o}){const r=c.useRef(null),a=c.useRef(null),m=c.useRef(null),x=c.useRef(0),h=c.useRef(null),p=c.useRef(!1),j=c.useRef(null),u=c.useMemo(()=>{if(t.length===0)return;const d=t.map((b,y)=>`${b} ${(y/t.length*100).toFixed(2)}%`);return d.push(`${t[0]} 100%`),`linear-gradient(to right, ${d.join(", ")})`},[t]),f=c.useCallback(d=>{a.current&&(a.current.style.left=`${d/360*100}%`),m.current&&(m.current.textContent=ne(d))},[]);c.useEffect(()=>{p.current||f(n)},[n,f]);const N=d=>{var M;const b=(M=r.current)==null?void 0:M.getBoundingClientRect();if(!b||b.width===0)return 0;const y=Math.min(1,Math.max(0,(d-b.left)/b.width));return Math.round(y*360)%360},w=c.useCallback(d=>{h.current=d,!x.current&&(x.current=requestAnimationFrame(()=>{x.current=0;const b=h.current;h.current=null,b!==null&&(f(b),le(b,document.documentElement,{context:j.current??void 0,live:!0}))}))},[f]);c.useEffect(()=>()=>cancelAnimationFrame(x.current),[]);const F=d=>{p.current=!1,j.current=null,cancelAnimationFrame(x.current),x.current=0,h.current=null,o(d)};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:m,className:"text-3xs font-medium text-fg-muted","aria-hidden":!0})]}),e.jsx("div",{ref:r,role:"slider",tabIndex:0,"aria-label":"Accent colour","aria-valuemin":0,"aria-valuemax":359,"aria-valuenow":n,"aria-valuetext":s?ne(n):"the theme’s own colour",onPointerDown:d=>{d.currentTarget.setPointerCapture(d.pointerId),p.current=!0,j.current=ve(),w(N(d.clientX))},onPointerMove:d=>{p.current&&w(N(d.clientX))},onPointerUp:d=>{p.current&&F(N(d.clientX))},onPointerCancel:()=>{p.current&&F(n)},onKeyDown:d=>{const b=d.key==="PageUp"||d.key==="PageDown"?15:d.shiftKey?10:2;let y=null;d.key==="ArrowLeft"||d.key==="ArrowDown"||d.key==="PageDown"?y=(n-b+360)%360:d.key==="ArrowRight"||d.key==="ArrowUp"||d.key==="PageUp"?y=(n+b)%360:d.key==="Home"?y=0:d.key==="End"&&(y=359),y!==null&&(d.preventDefault(),o(y))},style:{backgroundImage:u,touchAction:"none"},className:g("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:a,"aria-hidden":!0,style:{left:`${n/360*100}%`},className:g("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",!s&&"opacity-0")})})]})}function Le({className:t}){const[n,s]=c.useState(W),[o,r]=c.useState(null),a=typeof document<"u"&&document.documentElement.classList.contains("dark"),m=c.useRef(n),x=c.useCallback(u=>{const f={...m.current,...u};m.current=f,s(f),r(Z(f))},[]);c.useEffect(()=>{const u=f=>r(f.detail);return window.addEventListener(ee,u),r(Z(W())),()=>window.removeEventListener(ee,u)},[]);const h=c.useMemo(()=>pe(Ie),[n.theme,a,o==null?void 0:o.mode]),p=(o==null?void 0:o.hue)??0,j=n.hue!==null;return e.jsxs("div",{className:g("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:g("mt-2 grid gap-2","grid-cols-2 sm:grid-cols-4"),children:ae.map(u=>{const f=n.theme===u.id;return e.jsxs("button",{type:"button","aria-pressed":f,title:`${u.label} — ${u.blurb}`,onClick:()=>x({theme:u.id}),className:g("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:u.id,dark:a,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:u.label}),e.jsx("span",{className:"mt-0.5 line-clamp-2 text-3xs leading-snug text-fg-muted",children:u.blurb})]})]},u.id)})})]}),e.jsxs("div",{className:g("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:j,onCommit:u=>x({hue:u})}),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-1",children:[e.jsx("button",{type:"button",onClick:()=>x({hue:null}),"aria-pressed":!j,className:g("motion-fast rounded-md border px-2 py-1 text-3xs transition-colors","focus-visible:focus-ring",j?"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(u=>{const f=j&&Math.abs(p-u.hue)<2.5;return e.jsxs("button",{type:"button","aria-pressed":f,onClick:()=>x({hue:u.hue}),className:g("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(u.hue/5)%h.length]}}),u.name]},u.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(u=>e.jsx("button",{type:"button","aria-pressed":n.tint===u.level,onClick:()=>x({tint:u.level}),className:g("motion-fast rounded-md px-2.5 py-1 text-3xs transition-colors","focus-visible:focus-ring",n.tint===u.level?"bg-surface-active font-medium text-fg":"text-fg-muted hover:text-fg"),children:u.label},u.level))})]})]}),e.jsx(Oe,{})]})}function Oe(){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(R,{variant:"primary",size:"sm",children:"Send"}),e.jsx(R,{variant:"ghost",size:"sm",children:"Cancel"}),e.jsx(R,{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(O,{tone:"success"}),e.jsx(O,{tone:"warn"}),e.jsx(O,{tone:"danger"}),e.jsx(O,{tone:"info"}),e.jsx("span",{className:"text-2xs text-fg-subtle",children:"status hues (theme’s, not yours)"})]})]})]})}const z="mx-auto w-full max-w-4xl",De="sm:w-64";function Ve(){const[t,n]=c.useState(null),[s,o]=c.useState(!0),[r,a]=c.useState(null),[m,x]=c.useState({}),[h,p]=c.useState(!1),[j,u]=c.useState(null),[f,N]=c.useState(!1),[w,F]=c.useState(""),[d,b]=c.useState(!1),[y,M]=c.useState(null),K=c.useRef(null),de=ye("(min-width: 1024px)");c.useEffect(()=>{let i=!0;return o(!0),L.getInstanceConfig().then(l=>{i&&(n(l),a(null))}).catch(l=>i&&a(l instanceof Error?l.message:String(l))).finally(()=>i&&o(!1)),()=>{i=!1}},[]);const ue=(i,l)=>{N(!1),u(null),x(v=>({...v,[i]:l}))},me=i=>se(i,m),H=c.useMemo(()=>t?t.groups.flatMap(i=>i.fields):[],[t]),k=c.useMemo(()=>H.filter(i=>i.editable&&!i.envOverridden).filter(i=>Object.prototype.hasOwnProperty.call(m,i.key)).filter(i=>!re(m[i.key],q(i))).map(i=>i.key),[H,m]),X=c.useMemo(()=>new Set(k),[k]),C=c.useMemo(()=>{if(!t)return[];const i=w.trim().toLowerCase(),l=[];for(const v of t.groups){const P=i!==""&&v.label.toLowerCase().includes(i),I=v.fields.filter(A=>{const T=se(A,m);return d&&re(T,A.default)?!1:i===""||P?!0:Ye(A).includes(i)});I.length>0&&l.push({...v,fields:I})}return l},[t,w,d,m]),J=C.reduce((i,l)=>i+l.fields.length,0),xe=w.trim()!==""||d,U=!d&&(w.trim()===""||We.includes(w.trim().toLowerCase())),$=c.useMemo(()=>U?[V,...C]:C,[U,C]),he=C.some(i=>i.fields.some(l=>l.envOverridden)),Y=Qe(C,X);c.useEffect(()=>{const i=K.current;if(!i||$.length===0)return;const l=$.map(P=>P.id),v=()=>{const P=i.getBoundingClientRect().top;let I=l[0];for(const A of l){const T=document.getElementById(D(A));if(T)if(T.getBoundingClientRect().top-P<=80)I=A;else break}M(I)};return v(),i.addEventListener("scroll",v,{passive:!0}),()=>i.removeEventListener("scroll",v)},[$]);const Q=i=>{var v;const l=document.getElementById(D(i));(v=l==null?void 0:l.scrollIntoView)==null||v.call(l,{behavior:"smooth",block:"start"}),M(i)},fe=async()=>{if(k.length===0||!t)return;const i={};for(const l of k)i[l]=m[l];p(!0),u(null);try{await L.updateInstanceConfig(i,t.configVersion);const l=await L.getInstanceConfig();n(l),x({}),N(!0)}catch(l){if(l instanceof Ce&&l.status===409)try{n(await L.getInstanceConfig())}catch{}u(l instanceof Error?l.message:String(l))}finally{p(!1)}},ge=()=>{x({}),u(null),N(!1)};return e.jsxs("div",{className:"flex min-h-0 flex-1",children:[t&&e.jsx(Be,{groups:$,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:z,children:[e.jsx(Ue,{query:w,onQuery:F,modifiedOnly:d,onModifiedOnly:b,visibleCount:J,totalCount:H.length,filtering:xe,autoFocus:de}),e.jsx(He,{groups:$,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:z,children:[U&&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(Le,{})})}),e.jsx(_e,{saved:f,configPath:t==null?void 0:t.configPath,restartRequired:(t==null?void 0:t.restartRequired)??!1,fileError:t==null?void 0:t.configFileError}),s&&e.jsx("p",{className:"text-sm text-fg-muted",children:"Loading…"}),r&&e.jsxs("p",{className:"text-sm text-danger",role:"alert",children:["Failed to load settings: ",r]}),t&&he&&e.jsx(ze,{}),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(l=>e.jsx(Ge,{field:l,value:me(l),dirty:X.has(l.key),onChange:v=>ue(l.key,v)},l.key))})},i.id))]})}),t&&e.jsx("footer",{className:"border-t border-edge px-4 py-3 sm:px-6",children:e.jsxs("div",{className:`${z} flex items-center gap-3`,children:[j&&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:j})]}),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(R,{variant:"subtle",onClick:ge,disabled:k.length===0||h,children:"Reset"}),e.jsx(R,{variant:"primary",onClick:fe,disabled:k.length===0,loading:h,loadingLabel:"Saving…",children:"Save changes"})]})})]})]})}function Be({groups:t,active:n,onJump:s,dirtyCount:o}){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(r=>{const a=r.id===n,m=o[r.id]??0;return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:g("motion-fast flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm transition-colors",a?"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:r.label}),m>0&&e.jsx("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full bg-accent-solid","aria-label":`${m} unsaved`}),r.fields.length>0&&e.jsx("span",{className:"shrink-0 text-2xs tabular text-fg-subtle",children:r.fields.length})]})},r.id)})})})}function He({groups:t,active:n,onJump:s,dirtyCount:o}){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(r=>{const a=r.id===n,m=o[r.id]??0;return e.jsxs("button",{type:"button",onClick:()=>s(r.id),"aria-current":a?"true":void 0,className:g("motion-fast flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors",a?"bg-surface-selected font-medium text-fg":"text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[r.label,m>0&&e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent-solid","aria-label":`${m} unsaved`})]},r.id)})})}function Ue({query:t,onQuery:n,modifiedOnly:s,onModifiedOnly:o,visibleCount:r,totalCount:a,filtering:m,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":s,onClick:()=>o(!s),className:g("motion-fast shrink-0 rounded-md border px-2.5 py-1 text-xs transition-colors",s?"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:m?`${r} of ${a}`:`${a} settings`})]})}function _e({saved:t,configPath:n,restartRequired:s,fileError:o}){const r=o?"danger":t?"success":"warn";return e.jsx(Re,{tone:r,className:"mb-5 leading-snug",icon:r==="success"?e.jsx(ke,{width:15,height:15}):e.jsx(oe,{width:15,height:15}),children:e.jsx("span",{role:"status",children:o?e.jsxs(e.Fragment,{children:[e.jsxs("strong",{children:["Could not read ",G(n),"."]})," ",o," — 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."]}):s?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(E,{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 ze(){return e.jsxs("p",{className:"mb-5 text-xs leading-snug text-fg-muted",children:["Settings marked ",e.jsx(E,{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:s,onChange:o}){const r=!t.editable||t.envOverridden,a=`cfg-${t.key}`,m=t.help?`${a}-help`:void 0,x=t.type==="boolean",h=c.useMemo(()=>Je(t,q(t)),[t]),p=x&&!r,j=!t.help&&!t.envOverridden&&!t.pendingRestart,u=j?"items-center":"items-start",f=j?"sm:items-center":"sm:items-start",N=r?e.jsx(Xe,{field:t,value:n}):x?e.jsx(Me,{id:a,checked:!!n,onChange:o,label:t.label}):e.jsx(Ke,{field:t,value:n,onChange:o,inputId:a,describedBy:m});return e.jsxs("div",{className:"relative px-4 py-3",children:[s&&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:g(h?"":p?`flex gap-4 ${u}`:`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:r?void 0:a,className:"text-sm font-medium text-fg",children:t.label}),t.sensitive&&e.jsx(E,{tone:"warn",children:"sensitive"}),t.envOverridden&&e.jsx(E,{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(E,{tone:"neutral",children:"read-only"}),t.pendingRestart&&e.jsx(E,{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:m,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:g(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 s=(Array.isArray(t)?t.join(", "):String(t)).replace(/\s+/g," ").trim();return s.length>60?`${s.slice(0,60)}…`:s}function E({children:t,tone:n,title:s}){return e.jsx(ce,{tone:n,size:"sm",title:s,className:"uppercase tracking-wide",children:t})}function Ke({field:t,value:n,onChange:s,inputId:o,describedBy:r}){if(t.type==="enum")return e.jsx($e,{id:o,"aria-describedby":r,value:String(n??""),onChange:a=>s(a.target.value),children:(t.enumValues??[]).map(a=>e.jsx("option",{value:a,children:a},a))});if(t.type==="number")return e.jsx(B,{id:o,type:"number","aria-describedby":r,className:"tabular",value:n==null?"":String(n),placeholder:t.default===null?"default":String(t.default),onChange:a=>s(a.target.value===""?null:Number(a.target.value))});if(t.type==="text"){const a=n==null||n===t.default,m=n==null?String(t.default??""):String(n),x=typeof t.default=="string"&&!a;return e.jsxs("div",{children:[e.jsx(Pe,{id:o,"aria-describedby":r,className:"min-h-[7rem] font-mono text-xs leading-relaxed",rows:6,spellCheck:!1,value:m,onChange:h=>s(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:a?"Using the built-in default.":n===""?"Empty — nothing will be appended.":`${m.length.toLocaleString()} characters.`}),x&&e.jsx(R,{variant:"link",size:"sm",className:"shrink-0",onClick:()=>s(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const a=Array.isArray(n)?n.join(", "):String(n??"");return e.jsx(B,{id:o,type:"text","aria-describedby":r,value:a,onChange:m=>s(m.target.value.split(",").map(x=>x.trim()).filter(Boolean))})}return e.jsx(B,{id:o,type:"text","aria-describedby":r,value:n==null?"":String(n),placeholder:t.default===null?"":String(t.default),onChange:a=>s(a.target.value)})}function Xe({field:t,value:n}){const s="rounded-lg bg-surface-sunken px-3 py-2 font-mono text-xs text-fg-muted";return t.type==="boolean"?e.jsx("div",{className:s,children:n?"true":"false"}):n==null||n===""?e.jsx("div",{className:s,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:g(s,"max-h-40 overflow-y-auto whitespace-pre-wrap leading-relaxed"),children:String(n)}):e.jsx("div",{className:g(s,"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 s={};for(const o of t)s[o.id]=o.fields.filter(r=>n.has(r.key)).length;return s}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((s,o)=>s===n[o]):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
2
|
|