@edspencer/paddock 0.69.0 → 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/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/package.json +1 -1
- package/packages/web/dist/assets/{Chip-B8UU8Zpr.js → Chip-C8a-t439.js} +1 -1
- package/packages/web/dist/assets/DiscoverPage-C1khyCvD.js +2 -0
- package/packages/web/dist/assets/{DiscoverView-CKN93BnT.js → DiscoverView-DS_Z9xKH.js} +1 -1
- package/packages/web/dist/assets/{InstanceConfigPage-COc2rsu6.js → InstanceConfigPage-B1ei1FDo.js} +1 -1
- package/packages/web/dist/assets/{MarkdownRenderer-BlUYSdHR.js → MarkdownRenderer-DCj_ZwVG.js} +1 -1
- package/packages/web/dist/assets/{ProjectMenu-Davm1-P7.js → ProjectMenu-B7dGZSFB.js} +1 -1
- package/packages/web/dist/assets/{ProjectRedirect-COrC7Yvg.js → ProjectRedirect-bstvMvM9.js} +1 -1
- package/packages/web/dist/assets/{ProjectView-WIODXM93.js → ProjectView-iuiUIoIl.js} +11 -11
- package/packages/web/dist/assets/{ProjectsGrid-CfDehr5s.js → ProjectsGrid-DKvySDUQ.js} +1 -1
- package/packages/web/dist/assets/{RootHome-DniHfYAw.js → RootHome-CD_37qb-.js} +1 -1
- package/packages/web/dist/assets/{Surfaces-GzOkJJHQ.js → Surfaces-1dBayrsj.js} +1 -1
- package/packages/web/dist/assets/{arc-_I2xwzbW.js → arc-BJPb3ViJ.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-GW4T_vCB.js → architectureDiagram-3BPJPVTR-PkLOC5wV.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-rpMzVG3O.js → blockDiagram-GPEHLZMM-IPduhNH-.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-CwxpNlW3.js → c4Diagram-AAUBKEIU-dKTYV1Vq.js} +1 -1
- package/packages/web/dist/assets/channel-BhrgMiqg.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-BG9SyFJ-.js → chunk-2J33WTMH-B5C6geyg.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-DJlbnTd4.js → chunk-4BX2VUAB-1BRhFRhF.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-C-VMlU4m.js → chunk-55IACEB6-DNv-sTiI.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-Wigu1170.js → chunk-727SXJPM-CWezuVkx.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-C5CFWtjs.js → chunk-AQP2D5EJ-Bt4yEQnu.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-hQaZU9Hi.js → chunk-FMBD7UC4-lb_8q4JY.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-AMO00QGi.js → chunk-ND2GUHAM-DOwgGlQ_.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-T3F7CT-B.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-D1JA8p71.js → core-CAsyoNAa.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-C_fPZY7X.js → cose-bilkent-S5V4N54A-sVaVkwMI.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-nLjMp3c7.js → dagre-BM42HDAG-C9pKHSMo.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-qYzVcYYg.js → diagram-2AECGRRQ-CHdrmCfX.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-DVFKMWv0.js → diagram-5GNKFQAL-4UTa2Dfa.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-B8T7qnCR.js → diagram-KO2AKTUF-NidpfVwW.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-9-_-MiG8.js → diagram-LMA3HP47-ictQj03T.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-D4eE55Vg.js → diagram-OG6HWLK6-B7dTLMHC.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-adlALhlq.js → erDiagram-TEJ5UH35-C2QYYzJ8.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-jhJEXK0D.js → flowDiagram-I6XJVG4X-D2rcjSZ9.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-CHGNR8Fk.js → ganttDiagram-6RSMTGT7-BQcXTYzg.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-tBQ_60zD.js → gitGraphDiagram-PVQCEYII-DwB2Vqxa.js} +1 -1
- package/packages/web/dist/assets/index-BNzTD4hA.css +1 -0
- package/packages/web/dist/assets/{index-Djl4krRr.js → index-BeuEs7dL.js} +2 -2
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-D_LJZit4.js → infoDiagram-5YYISTIA-BoK4Mawg.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-CLsVMtFo.js → ishikawaDiagram-YF4QCWOH-DPP9svhg.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-DKLfsczG.js → journeyDiagram-JHISSGLW-TrggodYk.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-CG1dRRin.js → kanban-definition-UN3LZRKU-Bh69hRSR.js} +1 -1
- package/packages/web/dist/assets/{linear-Bc0TsEWL.js → linear-C1iYMpBz.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-7NBz7_-Q.js → mermaid.core-BZDABcuq.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-DD-2NsoA.js → mindmap-definition-RKZ34NQL-DTJON3dS.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-BTYpRP3j.js → pieDiagram-4H26LBE5-BxtFV74I.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-DScmlT0o.js → quadrantDiagram-W4KKPZXB-D2Ar8kmO.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-BzLuYCY3.js → requirementDiagram-4Y6WPE33-DiLSfeSQ.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-CH9nUHfL.js → sankeyDiagram-5OEKKPKP-D_CRQc7j.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-vQjaE3Ay.js → sequenceDiagram-3UESZ5HK-DjtfcRNV.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-C76FMvr4.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-zjhYOHh7.js → timeline-definition-PNZ67QCA-DXKspEG3.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-BpyreyjG.js → vennDiagram-CIIHVFJN-B_tXRMHH.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY-CugQjZZ8.js → wardley-L42UT6IY-DNaNoaJm.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-CTpxg9iQ.js → wardleyDiagram-YWT4CUSO-BuVDpC8s.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-COJLOF01.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-vz1s8GYQ.js +0 -2
- package/packages/web/dist/assets/channel-nPAjQX8p.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DuI-4XNG.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DuI-4XNG.js +0 -2
- package/packages/web/dist/assets/index-CJT1g4_p.css +0 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CWy9AQvb.js +0 -2
package/package.json
CHANGED
|
@@ -44,8 +44,14 @@ const KNOWN_CAUSES = [
|
|
|
44
44
|
// Anchored to `claude` specifically. A bare /ENOENT/ would claim a missing
|
|
45
45
|
// CLI for any file the engine failed to open, which is a confident wrong
|
|
46
46
|
// answer — worse than the raw error it replaces.
|
|
47
|
+
//
|
|
48
|
+
// Name only what actually reads PATH (#771): the CLI runtime. The sweeper
|
|
49
|
+
// is always on it; triggers and chat turns only on `driveMode: batch`. An
|
|
50
|
+
// earlier wording said "the sweeper and triggers", which sent an operator
|
|
51
|
+
// on the default `session` mode to check the wrong thing.
|
|
47
52
|
pattern: /ENOENT[^\n]{0,40}claude|claude: (command )?not found/i,
|
|
48
|
-
cause: "the `claude` CLI is not on PATH (needed by the sweeper and
|
|
53
|
+
cause: "the `claude` CLI is not on PATH (needed by the sweeper, and by " +
|
|
54
|
+
"triggers/turns on `driveMode: batch`)",
|
|
49
55
|
},
|
|
50
56
|
];
|
|
51
57
|
/**
|
|
@@ -78,14 +78,19 @@ function readVersion() {
|
|
|
78
78
|
/**
|
|
79
79
|
* Put our bundled `claude` on PATH for child processes.
|
|
80
80
|
*
|
|
81
|
-
* Chat turns do NOT need this
|
|
82
|
-
* the binary from the Claude Agent SDK's
|
|
83
|
-
* `require.resolve` and never consults PATH.
|
|
84
|
-
*
|
|
85
|
-
* `execa("claude", …)` — by
|
|
86
|
-
* install is invisible to it
|
|
81
|
+
* Chat turns do NOT need this on the default `driveMode: session`: they run
|
|
82
|
+
* herdctl's SDK runtime, which resolves the binary from the Claude Agent SDK's
|
|
83
|
+
* own platform package via `require.resolve` and never consults PATH. The
|
|
84
|
+
* post-turn sweeper is the one unconditional user: always a one-shot
|
|
85
|
+
* `trigger()` call on the CLI runtime, which does `execa("claude", …)` — by
|
|
86
|
+
* name, without execa's `preferLocal`, so a local install is invisible to it
|
|
87
|
+
* unless PATH says otherwise. Triggers join it there only on `driveMode:
|
|
88
|
+
* batch`: a trigger resolves its drive mode exactly like a chat does
|
|
89
|
+
* (per-project override else `cfg.driveMode` — `resolveDriveMode` in
|
|
90
|
+
* ws-triggers.ts), so on a stock instance no trigger consults PATH either.
|
|
87
91
|
*
|
|
88
|
-
* Without this, chats work and every sweep
|
|
92
|
+
* Without this, chats work and every sweep fails (logged, non-fatal) — plus
|
|
93
|
+
* every trigger and turn on `driveMode: batch`.
|
|
89
94
|
*/
|
|
90
95
|
function addBundledBinsToPath() {
|
|
91
96
|
const owner = findUp(path.join("node_modules", ".bin"));
|
|
@@ -386,11 +386,14 @@ export interface PaddockConfig {
|
|
|
386
386
|
warnings: string[];
|
|
387
387
|
};
|
|
388
388
|
/**
|
|
389
|
-
* Instance default for the hook-management MCP (Epic G / G5, GG-4) — the
|
|
390
|
-
* `mcp__paddock_manage__{
|
|
391
|
-
*
|
|
389
|
+
* Instance default for the hook-management MCP (Epic G / G5, GG-4) — now the
|
|
390
|
+
* unified TRIGGER tools `mcp__paddock_manage__{list_triggers,set_trigger,
|
|
391
|
+
* remove_trigger,run_trigger}` that let a project agent declare/edit/delete/fire
|
|
392
|
+
* its own triggers. Epic T / T3 collapsed the former `*_hook` and `*_schedule`
|
|
393
|
+
* verbs into these; the flag and its env var kept the `hooks` spelling.
|
|
394
|
+
* A sibling of {@link selfMcpWriteEnabled}:
|
|
392
395
|
* OFF by default (opt-in), and only surfaces when the self-MCP write tools are also
|
|
393
|
-
* present (the
|
|
396
|
+
* present (the trigger tools live on the same injected server, appended in the write
|
|
394
397
|
* block). Driven by `PADDOCK_HOOKS_MCP`; accepts 1/true/yes. A per-project
|
|
395
398
|
* `hooksMcpEnabled` override wins at dispatch (resolved via
|
|
396
399
|
* {@link import("./hook-config.js").resolveHooksMcpEnabled}), the same
|
|
@@ -580,7 +583,6 @@ export interface PaddockConfigFile {
|
|
|
580
583
|
autoReDrive?: boolean | string;
|
|
581
584
|
debounceMs?: number | string;
|
|
582
585
|
maxRetries?: number | string;
|
|
583
|
-
limboTimeoutMs?: number | string;
|
|
584
586
|
};
|
|
585
587
|
/**
|
|
586
588
|
* Inbound composer-attachment config (issue #328). Every field optional; a
|
|
@@ -456,7 +456,6 @@ function loadRecoveryConfig(file) {
|
|
|
456
456
|
autoReDrive: loadRecoveryBool("PADDOCK_RECOVERY_AUTODRIVE", f.autoReDrive, DEFAULT_RECOVERY.autoReDrive),
|
|
457
457
|
debounceMs: loadRecoveryInt("PADDOCK_RECOVERY_DEBOUNCE_MS", f.debounceMs, DEFAULT_RECOVERY.debounceMs),
|
|
458
458
|
maxRetries: loadRecoveryInt("PADDOCK_RECOVERY_MAX_RETRIES", f.maxRetries, DEFAULT_RECOVERY.maxRetries),
|
|
459
|
-
limboTimeoutMs: loadRecoveryInt("PADDOCK_RECOVERY_LIMBO_MS", f.limboTimeoutMs, DEFAULT_RECOVERY.limboTimeoutMs),
|
|
460
459
|
};
|
|
461
460
|
}
|
|
462
461
|
/**
|
|
@@ -254,7 +254,7 @@ export const FIELDS = [
|
|
|
254
254
|
{ key: "environmentPrompt", group: "capabilities", label: "Environment prompt", help: "Appended to every keeper turn's system prompt: what the agent should know about rendering into Paddock rather than a terminal. Clear it to append nothing.", type: "text", envVars: ["PADDOCK_ENVIRONMENT_PROMPT"], envShadowWhenDefined: true, default: DEFAULT_ENVIRONMENT_PROMPT, editable: true, coerce: promptText },
|
|
255
255
|
{ key: "selfMcpEnabled", group: "capabilities", label: "Self-management MCP (read)", help: "Let keepers list/read projects and other chats.", type: "boolean", envVars: ["PADDOCK_SELF_MCP"], default: false, editable: true, coerce: asBool },
|
|
256
256
|
{ key: "selfMcpWriteEnabled", group: "capabilities", label: "Self-management MCP (write)", help: "Let keepers create/fork/message chats (needs read enabled too).", type: "boolean", envVars: ["PADDOCK_SELF_MCP_WRITE"], default: false, editable: true, coerce: asBool },
|
|
257
|
-
{ key: "selfMcpProjectsEnabled", group: "capabilities", label: "Self-management MCP (projects)", help: "Let keepers create
|
|
257
|
+
{ key: "selfMcpProjectsEnabled", group: "capabilities", label: "Self-management MCP (projects)", help: "Let keepers create new projects and promote existing ones — including a git clone of a repo URL the agent supplies (needs self-MCP write).", type: "boolean", envVars: ["PADDOCK_SELF_MCP_PROJECTS"], default: false, editable: true, coerce: asBool },
|
|
258
258
|
{ key: "maxSpawnDepth", group: "capabilities", label: "Max spawn depth", help: "How deep a spawn tree may grow before children lose the self-MCP.", type: "number", envVars: ["PADDOCK_MAX_SPAWN_DEPTH"], default: DEFAULT_MAX_SPAWN_DEPTH, editable: true, coerce: spawnDepth },
|
|
259
259
|
{ key: "scheduleMutationEnabled", group: "capabilities", label: "Schedule mutation", help: "Allow programmatic schedule add/remove at runtime.", type: "boolean", envVars: ["PADDOCK_SCHEDULE_MUTATION"], default: false, editable: true, coerce: asBool },
|
|
260
260
|
{ key: "hooksMcpEnabled", group: "capabilities", label: "Hooks MCP", help: "Let agents declare/edit their own event hooks (needs self-MCP write).", type: "boolean", envVars: ["PADDOCK_HOOKS_MCP"], default: false, editable: true, coerce: asBool },
|
|
@@ -264,7 +264,6 @@ export const FIELDS = [
|
|
|
264
264
|
{ key: "recovery.autoReDrive", group: "recovery", label: "Auto re-drive", type: "boolean", envVars: ["PADDOCK_RECOVERY_AUTODRIVE"], default: DEFAULT_RECOVERY.autoReDrive, editable: true, coerce: asBool },
|
|
265
265
|
{ key: "recovery.debounceMs", group: "recovery", label: "Debounce (ms)", type: "number", envVars: ["PADDOCK_RECOVERY_DEBOUNCE_MS"], default: DEFAULT_RECOVERY.debounceMs, editable: true, coerce: nonNegInt },
|
|
266
266
|
{ key: "recovery.maxRetries", group: "recovery", label: "Max retries", type: "number", envVars: ["PADDOCK_RECOVERY_MAX_RETRIES"], default: DEFAULT_RECOVERY.maxRetries, editable: true, coerce: nonNegInt },
|
|
267
|
-
{ key: "recovery.limboTimeoutMs", group: "recovery", label: "Limbo timeout (ms)", type: "number", envVars: ["PADDOCK_RECOVERY_LIMBO_MS"], default: DEFAULT_RECOVERY.limboTimeoutMs, editable: true, coerce: nonNegInt },
|
|
268
267
|
// Attachments (issue #328).
|
|
269
268
|
{ key: "attachments.enabled", group: "attachments", label: "Enabled", type: "boolean", envVars: ["PADDOCK_ATTACHMENTS_ENABLED"], default: DEFAULT_ATTACHMENTS.enabled, editable: true, coerce: asBool },
|
|
270
269
|
{ key: "attachments.maxFileSizeMb", group: "attachments", label: "Max file size (MB)", type: "number", envVars: ["PADDOCK_ATTACHMENTS_MAX_FILE_SIZE_MB"], default: DEFAULT_ATTACHMENTS.maxFileSizeMb, editable: true, coerce: posInt },
|
|
@@ -67,12 +67,6 @@ export interface RecoveryConfig {
|
|
|
67
67
|
* `PADDOCK_RECOVERY_MAX_RETRIES`.
|
|
68
68
|
*/
|
|
69
69
|
maxRetries: number;
|
|
70
|
-
/**
|
|
71
|
-
* Layer 2 backstop — if a kept-alive keeper session shows no activity for this
|
|
72
|
-
* many ms after a killed-task notification, surface it as stuck. `0` disables
|
|
73
|
-
* the backstop (the default). Env `PADDOCK_RECOVERY_LIMBO_MS`.
|
|
74
|
-
*/
|
|
75
|
-
limboTimeoutMs: number;
|
|
76
70
|
}
|
|
77
71
|
/**
|
|
78
72
|
* A per-project recovery override as stored in `project.yaml` — every field
|
|
@@ -43,7 +43,6 @@ export const DEFAULT_RECOVERY = Object.freeze({
|
|
|
43
43
|
autoReDrive: false,
|
|
44
44
|
debounceMs: 5000,
|
|
45
45
|
maxRetries: 1,
|
|
46
|
-
limboTimeoutMs: 0,
|
|
47
46
|
});
|
|
48
47
|
/** The `<status>` values a killed-at-turn-boundary task notification carries. */
|
|
49
48
|
const TERMINATED_STATUSES = new Set(["killed", "stopped"]);
|
|
@@ -81,8 +80,6 @@ export function sanitizeRecoveryOverride(value) {
|
|
|
81
80
|
out.debounceMs = o.debounceMs;
|
|
82
81
|
if (isNonNegativeInt(o.maxRetries))
|
|
83
82
|
out.maxRetries = o.maxRetries;
|
|
84
|
-
if (isNonNegativeInt(o.limboTimeoutMs))
|
|
85
|
-
out.limboTimeoutMs = o.limboTimeoutMs;
|
|
86
83
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
87
84
|
}
|
|
88
85
|
/**
|
|
@@ -100,6 +97,5 @@ export function resolveRecoveryConfig(override, instanceDefault) {
|
|
|
100
97
|
autoReDrive: clean.autoReDrive ?? instanceDefault.autoReDrive,
|
|
101
98
|
debounceMs: clean.debounceMs ?? instanceDefault.debounceMs,
|
|
102
99
|
maxRetries: clean.maxRetries ?? instanceDefault.maxRetries,
|
|
103
|
-
limboTimeoutMs: clean.limboTimeoutMs ?? instanceDefault.limboTimeoutMs,
|
|
104
100
|
};
|
|
105
101
|
}
|
|
@@ -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-Djl4krRr.js";import{E as O,B as R,C as he}from"./Surfaces-GzOkJJHQ.js";import{a as W,d as M,C as T,T as K}from"./Chip-B8UU8Zpr.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-COc2rsu6.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-Djl4krRr.js";import{B as R,S as te}from"./Surfaces-GzOkJJHQ.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-B8UU8Zpr.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
|
|