@edspencer/paddock 0.59.0 → 0.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/package.json +1 -1
  2. package/packages/server/dist/cli/args.d.ts +56 -0
  3. package/packages/server/dist/cli/args.js +159 -0
  4. package/packages/server/dist/cli/paddock.d.ts +1 -30
  5. package/packages/server/dist/cli/paddock.js +6 -146
  6. package/packages/server/package.json +1 -1
  7. package/packages/web/dist/assets/{InstanceConfigPage-Cli_WHsM.js → InstanceConfigPage-CAwSnyga.js} +1 -1
  8. package/packages/web/dist/assets/{MarkdownRenderer-BYK9nmr4.js → MarkdownRenderer-DpGpkMzG.js} +1 -1
  9. package/packages/web/dist/assets/{ProjectRedirect-DWcMpdZJ.js → ProjectRedirect-D1ipv4jr.js} +1 -1
  10. package/packages/web/dist/assets/{ProjectView-CvD9WQsW.js → ProjectView-BI1TtrOK.js} +3 -3
  11. package/packages/web/dist/assets/{ProjectsGrid-Bf2cx9-Z.js → ProjectsGrid-Dwngb-m1.js} +1 -1
  12. package/packages/web/dist/assets/{arc-CZ9CFd-g.js → arc-BZh6Z9_D.js} +1 -1
  13. package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-BzOXUlLu.js → architectureDiagram-3BPJPVTR-iCtJiW4k.js} +1 -1
  14. package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-Bnkcx-Fn.js → blockDiagram-GPEHLZMM-BeI9Wi0h.js} +1 -1
  15. package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-C-nqckPS.js → c4Diagram-AAUBKEIU-D_j2LKZ-.js} +1 -1
  16. package/packages/web/dist/assets/channel-DszBVZgr.js +2 -0
  17. package/packages/web/dist/assets/{chunk-2J33WTMH-jVn7J_5N.js → chunk-2J33WTMH-DRlfPROq.js} +1 -1
  18. package/packages/web/dist/assets/{chunk-4BX2VUAB-D5eys7Hi.js → chunk-4BX2VUAB-BMY66MLs.js} +1 -1
  19. package/packages/web/dist/assets/{chunk-55IACEB6-CqpdXIoL.js → chunk-55IACEB6-BAQ92trf.js} +1 -1
  20. package/packages/web/dist/assets/{chunk-727SXJPM-SQikk09l.js → chunk-727SXJPM-Dxgb_nNN.js} +1 -1
  21. package/packages/web/dist/assets/{chunk-AQP2D5EJ-rfBNpUwD.js → chunk-AQP2D5EJ-D5cqv3Jv.js} +1 -1
  22. package/packages/web/dist/assets/{chunk-FMBD7UC4-CnL0tA20.js → chunk-FMBD7UC4-BOEqxzyA.js} +1 -1
  23. package/packages/web/dist/assets/{chunk-ND2GUHAM-CZGi4swC.js → chunk-ND2GUHAM-CkTZgv_W.js} +1 -1
  24. package/packages/web/dist/assets/{chunk-QZHKN3VN-Du4WKuCj.js → chunk-QZHKN3VN-DIr8TL7M.js} +1 -1
  25. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DuGqlnbT.js +2 -0
  26. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DuGqlnbT.js +2 -0
  27. package/packages/web/dist/assets/{core-LJ--cHnT.js → core-DyOZ2e1O.js} +1 -1
  28. package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-CEovKrYZ.js → cose-bilkent-S5V4N54A-D8Muyf4o.js} +1 -1
  29. package/packages/web/dist/assets/{dagre-BM42HDAG-jQhK8147.js → dagre-BM42HDAG-B_EUbUz6.js} +1 -1
  30. package/packages/web/dist/assets/{diagram-2AECGRRQ-BmiauiWQ.js → diagram-2AECGRRQ-DpAM0K6Q.js} +1 -1
  31. package/packages/web/dist/assets/{diagram-5GNKFQAL-VYdTkqGm.js → diagram-5GNKFQAL-Dhs9RMKk.js} +1 -1
  32. package/packages/web/dist/assets/{diagram-KO2AKTUF-DcOTKmwo.js → diagram-KO2AKTUF-LBeTHReu.js} +1 -1
  33. package/packages/web/dist/assets/{diagram-LMA3HP47-DaehIKcD.js → diagram-LMA3HP47-CxboRwue.js} +1 -1
  34. package/packages/web/dist/assets/{diagram-OG6HWLK6-DTqk6D4N.js → diagram-OG6HWLK6-BK_P-OSi.js} +1 -1
  35. package/packages/web/dist/assets/{erDiagram-TEJ5UH35-Dj4rI8M1.js → erDiagram-TEJ5UH35-CPSKRHI5.js} +1 -1
  36. package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-D0FWSohH.js → flowDiagram-I6XJVG4X-CbUumAP5.js} +1 -1
  37. package/packages/web/dist/assets/{format-CgkZTf5F.js → format-DDL0Q7H2.js} +1 -1
  38. package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-DgaRh12R.js → ganttDiagram-6RSMTGT7-l-p25ckA.js} +1 -1
  39. package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-5qiry4ao.js → gitGraphDiagram-PVQCEYII-i8kDIgga.js} +1 -1
  40. package/packages/web/dist/assets/{index-CcYeBUNk.js → index-DKDgTDXa.js} +2 -2
  41. package/packages/web/dist/assets/{infoDiagram-5YYISTIA-CZmDwouw.js → infoDiagram-5YYISTIA-CbyLnHIe.js} +1 -1
  42. package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-knkHstDa.js → ishikawaDiagram-YF4QCWOH-C1_3z8-9.js} +1 -1
  43. package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-ByfdmIVy.js → journeyDiagram-JHISSGLW-BzyAtQdy.js} +1 -1
  44. package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-DSzly2xb.js → kanban-definition-UN3LZRKU-Fp2VVm-b.js} +1 -1
  45. package/packages/web/dist/assets/{linear-BX6qYIpB.js → linear-6ZKEeWQ5.js} +1 -1
  46. package/packages/web/dist/assets/{mermaid.core-BXPz6_-1.js → mermaid.core-Dorg4Dl2.js} +4 -4
  47. package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-fzfZWy91.js → mindmap-definition-RKZ34NQL-Bk4Ax0bI.js} +1 -1
  48. package/packages/web/dist/assets/{pieDiagram-4H26LBE5-M99j1K9t.js → pieDiagram-4H26LBE5-DoTn5jHm.js} +1 -1
  49. package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-B7fKq1ce.js → quadrantDiagram-W4KKPZXB-ClNmIKCj.js} +1 -1
  50. package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-xCBFrXav.js → requirementDiagram-4Y6WPE33-DMF7i5KW.js} +1 -1
  51. package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-Dp9KLMhd.js → sankeyDiagram-5OEKKPKP-C-ALbVLg.js} +1 -1
  52. package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-CNNVWpta.js → sequenceDiagram-3UESZ5HK-DsUxj8IQ.js} +1 -1
  53. package/packages/web/dist/assets/{stateDiagram-AJRCARHV-CzKRXREb.js → stateDiagram-AJRCARHV-OCZiRRsz.js} +1 -1
  54. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BwcJspgG.js +2 -0
  55. package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-DfvQTe5J.js → timeline-definition-PNZ67QCA-5ifjxa-s.js} +1 -1
  56. package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-2PBM01eq.js → vennDiagram-CIIHVFJN-Bqvqpot5.js} +1 -1
  57. package/packages/web/dist/assets/{wardley-L42UT6IY-DC1EIjci.js → wardley-L42UT6IY-DwgnVd48.js} +1 -1
  58. package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-4kYoKkfS.js → wardleyDiagram-YWT4CUSO-F-VCH-oE.js} +1 -1
  59. package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-Bin8O1V8.js → xychartDiagram-2RQKCTM6-L4q6oV_7.js} +1 -1
  60. package/packages/web/dist/index.html +1 -1
  61. package/packages/web/dist/sw.js +1 -1
  62. package/packages/web/dist/assets/channel-By51cUN7.js +0 -2
  63. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-sIDgFl-L.js +0 -2
  64. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-sIDgFl-L.js +0 -2
  65. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-LKJwobEd.js +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edspencer/paddock",
3
- "version": "0.59.0",
3
+ "version": "0.59.1",
4
4
  "description": "Project-first launchpad for Claude Code: server-hosted, persistent, resumable sessions organized by project.",
5
5
  "keywords": [
6
6
  "claude",
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pure argument parsing and message formatting for the `paddock` CLI.
3
+ *
4
+ * ## Why this is its own module
5
+ *
6
+ * These functions want unit tests, and the entrypoint they used to live in
7
+ * cannot be imported without running. The first attempt kept them in
8
+ * `paddock.ts` behind a run-directly guard:
9
+ *
10
+ * ```ts
11
+ * if (pathToFileURL(process.argv[1]).href === import.meta.url) main();
12
+ * ```
13
+ *
14
+ * **That guard shipped a silent no-op to npm.** npm installs a `bin` as a
15
+ * SYMLINK at `node_modules/.bin/paddock`, so `process.argv[1]` is the symlink
16
+ * path while `import.meta.url` is the module's realpath. They never match, the
17
+ * condition is always false, and `npx @edspencer/paddock` printed nothing and
18
+ * exited 0 — in 0.57.0, 0.58.0 and 0.59.0. It went unnoticed because the manual
19
+ * checks invoked `node <file>` directly, which is the one path where the guard
20
+ * does hold.
21
+ *
22
+ * `realpathSync(argv[1])` would fix that instance. Splitting the module removes
23
+ * the need for the guard entirely, so there is no condition left to get wrong on
24
+ * the next shim, platform or package manager. `paddock.ts` now always runs.
25
+ */
26
+ export interface CliOptions {
27
+ port?: string;
28
+ host?: string;
29
+ dataDir?: string;
30
+ here: boolean;
31
+ open: boolean;
32
+ verbose: boolean;
33
+ help: boolean;
34
+ version: boolean;
35
+ }
36
+ /** A usage error. Thrown rather than exiting, so parsing stays testable. */
37
+ export declare class CliError extends Error {
38
+ }
39
+ export declare const MIN_NODE_MAJOR = 22;
40
+ export declare function parseArgs(argv: string[]): CliOptions;
41
+ /**
42
+ * Why this Node is unusable, or `undefined` if it is fine.
43
+ *
44
+ * `engines` only warns by default, and the failure it eventually produces is an
45
+ * unexplained syntax error deep inside a dependency.
46
+ */
47
+ export declare function nodeVersionProblem(nodeVersion: string): string | undefined;
48
+ /**
49
+ * Translate a listen failure into something a human can act on.
50
+ *
51
+ * `EADDRINUSE` on 4000 is the likeliest first-run failure — a popular port and
52
+ * Paddock's own default — and Node's raw error names neither the port nor the
53
+ * flag that fixes it.
54
+ */
55
+ export declare function explainListenError(err: unknown, host: string, port: string): string;
56
+ export declare const USAGE = "paddock \u2014 run a Paddock instance locally\n\nUsage\n npx @edspencer/paddock [options]\n\nOptions\n -p, --port <port> HTTP/WS port (default 4000, or $PORT)\n --host <host> Bind address (default 127.0.0.1)\n -d, --data-dir <path> Projects + state (default ~/.paddock, or $PADDOCK_DATA_DIR)\n --here Open the CURRENT directory as the workspace (see below)\n -o, --open Open the app in your browser once it is listening\n --verbose Show the server's own logs (quiet by default)\n -v, --version Print the Paddock version and exit\n -h, --help Show this help\n\nOpening a directory (--here)\n Run `paddock --here` inside a project and Paddock opens THAT directory as its\n workspace: Claude works in your files, and any Claude Code sessions you already\n have for the directory are offered for import. It:\n\n \u00B7 creates .paddock/ in the directory for this workspace's own state\n \u00B7 creates .chats/ for transcripts, and adds both to .gitignore\n \u00B7 links ~/.claude/projects/<encoded-dir> at this workspace\n\n Once done, later runs in the same directory resume it \u2014 no flag needed.\n Without --here, Paddock never touches the directory you ran it from.\n\nCredentials\n Paddock drives Claude Code, so it needs Claude credentials in the\n environment: CLAUDE_CODE_OAUTH_TOKEN (Max/Pro) or ANTHROPIC_API_KEY (API\n billing). If you already use Claude Code on this machine, an existing login\n under ~/.claude is picked up automatically. Otherwise run `claude setup-token`.\n\nYour data\n Everything lives in one directory \u2014 ~/.paddock unless you pass --data-dir.\n Projects, chat transcripts and settings all persist there between runs. Move\n that directory to move your instance; delete it to start over. Nothing is\n stored anywhere else.\n\nNotes\n Binds loopback with authentication disabled, which is safe for a laptop. To\n expose it on a network, set PADDOCK_AUTH_MODE first \u2014 Paddock refuses to bind\n a routable interface wide open. See AUTH.md.\n\nDocs: https://github.com/edspencer/paddock";
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Pure argument parsing and message formatting for the `paddock` CLI.
3
+ *
4
+ * ## Why this is its own module
5
+ *
6
+ * These functions want unit tests, and the entrypoint they used to live in
7
+ * cannot be imported without running. The first attempt kept them in
8
+ * `paddock.ts` behind a run-directly guard:
9
+ *
10
+ * ```ts
11
+ * if (pathToFileURL(process.argv[1]).href === import.meta.url) main();
12
+ * ```
13
+ *
14
+ * **That guard shipped a silent no-op to npm.** npm installs a `bin` as a
15
+ * SYMLINK at `node_modules/.bin/paddock`, so `process.argv[1]` is the symlink
16
+ * path while `import.meta.url` is the module's realpath. They never match, the
17
+ * condition is always false, and `npx @edspencer/paddock` printed nothing and
18
+ * exited 0 — in 0.57.0, 0.58.0 and 0.59.0. It went unnoticed because the manual
19
+ * checks invoked `node <file>` directly, which is the one path where the guard
20
+ * does hold.
21
+ *
22
+ * `realpathSync(argv[1])` would fix that instance. Splitting the module removes
23
+ * the need for the guard entirely, so there is no condition left to get wrong on
24
+ * the next shim, platform or package manager. `paddock.ts` now always runs.
25
+ */
26
+ /** A usage error. Thrown rather than exiting, so parsing stays testable. */
27
+ export class CliError extends Error {
28
+ }
29
+ export const MIN_NODE_MAJOR = 22;
30
+ export function parseArgs(argv) {
31
+ const opts = {
32
+ here: false,
33
+ open: false,
34
+ verbose: false,
35
+ help: false,
36
+ version: false,
37
+ };
38
+ for (let i = 0; i < argv.length; i++) {
39
+ const arg = argv[i];
40
+ const next = () => {
41
+ const v = argv[++i];
42
+ if (v === undefined)
43
+ throw new CliError(`${arg} needs a value`);
44
+ return v;
45
+ };
46
+ switch (arg) {
47
+ case "-p":
48
+ case "--port":
49
+ opts.port = next();
50
+ break;
51
+ case "--host":
52
+ opts.host = next();
53
+ break;
54
+ case "-d":
55
+ case "--data-dir":
56
+ opts.dataDir = next();
57
+ break;
58
+ case "--here":
59
+ opts.here = true;
60
+ break;
61
+ case "-o":
62
+ case "--open":
63
+ opts.open = true;
64
+ break;
65
+ case "--verbose":
66
+ opts.verbose = true;
67
+ break;
68
+ case "-h":
69
+ case "--help":
70
+ opts.help = true;
71
+ break;
72
+ case "-v":
73
+ case "--version":
74
+ opts.version = true;
75
+ break;
76
+ default:
77
+ throw new CliError(`unknown option: ${arg}\nRun \`paddock --help\` for usage.`);
78
+ }
79
+ }
80
+ return opts;
81
+ }
82
+ /**
83
+ * Why this Node is unusable, or `undefined` if it is fine.
84
+ *
85
+ * `engines` only warns by default, and the failure it eventually produces is an
86
+ * unexplained syntax error deep inside a dependency.
87
+ */
88
+ export function nodeVersionProblem(nodeVersion) {
89
+ const major = Number(nodeVersion.split(".")[0]);
90
+ if (!Number.isFinite(major) || major >= MIN_NODE_MAJOR)
91
+ return undefined;
92
+ return (`Node ${nodeVersion} is too old — Paddock needs Node ${MIN_NODE_MAJOR}+.\n` +
93
+ `Upgrade Node, then re-run. (nodejs.org, or \`nvm install ${MIN_NODE_MAJOR}\`)`);
94
+ }
95
+ /**
96
+ * Translate a listen failure into something a human can act on.
97
+ *
98
+ * `EADDRINUSE` on 4000 is the likeliest first-run failure — a popular port and
99
+ * Paddock's own default — and Node's raw error names neither the port nor the
100
+ * flag that fixes it.
101
+ */
102
+ export function explainListenError(err, host, port) {
103
+ const code = err?.code;
104
+ if (code === "EADDRINUSE") {
105
+ return (`port ${port} is already in use.\n` +
106
+ `Something else is listening on ${host}:${port} — possibly another Paddock.\n` +
107
+ `Pick a different port: paddock --port ${Number(port) + 1}`);
108
+ }
109
+ if (code === "EACCES") {
110
+ return (`not allowed to bind ${host}:${port}.\n` +
111
+ `Ports below 1024 need elevated privileges — use a higher one: paddock --port 4000`);
112
+ }
113
+ return String(err?.message ?? err);
114
+ }
115
+ export const USAGE = `paddock — run a Paddock instance locally
116
+
117
+ Usage
118
+ npx @edspencer/paddock [options]
119
+
120
+ Options
121
+ -p, --port <port> HTTP/WS port (default 4000, or $PORT)
122
+ --host <host> Bind address (default 127.0.0.1)
123
+ -d, --data-dir <path> Projects + state (default ~/.paddock, or $PADDOCK_DATA_DIR)
124
+ --here Open the CURRENT directory as the workspace (see below)
125
+ -o, --open Open the app in your browser once it is listening
126
+ --verbose Show the server's own logs (quiet by default)
127
+ -v, --version Print the Paddock version and exit
128
+ -h, --help Show this help
129
+
130
+ Opening a directory (--here)
131
+ Run \`paddock --here\` inside a project and Paddock opens THAT directory as its
132
+ workspace: Claude works in your files, and any Claude Code sessions you already
133
+ have for the directory are offered for import. It:
134
+
135
+ · creates .paddock/ in the directory for this workspace's own state
136
+ · creates .chats/ for transcripts, and adds both to .gitignore
137
+ · links ~/.claude/projects/<encoded-dir> at this workspace
138
+
139
+ Once done, later runs in the same directory resume it — no flag needed.
140
+ Without --here, Paddock never touches the directory you ran it from.
141
+
142
+ Credentials
143
+ Paddock drives Claude Code, so it needs Claude credentials in the
144
+ environment: CLAUDE_CODE_OAUTH_TOKEN (Max/Pro) or ANTHROPIC_API_KEY (API
145
+ billing). If you already use Claude Code on this machine, an existing login
146
+ under ~/.claude is picked up automatically. Otherwise run \`claude setup-token\`.
147
+
148
+ Your data
149
+ Everything lives in one directory — ~/.paddock unless you pass --data-dir.
150
+ Projects, chat transcripts and settings all persist there between runs. Move
151
+ that directory to move your instance; delete it to start over. Nothing is
152
+ stored anywhere else.
153
+
154
+ Notes
155
+ Binds loopback with authentication disabled, which is safe for a laptop. To
156
+ expose it on a network, set PADDOCK_AUTH_MODE first — Paddock refuses to bind
157
+ a routable interface wide open. See AUTH.md.
158
+
159
+ Docs: https://github.com/edspencer/paddock`;
@@ -1,31 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export interface CliOptions {
3
- port?: string;
4
- host?: string;
5
- dataDir?: string;
6
- here: boolean;
7
- open: boolean;
8
- verbose: boolean;
9
- help: boolean;
10
- version: boolean;
11
- }
12
- /** A usage error. Thrown rather than exiting, so `parseArgs` stays testable. */
13
- export declare class CliError extends Error {
14
- }
15
- export declare function parseArgs(argv: string[]): CliOptions;
16
- /**
17
- * Why this Node is unusable, or `undefined` if it is fine.
18
- *
19
- * Split from the exit so it can be tested. `engines` only warns by default, and
20
- * the failure it eventually produces is an unexplained syntax error deep inside
21
- * a dependency — which is nobody's idea of a first-run experience.
22
- */
23
- export declare function nodeVersionProblem(nodeVersion: string): string | undefined;
24
- /**
25
- * Translate a listen failure into something a human can act on.
26
- *
27
- * `EADDRINUSE` on 4000 is the single most likely first-run failure — it is a
28
- * popular port and Paddock's own default — and Node's raw error names neither
29
- * the port nor the flag that fixes it.
30
- */
31
- export declare function explainListenError(err: unknown, host: string, port: string): string;
2
+ export {};
@@ -22,9 +22,9 @@ import fs from "node:fs";
22
22
  import os from "node:os";
23
23
  import path from "node:path";
24
24
  import { spawn } from "node:child_process";
25
- import { fileURLToPath, pathToFileURL } from "node:url";
25
+ import { fileURLToPath } from "node:url";
26
26
  import { HERE_MARKER, isHereWorkspace, countClaudeSessions, ensureGitignored } from "./here.js";
27
- const MIN_NODE_MAJOR = 22;
27
+ import { CliError, USAGE, parseArgs, nodeVersionProblem, explainListenError, } from "./args.js";
28
28
  /** This module's own directory: `<…>/packages/server/dist/cli`. */
29
29
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
30
30
  /**
@@ -53,61 +53,6 @@ function findUp(rel) {
53
53
  }
54
54
  /** Nearest ancestor holding a `package.json` — `packages/server` in both layouts. */
55
55
  const packageRoot = findUp("package.json") ?? path.resolve(moduleDir, "../..");
56
- /** A usage error. Thrown rather than exiting, so `parseArgs` stays testable. */
57
- export class CliError extends Error {
58
- }
59
- export function parseArgs(argv) {
60
- const opts = {
61
- here: false,
62
- open: false,
63
- verbose: false,
64
- help: false,
65
- version: false,
66
- };
67
- for (let i = 0; i < argv.length; i++) {
68
- const arg = argv[i];
69
- const next = () => {
70
- const v = argv[++i];
71
- if (v === undefined)
72
- throw new CliError(`${arg} needs a value`);
73
- return v;
74
- };
75
- switch (arg) {
76
- case "-p":
77
- case "--port":
78
- opts.port = next();
79
- break;
80
- case "--host":
81
- opts.host = next();
82
- break;
83
- case "-d":
84
- case "--data-dir":
85
- opts.dataDir = next();
86
- break;
87
- case "--here":
88
- opts.here = true;
89
- break;
90
- case "-o":
91
- case "--open":
92
- opts.open = true;
93
- break;
94
- case "--verbose":
95
- opts.verbose = true;
96
- break;
97
- case "-h":
98
- case "--help":
99
- opts.help = true;
100
- break;
101
- case "-v":
102
- case "--version":
103
- opts.version = true;
104
- break;
105
- default:
106
- throw new CliError(`unknown option: ${arg}\nRun \`paddock --help\` for usage.`);
107
- }
108
- }
109
- return opts;
110
- }
111
56
  function fail(message) {
112
57
  console.error(`paddock: ${message}`);
113
58
  process.exit(1);
@@ -121,65 +66,6 @@ function readVersion() {
121
66
  return "unknown";
122
67
  }
123
68
  }
124
- const USAGE = `paddock — run a Paddock instance locally
125
-
126
- Usage
127
- npx @edspencer/paddock [options]
128
-
129
- Options
130
- -p, --port <port> HTTP/WS port (default 4000, or $PORT)
131
- --host <host> Bind address (default 127.0.0.1)
132
- -d, --data-dir <path> Projects + state (default ~/.paddock, or $PADDOCK_DATA_DIR)
133
- --here Open the CURRENT directory as the workspace (see below)
134
- -o, --open Open the app in your browser once it is listening
135
- --verbose Show the server's own logs (quiet by default)
136
- -v, --version Print the Paddock version and exit
137
- -h, --help Show this help
138
-
139
- Opening a directory (--here)
140
- Run \`paddock --here\` inside a project and Paddock opens THAT directory as its
141
- workspace: Claude works in your files, and any Claude Code sessions you already
142
- have for the directory are offered for import. It:
143
-
144
- · creates .paddock/ in the directory for this workspace's own state
145
- · creates .chats/ for transcripts, and adds both to .gitignore
146
- · links ~/.claude/projects/<encoded-dir> at this workspace
147
-
148
- Once done, later runs in the same directory resume it — no flag needed.
149
- Without --here, Paddock never touches the directory you ran it from.
150
-
151
- Credentials
152
- Paddock drives Claude Code, so it needs Claude credentials in the
153
- environment: CLAUDE_CODE_OAUTH_TOKEN (Max/Pro) or ANTHROPIC_API_KEY (API
154
- billing). If you already use Claude Code on this machine, an existing login
155
- under ~/.claude is picked up automatically. Otherwise run \`claude setup-token\`.
156
-
157
- Your data
158
- Everything lives in one directory — ~/.paddock unless you pass --data-dir.
159
- Projects, chat transcripts and settings all persist there between runs. Move
160
- that directory to move your instance; delete it to start over. Nothing is
161
- stored anywhere else.
162
-
163
- Notes
164
- Binds loopback with authentication disabled, which is safe for a laptop. To
165
- expose it on a network, set PADDOCK_AUTH_MODE first — Paddock refuses to bind
166
- a routable interface wide open. See AUTH.md.
167
-
168
- Docs: https://github.com/edspencer/paddock`;
169
- /**
170
- * Why this Node is unusable, or `undefined` if it is fine.
171
- *
172
- * Split from the exit so it can be tested. `engines` only warns by default, and
173
- * the failure it eventually produces is an unexplained syntax error deep inside
174
- * a dependency — which is nobody's idea of a first-run experience.
175
- */
176
- export function nodeVersionProblem(nodeVersion) {
177
- const major = Number(nodeVersion.split(".")[0]);
178
- if (!Number.isFinite(major) || major >= MIN_NODE_MAJOR)
179
- return undefined;
180
- return (`Node ${nodeVersion} is too old — Paddock needs Node ${MIN_NODE_MAJOR}+.\n` +
181
- `Upgrade Node, then re-run. (nodejs.org, or \`nvm install ${MIN_NODE_MAJOR}\`)`);
182
- }
183
69
  /**
184
70
  * Put our bundled `claude` on PATH for child processes.
185
71
  *
@@ -308,26 +194,6 @@ function openBrowser(url) {
308
194
  /* as above */
309
195
  }
310
196
  }
311
- /**
312
- * Translate a listen failure into something a human can act on.
313
- *
314
- * `EADDRINUSE` on 4000 is the single most likely first-run failure — it is a
315
- * popular port and Paddock's own default — and Node's raw error names neither
316
- * the port nor the flag that fixes it.
317
- */
318
- export function explainListenError(err, host, port) {
319
- const code = err?.code;
320
- if (code === "EADDRINUSE") {
321
- return (`port ${port} is already in use.\n` +
322
- `Something else is listening on ${host}:${port} — possibly another Paddock.\n` +
323
- `Pick a different port: paddock --port ${Number(port) + 1}`);
324
- }
325
- if (code === "EACCES") {
326
- return (`not allowed to bind ${host}:${port}.\n` +
327
- `Ports below 1024 need elevated privileges — use a higher one: paddock --port 4000`);
328
- }
329
- return String(err?.message ?? err);
330
- }
331
197
  async function main() {
332
198
  let opts;
333
199
  try {
@@ -433,13 +299,7 @@ async function main() {
433
299
  if (opts.open)
434
300
  openBrowser(url);
435
301
  }
436
- // Run only when executed directly, so the unit tests can import the pure parts.
437
- // `pathToFileURL`, not `"file://" + argv[1]`: the naive concatenation breaks on
438
- // any path containing a space or non-ASCII character — the same percent-encoding
439
- // trap as #636.
440
- if (process.argv[1] !== undefined && pathToFileURL(process.argv[1]).href === import.meta.url) {
441
- main().catch((err) => {
442
- console.error("fatal:", err);
443
- process.exit(1);
444
- });
445
- }
302
+ main().catch((err) => {
303
+ console.error("fatal:", err);
304
+ process.exit(1);
305
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paddock/server",
3
- "version": "0.59.0",
3
+ "version": "0.59.1",
4
4
  "private": true,
5
5
  "type": "module"
6
6
  }
@@ -1,2 +1,2 @@
1
- import{r as o,b as f,j as e,A as b,k as E,l as A,m as O,M as F,n as I}from"./index-CcYeBUNk.js";function $(){const[t,s]=o.useState(null),[l,i]=o.useState(!0),[r,c]=o.useState(null),[d,m]=o.useState({}),[h,k]=o.useState(!1),[j,p]=o.useState(null),[N,u]=o.useState(!1);o.useEffect(()=>{let a=!0;return i(!0),f.getInstanceConfig().then(n=>{a&&(s(n),c(null))}).catch(n=>a&&c(n instanceof Error?n.message:String(n))).finally(()=>a&&i(!1)),()=>{a=!1}},[]);const v=(a,n)=>{u(!1),p(null),m(g=>({...g,[a]:n}))},S=a=>Object.prototype.hasOwnProperty.call(d,a.key)?d[a.key]:a.value,y=o.useMemo(()=>t?t.groups.flatMap(a=>a.fields):[],[t]),x=o.useMemo(()=>y.filter(a=>a.editable&&!a.envOverridden).filter(a=>Object.prototype.hasOwnProperty.call(d,a.key)).filter(a=>!B(d[a.key],a.value)).map(a=>a.key),[y,d]),w=async()=>{if(x.length===0)return;const a={};for(const n of x)a[n]=d[n];k(!0),p(null);try{await f.updateInstanceConfig(a);const n=await f.getInstanceConfig();s(n),m({}),u(!0)}catch(n){p(n instanceof A||n instanceof Error?n.message:String(n))}finally{k(!1)}},C=()=>{m({}),p(null),u(!1)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"min-h-0 flex-1 overflow-y-auto px-4 py-5 sm:px-6",children:e.jsxs("div",{className:"mx-auto max-w-2xl",children:[e.jsx(L,{saved:N,configPath:t==null?void 0:t.configPath}),l&&e.jsx("p",{className:"text-sm text-paddock-500",children:"Loading…"}),r&&e.jsxs("p",{className:"text-sm text-red-600 dark:text-red-400",role:"alert",children:["Failed to load settings: ",r]}),t&&t.groups.map(a=>e.jsx(M,{title:a.label,description:a.description,children:e.jsx("div",{className:"grid grid-cols-1 gap-4",children:a.fields.map(n=>e.jsx(P,{field:n,value:S(n),onChange:g=>v(n.key,g)},n.key))})},a.id))]})}),t&&e.jsxs("footer",{className:"flex items-center gap-3 border-t border-paddock-200 px-4 py-3 dark:border-paddock-800 sm:px-6",children:[j&&e.jsxs("span",{className:"flex items-center gap-1.5 text-[13px] text-red-600 dark:text-red-400",role:"alert",children:[e.jsx(b,{width:14,height:14,className:"shrink-0"}),j]}),e.jsx("span",{className:"ml-auto text-[12px] text-paddock-400",children:x.length>0?`${x.length} unsaved change${x.length===1?"":"s"}`:"No changes"}),e.jsx("button",{type:"button",className:"btn-subtle",onClick:C,disabled:x.length===0||h,children:"Reset"}),e.jsx("button",{type:"button",className:"btn-primary",onClick:w,disabled:x.length===0||h,children:h?"Saving…":"Save changes"})]})]})}function L({saved:t,configPath:s}){return e.jsxs("div",{role:"status",className:`mb-6 flex items-start gap-2 rounded-lg border px-3 py-2.5 text-[13px] leading-snug ${t?"border-emerald-300 bg-emerald-50 text-emerald-800 dark:border-emerald-700/60 dark:bg-emerald-900/20 dark:text-emerald-300":"border-amber-300 bg-amber-50 text-amber-800 dark:border-amber-700/60 dark:bg-amber-900/20 dark:text-amber-300"}`,children:[t?e.jsx(E,{width:15,height:15,className:"mt-0.5 shrink-0"}):e.jsx(b,{width:15,height:15,className:"mt-0.5 shrink-0"}),e.jsx("span",{children:t?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved to disk."})," These changes take effect only after the server restarts."]}):e.jsxs(e.Fragment,{children:["Changes here are written to ",e.jsx("code",{className:"font-mono text-[12px]",children:T(s)})," ","and take effect only after the server restarts — the running instance keeps its current config until then."]})})]})}function M({title:t,description:s,children:l}){return e.jsxs("section",{className:"mb-6",children:[e.jsx("h2",{className:"text-sm font-semibold uppercase tracking-wide text-paddock-500",children:t}),s&&e.jsx("p",{className:"mb-3 mt-0.5 text-[13px] text-paddock-500",children:s}),e.jsx("div",{className:`card ${s?"":"mt-2"}`,children:l})]})}function P({field:t,value:s,onChange:l}){const i=!t.editable||t.envOverridden,r=`cfg-${t.key}`;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("label",{htmlFor:i?void 0:r,className:"text-sm font-medium",children:[t.label,t.sensitive&&e.jsx("span",{className:"ml-1.5 align-middle text-[10px] font-semibold uppercase tracking-wide text-amber-600 dark:text-amber-400",children:"sensitive"})]}),t.type==="boolean"&&!i&&e.jsx("input",{id:r,type:"checkbox",className:"h-4 w-4 accent-accent",checked:!!s,onChange:c=>l(c.target.checked)})]}),t.help&&e.jsx("p",{className:"mt-0.5 text-[12px] leading-snug text-paddock-500",children:t.help}),i?e.jsx(V,{field:t,value:s}):t.type!=="boolean"&&e.jsx(R,{field:t,value:s,onChange:l,inputId:r}),t.envOverridden&&e.jsxs("p",{className:"mt-1 flex items-start gap-1.5 text-[12px] leading-snug text-amber-600 dark:text-amber-400",children:[e.jsx(b,{width:13,height:13,className:"mt-0.5 shrink-0"}),e.jsxs("span",{children:["Overridden by environment variable ",e.jsx("code",{className:"font-mono",children:t.envVar})," — edit that env var (and restart) to change it."]})]})]})}function R({field:t,value:s,onChange:l,inputId:i}){if(t.type==="enum")return e.jsx("select",{id:i,className:"input mt-1.5",value:String(s??""),onChange:r=>l(r.target.value),children:(t.enumValues??[]).map(r=>e.jsx("option",{value:r,children:r},r))});if(t.type==="number")return e.jsx("input",{id:i,type:"number",className:"input mt-1.5",value:s==null?"":String(s),placeholder:t.default===null?"default":String(t.default),onChange:r=>l(r.target.value===""?null:Number(r.target.value))});if(t.type==="text"){const r=s==null||s===t.default,c=s==null?String(t.default??""):String(s),d=typeof t.default=="string"&&!r;return e.jsxs("div",{className:"mt-1.5",children:[e.jsx("textarea",{id:i,className:"input min-h-[9rem] resize-y font-mono text-[12px] leading-relaxed",rows:10,spellCheck:!1,value:c,onChange:m=>l(m.target.value)}),e.jsxs("div",{className:"mt-1 flex items-center justify-between gap-3 text-[12px] text-paddock-500",children:[e.jsx("span",{children:r?"Using the built-in default.":s===""?"Empty — nothing will be appended.":`${c.length.toLocaleString()} characters.`}),d&&e.jsx("button",{type:"button",className:"shrink-0 underline underline-offset-2 hover:text-paddock-700 dark:hover:text-paddock-300",onClick:()=>l(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const r=Array.isArray(s)?s.join(", "):String(s??"");return e.jsx("input",{id:i,type:"text",className:"input mt-1.5",value:r,onChange:c=>l(c.target.value.split(",").map(d=>d.trim()).filter(Boolean))})}return e.jsx("input",{id:i,type:"text",className:"input mt-1.5",value:s==null?"":String(s),placeholder:t.default===null?"":String(t.default),onChange:r=>l(r.target.value)})}function V({field:t,value:s}){return e.jsx("div",{className:"mt-1.5 rounded-md border border-dashed border-paddock-300 bg-paddock-50 px-2.5 py-1.5 text-[13px] text-paddock-600 dark:border-paddock-700 dark:bg-paddock-900/40 dark:text-paddock-300",children:t.type==="boolean"?e.jsx("span",{className:"font-mono",children:s?"true":"false"}):s==null||s===""?e.jsx("span",{className:"italic text-paddock-400",children:t.type==="text"&&s===""?"(empty — nothing appended)":"(not set)"}):t.type==="text"?e.jsx("span",{className:"block max-h-64 overflow-y-auto whitespace-pre-wrap font-mono text-[12px] leading-relaxed",children:String(s)}):e.jsx("span",{className:"break-all font-mono",children:Array.isArray(s)?s.join(", "):String(s)})})}function B(t,s){return Array.isArray(t)&&Array.isArray(s)?t.length===s.length&&t.every((l,i)=>l===s[i]):t===s}function T(t){if(!t)return"paddock.config.yaml";const s=t.split("/");return s[s.length-1]||t}function z(){const t=O(),s=(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-paddock-200 px-3 pb-2.5 dark:border-paddock-800 sm:px-6 lg:py-4",children:[e.jsx("button",{type:"button",onClick:s,"aria-label":"Open menu",className:"btn-subtle -ml-1 shrink-0 px-2 py-1.5 lg:hidden",children:e.jsx(F,{width:20,height:20})}),e.jsx(I,{width:18,height:18,className:"shrink-0 text-paddock-400"}),e.jsx("h1",{className:"text-[15px] font-semibold tracking-tight",children:"Config"})]}),e.jsx($,{})]})}export{z as InstanceConfigPage};
1
+ import{r as o,b as f,j as e,A as b,k as E,l as A,m as O,M as F,n as I}from"./index-DKDgTDXa.js";function $(){const[t,s]=o.useState(null),[l,i]=o.useState(!0),[r,c]=o.useState(null),[d,m]=o.useState({}),[h,k]=o.useState(!1),[j,p]=o.useState(null),[N,u]=o.useState(!1);o.useEffect(()=>{let a=!0;return i(!0),f.getInstanceConfig().then(n=>{a&&(s(n),c(null))}).catch(n=>a&&c(n instanceof Error?n.message:String(n))).finally(()=>a&&i(!1)),()=>{a=!1}},[]);const v=(a,n)=>{u(!1),p(null),m(g=>({...g,[a]:n}))},S=a=>Object.prototype.hasOwnProperty.call(d,a.key)?d[a.key]:a.value,y=o.useMemo(()=>t?t.groups.flatMap(a=>a.fields):[],[t]),x=o.useMemo(()=>y.filter(a=>a.editable&&!a.envOverridden).filter(a=>Object.prototype.hasOwnProperty.call(d,a.key)).filter(a=>!B(d[a.key],a.value)).map(a=>a.key),[y,d]),w=async()=>{if(x.length===0)return;const a={};for(const n of x)a[n]=d[n];k(!0),p(null);try{await f.updateInstanceConfig(a);const n=await f.getInstanceConfig();s(n),m({}),u(!0)}catch(n){p(n instanceof A||n instanceof Error?n.message:String(n))}finally{k(!1)}},C=()=>{m({}),p(null),u(!1)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"min-h-0 flex-1 overflow-y-auto px-4 py-5 sm:px-6",children:e.jsxs("div",{className:"mx-auto max-w-2xl",children:[e.jsx(L,{saved:N,configPath:t==null?void 0:t.configPath}),l&&e.jsx("p",{className:"text-sm text-paddock-500",children:"Loading…"}),r&&e.jsxs("p",{className:"text-sm text-red-600 dark:text-red-400",role:"alert",children:["Failed to load settings: ",r]}),t&&t.groups.map(a=>e.jsx(M,{title:a.label,description:a.description,children:e.jsx("div",{className:"grid grid-cols-1 gap-4",children:a.fields.map(n=>e.jsx(P,{field:n,value:S(n),onChange:g=>v(n.key,g)},n.key))})},a.id))]})}),t&&e.jsxs("footer",{className:"flex items-center gap-3 border-t border-paddock-200 px-4 py-3 dark:border-paddock-800 sm:px-6",children:[j&&e.jsxs("span",{className:"flex items-center gap-1.5 text-[13px] text-red-600 dark:text-red-400",role:"alert",children:[e.jsx(b,{width:14,height:14,className:"shrink-0"}),j]}),e.jsx("span",{className:"ml-auto text-[12px] text-paddock-400",children:x.length>0?`${x.length} unsaved change${x.length===1?"":"s"}`:"No changes"}),e.jsx("button",{type:"button",className:"btn-subtle",onClick:C,disabled:x.length===0||h,children:"Reset"}),e.jsx("button",{type:"button",className:"btn-primary",onClick:w,disabled:x.length===0||h,children:h?"Saving…":"Save changes"})]})]})}function L({saved:t,configPath:s}){return e.jsxs("div",{role:"status",className:`mb-6 flex items-start gap-2 rounded-lg border px-3 py-2.5 text-[13px] leading-snug ${t?"border-emerald-300 bg-emerald-50 text-emerald-800 dark:border-emerald-700/60 dark:bg-emerald-900/20 dark:text-emerald-300":"border-amber-300 bg-amber-50 text-amber-800 dark:border-amber-700/60 dark:bg-amber-900/20 dark:text-amber-300"}`,children:[t?e.jsx(E,{width:15,height:15,className:"mt-0.5 shrink-0"}):e.jsx(b,{width:15,height:15,className:"mt-0.5 shrink-0"}),e.jsx("span",{children:t?e.jsxs(e.Fragment,{children:[e.jsx("strong",{children:"Saved to disk."})," These changes take effect only after the server restarts."]}):e.jsxs(e.Fragment,{children:["Changes here are written to ",e.jsx("code",{className:"font-mono text-[12px]",children:T(s)})," ","and take effect only after the server restarts — the running instance keeps its current config until then."]})})]})}function M({title:t,description:s,children:l}){return e.jsxs("section",{className:"mb-6",children:[e.jsx("h2",{className:"text-sm font-semibold uppercase tracking-wide text-paddock-500",children:t}),s&&e.jsx("p",{className:"mb-3 mt-0.5 text-[13px] text-paddock-500",children:s}),e.jsx("div",{className:`card ${s?"":"mt-2"}`,children:l})]})}function P({field:t,value:s,onChange:l}){const i=!t.editable||t.envOverridden,r=`cfg-${t.key}`;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("label",{htmlFor:i?void 0:r,className:"text-sm font-medium",children:[t.label,t.sensitive&&e.jsx("span",{className:"ml-1.5 align-middle text-[10px] font-semibold uppercase tracking-wide text-amber-600 dark:text-amber-400",children:"sensitive"})]}),t.type==="boolean"&&!i&&e.jsx("input",{id:r,type:"checkbox",className:"h-4 w-4 accent-accent",checked:!!s,onChange:c=>l(c.target.checked)})]}),t.help&&e.jsx("p",{className:"mt-0.5 text-[12px] leading-snug text-paddock-500",children:t.help}),i?e.jsx(V,{field:t,value:s}):t.type!=="boolean"&&e.jsx(R,{field:t,value:s,onChange:l,inputId:r}),t.envOverridden&&e.jsxs("p",{className:"mt-1 flex items-start gap-1.5 text-[12px] leading-snug text-amber-600 dark:text-amber-400",children:[e.jsx(b,{width:13,height:13,className:"mt-0.5 shrink-0"}),e.jsxs("span",{children:["Overridden by environment variable ",e.jsx("code",{className:"font-mono",children:t.envVar})," — edit that env var (and restart) to change it."]})]})]})}function R({field:t,value:s,onChange:l,inputId:i}){if(t.type==="enum")return e.jsx("select",{id:i,className:"input mt-1.5",value:String(s??""),onChange:r=>l(r.target.value),children:(t.enumValues??[]).map(r=>e.jsx("option",{value:r,children:r},r))});if(t.type==="number")return e.jsx("input",{id:i,type:"number",className:"input mt-1.5",value:s==null?"":String(s),placeholder:t.default===null?"default":String(t.default),onChange:r=>l(r.target.value===""?null:Number(r.target.value))});if(t.type==="text"){const r=s==null||s===t.default,c=s==null?String(t.default??""):String(s),d=typeof t.default=="string"&&!r;return e.jsxs("div",{className:"mt-1.5",children:[e.jsx("textarea",{id:i,className:"input min-h-[9rem] resize-y font-mono text-[12px] leading-relaxed",rows:10,spellCheck:!1,value:c,onChange:m=>l(m.target.value)}),e.jsxs("div",{className:"mt-1 flex items-center justify-between gap-3 text-[12px] text-paddock-500",children:[e.jsx("span",{children:r?"Using the built-in default.":s===""?"Empty — nothing will be appended.":`${c.length.toLocaleString()} characters.`}),d&&e.jsx("button",{type:"button",className:"shrink-0 underline underline-offset-2 hover:text-paddock-700 dark:hover:text-paddock-300",onClick:()=>l(null),children:"Restore default"})]})]})}if(t.type==="string-list"){const r=Array.isArray(s)?s.join(", "):String(s??"");return e.jsx("input",{id:i,type:"text",className:"input mt-1.5",value:r,onChange:c=>l(c.target.value.split(",").map(d=>d.trim()).filter(Boolean))})}return e.jsx("input",{id:i,type:"text",className:"input mt-1.5",value:s==null?"":String(s),placeholder:t.default===null?"":String(t.default),onChange:r=>l(r.target.value)})}function V({field:t,value:s}){return e.jsx("div",{className:"mt-1.5 rounded-md border border-dashed border-paddock-300 bg-paddock-50 px-2.5 py-1.5 text-[13px] text-paddock-600 dark:border-paddock-700 dark:bg-paddock-900/40 dark:text-paddock-300",children:t.type==="boolean"?e.jsx("span",{className:"font-mono",children:s?"true":"false"}):s==null||s===""?e.jsx("span",{className:"italic text-paddock-400",children:t.type==="text"&&s===""?"(empty — nothing appended)":"(not set)"}):t.type==="text"?e.jsx("span",{className:"block max-h-64 overflow-y-auto whitespace-pre-wrap font-mono text-[12px] leading-relaxed",children:String(s)}):e.jsx("span",{className:"break-all font-mono",children:Array.isArray(s)?s.join(", "):String(s)})})}function B(t,s){return Array.isArray(t)&&Array.isArray(s)?t.length===s.length&&t.every((l,i)=>l===s[i]):t===s}function T(t){if(!t)return"paddock.config.yaml";const s=t.split("/");return s[s.length-1]||t}function z(){const t=O(),s=(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-paddock-200 px-3 pb-2.5 dark:border-paddock-800 sm:px-6 lg:py-4",children:[e.jsx("button",{type:"button",onClick:s,"aria-label":"Open menu",className:"btn-subtle -ml-1 shrink-0 px-2 py-1.5 lg:hidden",children:e.jsx(F,{width:20,height:20})}),e.jsx(I,{width:18,height:18,className:"shrink-0 text-paddock-400"}),e.jsx("h1",{className:"text-[15px] font-semibold tracking-tight",children:"Config"})]}),e.jsx($,{})]})}export{z as InstanceConfigPage};
2
2