diff --git a/INSTALL_FOR_AGENTS.md b/INSTALL_FOR_AGENTS.md index 6934527..c787ec8 100644 --- a/INSTALL_FOR_AGENTS.md +++ b/INSTALL_FOR_AGENTS.md @@ -64,12 +64,19 @@ Two questions: 2. **Which folder syncs?** ALWAYS ask, and always ask with a named recommendation — never an open-ended "which folder and what scope?". Pick your recommendation with this rule, in order: + - **You know the project's name** (the paste prompt carries it, or the + user gave one): **recommend a folder of that name** — "create + `/` here and sync that", lowercased with spaces as + dashes. Folder name = project name is what makes every teammate's + checkout look the same and the hub links read right. - **You found a knowledge folder** (markdown-heavy, not source code — - `wiki/`, `docs/`, `notes/`, an Obsidian vault, or any folder that + `docs/`, `notes/`, an Obsidian vault, or any folder that looks like one whatever its name): recommend it. - - **You found none** (including when the folder is empty): - **recommend creating a dedicated subfolder**, and name it — - "create `wiki/` here and sync that". An empty folder is not + - **Neither** (no project name given, no knowledge folder, including + when the folder is empty): **recommend creating `shared/`** — + "create `shared/` here and sync that". `bdrive init shared` names the + new project after the folder, so the project is `shared` too, and + that pairing is the default for a fresh setup. An empty folder is not evidence that it is meant to be the knowledge folder, and the folder *not* being a git repo is not a reason to sync it whole — the recommendation is the same either way. The repo-root rule @@ -82,14 +89,15 @@ Two questions: Hard rule: **never mount a repo root bare.** The one sanctioned way to sync inside a repo without picking a single subfolder is to mount the - root *narrowed*: `bdrive init . --only wiki,docs`, which syncs only + root *narrowed*: `bdrive init . --only docs,notes`, which syncs only those subfolders. That is exactly how several sibling folders share one project — do not propose moving folders around to give them a common parent. Wait for the pick. - The shape to aim for: "I recommend creating `wiki/` here and syncing + The shape to aim for: "I recommend creating `shared/` here and syncing that. Alternatives: a different path, or this whole folder if you - mean it to be the knowledge folder itself. Which do you want?" + mean it to be the knowledge folder itself. Which do you want?" — with + `shared/` replaced by the project's name when you have one. **On Claude Code, ask with the AskUserQuestion tool** rather than plain prose — one question, header "Sync folder", your recommendation @@ -97,12 +105,12 @@ Two questions: The user picks instead of typing a path. Every other agent: prose. Executing the pick — **the mount is always exactly the folder you name.** -`bdrive init wiki --project ` makes ./wiki the project, so the +`bdrive init shared --project ` makes ./shared the project, so the project's files land inside it. There is no flag that re-roots a mount somewhere else. Syncing only part of a folder is `--only`, which narrows -a mount without moving it: `bdrive init . --only wiki,docs` keeps the +a mount without moving it: `bdrive init . --only docs,notes` keeps the mount at `.` and writes `.bdriveignore` rules so only those subfolders -sync (their paths keep the `wiki/` prefix on the hub, which is what +sync (their paths keep the `docs/` prefix on the hub, which is what teammates then see). **Hard gate: do not run `bdrive init` until the user has answered @@ -123,12 +131,15 @@ with `command -v bdrive` or `bdrive --version`: every extra command is another permission prompt, and if the binary is missing this one says so. ```sh -bdrive init wiki --project --server --yes # ./wiki is the project -bdrive init . --name --only wiki,docs --yes # this folder, only those subfolders sync +bdrive init --project --server --yes # that subfolder is the project +bdrive init shared --yes # fresh setup: ./shared, project "shared" +bdrive init . --name --only docs,notes --yes # this folder, only those subfolders sync ``` Drop `--server` when the user gave no hub URL (BearDrive Cloud is the -default), and `--project`/`--name` follow the answer to question 1. +default), and `--project`/`--name` follow the answer to question 1 — with +no name given, `bdrive init shared` names the project after the folder, +so no `--name` is needed. **Run one command per shell call.** Never chain with `&&`, `;` or a pipe: a compound command needs approval for each part, so chaining multiplies the @@ -194,7 +205,11 @@ page shows it pre-filled): ``` Follow https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md -to set up BearDrive project on . Ask me which folder to sync. +to set up BearDrive project on . Ask me which folder to +sync (the project is named ""). ``` +The project name is in the prompt so the agent can recommend a folder of the +same name; without it, the recommendation is `shared/`. + On BearDrive Cloud, drop `on ` — login defaults to beardrive.ai. diff --git a/README.md b/README.md index a484b96..ce3e267 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ $ bdrive login https://your-hub # once per device — self-host a hub in ~10 m $ cd ~/workspace && bdrive init initialized /Users/snow/workspace server: https://your-hub - project: workspace (p-7f3a2c91) + project: workspace (7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4) claude hooks registered → /Users/snow/.claude/settings.json login: autostart registered → ~/Library/LaunchAgents/ai.beardrive.daemon.plist daemon: running (pid 55434, scan 3s, remote sync 10s) @@ -185,7 +185,7 @@ the project: ```jsonc // .bdrive/config.json { "id": "m-5a10b713", "volume": "notes", - "remote": "https://drive.example.com/p/p-7f3a2c91" } + "remote": "https://drive.example.com/p/7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4" } ``` Opting out is non-destructive: when a pattern starts matching an @@ -346,7 +346,7 @@ viewer URL, gated by sign-in and the project's org membership: ```console $ bdrive url wiki/report.html -https://drive.example.com/p-1a2b3c4d/wiki/report.html +https://drive.example.com/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d/wiki/report.html ``` It's computed locally (no network), always shows the latest synced @@ -464,9 +464,14 @@ in the folder you want synced and give it one paste: ``` Follow https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md -to set up BearDrive project on . Ask me which folder to sync. +to set up BearDrive project on . Ask me which folder to +sync (the project is named ""). ``` +Naming the project makes the agent recommend a folder of the same name, so +every teammate's checkout looks alike; with no project at all it recommends +`shared/` and names the new project `shared`. + The agent fetches [INSTALL_FOR_AGENTS.md](INSTALL_FOR_AGENTS.md) and follows it: install the CLI, then one `bdrive init` — which signs in (an approval link when there is no local browser), registers the sync hooks, and prints the diff --git a/cmd/bdrive/init.go b/cmd/bdrive/init.go index f992a84..eca1292 100644 --- a/cmd/bdrive/init.go +++ b/cmd/bdrive/init.go @@ -79,8 +79,8 @@ the folder was renamed or moved.`, Example: ` bdrive init # interactive bdrive init wiki # ./wiki is the project bdrive init ./notes --name shared-notes - bdrive init --project p-7f3a2c91 # connect an existing project - bdrive init --project p-7f3a2c91 --server https://hub.example.com + bdrive init --project 7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4 # connect an existing project + bdrive init --project 7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4 --server https://hub.example.com bdrive init . --only wiki,docs # this folder, but only ./wiki and ./docs sync bdrive init --yes # accept all defaults (no prompts)`, Args: cobra.MaximumNArgs(1), diff --git a/cmd/bdrive/share.go b/cmd/bdrive/share.go index 692aaa5..2a268ad 100644 --- a/cmd/bdrive/share.go +++ b/cmd/bdrive/share.go @@ -197,7 +197,9 @@ func findProject(dir string) (string, config.Project, error) { } } -var hubRemoteRe = regexp.MustCompile(`^(https?://[^/]+)/p/(p-[0-9a-f]{8})$`) +// Same loose id shape as remote/http.go: UUID today, legacy `p-xxxxxxxx` on +// older hubs — the hub validates, this only splits the URL. +var hubRemoteRe = regexp.MustCompile(`^(https?://[^/]+)/p/([A-Za-z0-9._-]{4,64})$`) // splitHubRemote splits an https://host/p/ remote into server + project. func splitHubRemote(remote string) (string, string, error) { diff --git a/go.mod b/go.mod index 5ddfefc..35b1fe1 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.32.25 github.com/aws/aws-sdk-go-v2/service/s3 v1.103.3 github.com/aws/smithy-go v1.27.2 + github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.10.0 github.com/mattn/go-isatty v0.0.20 github.com/spf13/cobra v1.10.2 @@ -56,7 +57,6 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.16 // indirect github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/internal/remote/http.go b/internal/remote/http.go index 666db06..677d8e7 100644 --- a/internal/remote/http.go +++ b/internal/remote/http.go @@ -36,7 +36,10 @@ type httpBackend struct { hc *http.Client } -var projectPathRe = regexp.MustCompile(`^/p/(p-[0-9a-f]{8})/?$`) +// The id is whatever the hub minted (a UUID today, `p-xxxxxxxx` on older +// hubs), so this only checks the shape of a URL segment — the hub is the +// authority on which ids exist. +var projectPathRe = regexp.MustCompile(`^/p/([A-Za-z0-9._-]{4,64})/?$`) func newHTTPBackend(raw string) (*httpBackend, error) { u, err := url.Parse(raw) diff --git a/internal/webapp/frontend/e2e/home.spec.ts b/internal/webapp/frontend/e2e/home.spec.ts index f78517c..be820c0 100644 --- a/internal/webapp/frontend/e2e/home.spec.ts +++ b/internal/webapp/frontend/e2e/home.spec.ts @@ -28,6 +28,8 @@ test("guide: one paste for every agent, one line of prose, details collapsed", a "Follow https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md", ); expect(prompt).toContain(`project ${pid} on http://localhost:8993`); + // The name rides along so the agent can recommend it as the folder name. + expect(prompt).toContain('the project is named "wiki"'); expect(prompt).not.toContain("brew install"); // Detail lives behind the two collapsed sections. await expect(page.locator(".gd-manual > summary")).toHaveText([ diff --git a/internal/webapp/frontend/e2e/hub.spec.ts b/internal/webapp/frontend/e2e/hub.spec.ts index e90af38..fbe68d4 100644 --- a/internal/webapp/frontend/e2e/hub.spec.ts +++ b/internal/webapp/frontend/e2e/hub.spec.ts @@ -25,7 +25,7 @@ test("deep link to a project resolves after reload", async ({ page }) => { test("unknown project id falls back to a real project", async ({ page }) => { await login(page); await page.goto("/p-00000000"); - await page.waitForURL(/\/p-[0-9a-f]{8}$/); + await page.waitForURL(/\/[0-9a-f-]{36}$/); await expect(page.locator("#project-select")).toContainText(/.+/); }); @@ -65,7 +65,7 @@ test("join link accepts an invite after sign-in", async ({ page, browser }) => { await p2.fill('input[name="password"]', PASSWORD); await p2.click("form button"); await expectToast(p2, "you joined"); - await p2.waitForURL(/\/p-[0-9a-f]{8}$/); // lands on the org's project + await p2.waitForURL(/\/[0-9a-f-]{36}$/); // lands on the org's project await ctx.close(); }); @@ -91,13 +91,13 @@ test("new project via the sidebar + modal", async ({ page }) => { await page.click("#projects .nav-add"); await page.fill(".modal-input", "scratch"); await page.click(".modal .pbtn"); - await page.waitForURL(/\/p-[0-9a-f]{8}$/); + await page.waitForURL(/\/[0-9a-f-]{36}$/); await expect(page.locator("#project-select")).toContainText("scratch"); // Open the switcher: both projects listed; picking one navigates. await page.click("#project-select"); await expect(page.getByRole("option", { name: "wiki" })).toBeVisible(); await page.getByRole("option", { name: "wiki" }).click(); - await page.waitForURL(/\/p-[0-9a-f]{8}$/); + await page.waitForURL(/\/[0-9a-f-]{36}$/); await expect(page.locator("#project-select")).toContainText("wiki"); await expectToast(page, "Created"); }); diff --git a/internal/webapp/frontend/src/components/ConnectGuide.tsx b/internal/webapp/frontend/src/components/ConnectGuide.tsx index e69e5e6..abc0800 100644 --- a/internal/webapp/frontend/src/components/ConnectGuide.tsx +++ b/internal/webapp/frontend/src/components/ConnectGuide.tsx @@ -6,8 +6,9 @@ import { projColor } from "./ProjectNav"; /* ---- project home guide ---- One paste sets up any coding agent: the prompt points at the canonical - INSTALL_FOR_AGENTS.md with this hub's URL and this project's id filled - in. The agent fetches the doc and handles every deviation — already + INSTALL_FOR_AGENTS.md with this hub's URL and this project's id and + name filled in (the name is what the agent recommends as the folder + name). The agent fetches the doc and handles every deviation — already installed, no Homebrew, sign-in, wrong folder — so the page itself stays to one line of prose; detail lives in the collapsed sections. */ @@ -22,7 +23,9 @@ export function ConnectGuide({ project }: { project: Project }) { project.id + " on " + origin + - ". Ask me which folder to sync."; + '. Ask me which folder to sync (the project is named "' + + project.name + + '").'; const manual = "brew install runbear-io/tap/beardrive" + "\nbdrive login " + diff --git a/internal/webapp/frontend/src/router.ts b/internal/webapp/frontend/src/router.ts index f4e9a88..07922ca 100644 --- a/internal/webapp/frontend/src/router.ts +++ b/internal/webapp/frontend/src/router.ts @@ -39,7 +39,7 @@ export interface Route { org?: string; // Billing (managed hubs) is hub-level like the org route; the URL comes // from /api/config's billing block. Reserved only in hub mode — project - // ids are p-… so the segment can't collide with a project. + // ids are UUIDs (or legacy p-…), so the segment can't collide with one. billing?: boolean; project?: string; path: string; diff --git a/internal/webapp/projects.go b/internal/webapp/projects.go index fea9a68..edfbff0 100644 --- a/internal/webapp/projects.go +++ b/internal/webapp/projects.go @@ -1,8 +1,6 @@ package webapp import ( - "crypto/rand" - "encoding/hex" "fmt" "regexp" "sort" @@ -10,6 +8,8 @@ import ( "sync" "time" "unicode/utf8" + + "github.com/google/uuid" ) // Project is one synced project hosted by this server. Its storage lives @@ -41,7 +41,12 @@ func (p Project) level() string { return p.Default } -var projectIDRe = regexp.MustCompile(`^p-[0-9a-f]{8}$`) +// projectIDRe is the authority on what a project id may look like: a UUID +// (what new projects get) or the legacy `p-xxxxxxxx` form hubs minted before +// — ids are permanent, so the old shape stays valid forever. Client-side +// parsers (remote/http.go, the share command) only check the loose shape and +// let the hub decide. +var projectIDRe = regexp.MustCompile(`^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|p-[0-9a-f]{8})$`) // iconRe validates the *shape* of an icon name only. The list of icons a // project may pick from lives in the frontend (shell.tsx's PROJECT_ICONS) — @@ -122,11 +127,7 @@ func (db *ProjectDB) GetOrCreate(name, org string) (Project, bool, error) { return p, false, nil } } - var buf [4]byte - if _, err := rand.Read(buf[:]); err != nil { - return Project{}, false, err - } - p := Project{ID: "p-" + hex.EncodeToString(buf[:]), Name: name, Org: org, Created: time.Now().UTC()} + p := Project{ID: uuid.NewString(), Name: name, Org: org, Created: time.Now().UTC()} db.byID[p.ID] = p if err := db.repo.Put(p); err != nil { delete(db.byID, p.ID) diff --git a/internal/webapp/static/assets/index-BCH1-K2y.js b/internal/webapp/static/assets/index-D89jvKKO.js similarity index 99% rename from internal/webapp/static/assets/index-BCH1-K2y.js rename to internal/webapp/static/assets/index-D89jvKKO.js index c245d0a..77c9976 100644 --- a/internal/webapp/static/assets/index-BCH1-K2y.js +++ b/internal/webapp/static/assets/index-D89jvKKO.js @@ -113,7 +113,7 @@ Error generating stack: `+c.message+` `)}x.write("payload.value = newResult;"),x.write("return payload;");const O=x.compile();return(A,z)=>O(b,A,z)};let l;const u=wu,d=!Wp.jitless,h=d&&C4.value,y=n.catchall;let v;e._zod.parse=(b,x)=>{v??(v=o.value);const C=b.value;return u(C)?d&&h&&x?.async===!1&&x.jitless!==!0?(l||(l=s(n.shape)),b=l(b,x),y?aC([],C,b,x,v,e):b):r(b,x):(b.issues.push({expected:"object",code:"invalid_type",input:C,inst:e}),b)}});function Nx(e,n,r,o){for(const l of e)if(l.issues.length===0)return n.value=l.value,n;const s=e.filter(l=>!Ma(l));return s.length===1?(n.value=s[0].value,s[0]):(n.issues.push({code:"invalid_union",input:n.value,inst:r,errors:e.map(l=>l.issues.map(u=>To(u,o,Ro())))}),n)}const c6=ue("$ZodUnion",(e,n)=>{Pt.init(e,n),dt(e._zod,"optin",()=>n.options.some(o=>o._zod.optin==="optional")?"optional":void 0),dt(e._zod,"optout",()=>n.options.some(o=>o._zod.optout==="optional")?"optional":void 0),dt(e._zod,"values",()=>{if(n.options.every(o=>o._zod.values))return new Set(n.options.flatMap(o=>Array.from(o._zod.values)))}),dt(e._zod,"pattern",()=>{if(n.options.every(o=>o._zod.pattern)){const o=n.options.map(s=>s._zod.pattern);return new RegExp(`^(${o.map(s=>ng(s.source)).join("|")})$`)}});const r=n.options.length===1?n.options[0]._zod.run:null;e._zod.parse=(o,s)=>{if(r)return r(o,s);let l=!1;const u=[];for(const d of n.options){const p=d._zod.run({value:o.value,issues:[]},s);if(p instanceof Promise)u.push(p),l=!0;else{if(p.issues.length===0)return p;u.push(p)}}return l?Promise.all(u).then(d=>Nx(d,o,e,s)):Nx(u,o,e,s)}}),u6=ue("$ZodIntersection",(e,n)=>{Pt.init(e,n),e._zod.parse=(r,o)=>{const s=r.value,l=n.left._zod.run({value:s,issues:[]},o),u=n.right._zod.run({value:s,issues:[]},o);return l instanceof Promise||u instanceof Promise?Promise.all([l,u]).then(([p,h])=>Dx(r,p,h)):Dx(r,l,u)}});function Vm(e,n){if(e===n)return{valid:!0,data:e};if(e instanceof Date&&n instanceof Date&&+e==+n)return{valid:!0,data:e};if(ll(e)&&ll(n)){const r=Object.keys(n),o=Object.keys(e).filter(l=>r.indexOf(l)!==-1),s={...e,...n};for(const l of o){const u=Vm(e[l],n[l]);if(!u.valid)return{valid:!1,mergeErrorPath:[l,...u.mergeErrorPath]};s[l]=u.data}return{valid:!0,data:s}}if(Array.isArray(e)&&Array.isArray(n)){if(e.length!==n.length)return{valid:!1,mergeErrorPath:[]};const r=[];for(let o=0;od.l&&d.r).map(([d])=>d);if(l.length&&s&&e.issues.push({...s,keys:l}),Ma(e))return e;const u=Vm(n.value,r.value);if(!u.valid)throw new Error(`Unmergable intersection. Error path: ${JSON.stringify(u.mergeErrorPath)}`);return e.value=u.data,e}const d6=ue("$ZodEnum",(e,n)=>{Pt.init(e,n);const r=Q_(n.entries),o=new Set(r);e._zod.values=o,e._zod.pattern=new RegExp(`^(${r.filter(s=>E4.has(typeof s)).map(s=>typeof s=="string"?ed(s):s.toString()).join("|")})$`),e._zod.parse=(s,l)=>{const u=s.value;return o.has(u)||s.issues.push({code:"invalid_value",values:r,input:u,inst:e}),s}}),f6=ue("$ZodTransform",(e,n)=>{Pt.init(e,n),e._zod.optin="optional",e._zod.parse=(r,o)=>{if(o.direction==="backward")throw new Y_(e.constructor.name);const s=n.transform(r.value,r);if(o.async)return(s instanceof Promise?s:Promise.resolve(s)).then(u=>(r.value=u,r.fallback=!0,r));if(s instanceof Promise)throw new La;return r.value=s,r.fallback=!0,r}});function zx(e,n){return n===void 0&&(e.issues.length||e.fallback)?{issues:[],value:void 0}:e}const sC=ue("$ZodOptional",(e,n)=>{Pt.init(e,n),e._zod.optin="optional",e._zod.optout="optional",dt(e._zod,"values",()=>n.innerType._zod.values?new Set([...n.innerType._zod.values,void 0]):void 0),dt(e._zod,"pattern",()=>{const r=n.innerType._zod.pattern;return r?new RegExp(`^(${ng(r.source)})?$`):void 0}),e._zod.parse=(r,o)=>{if(n.innerType._zod.optin==="optional"){const s=r.value,l=n.innerType._zod.run(r,o);return l instanceof Promise?l.then(u=>zx(u,s)):zx(l,s)}return r.value===void 0?r:n.innerType._zod.run(r,o)}}),h6=ue("$ZodExactOptional",(e,n)=>{sC.init(e,n),dt(e._zod,"values",()=>n.innerType._zod.values),dt(e._zod,"pattern",()=>n.innerType._zod.pattern),e._zod.parse=(r,o)=>n.innerType._zod.run(r,o)}),m6=ue("$ZodNullable",(e,n)=>{Pt.init(e,n),dt(e._zod,"optin",()=>n.innerType._zod.optin),dt(e._zod,"optout",()=>n.innerType._zod.optout),dt(e._zod,"pattern",()=>{const r=n.innerType._zod.pattern;return r?new RegExp(`^(${ng(r.source)}|null)$`):void 0}),dt(e._zod,"values",()=>n.innerType._zod.values?new Set([...n.innerType._zod.values,null]):void 0),e._zod.parse=(r,o)=>r.value===null?r:n.innerType._zod.run(r,o)}),p6=ue("$ZodDefault",(e,n)=>{Pt.init(e,n),e._zod.optin="optional",dt(e._zod,"values",()=>n.innerType._zod.values),e._zod.parse=(r,o)=>{if(o.direction==="backward")return n.innerType._zod.run(r,o);if(r.value===void 0)return r.value=n.defaultValue,r;const s=n.innerType._zod.run(r,o);return s instanceof Promise?s.then(l=>kx(l,n)):kx(s,n)}});function kx(e,n){return e.value===void 0&&(e.value=n.defaultValue),e}const g6=ue("$ZodPrefault",(e,n)=>{Pt.init(e,n),e._zod.optin="optional",dt(e._zod,"values",()=>n.innerType._zod.values),e._zod.parse=(r,o)=>(o.direction==="backward"||r.value===void 0&&(r.value=n.defaultValue),n.innerType._zod.run(r,o))}),v6=ue("$ZodNonOptional",(e,n)=>{Pt.init(e,n),dt(e._zod,"values",()=>{const r=n.innerType._zod.values;return r?new Set([...r].filter(o=>o!==void 0)):void 0}),e._zod.parse=(r,o)=>{const s=n.innerType._zod.run(r,o);return s instanceof Promise?s.then(l=>Lx(l,e)):Lx(s,e)}});function Lx(e,n){return!e.issues.length&&e.value===void 0&&e.issues.push({code:"invalid_type",expected:"nonoptional",input:e.value,inst:n}),e}const y6=ue("$ZodCatch",(e,n)=>{Pt.init(e,n),e._zod.optin="optional",dt(e._zod,"optout",()=>n.innerType._zod.optout),dt(e._zod,"values",()=>n.innerType._zod.values),e._zod.parse=(r,o)=>{if(o.direction==="backward")return n.innerType._zod.run(r,o);const s=n.innerType._zod.run(r,o);return s instanceof Promise?s.then(l=>(r.value=l.value,l.issues.length&&(r.value=n.catchValue({...r,error:{issues:l.issues.map(u=>To(u,o,Ro()))},input:r.value}),r.issues=[],r.fallback=!0),r)):(r.value=s.value,s.issues.length&&(r.value=n.catchValue({...r,error:{issues:s.issues.map(l=>To(l,o,Ro()))},input:r.value}),r.issues=[],r.fallback=!0),r)}}),b6=ue("$ZodPipe",(e,n)=>{Pt.init(e,n),dt(e._zod,"values",()=>n.in._zod.values),dt(e._zod,"optin",()=>n.in._zod.optin),dt(e._zod,"optout",()=>n.out._zod.optout),dt(e._zod,"propValues",()=>n.in._zod.propValues),e._zod.parse=(r,o)=>{if(o.direction==="backward"){const l=n.out._zod.run(r,o);return l instanceof Promise?l.then(u=>Xc(u,n.in,o)):Xc(l,n.in,o)}const s=n.in._zod.run(r,o);return s instanceof Promise?s.then(l=>Xc(l,n.out,o)):Xc(s,n.out,o)}});function Xc(e,n,r){return e.issues.length?(e.aborted=!0,e):n._zod.run({value:e.value,issues:e.issues,fallback:e.fallback},r)}const x6=ue("$ZodReadonly",(e,n)=>{Pt.init(e,n),dt(e._zod,"propValues",()=>n.innerType._zod.propValues),dt(e._zod,"values",()=>n.innerType._zod.values),dt(e._zod,"optin",()=>n.innerType?._zod?.optin),dt(e._zod,"optout",()=>n.innerType?._zod?.optout),e._zod.parse=(r,o)=>{if(o.direction==="backward")return n.innerType._zod.run(r,o);const s=n.innerType._zod.run(r,o);return s instanceof Promise?s.then($x):$x(s)}});function $x(e){return e.value=Object.freeze(e.value),e}const w6=ue("$ZodCustom",(e,n)=>{Nr.init(e,n),Pt.init(e,n),e._zod.parse=(r,o)=>r,e._zod.check=r=>{const o=r.value,s=n.fn(o);if(s instanceof Promise)return s.then(l=>Ix(l,r,o,e));Ix(s,r,o,e)}});function Ix(e,n,r,o){if(!e){const s={code:"custom",input:r,inst:o,path:[...o._zod.def.path??[]],continue:!o._zod.def.abort};o._zod.def.params&&(s.params=o._zod.def.params),n.issues.push(cl(s))}}var Vx;class S6{constructor(){this._map=new WeakMap,this._idmap=new Map}add(n,...r){const o=r[0];return this._map.set(n,o),o&&typeof o=="object"&&"id"in o&&this._idmap.set(o.id,n),this}clear(){return this._map=new WeakMap,this._idmap=new Map,this}remove(n){const r=this._map.get(n);return r&&typeof r=="object"&&"id"in r&&this._idmap.delete(r.id),this._map.delete(n),this}get(n){const r=n._zod.parent;if(r){const o={...this.get(r)??{}};delete o.id;const s={...o,...this._map.get(n)};return Object.keys(s).length?s:void 0}return this._map.get(n)}has(n){return this._map.has(n)}}function _6(){return new S6}(Vx=globalThis).__zod_globalRegistry??(Vx.__zod_globalRegistry=_6());const Zs=globalThis.__zod_globalRegistry;function C6(e,n){return new e({type:"string",...Ie(n)})}function E6(e,n){return new e({type:"string",format:"email",check:"string_format",abort:!1,...Ie(n)})}function Fx(e,n){return new e({type:"string",format:"guid",check:"string_format",abort:!1,...Ie(n)})}function R6(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,...Ie(n)})}function T6(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...Ie(n)})}function O6(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...Ie(n)})}function j6(e,n){return new e({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...Ie(n)})}function A6(e,n){return new e({type:"string",format:"url",check:"string_format",abort:!1,...Ie(n)})}function M6(e,n){return new e({type:"string",format:"emoji",check:"string_format",abort:!1,...Ie(n)})}function N6(e,n){return new e({type:"string",format:"nanoid",check:"string_format",abort:!1,...Ie(n)})}function D6(e,n){return new e({type:"string",format:"cuid",check:"string_format",abort:!1,...Ie(n)})}function z6(e,n){return new e({type:"string",format:"cuid2",check:"string_format",abort:!1,...Ie(n)})}function k6(e,n){return new e({type:"string",format:"ulid",check:"string_format",abort:!1,...Ie(n)})}function L6(e,n){return new e({type:"string",format:"xid",check:"string_format",abort:!1,...Ie(n)})}function $6(e,n){return new e({type:"string",format:"ksuid",check:"string_format",abort:!1,...Ie(n)})}function I6(e,n){return new e({type:"string",format:"ipv4",check:"string_format",abort:!1,...Ie(n)})}function V6(e,n){return new e({type:"string",format:"ipv6",check:"string_format",abort:!1,...Ie(n)})}function F6(e,n){return new e({type:"string",format:"cidrv4",check:"string_format",abort:!1,...Ie(n)})}function P6(e,n){return new e({type:"string",format:"cidrv6",check:"string_format",abort:!1,...Ie(n)})}function U6(e,n){return new e({type:"string",format:"base64",check:"string_format",abort:!1,...Ie(n)})}function H6(e,n){return new e({type:"string",format:"base64url",check:"string_format",abort:!1,...Ie(n)})}function B6(e,n){return new e({type:"string",format:"e164",check:"string_format",abort:!1,...Ie(n)})}function q6(e,n){return new e({type:"string",format:"jwt",check:"string_format",abort:!1,...Ie(n)})}function G6(e,n){return new e({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...Ie(n)})}function Z6(e,n){return new e({type:"string",format:"date",check:"string_format",...Ie(n)})}function K6(e,n){return new e({type:"string",format:"time",check:"string_format",precision:null,...Ie(n)})}function Y6(e,n){return new e({type:"string",format:"duration",check:"string_format",...Ie(n)})}function Q6(e,n){return new e({type:"boolean",...Ie(n)})}function X6(e){return new e({type:"unknown"})}function J6(e,n){return new e({type:"never",...Ie(n)})}function lC(e,n){return new x5({check:"max_length",...Ie(n),maximum:e})}function _u(e,n){return new w5({check:"min_length",...Ie(n),minimum:e})}function cC(e,n){return new S5({check:"length_equals",...Ie(n),length:e})}function W6(e,n){return new _5({check:"string_format",format:"regex",...Ie(n),pattern:e})}function eL(e){return new C5({check:"string_format",format:"lowercase",...Ie(e)})}function tL(e){return new E5({check:"string_format",format:"uppercase",...Ie(e)})}function nL(e,n){return new R5({check:"string_format",format:"includes",...Ie(n),includes:e})}function rL(e,n){return new T5({check:"string_format",format:"starts_with",...Ie(n),prefix:e})}function iL(e,n){return new O5({check:"string_format",format:"ends_with",...Ie(n),suffix:e})}function Za(e){return new j5({check:"overwrite",tx:e})}function oL(e){return Za(n=>n.normalize(e))}function aL(){return Za(e=>e.trim())}function sL(){return Za(e=>e.toLowerCase())}function lL(){return Za(e=>e.toUpperCase())}function cL(){return Za(e=>_4(e))}function uL(e,n,r){return new e({type:"array",element:n,...Ie(r)})}function dL(e,n,r){return new e({type:"custom",check:"custom",fn:n,...Ie(r)})}function fL(e,n){const r=hL(o=>(o.addIssue=s=>{if(typeof s=="string")o.issues.push(cl(s,o.value,r._zod.def));else{const l=s;l.fatal&&(l.continue=!1),l.code??(l.code="custom"),l.input??(l.input=o.value),l.inst??(l.inst=r),l.continue??(l.continue=!r._zod.def.abort),o.issues.push(cl(l))}},e(o.value,o)),n);return r}function hL(e,n){const r=new Nr({check:"custom",...Ie(n)});return r._zod.check=e,r}function uC(e){let n=e?.target??"draft-2020-12";return n==="draft-4"&&(n="draft-04"),n==="draft-7"&&(n="draft-07"),{processors:e.processors??{},metadataRegistry:e?.metadata??Zs,target:n,unrepresentable:e?.unrepresentable??"throw",override:e?.override??(()=>{}),io:e?.io??"output",counter:0,seen:new Map,cycles:e?.cycles??"ref",reused:e?.reused??"inline",external:e?.external??void 0}}function un(e,n,r={path:[],schemaPath:[]}){var o;const s=e._zod.def,l=n.seen.get(e);if(l)return l.count++,r.schemaPath.includes(e)&&(l.cycle=r.path),l.schema;const u={schema:{},count:1,cycle:void 0,path:r.path};n.seen.set(e,u);const d=e._zod.toJSONSchema?.();if(d)u.schema=d;else{const y={...r,schemaPath:[...r.schemaPath,e],path:r.path};if(e._zod.processJSONSchema)e._zod.processJSONSchema(n,u.schema,y);else{const b=u.schema,x=n.processors[s.type];if(!x)throw new Error(`[toJSONSchema]: Non-representable type encountered: ${s.type}`);x(e,n,b,y)}const v=e._zod.parent;v&&(u.ref||(u.ref=v),un(v,n,y),n.seen.get(v).isParent=!0)}const p=n.metadataRegistry.get(e);return p&&Object.assign(u.schema,p),n.io==="input"&&vn(e)&&(delete u.schema.examples,delete u.schema.default),n.io==="input"&&"_prefault"in u.schema&&((o=u.schema).default??(o.default=u.schema._prefault)),delete u.schema._prefault,n.seen.get(e).schema}function dC(e,n){const r=e.seen.get(n);if(!r)throw new Error("Unprocessed schema. This is a bug in Zod.");const o=new Map;for(const u of e.seen.entries()){const d=e.metadataRegistry.get(u[0])?.id;if(d){const p=o.get(d);if(p&&p!==u[0])throw new Error(`Duplicate schema id "${d}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);o.set(d,u[0])}}const s=u=>{const d=e.target==="draft-2020-12"?"$defs":"definitions";if(e.external){const v=e.external.registry.get(u[0])?.id,b=e.external.uri??(C=>C);if(v)return{ref:b(v)};const x=u[1].defId??u[1].schema.id??`schema${e.counter++}`;return u[1].defId=x,{defId:x,ref:`${b("__shared")}#/${d}/${x}`}}if(u[1]===r)return{ref:"#"};const h=`#/${d}/`,y=u[1].schema.id??`__schema${e.counter++}`;return{defId:y,ref:h+y}},l=u=>{if(u[1].schema.$ref)return;const d=u[1],{ref:p,defId:h}=s(u);d.def={...d.schema},h&&(d.defId=h);const y=d.schema;for(const v in y)delete y[v];y.$ref=p};if(e.cycles==="throw")for(const u of e.seen.entries()){const d=u[1];if(d.cycle)throw new Error(`Cycle detected: #/${d.cycle?.join("/")}/ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`)}for(const u of e.seen.entries()){const d=u[1];if(n===u[0]){l(u);continue}if(e.external){const h=e.external.registry.get(u[0])?.id;if(n!==u[0]&&h){l(u);continue}}if(e.metadataRegistry.get(u[0])?.id){l(u);continue}if(d.cycle){l(u);continue}if(d.count>1&&e.reused==="ref"){l(u);continue}}}function fC(e,n){const r=e.seen.get(n);if(!r)throw new Error("Unprocessed schema. This is a bug in Zod.");const o=d=>{const p=e.seen.get(d);if(p.ref===null)return;const h=p.def??p.schema,y={...h},v=p.ref;if(p.ref=null,v){o(v);const x=e.seen.get(v),C=x.schema;if(C.$ref&&(e.target==="draft-07"||e.target==="draft-04"||e.target==="openapi-3.0")?(h.allOf=h.allOf??[],h.allOf.push(C)):Object.assign(h,C),Object.assign(h,y),d._zod.parent===v)for(const E in h)E==="$ref"||E==="allOf"||E in y||delete h[E];if(C.$ref&&x.def)for(const E in h)E==="$ref"||E==="allOf"||E in x.def&&JSON.stringify(h[E])===JSON.stringify(x.def[E])&&delete h[E]}const b=d._zod.parent;if(b&&b!==v){o(b);const x=e.seen.get(b);if(x?.schema.$ref&&(h.$ref=x.schema.$ref,x.def))for(const C in h)C==="$ref"||C==="allOf"||C in x.def&&JSON.stringify(h[C])===JSON.stringify(x.def[C])&&delete h[C]}e.override({zodSchema:d,jsonSchema:h,path:p.path??[]})};for(const d of[...e.seen.entries()].reverse())o(d[0]);const s={};if(e.target==="draft-2020-12"?s.$schema="https://json-schema.org/draft/2020-12/schema":e.target==="draft-07"?s.$schema="http://json-schema.org/draft-07/schema#":e.target==="draft-04"?s.$schema="http://json-schema.org/draft-04/schema#":e.target,e.external?.uri){const d=e.external.registry.get(n)?.id;if(!d)throw new Error("Schema is missing an `id` property");s.$id=e.external.uri(d)}Object.assign(s,r.def??r.schema);const l=e.metadataRegistry.get(n)?.id;l!==void 0&&s.id===l&&delete s.id;const u=e.external?.defs??{};for(const d of e.seen.entries()){const p=d[1];p.def&&p.defId&&(p.def.id===p.defId&&delete p.def.id,u[p.defId]=p.def)}e.external||Object.keys(u).length>0&&(e.target==="draft-2020-12"?s.$defs=u:s.definitions=u);try{const d=JSON.parse(JSON.stringify(s));return Object.defineProperty(d,"~standard",{value:{...n["~standard"],jsonSchema:{input:Cu(n,"input",e.processors),output:Cu(n,"output",e.processors)}},enumerable:!1,writable:!1}),d}catch{throw new Error("Error converting schema to JSON.")}}function vn(e,n){const r=n??{seen:new Set};if(r.seen.has(e))return!1;r.seen.add(e);const o=e._zod.def;if(o.type==="transform")return!0;if(o.type==="array")return vn(o.element,r);if(o.type==="set")return vn(o.valueType,r);if(o.type==="lazy")return vn(o.getter(),r);if(o.type==="promise"||o.type==="optional"||o.type==="nonoptional"||o.type==="nullable"||o.type==="readonly"||o.type==="default"||o.type==="prefault")return vn(o.innerType,r);if(o.type==="intersection")return vn(o.left,r)||vn(o.right,r);if(o.type==="record"||o.type==="map")return vn(o.keyType,r)||vn(o.valueType,r);if(o.type==="pipe")return e._zod.traits.has("$ZodCodec")?!0:vn(o.in,r)||vn(o.out,r);if(o.type==="object"){for(const s in o.shape)if(vn(o.shape[s],r))return!0;return!1}if(o.type==="union"){for(const s of o.options)if(vn(s,r))return!0;return!1}if(o.type==="tuple"){for(const s of o.items)if(vn(s,r))return!0;return!!(o.rest&&vn(o.rest,r))}return!1}const mL=(e,n={})=>r=>{const o=uC({...r,processors:n});return un(e,o),dC(o,e),fC(o,e)},Cu=(e,n,r={})=>o=>{const{libraryOptions:s,target:l}=o??{},u=uC({...s??{},target:l,io:n,processors:r});return un(e,u),dC(u,e),fC(u,e)},pL={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},gL=(e,n,r,o)=>{const s=r;s.type="string";const{minimum:l,maximum:u,format:d,patterns:p,contentEncoding:h}=e._zod.bag;if(typeof l=="number"&&(s.minLength=l),typeof u=="number"&&(s.maxLength=u),d&&(s.format=pL[d]??d,s.format===""&&delete s.format,d==="time"&&delete s.format),h&&(s.contentEncoding=h),p&&p.size>0){const y=[...p];y.length===1?s.pattern=y[0].source:y.length>1&&(s.allOf=[...y.map(v=>({...n.target==="draft-07"||n.target==="draft-04"||n.target==="openapi-3.0"?{type:"string"}:{},pattern:v.source}))])}},vL=(e,n,r,o)=>{r.type="boolean"},yL=(e,n,r,o)=>{r.not={}},bL=(e,n,r,o)=>{},xL=(e,n,r,o)=>{const s=e._zod.def,l=Q_(s.entries);l.every(u=>typeof u=="number")&&(r.type="number"),l.every(u=>typeof u=="string")&&(r.type="string"),r.enum=l},wL=(e,n,r,o)=>{if(n.unrepresentable==="throw")throw new Error("Custom types cannot be represented in JSON Schema")},SL=(e,n,r,o)=>{if(n.unrepresentable==="throw")throw new Error("Transforms cannot be represented in JSON Schema")},_L=(e,n,r,o)=>{const s=r,l=e._zod.def,{minimum:u,maximum:d}=e._zod.bag;typeof u=="number"&&(s.minItems=u),typeof d=="number"&&(s.maxItems=d),s.type="array",s.items=un(l.element,n,{...o,path:[...o.path,"items"]})},CL=(e,n,r,o)=>{const s=r,l=e._zod.def;s.type="object",s.properties={};const u=l.shape;for(const h in u)s.properties[h]=un(u[h],n,{...o,path:[...o.path,"properties",h]});const d=new Set(Object.keys(u)),p=new Set([...d].filter(h=>{const y=l.shape[h]._zod;return n.io==="input"?y.optin===void 0:y.optout===void 0}));p.size>0&&(s.required=Array.from(p)),l.catchall?._zod.def.type==="never"?s.additionalProperties=!1:l.catchall?l.catchall&&(s.additionalProperties=un(l.catchall,n,{...o,path:[...o.path,"additionalProperties"]})):n.io==="output"&&(s.additionalProperties=!1)},EL=(e,n,r,o)=>{const s=e._zod.def,l=s.inclusive===!1,u=s.options.map((d,p)=>un(d,n,{...o,path:[...o.path,l?"oneOf":"anyOf",p]}));l?r.oneOf=u:r.anyOf=u},RL=(e,n,r,o)=>{const s=e._zod.def,l=un(s.left,n,{...o,path:[...o.path,"allOf",0]}),u=un(s.right,n,{...o,path:[...o.path,"allOf",1]}),d=h=>"allOf"in h&&Object.keys(h).length===1,p=[...d(l)?l.allOf:[l],...d(u)?u.allOf:[u]];r.allOf=p},TL=(e,n,r,o)=>{const s=e._zod.def,l=un(s.innerType,n,o),u=n.seen.get(e);n.target==="openapi-3.0"?(u.ref=s.innerType,r.nullable=!0):r.anyOf=[l,{type:"null"}]},OL=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType},jL=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType,r.default=JSON.parse(JSON.stringify(s.defaultValue))},AL=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType,n.io==="input"&&(r._prefault=JSON.parse(JSON.stringify(s.defaultValue)))},ML=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType;let u;try{u=s.catchValue(void 0)}catch{throw new Error("Dynamic catch values are not supported in JSON Schema")}r.default=u},NL=(e,n,r,o)=>{const s=e._zod.def,l=s.in._zod.traits.has("$ZodTransform"),u=n.io==="input"?l?s.out:s.in:s.out;un(u,n,o);const d=n.seen.get(e);d.ref=u},DL=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType,r.readOnly=!0},hC=(e,n,r,o)=>{const s=e._zod.def;un(s.innerType,n,o);const l=n.seen.get(e);l.ref=s.innerType};function Fm(){return Fm=Object.assign?Object.assign.bind():function(e){for(var n=1;n0){var p=s.errors[0][0];r[d]={message:p.message,type:p.code}}else r[d]={message:u,type:l};if(s.code==="invalid_union"&&s.errors.forEach(function(v){return v.forEach(function(b){return e.push(Fm({},b,{path:[].concat(s.path,b.path)}))})}),n){var h=r[d].types,y=h&&h[s.code];r[d]=Xp(d,n,r,l,y?[].concat(y,s.message):s.message)}e.shift()};e.length;)o();return r}function ag(e,n,r){if(r===void 0&&(r={}),(function(o){return"_def"in o&&typeof o._def=="object"&&"typeName"in o._def})(e))return function(o,s,l){try{return Promise.resolve(Px(function(){return Promise.resolve(e[r.mode==="sync"?"parse":"parseAsync"](o,n)).then(function(u){return l.shouldUseNativeValidation&&$m({},l),{errors:{},values:r.raw?Object.assign({},o):u}})},function(u){if((function(d){return Array.isArray(d?.issues)})(u))return{values:{},errors:Ex(zL(u.errors,!l.shouldUseNativeValidation&&l.criteriaMode==="all"),l)};throw u}))}catch(u){return Promise.reject(u)}};if((function(o){return"_zod"in o&&typeof o._zod=="object"})(e))return function(o,s,l){try{return Promise.resolve(Px(function(){return Promise.resolve((r.mode==="sync"?$4:I4)(e,o,n)).then(function(u){return l.shouldUseNativeValidation&&$m({},l),{errors:{},values:r.raw?Object.assign({},o):u}})},function(u){if((function(d){return d instanceof ig})(u))return{values:{},errors:Ex(kL(u.issues,!l.shouldUseNativeValidation&&l.criteriaMode==="all"),l)};throw u}))}catch(u){return Promise.reject(u)}};throw new Error("Invalid input: not a Zod schema")}const LL=ue("ZodISODateTime",(e,n)=>{H5.init(e,n),Et.init(e,n)});function $L(e){return G6(LL,e)}const IL=ue("ZodISODate",(e,n)=>{B5.init(e,n),Et.init(e,n)});function VL(e){return Z6(IL,e)}const FL=ue("ZodISOTime",(e,n)=>{q5.init(e,n),Et.init(e,n)});function PL(e){return K6(FL,e)}const UL=ue("ZodISODuration",(e,n)=>{G5.init(e,n),Et.init(e,n)});function HL(e){return Y6(UL,e)}const BL=(e,n)=>{ig.init(e,n),e.name="ZodError",Object.defineProperties(e,{format:{value:r=>L4(e,r)},flatten:{value:r=>k4(e,r)},addIssue:{value:r=>{e.issues.push(r),e.message=JSON.stringify(e.issues,Im,2)}},addIssues:{value:r=>{e.issues.push(...r),e.message=JSON.stringify(e.issues,Im,2)}},isEmpty:{get(){return e.issues.length===0}}})},ir=ue("ZodError",BL,{Parent:Error}),qL=nd(ir),GL=rd(ir),ZL=id(ir),KL=od(ir),YL=P4(ir),QL=U4(ir),XL=H4(ir),JL=B4(ir),WL=q4(ir),e8=G4(ir),t8=Z4(ir),n8=K4(ir),Ux=new WeakMap;function sd(e,n,r){const o=Object.getPrototypeOf(e);let s=Ux.get(o);if(s||(s=new Set,Ux.set(o,s)),!s.has(n)){s.add(n);for(const l in r){const u=r[l];Object.defineProperty(o,l,{configurable:!0,enumerable:!1,get(){const d=u.bind(this);return Object.defineProperty(this,l,{configurable:!0,writable:!0,enumerable:!0,value:d}),d},set(d){Object.defineProperty(this,l,{configurable:!0,writable:!0,enumerable:!0,value:d})}})}}}const Ut=ue("ZodType",(e,n)=>(Pt.init(e,n),Object.assign(e["~standard"],{jsonSchema:{input:Cu(e,"input"),output:Cu(e,"output")}}),e.toJSONSchema=mL(e,{}),e.def=n,e.type=n.type,Object.defineProperty(e,"_def",{value:n}),e.parse=(r,o)=>qL(e,r,o,{callee:e.parse}),e.safeParse=(r,o)=>ZL(e,r,o),e.parseAsync=async(r,o)=>GL(e,r,o,{callee:e.parseAsync}),e.safeParseAsync=async(r,o)=>KL(e,r,o),e.spa=e.safeParseAsync,e.encode=(r,o)=>YL(e,r,o),e.decode=(r,o)=>QL(e,r,o),e.encodeAsync=async(r,o)=>XL(e,r,o),e.decodeAsync=async(r,o)=>JL(e,r,o),e.safeEncode=(r,o)=>WL(e,r,o),e.safeDecode=(r,o)=>e8(e,r,o),e.safeEncodeAsync=async(r,o)=>t8(e,r,o),e.safeDecodeAsync=async(r,o)=>n8(e,r,o),sd(e,"ZodType",{check(...r){const o=this.def;return this.clone(Yi(o,{checks:[...o.checks??[],...r.map(s=>typeof s=="function"?{_zod:{check:s,def:{check:"custom"},onattach:[]}}:s)]}),{parent:!0})},with(...r){return this.check(...r)},clone(r,o){return Qi(this,r,o)},brand(){return this},register(r,o){return r.add(this,o),this},refine(r,o){return this.check(Y8(r,o))},superRefine(r,o){return this.check(Q8(r,o))},overwrite(r){return this.check(Za(r))},optional(){return Gx(this)},exactOptional(){return L8(this)},nullable(){return Zx(this)},nullish(){return Gx(Zx(this))},nonoptional(r){return U8(this,r)},array(){return R8(this)},or(r){return j8([this,r])},and(r){return M8(this,r)},transform(r){return Kx(this,z8(r))},default(r){return V8(this,r)},prefault(r){return P8(this,r)},catch(r){return B8(this,r)},pipe(r){return Kx(this,r)},readonly(){return Z8(this)},describe(r){const o=this.clone();return Zs.add(o,{description:r}),o},meta(...r){if(r.length===0)return Zs.get(this);const o=this.clone();return Zs.add(o,r[0]),o},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(r){return r(this)}}),Object.defineProperty(e,"description",{get(){return Zs.get(e)?.description},configurable:!0}),e)),mC=ue("_ZodString",(e,n)=>{og.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(o,s,l)=>gL(e,o,s);const r=e._zod.bag;e.format=r.format??null,e.minLength=r.minimum??null,e.maxLength=r.maximum??null,sd(e,"_ZodString",{regex(...o){return this.check(W6(...o))},includes(...o){return this.check(nL(...o))},startsWith(...o){return this.check(rL(...o))},endsWith(...o){return this.check(iL(...o))},min(...o){return this.check(_u(...o))},max(...o){return this.check(lC(...o))},length(...o){return this.check(cC(...o))},nonempty(...o){return this.check(_u(1,...o))},lowercase(o){return this.check(eL(o))},uppercase(o){return this.check(tL(o))},trim(){return this.check(aL())},normalize(...o){return this.check(oL(...o))},toLowerCase(){return this.check(sL())},toUpperCase(){return this.check(lL())},slugify(){return this.check(cL())}})}),r8=ue("ZodString",(e,n)=>{og.init(e,n),mC.init(e,n),e.email=r=>e.check(E6(i8,r)),e.url=r=>e.check(A6(o8,r)),e.jwt=r=>e.check(q6(x8,r)),e.emoji=r=>e.check(M6(a8,r)),e.guid=r=>e.check(Fx(Hx,r)),e.uuid=r=>e.check(R6(Jc,r)),e.uuidv4=r=>e.check(T6(Jc,r)),e.uuidv6=r=>e.check(O6(Jc,r)),e.uuidv7=r=>e.check(j6(Jc,r)),e.nanoid=r=>e.check(N6(s8,r)),e.guid=r=>e.check(Fx(Hx,r)),e.cuid=r=>e.check(D6(l8,r)),e.cuid2=r=>e.check(z6(c8,r)),e.ulid=r=>e.check(k6(u8,r)),e.base64=r=>e.check(U6(v8,r)),e.base64url=r=>e.check(H6(y8,r)),e.xid=r=>e.check(L6(d8,r)),e.ksuid=r=>e.check($6(f8,r)),e.ipv4=r=>e.check(I6(h8,r)),e.ipv6=r=>e.check(V6(m8,r)),e.cidrv4=r=>e.check(F6(p8,r)),e.cidrv6=r=>e.check(P6(g8,r)),e.e164=r=>e.check(B6(b8,r)),e.datetime=r=>e.check($L(r)),e.date=r=>e.check(VL(r)),e.time=r=>e.check(PL(r)),e.duration=r=>e.check(HL(r))});function au(e){return C6(r8,e)}const Et=ue("ZodStringFormat",(e,n)=>{wt.init(e,n),mC.init(e,n)}),i8=ue("ZodEmail",(e,n)=>{z5.init(e,n),Et.init(e,n)}),Hx=ue("ZodGUID",(e,n)=>{N5.init(e,n),Et.init(e,n)}),Jc=ue("ZodUUID",(e,n)=>{D5.init(e,n),Et.init(e,n)}),o8=ue("ZodURL",(e,n)=>{k5.init(e,n),Et.init(e,n)}),a8=ue("ZodEmoji",(e,n)=>{L5.init(e,n),Et.init(e,n)}),s8=ue("ZodNanoID",(e,n)=>{$5.init(e,n),Et.init(e,n)}),l8=ue("ZodCUID",(e,n)=>{I5.init(e,n),Et.init(e,n)}),c8=ue("ZodCUID2",(e,n)=>{V5.init(e,n),Et.init(e,n)}),u8=ue("ZodULID",(e,n)=>{F5.init(e,n),Et.init(e,n)}),d8=ue("ZodXID",(e,n)=>{P5.init(e,n),Et.init(e,n)}),f8=ue("ZodKSUID",(e,n)=>{U5.init(e,n),Et.init(e,n)}),h8=ue("ZodIPv4",(e,n)=>{Z5.init(e,n),Et.init(e,n)}),m8=ue("ZodIPv6",(e,n)=>{K5.init(e,n),Et.init(e,n)}),p8=ue("ZodCIDRv4",(e,n)=>{Y5.init(e,n),Et.init(e,n)}),g8=ue("ZodCIDRv6",(e,n)=>{Q5.init(e,n),Et.init(e,n)}),v8=ue("ZodBase64",(e,n)=>{X5.init(e,n),Et.init(e,n)}),y8=ue("ZodBase64URL",(e,n)=>{W5.init(e,n),Et.init(e,n)}),b8=ue("ZodE164",(e,n)=>{e6.init(e,n),Et.init(e,n)}),x8=ue("ZodJWT",(e,n)=>{n6.init(e,n),Et.init(e,n)}),w8=ue("ZodBoolean",(e,n)=>{r6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>vL(e,r,o)});function Bx(e){return Q6(w8,e)}const S8=ue("ZodUnknown",(e,n)=>{i6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>bL()});function qx(){return X6(S8)}const _8=ue("ZodNever",(e,n)=>{o6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>yL(e,r,o)});function C8(e){return J6(_8,e)}const E8=ue("ZodArray",(e,n)=>{a6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>_L(e,r,o,s),e.element=n.element,sd(e,"ZodArray",{min(r,o){return this.check(_u(r,o))},nonempty(r){return this.check(_u(1,r))},max(r,o){return this.check(lC(r,o))},length(r,o){return this.check(cC(r,o))},unwrap(){return this.element}})});function R8(e,n){return uL(E8,e,n)}const T8=ue("ZodObject",(e,n)=>{l6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>CL(e,r,o,s),dt(e,"shape",()=>n.shape),sd(e,"ZodObject",{keyof(){return N8(Object.keys(this._zod.def.shape))},catchall(r){return this.clone({...this._zod.def,catchall:r})},passthrough(){return this.clone({...this._zod.def,catchall:qx()})},loose(){return this.clone({...this._zod.def,catchall:qx()})},strict(){return this.clone({...this._zod.def,catchall:C8()})},strip(){return this.clone({...this._zod.def,catchall:void 0})},extend(r){return j4(this,r)},safeExtend(r){return A4(this,r)},merge(r){return M4(this,r)},pick(r){return T4(this,r)},omit(r){return O4(this,r)},partial(...r){return N4(pC,this,r[0])},required(...r){return D4(gC,this,r[0])}})});function sg(e,n){const r={type:"object",shape:e??{},...Ie(n)};return new T8(r)}const O8=ue("ZodUnion",(e,n)=>{c6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>EL(e,r,o,s),e.options=n.options});function j8(e,n){return new O8({type:"union",options:e,...Ie(n)})}const A8=ue("ZodIntersection",(e,n)=>{u6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>RL(e,r,o,s)});function M8(e,n){return new A8({type:"intersection",left:e,right:n})}const Pm=ue("ZodEnum",(e,n)=>{d6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(o,s,l)=>xL(e,o,s),e.enum=n.entries,e.options=Object.values(n.entries);const r=new Set(Object.keys(n.entries));e.extract=(o,s)=>{const l={};for(const u of o)if(r.has(u))l[u]=n.entries[u];else throw new Error(`Key ${u} not found in enum`);return new Pm({...n,checks:[],...Ie(s),entries:l})},e.exclude=(o,s)=>{const l={...n.entries};for(const u of o)if(r.has(u))delete l[u];else throw new Error(`Key ${u} not found in enum`);return new Pm({...n,checks:[],...Ie(s),entries:l})}});function N8(e,n){const r=Array.isArray(e)?Object.fromEntries(e.map(o=>[o,o])):e;return new Pm({type:"enum",entries:r,...Ie(n)})}const D8=ue("ZodTransform",(e,n)=>{f6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>SL(e,r),e._zod.parse=(r,o)=>{if(o.direction==="backward")throw new Y_(e.constructor.name);r.addIssue=l=>{if(typeof l=="string")r.issues.push(cl(l,r.value,n));else{const u=l;u.fatal&&(u.continue=!1),u.code??(u.code="custom"),u.input??(u.input=r.value),u.inst??(u.inst=e),r.issues.push(cl(u))}};const s=n.transform(r.value,r);return s instanceof Promise?s.then(l=>(r.value=l,r.fallback=!0,r)):(r.value=s,r.fallback=!0,r)}});function z8(e){return new D8({type:"transform",transform:e})}const pC=ue("ZodOptional",(e,n)=>{sC.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>hC(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function Gx(e){return new pC({type:"optional",innerType:e})}const k8=ue("ZodExactOptional",(e,n)=>{h6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>hC(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function L8(e){return new k8({type:"optional",innerType:e})}const $8=ue("ZodNullable",(e,n)=>{m6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>TL(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function Zx(e){return new $8({type:"nullable",innerType:e})}const I8=ue("ZodDefault",(e,n)=>{p6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>jL(e,r,o,s),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function V8(e,n){return new I8({type:"default",innerType:e,get defaultValue(){return typeof n=="function"?n():J_(n)}})}const F8=ue("ZodPrefault",(e,n)=>{g6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>AL(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function P8(e,n){return new F8({type:"prefault",innerType:e,get defaultValue(){return typeof n=="function"?n():J_(n)}})}const gC=ue("ZodNonOptional",(e,n)=>{v6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>OL(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function U8(e,n){return new gC({type:"nonoptional",innerType:e,...Ie(n)})}const H8=ue("ZodCatch",(e,n)=>{y6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>ML(e,r,o,s),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function B8(e,n){return new H8({type:"catch",innerType:e,catchValue:typeof n=="function"?n:()=>n})}const q8=ue("ZodPipe",(e,n)=>{b6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>NL(e,r,o,s),e.in=n.in,e.out=n.out});function Kx(e,n){return new q8({type:"pipe",in:e,out:n})}const G8=ue("ZodReadonly",(e,n)=>{x6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>DL(e,r,o,s),e.unwrap=()=>e._zod.def.innerType});function Z8(e){return new G8({type:"readonly",innerType:e})}const K8=ue("ZodCustom",(e,n)=>{w6.init(e,n),Ut.init(e,n),e._zod.processJSONSchema=(r,o,s)=>wL(e,r)});function Y8(e,n={}){return dL(K8,e,n)}function Q8(e,n){return fL(e,n)}const X8=/\.(md|markdown)$/i,J8=/\.(png|jpe?g|gif|svg|webp|ico|bmp|avif)$/i,vC=/\.html?$/i,W8=/\.(txt|log|json|ya?ml|toml|csv|go|py|js|ts|jsx|tsx|sh|bash|zsh|rb|rs|c|h|cpp|java|kt|swift|sql|css|xml|ini|conf|env|mod|sum|jsonl)$/i;function yC(e){if(e<1024)return e+" B";const n=["KB","MB","GB","TB"];let r=-1;do e/=1024,r++;while(e>=1024&&r`:e.user||e.author||"unknown"}function e$({className:e,...n}){return m.jsx("div",{"data-slot":"table-container",className:"relative w-full overflow-x-auto",children:m.jsx("table",{"data-slot":"table",className:We("w-full caption-bottom text-sm",e),...n})})}function t$({className:e,...n}){return m.jsx("thead",{"data-slot":"table-header",className:We("[&_tr]:border-b",e),...n})}function n$({className:e,...n}){return m.jsx("tbody",{"data-slot":"table-body",className:We("[&_tr:last-child]:border-0",e),...n})}function Yx({className:e,...n}){return m.jsx("tr",{"data-slot":"table-row",className:We("border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",e),...n})}function Qx({className:e,...n}){return m.jsx("th",{"data-slot":"table-head",className:We("h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",e),...n})}function r$({className:e,...n}){return m.jsx("td",{"data-slot":"table-cell",className:We("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",e),...n})}function i$({header:e}){const n=e.column.getIsSorted();return e.column.getCanSort()?m.jsx(Qx,{"data-sort":n||void 0,"aria-sort":n==="asc"?"ascending":n==="desc"?"descending":"none",children:m.jsxs("button",{type:"button",className:"th-sort",onClick:e.column.getToggleSortingHandler(),children:[Dm(e.column.columnDef.header,e.getContext()),n==="asc"?" ↑":n==="desc"?" ↓":""]})}):m.jsx(Qx,{children:Dm(e.column.columnDef.header,e.getContext())})}function xC({table:e,className:n}){return m.jsx("div",{className:"admin-list admin-card-table"+(n?" "+n:""),children:m.jsxs(e$,{className:"admin-table",children:[m.jsx(t$,{children:e.getHeaderGroups().map(r=>m.jsx(Yx,{children:r.headers.map(o=>m.jsx(i$,{header:o},o.id))},r.id))}),m.jsx(n$,{children:e.getRowModel().rows.map(r=>m.jsx(Yx,{className:"admin-item",children:r.getVisibleCells().map(o=>m.jsx(r$,{children:Dm(o.column.columnDef.cell,o.getContext())},o.id))},r.id))})]})})}function wC(e){return e?"expires "+new Date(e).toLocaleDateString():"no expiry"}function SC(e,n){const r=[];return n&&e.project_name&&r.push(e.project_name),e.creator&&r.push("by "+e.creator),e.created&&r.push(new Date(e.created).toLocaleDateString()),r.push(wC(e.expires)),r.join(" · ")}function _C({shares:e,onChanged:n,showProject:r=!1,canRevoke:o=!0,empty:s="No public shares."}){const[l,u]=w.useState([]),d=w.useMemo(()=>__(),[]),p=w.useMemo(()=>[d.accessor("path",{header:"Path",cell:y=>m.jsx("a",{className:"ai-main mono",title:y.getValue(),...yu(Qu(y.getValue(),y.row.original.project)),children:y.getValue()})}),d.accessor(y=>SC(y,r),{id:"detail",header:r?"Project":"Shared",cell:y=>m.jsx("span",{className:"ai-tag",children:y.getValue()})}),d.display({id:"actions",header:"",cell:y=>o?m.jsx("button",{className:"ai-del","aria-label":`Revoke the share of ${y.row.original.path}`,onClick:()=>CC(y.row.original,n),children:"Revoke"}):null})],[d,n,r,o]),h=k_({data:e,columns:p,state:{sorting:l},onSortingChange:u,getCoreRowModel:D_(),getSortedRowModel:z_()});return e.length===0?m.jsx("div",{className:"admin-list",children:m.jsx("div",{className:"admin-empty",children:s})}):m.jsx(xC,{table:h,className:"shares-table"})}async function CC(e,n){if(await Yu("Revoke share link",`Revoke the public link to “${e.path}”? Anyone with the URL will lose access.`,"Revoke",!0))try{await Un("DELETE","/api/shares/"+e.token),Qe("Share revoked."),n()}catch(r){Qe(r.message,!0)}}const o$=sg({name:au().trim().min(1,"Give the organization a name.").max(60,"Keep it under 60 characters.")});function a$({org:e,projects:n,myEmail:r}){const o=jo(),s=e.role==="owner",l=()=>o.invalidateQueries({queryKey:["orgs"]}),u=()=>o.invalidateQueries({queryKey:["invites",e.id]}),d=()=>o.invalidateQueries({queryKey:["orgShares",e.id]}),p=Jp({resolver:ag(o$),values:{name:e.name}}),{data:h}=Gt({queryKey:["invites",e.id],queryFn:()=>cn(`/api/orgs/${e.id}/invites`),enabled:s,select:b=>b.invites||[]}),{data:y}=Gt({queryKey:["orgShares",e.id],queryFn:()=>cn(`/api/orgs/${e.id}/shares`),enabled:s,select:b=>b.shares||[]}),v=n.filter(b=>b.org===e.id);return m.jsxs("div",{className:"admin",children:[m.jsx("h1",{id:"org-title",children:e.name}),!s&&m.jsx("p",{className:"role-chip-row",children:m.jsx("span",{className:"ai-tag role-chip",children:"Member"})}),!s&&m.jsx("p",{className:"admin-sub",children:"Only owners can rename this organization, manage members, or issue invite links."}),s&&m.jsxs("form",{className:"admin-row",onSubmit:p.handleSubmit(async({name:b})=>{try{await Un("PATCH","/api/orgs/"+e.id,{name:b}),Qe("Renamed."),l()}catch(x){Qe(x.message,!0)}}),children:[m.jsx("label",{className:"admin-lbl",htmlFor:"org-rename",children:"Organization name"}),m.jsx("input",{id:"org-rename",type:"text","aria-invalid":!!p.formState.errors.name,"aria-describedby":p.formState.errors.name?"org-rename-err":void 0,...p.register("name")}),m.jsx(Ct,{variant:"subtle",id:"org-rename-btn",type:"submit",disabled:!p.formState.isDirty,children:"Rename org"}),p.formState.errors.name&&m.jsx("span",{id:"org-rename-err",role:"alert",className:"field-err",children:p.formState.errors.name.message})]}),m.jsx("h3",{children:"Members"}),m.jsx(s$,{org:e,owner:s,myEmail:r,onChanged:l}),m.jsx("h3",{children:"Projects"}),m.jsxs("div",{className:"admin-list",children:[v.length===0&&m.jsx("div",{className:"admin-empty",children:"No projects yet."}),v.map(b=>m.jsx("div",{className:"admin-item",children:m.jsx("span",{className:"ai-main",title:b.name,children:b.name})},b.id))]}),s&&m.jsxs(m.Fragment,{children:[m.jsxs("div",{className:"admin-h",children:[m.jsx("h3",{children:"Invite links"}),m.jsx(Ct,{variant:"primary",onClick:async()=>{try{const b=await Ia(`/api/orgs/${e.id}/invites`),x=await Ha(b.url);Qe(x?"Invite link copied to clipboard.":"Invite created — copy it from the list below."),u()}catch(b){Qe(b.message,!0)}},children:"New invite"})]}),m.jsxs("div",{className:"admin-list",children:[h&&h.length===0&&m.jsx("div",{className:"admin-empty",children:"No active invite links."}),(h||[]).map(b=>m.jsxs("div",{className:"admin-item",children:[m.jsx("button",{type:"button",className:"ai-main mono ai-copy","aria-label":`Copy invite link ${b.url}`,title:b.url,onClick:()=>Ha(b.url).then(x=>Qe(x?"Copied.":"Select and copy the link.")),children:b.url}),m.jsx("span",{className:"ai-tag",children:(b.creator?"by "+b.creator+" · ":"")+(b.uses?b.uses+" joined · ":"unused · ")+"expires "+new Date(b.expires).toLocaleDateString()}),m.jsx("button",{className:"ai-del","aria-label":`Revoke invite ${b.token.slice(0,8)}`,onClick:async()=>{if(await Yu("Revoke invite",`Revoke the link starting ${b.token.slice(0,8)}…? Anyone still holding it won't be able to join.`,"Revoke",!0))try{await Un("DELETE",`/api/orgs/${e.id}/invites/${b.token}`),Qe("Revoked."),u()}catch(x){Qe(x.message,!0)}},children:"Revoke"})]},b.token))]}),m.jsx("h3",{children:"Public share links"}),m.jsx("p",{className:"admin-sub",children:"Every live link across this organization's projects. A project's own links are on its Settings page, and on the file itself."}),m.jsx(_C,{shares:y||[],onChanged:d,showProject:!0})]})]})}function s$({org:e,owner:n,myEmail:r,onChanged:o}){const[s,l]=w.useState([{id:"email",desc:!1}]),u=w.useMemo(()=>__(),[]),d=w.useMemo(()=>[u.accessor("email",{id:"email",header:"Member",cell:h=>{const y=!!r&&h.getValue().toLowerCase()===r.toLowerCase();return m.jsx("span",{className:"ai-main",title:h.getValue(),children:h.getValue()+(y?" (you)":"")})}}),u.accessor("role",{id:"role",header:"Role",cell:h=>{const y=h.row.original,v=!!r&&y.email.toLowerCase()===r.toLowerCase();return!n||v?m.jsx("span",{className:"ai-tag role-static",children:y.role}):m.jsxs("span",{className:"role-cell",children:[m.jsxs("select",{"aria-label":`Role for ${y.email}`,value:y.role,onChange:async b=>{try{await Un("PATCH",`/api/orgs/${e.id}/members/${encodeURIComponent(y.email)}`,{role:b.target.value}),Qe("Role updated.")}catch(x){Qe(x.message,!0)}o()},children:[m.jsx("option",{value:"owner",children:"owner"}),m.jsx("option",{value:"member",children:"member"})]}),m.jsx("button",{className:"ai-del","aria-label":`Remove ${y.email}`,onClick:async()=>{if(await Yu("Remove member",`Remove ${y.email} from ${e.name}?`,"Remove",!0))try{await Un("DELETE",`/api/orgs/${e.id}/members/${encodeURIComponent(y.email)}`),Qe("Removed."),o()}catch(b){Qe(b.message,!0)}},children:"Remove"})]})}})],[u,e.id,e.name,n,r]),p=k_({data:e.members,columns:d,state:{sorting:s},onSortingChange:l,getCoreRowModel:D_(),getSortedRowModel:z_()});return m.jsx(xC,{table:p})}const l$=sg({require_verification:Bx(),require_approval:Bx()});function c$(){const e=jo(),{data:n,error:r}=Gt({queryKey:["admin","policy"],queryFn:()=>cn("/api/admin/policy")}),{data:o}=b_(!0),s=Jp({resolver:ag(l$),values:n?{require_verification:n.require_verification&&n.mailer,require_approval:n.require_approval}:{require_verification:!1,require_approval:!1}});if(w.useEffect(()=>{r&&Qe(r.message,!0)},[r]),!n)return null;const l=async(u,d,p)=>{try{await Ia(`/api/admin/pending/${u}/${d}`),Qe((d==="approve"?"Approved ":"Denied ")+p),e.invalidateQueries({queryKey:["admin","pending"]})}catch(h){Qe(h.message,!0)}};return m.jsxs("div",{className:"admin",children:[m.jsx("h1",{children:"Signup & access"}),m.jsx("p",{className:"admin-sub",children:"Who can create an account on this hub, and how new accounts are vetted."}),m.jsx("h3",{children:"New-account vetting"}),m.jsxs("form",{onSubmit:s.handleSubmit(async u=>{try{await Ia("/api/admin/policy",u),Qe("Signup policy saved."),e.invalidateQueries({queryKey:["admin","policy"]})}catch(d){Qe(d.message,!0)}}),children:[m.jsxs("div",{className:"admin-list",children:[m.jsx(Xx,{label:"Require email verification",desc:n.mailer?"New accounts must click an emailed link before they can sign in — proves they control the address.":"Configure SMTP on the server (auth.smtp) to enable email verification.",disabled:!n.mailer,inputProps:s.register("require_verification")}),m.jsx(Xx,{label:"Require admin approval",desc:"New accounts wait for a hub admin to approve them before they gain access.",inputProps:s.register("require_approval")})]}),m.jsx(Ct,{variant:"primary",type:"submit",style:{marginTop:14},disabled:!s.formState.isDirty,children:"Save policy"})]}),m.jsx("h3",{children:"Who can sign up"}),m.jsxs("div",{className:"admin-list",children:[m.jsxs("div",{className:"admin-item",children:[m.jsx("span",{className:"ai-main",children:"Allowed email domains"}),m.jsx("span",{className:"ai-tag",children:n.allowed_domains&&n.allowed_domains.length?n.allowed_domains.map(u=>"@"+u).join(", "):"any"})]}),m.jsxs("div",{className:"admin-item",children:[m.jsx("span",{className:"ai-main",children:"Self-signup"}),m.jsx("span",{className:"ai-tag",children:n.allow_signup?"open":"invite-only"})]}),m.jsxs("div",{className:"admin-item",children:[m.jsx("span",{className:"ai-main",children:"Hub admins"}),m.jsx("span",{className:"ai-tag",children:n.admins&&n.admins.length?n.admins.join(", "):"none"})]})]}),m.jsx("p",{className:"admin-sub",children:"Domains and admins are set in the server config file (they can't be widened from the browser)."}),m.jsx("h3",{children:"Pending signups"}),m.jsxs("div",{className:"admin-list",children:[(!o||o.length===0)&&m.jsx("div",{className:"admin-empty",children:"No one is waiting for approval."}),(o||[]).map(u=>m.jsxs("div",{className:"admin-item",children:[m.jsx("span",{className:"ai-main",children:(u.name?u.name+" · ":"")+u.email}),m.jsx(Ct,{variant:"primary",onClick:()=>l(u.id,"approve",u.email),children:"Approve"}),m.jsx("button",{className:"ai-del",onClick:()=>l(u.id,"deny",u.email),children:"Deny"})]},u.id))]})]})}function Xx({label:e,desc:n,disabled:r,inputProps:o}){return m.jsxs("label",{className:"admin-item toggle",style:r?{opacity:.55}:void 0,children:[m.jsxs("span",{className:"ai-main",children:[m.jsx("div",{className:"tg-label",children:e}),m.jsx("div",{className:"tg-desc",children:n})]}),m.jsx("input",{type:"checkbox",disabled:r,...o})]})}function u$({...e}){return m.jsx(r1,{"data-slot":"select",...e})}function d$({...e}){return m.jsx(s1,{"data-slot":"select-value",...e})}function f$({className:e,size:n="default",children:r,...o}){return m.jsxs(o1,{"data-slot":"select-trigger","data-size":n,className:We("flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",e),...o,children:[r,m.jsx(l1,{asChild:!0,children:m.jsx(Lp,{className:"size-4 opacity-50"})})]})}function h$({className:e,children:n,position:r="item-aligned",align:o="center",...s}){return m.jsx(u1,{children:m.jsxs(d1,{"data-slot":"select-content",className:We("relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",r==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",e),position:r,align:o,...s,children:[m.jsx(p$,{}),m.jsx(g1,{className:We("p-1",r==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"),children:n}),m.jsx(g$,{})]})})}function m$({className:e,children:n,...r}){return m.jsxs(x1,{"data-slot":"select-item",className:We("relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",e),...r,children:[m.jsx("span",{"data-slot":"select-item-indicator",className:"absolute right-2 flex size-3.5 items-center justify-center",children:m.jsx(_1,{children:m.jsx(o_,{className:"size-4"})})}),m.jsx(w1,{children:n})]})}function p$({className:e,...n}){return m.jsx(C1,{"data-slot":"select-scroll-up-button",className:We("flex cursor-default items-center justify-center py-1",e),...n,children:m.jsx(HD,{className:"size-4"})})}function g$({className:e,...n}){return m.jsx(E1,{"data-slot":"select-scroll-down-button",className:We("flex cursor-default items-center justify-center py-1",e),...n,children:m.jsx(Lp,{className:"size-4"})})}const Jx=["#5b8def","#f5a623","#4cc38a","#e0679b","#8b7bf0","#3ec8c8","#e6934a"];function ul(e){let n=0;for(const r of e)n=n*31+r.charCodeAt(0)>>>0;return Jx[n%Jx.length]}function Wx({projects:e,currentId:n,menu:r}){const o=Pp(),s=e.find(u=>u.id===n),l=async()=>{const u=await Fp("New project","Project name","","Create");if(u!==null)try{const d=await Ia("/api/projects",{name:u});await o(),yn("/"+d.project.id),Qe(`Created “${d.project.name}”.`)}catch(d){Qe("Could not create the project: "+d.message,!0)}};return m.jsxs("nav",{id:"projects","aria-label":"Projects",children:[m.jsxs("div",{className:"nav-head",children:[m.jsx("span",{children:"Projects"}),m.jsx("button",{className:"nav-add",title:"New project","aria-label":"New project",onClick:l,children:"+"})]}),m.jsx("div",{className:"proj-row",children:m.jsxs(u$,{value:n||"",onValueChange:u=>{u&&u!==n&&(yn("/"+u),mr())},children:[m.jsxs(f$,{id:"project-select","aria-label":`Switch project — current: ${s?.name??"none"}`,title:s?.name,className:"proj-trigger",children:[s&&m.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:ul(s.name)},children:m.jsx(ka,{name:s.icon})}),s?m.jsx("span",{"data-slot":"select-value",children:s.name}):m.jsx(d$,{placeholder:"Select a project"})]}),m.jsx(h$,{className:"proj-menu",position:"popper",sideOffset:4,children:e.map(u=>m.jsxs(m$,{value:u.id,children:[m.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:ul(u.name)},children:m.jsx(ka,{name:u.icon})}),u.name]},u.id))})]})}),r&&m.jsx("ul",{className:"nav-menu","aria-label":"Project pages",children:[["dashboard","Dashboard","dashboard",r.onDashboard],["install","Installation","terminal",r.onInstall],["history","History","hist",r.onHistory],["settings","Settings","gear",r.onSettings]].map(([u,d,p,h])=>m.jsx("li",{children:m.jsxs("div",{id:"nav-"+u,className:"row"+(r.active===u?" active":""),role:"button",tabIndex:0,onClick:h,onKeyDown:y=>{(y.key==="Enter"||y.key===" ")&&(y.preventDefault(),h())},children:[m.jsx(yt,{name:p}),m.jsx("span",{className:"label",children:d})]})},u))})]})}function EC({...e}){return m.jsx(wM,{"data-slot":"dropdown-menu",...e})}function RC({...e}){return m.jsx(SM,{"data-slot":"dropdown-menu-trigger",...e})}function TC({className:e,sideOffset:n=4,...r}){return m.jsx(_M,{children:m.jsx(CM,{"data-slot":"dropdown-menu-content",sideOffset:n,className:We("z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",e),...r})})}function Na({className:e,inset:n,variant:r="default",...o}){return m.jsx(RM,{"data-slot":"dropdown-menu-item","data-inset":n,"data-variant":r,className:We("relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",e),...o})}function Xh({className:e,inset:n,...r}){return m.jsx(EM,{"data-slot":"dropdown-menu-label","data-inset":n,className:We("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",e),...r})}function v$({me:e,org:n,admin:r,orgActive:o,billing:s}){const l=e.name||e.email,[u,d]=w.useState(!1),p=n?yu(n.manage_url):null,h=s?yu(s.url):null;return m.jsx("footer",{id:"accountbar",children:m.jsxs(EC,{modal:!1,open:u,onOpenChange:d,children:[m.jsx(RC,{asChild:!0,children:m.jsxs("button",{id:"account-btn",className:o?"active":void 0,"aria-label":"Account menu",children:[m.jsx("span",{className:"avatar",style:{background:ul(e.email)},"aria-hidden":"true",children:(l.trim()[0]||"?").toUpperCase()}),m.jsxs("span",{className:"acct",children:[m.jsx("b",{children:l}),e.name&&m.jsx("small",{children:e.email})]}),m.jsx(yt,{name:"chev"})]})}),m.jsxs(TC,{id:"account-menu",side:"top",align:"start",sideOffset:6,className:"acct-menu",children:[n&&m.jsxs(m.Fragment,{children:[m.jsx(Xh,{className:"menu-sec",children:"Organization"}),m.jsx(Na,{asChild:!0,children:m.jsxs("a",{id:"menu-org-settings","aria-current":o?"page":void 0,...p,onClick:y=>{p?.onClick?.(y),d(!1)},children:[m.jsx(yt,{name:"gear"}),m.jsxs("span",{children:[m.jsx("b",{children:n.name})," Settings"]}),!n.manage_url.startsWith("/")&&m.jsxs(m.Fragment,{children:[m.jsx("span",{className:"ext","aria-hidden":"true",children:"↗"}),m.jsx("span",{className:"sr-only",children:" (opens in a new tab)"})]})]})}),s&&m.jsx(Na,{asChild:!0,children:m.jsxs("a",{id:"menu-billing",...h,onClick:y=>{h?.onClick?.(y),d(!1)},children:[m.jsx(yt,{name:"card"}),m.jsx("span",{children:"Billing"}),m.jsx("span",{className:"ps-chip plan-chip",children:s.plan})]})})]}),r&&m.jsxs(m.Fragment,{children:[m.jsx(Xh,{className:"menu-sec",children:"Hub"}),m.jsxs(Na,{id:"menu-hub-admin",onSelect:r.onClick,children:[m.jsx(yt,{name:"shield"}),m.jsxs("span",{children:["Signup & access",r.pending?` · ${r.pending}`:""]})]})]}),m.jsx(Xh,{className:"menu-sec",children:"Account"}),m.jsx(Na,{asChild:!0,children:m.jsxs("a",{id:"signout",href:"/auth/logout",children:[m.jsx(yt,{name:"power"}),m.jsx("span",{children:"Log out"})]})})]})]})})}function ki({className:e,...n}){return m.jsx("div",{"data-slot":"card",className:We("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",e),...n})}function Li({className:e,...n}){return m.jsx("div",{"data-slot":"card-header",className:We("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",e),...n})}function $i({className:e,...n}){return m.jsx("div",{"data-slot":"card-title",className:We("leading-none font-semibold",e),...n})}function $a({className:e,...n}){return m.jsx("div",{"data-slot":"card-description",className:We("text-muted-foreground text-sm",e),...n})}function Ii({className:e,...n}){return m.jsx("div",{"data-slot":"card-content",className:We("px-6",e),...n})}function ei({className:e,orientation:n="horizontal",decorative:r=!0,...o}){return m.jsx(rN,{"data-slot":"separator",decorative:r,orientation:n,className:We("bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",e),...o})}function y$({url:e}){const n=Gt({queryKey:["billing"],queryFn:()=>cn(e)});if(n.isLoading)return m.jsx("div",{className:"empty",children:"Loading…"});if(n.error||!n.data)return m.jsxs("div",{className:"empty",children:[m.jsx("h3",{children:"Billing is unavailable"}),m.jsx("p",{children:n.error?.message||"Try again shortly."})]});const r=n.data;return m.jsxs("div",{className:"project-settings",id:"billing-view",children:[m.jsxs("h2",{children:["Billing",m.jsx("span",{className:"ps-chip plan-chip",children:r.plan.name})]}),m.jsxs(ki,{children:[m.jsxs(Li,{children:[m.jsxs($i,{children:[r.plan.name," plan",r.plan.status?` (${r.plan.status})`:""]}),m.jsxs($a,{children:["Organization ",r.org," · ",r.usage.used," of ",r.usage.cap," used · ",r.seats.used," of ",r.seats.cap," ",r.seats.cap===1?"seat":"seats"]})]}),m.jsx(ei,{}),m.jsx(Ii,{children:m.jsx("div",{className:"usage-bar",children:m.jsx("div",{style:{width:`${r.usage.pct}%`}})})})]}),r.owner?m.jsx("div",{className:"plan-grid",children:r.plans.map(o=>m.jsxs(ki,{children:[m.jsxs(Li,{children:[m.jsx($i,{children:o.name}),m.jsx($a,{children:o.blurb})]}),m.jsx(ei,{}),m.jsxs(Ii,{children:[m.jsxs("p",{className:"plan-price",children:[o.price,m.jsx("small",{children:" / user / month"})]}),m.jsxs("form",{method:"post",action:r.checkout_url,children:[m.jsx("input",{type:"hidden",name:"plan",value:o.id}),m.jsx(Ct,{type:"submit",disabled:o.current,variant:o.current?"subtle":"default",children:o.current?"Current plan":`Upgrade to ${o.name}`})]})]})]},o.id))}):m.jsx("p",{className:"muted-note",children:"Only an organization owner can change the plan."}),r.owner&&r.has_customer&&m.jsxs(ki,{children:[m.jsxs(Li,{children:[m.jsx($i,{children:"Manage subscription"}),m.jsx($a,{children:"Change seats, update the card, download invoices, or cancel."})]}),m.jsx(ei,{}),m.jsx(Ii,{children:m.jsx("form",{method:"post",action:r.portal_url,children:m.jsx(Ct,{type:"submit",variant:"subtle",children:"Open the billing portal"})})})]})]})}function b$({className:e,type:n,...r}){return m.jsx("input",{type:n,"data-slot":"input",className:We("h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30","focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50","aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",e),...r})}function Jh({className:e,...n}){return m.jsx(OM,{"data-slot":"label",className:We("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",e),...n})}function x$({className:e,...n}){return m.jsx("textarea",{"data-slot":"textarea",className:We("border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",e),...n})}const ew={read:1,write:2,admin:3};function wo(e,n){return(ew[e||""]||0)>=(ew[n]||0)}const Um=280,w$=sg({name:au().trim().min(1,"Give the project a name.").max(120,"Keep the name under 120 characters."),description:au().max(Um,`Keep the description under ${Um} characters.`),icon:au()});function S$({project:e,org:n,onDeleted:r}){const o=Pp(),s=wo(e.perm,"admin"),l=Jp({resolver:ag(w$),defaultValues:{name:e.name,description:e.description??"",icon:e.icon??""}});w.useEffect(()=>{l.reset({name:e.name,description:e.description??"",icon:e.icon??""})},[e.id,e.name,e.description,e.icon]);const u=l.watch("icon"),d=l.watch("description"),p=l.handleSubmit(async h=>{const y=l.formState.dirtyFields,v={};if(y.name&&(v.name=h.name.trim()),y.description&&(v.description=h.description),y.icon&&(v.icon=h.icon),Object.keys(v).length!==0)try{await Un("PATCH","/api/projects/"+e.id,v),Qe("Saved."),l.reset({...h,name:h.name.trim()}),await o()}catch(b){Qe(b.message,!0)}});return m.jsxs("div",{className:"project-settings",children:[m.jsxs("h2",{children:[e.name,!wo(e.perm,"write")&&m.jsx("span",{className:"ps-chip",children:"Read-only"})]}),m.jsxs(ki,{children:[m.jsxs(Li,{children:[m.jsx($i,{children:"General"}),m.jsx($a,{children:"Name, description and icon for this project."})]}),m.jsx(ei,{}),m.jsx(Ii,{children:m.jsxs("form",{className:"ps-form",onSubmit:p,children:[m.jsxs("div",{className:"ps-field",children:[m.jsx(Jh,{htmlFor:"ps-icon-btn",children:"Icon"}),m.jsxs("div",{className:"ps-icon-row",children:[m.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:ul(e.name)},children:m.jsx(ka,{name:u})}),m.jsxs(EC,{children:[m.jsx(RC,{asChild:!0,children:m.jsx(Ct,{id:"ps-icon-btn",type:"button",variant:"subtle",disabled:!s,children:"Change"})}),m.jsxs(TC,{align:"start",className:"ps-icon-grid",children:[m.jsx(Na,{className:"ps-icon-cell"+(u===""?" active":""),title:"Default","aria-label":"Default icon",onSelect:()=>l.setValue("icon","",{shouldDirty:!0}),children:m.jsx(ka,{})}),Object.keys(g_).map(h=>m.jsx(Na,{className:"ps-icon-cell"+(u===h?" active":""),title:h,"aria-label":h,onSelect:()=>l.setValue("icon",h,{shouldDirty:!0}),children:m.jsx(ka,{name:h})},h))]})]})]})]}),m.jsxs("div",{className:"ps-field",children:[m.jsx(Jh,{htmlFor:"ps-name",children:"Name"}),m.jsx(b$,{id:"ps-name",disabled:!s,"aria-invalid":!!l.formState.errors.name,"aria-describedby":l.formState.errors.name?"ps-name-err":void 0,...l.register("name")}),l.formState.errors.name&&m.jsx("span",{id:"ps-name-err",role:"alert",className:"field-err",children:l.formState.errors.name.message})]}),m.jsxs("div",{className:"ps-field",children:[m.jsxs(Jh,{htmlFor:"ps-desc",children:["Description ",m.jsx("span",{className:"ps-opt",children:"(optional)"})]}),m.jsx(x$,{id:"ps-desc",rows:2,disabled:!s,placeholder:"What this project is for.","aria-invalid":!!l.formState.errors.description,"aria-describedby":l.formState.errors.description?"ps-desc-err":void 0,...l.register("description")}),m.jsxs("div",{className:"ps-meta",children:[l.formState.errors.description?m.jsx("span",{id:"ps-desc-err",role:"alert",className:"field-err",children:l.formState.errors.description.message}):m.jsx("span",{}),m.jsxs("span",{className:"ps-count",children:[d.length," / ",Um]})]})]}),s&&m.jsxs(m.Fragment,{children:[m.jsx(ei,{}),m.jsx("div",{className:"ps-actions",children:m.jsx(Ct,{id:"ps-save",type:"submit",variant:"primary",disabled:!l.formState.isDirty||l.formState.isSubmitting,children:"Save changes"})})]})]})})]}),m.jsxs(ki,{children:[m.jsx(Li,{children:m.jsx($i,{children:"About"})}),m.jsx(ei,{}),m.jsx(Ii,{children:m.jsxs("dl",{className:"ps-facts",children:[m.jsx("dt",{children:"Project id"}),m.jsx("dd",{children:m.jsx("code",{children:e.id})}),n&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{children:"Workspace"}),m.jsx("dd",{children:n.name})]}),e.created&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{children:"Created"}),m.jsx("dd",{children:new Date(e.created).toLocaleDateString()})]})]})})]}),m.jsx(E$,{project:e,org:n}),m.jsx(_$,{project:e}),s&&m.jsxs(ki,{className:"ps-danger",children:[m.jsx(Li,{children:m.jsx($i,{children:"Danger zone"})}),m.jsx(ei,{}),m.jsxs(Ii,{children:[m.jsx("p",{children:"Deleting removes the project from this hub. Its files stay in storage. This can't be undone."}),m.jsx(Ct,{variant:"danger",onClick:async()=>{if(await Fp(`Delete “${e.name}”?`,"This can't be undone. Type the project name to confirm:","","Delete project",{match:e.name,danger:!0})!==null)try{await Un("DELETE","/api/projects/"+e.id),Qe(`Deleted “${e.name}”.`),await r()}catch(y){Qe(y.message,!0)}},children:"Delete project"})]})]})]})}function _$({project:e}){const n=jo(),{data:r,error:o}=y_(e.id);return o?null:m.jsxs(ki,{children:[m.jsxs(Li,{children:[m.jsx($i,{children:"Public links"}),m.jsx($a,{children:"Files in this project that anyone with the URL can read — no account needed."})]}),m.jsx(ei,{}),m.jsx(Ii,{children:m.jsx(_C,{shares:r||[],canRevoke:wo(e.perm,"write"),onChanged:()=>n.invalidateQueries({queryKey:["shares",e.id]}),empty:"No public links."})})]})}const Hm=[{value:"admin",label:"Admin"},{value:"write",label:"Write"},{value:"read",label:"Read"},{value:"none",label:"No access"}],C$=Object.fromEntries(Hm.map(e=>[e.value,e.label]));function E$({project:e,org:n}){const r=jo(),{data:o,error:s}=a3(e.id),l=wo(e.perm,"admin"),u=()=>{r.invalidateQueries({queryKey:["permissions",e.id]}),r.invalidateQueries({queryKey:["projects"]})},d=async(x,C)=>{try{await x(),Qe(C)}catch(_){Qe(_.message,!0)}u()};if(s||!o)return null;const p=o,h=`/api/p/${e.id}/permissions`,y=new Set((n?.members||[]).filter(x=>x.role==="owner").map(x=>x.email.toLowerCase())),v=[...p.grants.filter(x=>!y.has(x.email.toLowerCase())),...[...y].sort().map(x=>({email:x,level:"admin",owner:!0}))],b=async()=>{const x=await Fp("Add an exception","Email of a workspace member. They get Read access; change it in the table.","","Add");x===null||!x.trim()||await d(()=>Un("PUT",`${h}/${encodeURIComponent(x.trim())}`,{level:"read"}),"Added.")};return m.jsxs(ki,{className:"ps-people",children:[m.jsxs(Li,{children:[m.jsx($i,{children:"People"}),m.jsx($a,{children:"Who can see and change this project."})]}),m.jsx(ei,{}),m.jsxs(Ii,{children:[m.jsxs("p",{className:"ps-row",children:[m.jsxs("span",{children:["Everyone in ",n?.name||"this workspace"," can"]}),m.jsx("select",{"aria-label":"Default access for workspace members",disabled:!l,value:p.default,onChange:async x=>{const C=x.target.value;if(C==="none"&&!await Yu("Make this project invite-only?","Only people listed below (and workspace owners) will see this project.","Make invite-only")){u();return}await d(()=>Un("PUT",h,{default:C}),"Default access updated.")},children:Hm.filter(x=>x.value!=="admin").map(x=>m.jsx("option",{value:x.value,children:x.label},x.value))})]}),p.default==="none"&&m.jsx("p",{className:"ps-note",children:"This project is invite-only: only the people below and workspace owners can see it."}),m.jsxs("div",{className:"ps-people-head",children:[m.jsx("h4",{children:"Exceptions"}),l&&m.jsx(Ct,{type:"button",variant:"subtle",onClick:b,children:"+ Add"})]}),v.length===0?m.jsx("p",{className:"ps-note",children:"No exceptions — everyone gets the access above."}):m.jsx("div",{className:"admin-list",children:v.map(x=>{const C="owner"in x;return m.jsxs("div",{className:"admin-item",children:[m.jsxs("span",{className:"ai-main",title:x.email,children:[x.email,p.creator&&x.email.toLowerCase()===p.creator.toLowerCase()&&m.jsx("span",{className:"ai-tag",children:" (creator)"})]}),C?m.jsx("span",{className:"ai-tag",children:"Workspace owner — always admin"}):m.jsxs("span",{className:"role-cell",children:[m.jsx("select",{"aria-label":`Access for ${x.email}`,disabled:!l,value:x.level,onChange:_=>d(()=>Un("PUT",`${h}/${encodeURIComponent(x.email)}`,{level:_.target.value}),`${x.email} is now ${C$[_.target.value]||_.target.value}.`),children:Hm.map(_=>m.jsx("option",{value:_.value,children:_.label},_.value))}),l&&m.jsx("button",{className:"ai-del","aria-label":`Remove exception for ${x.email}`,onClick:()=>d(()=>Un("DELETE",`${h}/${encodeURIComponent(x.email)}`),"Reverted to the default access."),children:"Remove"})]})]},x.email)})})]})]})}const OC="https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md";function jC({project:e}){const n=window.location.origin,r="Follow "+OC+` -to set up BearDrive project `+e.id+" on "+n+". Ask me which folder to sync.",o=`brew install runbear-io/tap/beardrive +to set up BearDrive project `+e.id+" on "+n+'. Ask me which folder to sync (the project is named "'+e.name+'").',o=`brew install runbear-io/tap/beardrive bdrive login `+n+` bdrive init --project `+e.id;return m.jsxs("div",{className:"guide",children:[m.jsxs("h1",{className:"in-title gd-head",children:[m.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:ul(e.name)},children:m.jsx(ka,{name:e.icon})}),e.name]}),e.description&&m.jsx("p",{className:"in-desc",children:e.description}),m.jsxs("div",{className:"gd-body",children:[m.jsx("p",{className:"gd-desc",children:"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder where you want the files:"}),m.jsx(Bm,{code:r}),m.jsx("p",{className:"gd-desc",children:"The agent installs the CLI, signs this machine in, and registers the sync hooks — asking before anything it changes."}),m.jsxs("details",{className:"gd-manual",children:[m.jsx("summary",{children:"What exactly happens"}),m.jsxs("ul",{className:"gd-desc gd-list",children:[m.jsx("li",{children:"Sign-in uses a device code you approve in this browser — the folder itself never holds credentials."}),m.jsx("li",{children:"Sync hooks pull the latest before every agent turn, push edits seconds after they happen, and stamp each change with the session that made it; agent reads feed Insights. They register once per machine in your agent's own config, so every session is covered and nothing is written into the synced folder."}),m.jsx("li",{children:"Codex hooks are off by default: set [features] codex_hooks = true in ~/.codex/config.toml."})]})]}),m.jsxs("details",{className:"gd-manual",children:[m.jsx("summary",{children:"Or run it yourself"}),m.jsx("p",{className:"gd-desc",children:"Same result, in the folder you want the files. One command: init signs this device in, registers the sync hooks and starts syncing."}),m.jsx(Bm,{code:o}),m.jsx("p",{className:"gd-desc",children:m.jsx("a",{href:"https://docs.beardrive.ai/manual/install/",target:"_blank",rel:"noreferrer",children:"Full manual setup guide →"})})]})]})]})}function Bm({code:e}){const[n,r]=w.useState("Copy");return m.jsxs("pre",{className:"gd-code",children:[m.jsx("code",{children:e}),m.jsx("button",{className:"gd-copy",onClick:async()=>{r(await Ha(e)?"Copied":"Copy failed"),setTimeout(()=>r("Copy"),1400)},children:n})]})}function R$(){return m.jsxs("div",{className:"onboard",children:[m.jsx("h1",{children:"Welcome to BearDrive"}),m.jsx("p",{children:"You're signed in, but you're not part of any project yet."}),m.jsxs("div",{className:"ob-card",children:[m.jsx("h3",{children:"Connect a new drive to your project"}),m.jsx("p",{children:"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder where you want the files. It creates the project and starts syncing:"}),m.jsx(Bm,{code:"Follow "+OC+` to set up a new BearDrive project on `+window.location.origin+". Ask me which folder to sync."}),m.jsx("p",{className:"ob-alt",children:m.jsx("a",{href:"https://docs.beardrive.ai/manual/setup-by-hand/",target:"_blank",rel:"noreferrer",children:"Or start a project manually →"})})]})]})}function T$(e,n=!0){const r=Gt({queryKey:["tree",e],queryFn:()=>cn(e+"tree"),enabled:n,refetchInterval:15e3}),o=w.useMemo(()=>{const s=[],l=new Map,u=d=>{for(const p of d.children||[])p.dir?(l.set(p.path,p),u(p)):s.push(p)};return r.data&&u(r.data),{flatFiles:s,dirIndex:l}},[r.data]);return{tree:r.data,...o,loaded:!!r.data}}function O$(e,n){return Gt({queryKey:["heat",e],queryFn:()=>cn(e+"heat?days=30"),enabled:n,staleTime:6e4,refetchInterval:6e4}).data?.entries??null}function j$(e,n,r){return Gt({queryKey:["history",e,"prefix",n,20],queryFn:()=>cn(e+"history?prefix="+encodeURIComponent(n)+"&n=20"),enabled:r,staleTime:15e3}).data?.entries??null}function tw(e,n,r){if(!e)return null;if(!r)return e[n]||null;const o={human:0,agent:0,share:0};for(const[s,l]of Object.entries(e))s.startsWith(n+"/")&&(o.human+=l.human||0,o.agent+=l.agent||0,o.share+=l.share||0);return o.human||o.agent||o.share?o:null}function dl(e){return(e.human||0)+(e.agent||0)+(e.share||0)}function Ks(e){const n=dl(e);if(!n)return"";const r=n+(n===1?" read":" reads");if(!e.agent&&!e.share)return r;const o=[];return e.human&&o.push(e.human+" human"),e.agent&&o.push(e.agent+" agent"),e.share&&o.push(e.share+" shared"),r+" ("+o.join(", ")+")"}function A$(e){const n=dl(e);return n?n<3?1:n<10?2:n<30?3:4:0}function M$(e,n,r){const o=new Array(e);return new Proxy(o,{get(s,l,u){if(typeof l=="string"){const d=l.charCodeAt(0);if(d>=48&&d<=57){const p=+l;if(Number.isInteger(p)&&p>=0&&po[y]!==h))&&(o=d,s=n(...d),r?.onChange&&!(l&&r.skipInitialOnChange)&&r.onChange(s),l=!1),s}return u.updateDeps=d=>{o=d},u}function nw(e,n){if(e===void 0)throw new Error("Unexpected undefined");return e}const N$=(e,n)=>Math.abs(e-n)<1.01,D$=(e,n,r)=>{let o;return function(...s){e.clearTimeout(o),o=e.setTimeout(()=>n.apply(this,s),r)}};let Hs;const Wh=()=>{if(Hs!==void 0)return Hs;if(typeof navigator>"u")return Hs=!1;if(/iP(hone|od|ad)/.test(navigator.userAgent))return Hs=!0;const e=navigator.maxTouchPoints;return Hs=navigator.platform==="MacIntel"&&e!==void 0&&e>0},rw=e=>{const{offsetWidth:n,offsetHeight:r}=e;return{width:n,height:r}},z$=e=>e,k$=e=>{const n=Math.max(e.startIndex-e.overscan,0),o=Math.min(e.endIndex+e.overscan,e.count-1)-n+1,s=new Array(o);for(let l=0;l{const r=e.scrollElement;if(!r)return;const o=e.targetWindow;if(!o)return;const s=u=>{const{width:d,height:p}=u;n({width:Math.round(d),height:Math.round(p)})};if(s(rw(r)),!o.ResizeObserver)return()=>{};const l=new o.ResizeObserver(u=>{const d=()=>{const p=u[0];if(p?.borderBoxSize){const h=p.borderBoxSize[0];if(h){s({width:h.inlineSize,height:h.blockSize});return}}s(rw(r))};e.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(d):d()});return l.observe(r,{box:"border-box"}),()=>{l.unobserve(r)}},Eu={passive:!0},$$=typeof window>"u"?!0:"onscrollend"in window,I$=(e,n,r)=>{const o=e.scrollElement;if(!o)return;const s=e.targetWindow;if(!s)return;const l=e.options.useScrollendEvent&&$$;let u=0;const d=l?null:D$(s,()=>n(u,!1),e.options.isScrollingResetDelay),p=v=>()=>{u=r(o),d?.(),n(u,v)},h=p(!0),y=p(!1);return o.addEventListener("scroll",h,Eu),l&&o.addEventListener("scrollend",y,Eu),()=>{o.removeEventListener("scroll",h),l&&o.removeEventListener("scrollend",y)}},V$=(e,n)=>I$(e,n,r=>{const{horizontal:o,isRtl:s}=e.options;return o?r.scrollLeft*(s&&-1||1):r.scrollTop}),F$=(e,n,r)=>{if(r.options.useCachedMeasurements){const o=r.indexFromElement(e),s=r.options.getItemKey(o);return r.itemSizeCache.get(s)??r.options.estimateSize(o)}if(n?.borderBoxSize){const o=n.borderBoxSize[0];if(o)return Math.round(o[r.options.horizontal?"inlineSize":"blockSize"])}if(!n){const o=r.indexFromElement(e),s=r.options.getItemKey(o),l=r.itemSizeCache.get(s);if(l!==void 0)return l}return e[r.options.horizontal?"offsetWidth":"offsetHeight"]},P$=(e,{adjustments:n=0,behavior:r},o)=>{var s,l;(l=(s=o.scrollElement)==null?void 0:s.scrollTo)==null||l.call(s,{[o.options.horizontal?"left":"top"]:e+n,behavior:r})},U$=P$;class H${constructor(n){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollState=null,this.measurementsCache=[],this._flatMeasurements=null,this.itemSizeCache=new Map,this.itemSizeCacheVersion=0,this.laneAssignments=new Map,this.pendingMin=null,this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.pendingScrollAnchor=null,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._intendedScrollOffset=null,this.elementsCache=new Map,this.now=()=>{var r,o,s;return((s=(o=(r=this.targetWindow)==null?void 0:r.performance)==null?void 0:o.now)==null?void 0:s.call(o))??Date.now()},this.observer=(()=>{let r=null;const o=()=>r||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:r=new this.targetWindow.ResizeObserver(s=>{s.forEach(l=>{const u=()=>{const d=l.target,p=this.indexFromElement(d);if(!d.isConnected){this.observer.unobserve(d);for(const[h,y]of this.elementsCache)if(y===d){this.elementsCache.delete(h);break}return}this.shouldMeasureDuringScroll(p)&&this.resizeItem(p,this.options.measureElement(d,l,this))};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(u):u()})}));return{disconnect:()=>{var s;(s=o())==null||s.disconnect(),r=null},observe:s=>{var l;return(l=o())==null?void 0:l.observe(s,{box:"border-box"})},unobserve:s=>{var l;return(l=o())==null?void 0:l.unobserve(s)}}})(),this.range=null,this.setOptions=r=>{var o,s;const l={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:z$,rangeExtractor:k$,onChange:()=>{},measureElement:F$,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,anchorTo:"start",followOnAppend:!1,scrollEndThreshold:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,laneAssignmentMode:"estimate",useCachedMeasurements:!1};for(const b in r){const x=r[b];x!==void 0&&(l[b]=x)}const u=this.options;let d=null,p=null,h=!1;if(u!==void 0&&u.enabled&&l.enabled&&l.anchorTo==="end"&&this.scrollElement!==null){const b=u.count,x=l.count,C=this.getMeasurements(),_=b>0?((o=C[0])==null?void 0:o.key)??u.getItemKey(0):null,E=b>0?((s=C[b-1])==null?void 0:s.key)??u.getItemKey(b-1):null;if(x!==b||b>0&&x>0&&(l.getItemKey(0)!==_||l.getItemKey(x-1)!==E)){h=!0;const A=b>0?this.getVirtualItemForOffset(this.getScrollOffset())??C[0]:null;A&&(d=[A.key,this.getScrollOffset()-A.start]);const z=l.followOnAppend===!0?"auto":l.followOnAppend||null;z&&x>b&&this.isAtEnd(u.scrollEndThreshold)&&(b===0||l.getItemKey(x-1)!==E)&&(p=z)}}this.options=l,h&&(this.pendingMin=0,this.itemSizeCacheVersion++);let y=!1,v=0;if(d&&this.scrollOffset!==null){const[b,x]=d,C=this.getMeasurements(),{count:_,getItemKey:E}=this.options;let T=0;for(;T<_&&E(T)!==b;)T++;if(T<_){const O=C[T];if(O){const A=O.start+x;A!==this.scrollOffset&&(v=A-this.scrollOffset,this.scrollOffset=A,y=!0)}}}(y||p)&&(this.pendingScrollAnchor=[y?d[0]:null,y?d[1]:0,p,v])},this.notify=r=>{var o,s;(s=(o=this.options).onChange)==null||s.call(o,this,r)},this.maybeNotify=Ta(()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]),r=>{this.notify(r)},{key:!1,debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(r=>r()),this.unsubs=[],this.observer.disconnect(),this.rafId!=null&&this.targetWindow&&(this.targetWindow.cancelAnimationFrame(this.rafId),this.rafId=null),this.scrollState=null,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var r;const o=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==o){if(this.cleanup(),!o){this.maybeNotify();return}if(this.scrollElement=o,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((r=this.scrollElement)==null?void 0:r.window)??null,this.elementsCache.forEach(l=>{this.observer.observe(l)}),this.unsubs.push(this.options.observeElementRect(this,l=>{this.scrollRect=l,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(l,u)=>{if(u&&this._intendedScrollOffset===null&&l===this.scrollOffset)return;this._intendedScrollOffset!==null&&Math.abs(l-this._intendedScrollOffset)<1.5&&(l=this._intendedScrollOffset),this._intendedScrollOffset=null,this.scrollAdjustments=0;const d=this.getScrollOffset();this.scrollDirection=u?d===l?this.scrollDirection:d{this._iosTouching=!0,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)},d=()=>{this._iosTouching=!1,!(!Wh()||this.targetWindow==null)&&(this._iosJustTouchEnded=!0,this._iosTouchEndTimerId=this.targetWindow.setTimeout(()=>{this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._flushIosDeferredIfReady()},150))};l.addEventListener("touchstart",u,Eu),l.addEventListener("touchend",d,Eu),this.unsubs.push(()=>{l.removeEventListener("touchstart",u),l.removeEventListener("touchend",d),this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)})}this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}const s=this.pendingScrollAnchor;if(this.pendingScrollAnchor=null,s&&this.scrollElement&&this.options.enabled){const[l,u,d,p]=s;l!==null&&!d&&(Wh()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?p!==0&&(this._iosDeferredAdjustment+=p):this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})),d&&this.scrollToEnd({behavior:d})}},this._flushIosDeferredIfReady=()=>{if(this._iosDeferredAdjustment===0||this.isScrolling||this._iosTouching||this._iosJustTouchEnded)return;const r=this.getScrollOffset(),o=this.getMaxScrollOffset();if(r<0||r>o)return;const s=this._iosDeferredAdjustment;this._iosDeferredAdjustment=0,this._scrollToOffset(r,{adjustments:this.scrollAdjustments+=s,behavior:void 0})},this.rafId=null,this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getMeasurementOptions=Ta(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes,this.options.laneAssignmentMode,this.options.gap],(r,o,s,l,u,d,p,h)=>(this.prevLanes!==void 0&&this.prevLanes!==d&&(this.lanesChangedFlag=!0),this.prevLanes=d,this.pendingMin=null,{count:r,paddingStart:o,scrollMargin:s,getItemKey:l,enabled:u,lanes:d,laneAssignmentMode:p,gap:h}),{key:!1}),this.getMeasurements=Ta(()=>[this.getMeasurementOptions(),this.itemSizeCacheVersion],({count:r,paddingStart:o,scrollMargin:s,getItemKey:l,enabled:u,lanes:d,laneAssignmentMode:p,gap:h},y)=>{const v=this.itemSizeCache;if(!u)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>r)for(const T of this.laneAssignments.keys())T>=r&&this.laneAssignments.delete(T);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMin=null),this.measurementsCache.length===0&&!this.lanesSettling&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(T=>{this.itemSizeCache.set(T.key,T.size)}));const b=this.lanesSettling?0:this.pendingMin??0;if(this.pendingMin=null,this.lanesSettling&&this.measurementsCache.length===r&&(this.lanesSettling=!1),d===1){const T=r*2;let O=this._flatMeasurements;if(!O||O.length0&&L.set(O.subarray(0,b*2)),O=L,this._flatMeasurements=O}let A;if(b===0)A=o+s;else{const L=b-1;A=O[L*2]+O[L*2+1]+h}for(let L=b;L1){z=A;const ve=C[z],fe=ve!==void 0?x[ve]:void 0;L=fe?fe.end+h:o+s}else if(E===d){let ve=0,fe=_[0],ce=C[0];for(let le=1;lethis.options.debug}),this.calculateRange=Ta(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(r,o,s,l)=>r.length===0||o===0?(this.range=null,null):(this.range=q$(r,o,s,l,l===1&&this._flatMeasurements!=null?this._flatMeasurements:null),this.range),{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=Ta(()=>{let r=null,o=null;const s=this.calculateRange();return s&&(r=s.startIndex,o=s.endIndex),this.maybeNotify.updateDeps([this.isScrolling,r,o]),[this.options.rangeExtractor,this.options.overscan,this.options.count,r,o]},(r,o,s,l,u)=>l===null||u===null?[]:r({startIndex:l,endIndex:u,overscan:o,count:s}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=r=>{const o=this.options.indexAttribute,s=r.getAttribute(o);return s?parseInt(s,10):(console.warn(`Missing attribute name '${o}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=r=>{var o;if(!this.scrollState||this.scrollState.behavior!=="smooth")return!0;const s=this.scrollState.index??((o=this.getVirtualItemForOffset(this.scrollState.lastTargetOffset))==null?void 0:o.index);if(s!==void 0&&this.range){const l=Math.max(this.options.overscan,Math.ceil((this.range.endIndex-this.range.startIndex)/2)),u=Math.max(0,s-l),d=Math.min(this.options.count-1,s+l);return r>=u&&r<=d}return!0},this.measureElement=r=>{if(!r){this.elementsCache.forEach((u,d)=>{u.isConnected||(this.observer.unobserve(u),this.elementsCache.delete(d))});return}const o=this.indexFromElement(r),s=this.options.getItemKey(o),l=this.elementsCache.get(s);l!==r&&(l&&this.observer.unobserve(l),this.observer.observe(r),this.elementsCache.set(s,r)),(!this.isScrolling||this.scrollState)&&this.shouldMeasureDuringScroll(o)&&this.resizeItem(o,this.options.measureElement(r,void 0,this))},this.resizeItem=(r,o)=>{var s,l;if(r<0||r>=this.options.count)return;let u,d,p;const h=this._flatMeasurements;if(this.options.lanes===1&&h!==null)p=this.options.getItemKey(r),d=h[r*2],u=h[r*2+1];else{const b=this.measurementsCache[r];if(!b)return;p=b.key,d=b.start,u=b.size}const y=this.itemSizeCache.get(p)??u,v=o-y;if(v!==0){const b=this.options.anchorTo==="end"&&((s=this.scrollState)==null?void 0:s.behavior)!=="smooth"&&this.getVirtualDistanceFromEnd()<=this.options.scrollEndThreshold,x=b?this.getTotalSize():0,C=((l=this.scrollState)==null?void 0:l.behavior)!=="smooth"&&(this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(this.measurementsCache[r]??{index:r,key:p,start:d,size:u,end:d+u,lane:0},v,this):d[this.getVirtualIndexes(),this.getMeasurements()],(r,o)=>{const s=[];for(let l=0,u=r.length;lthis.options.debug}),this.getVirtualItemForOffset=r=>{const o=this.getMeasurements();if(o.length===0)return;const s=this._flatMeasurements,l=this.options.lanes===1&&s!=null,u=AC(0,o.length-1,l?d=>s[d*2]:d=>nw(o[d]).start,r);return nw(o[u])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if("scrollHeight"in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{const r=this.scrollElement.document.documentElement;return this.options.horizontal?r.scrollWidth-this.scrollElement.innerWidth:r.scrollHeight-this.scrollElement.innerHeight}},this.getVirtualDistanceFromEnd=()=>Math.max(this.getTotalSize()-this.getSize()-this.getScrollOffset(),0),this.getDistanceFromEnd=()=>Math.max(this.getMaxScrollOffset()-this.getScrollOffset(),0),this.isAtEnd=(r=this.options.scrollEndThreshold)=>this.getDistanceFromEnd()<=r,this.getOffsetForAlignment=(r,o,s=0)=>{if(!this.scrollElement)return 0;const l=this.getSize(),u=this.getScrollOffset();o==="auto"&&(o=r>=u+l?"end":"start"),o==="center"?r+=(s-l)/2:o==="end"&&(r-=l);const d=this.getMaxScrollOffset();return Math.max(Math.min(d,r),0)},this.getOffsetForIndex=(r,o="auto")=>{r=Math.max(0,Math.min(r,this.options.count-1));const s=this.getSize(),l=this.getScrollOffset(),u=this.measurementsCache[r];if(!u)return;if(o==="auto")if(u.end>=l+s-this.options.scrollPaddingEnd)o="end";else if(u.start<=l+this.options.scrollPaddingStart)o="start";else return[l,o];if(o==="end"&&r===this.options.count-1)return[this.getMaxScrollOffset(),o];const d=o==="end"?u.end+this.options.scrollPaddingEnd:u.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(d,o,u.size),o]},this.scrollToOffset=(r,{align:o="start",behavior:s="auto"}={})=>{const l=this.getOffsetForAlignment(r,o),u=this.now();this.scrollState={index:null,align:o,behavior:s,startedAt:u,lastTargetOffset:l,stableFrames:0},this._scrollToOffset(l,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollToIndex=(r,{align:o="auto",behavior:s="auto"}={})=>{r=Math.max(0,Math.min(r,this.options.count-1));const l=this.getOffsetForIndex(r,o);if(!l)return;const[u,d]=l,p=this.now();this.scrollState={index:r,align:d,behavior:s,startedAt:p,lastTargetOffset:u,stableFrames:0},this._scrollToOffset(u,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollBy=(r,{behavior:o="auto"}={})=>{const s=this.getScrollOffset()+r,l=this.now();this.scrollState={index:null,align:"start",behavior:o,startedAt:l,lastTargetOffset:s,stableFrames:0},this._scrollToOffset(s,{adjustments:void 0,behavior:o}),this.scheduleScrollReconcile()},this.scrollToEnd=({behavior:r="auto"}={})=>{if(this.options.count>0){this.scrollToIndex(this.options.count-1,{align:"end",behavior:r});return}this.scrollToOffset(Math.max(this.getTotalSize()-this.getSize(),0),{behavior:r})},this.getTotalSize=()=>{var r;const o=this.getMeasurements();let s;if(o.length===0)s=this.options.paddingStart;else if(this.options.lanes===1){const l=o.length-1,u=this._flatMeasurements;u!=null?s=u[l*2]+u[l*2+1]:s=((r=o[l])==null?void 0:r.end)??0}else{const l=Array(this.options.lanes).fill(null);let u=o.length-1;for(;u>=0&&l.some(d=>d===null);){const d=o[u];l[d.lane]===null&&(l[d.lane]=d.end),u--}s=Math.max(...l.filter(d=>d!==null))}return Math.max(s-this.options.scrollMargin+this.options.paddingEnd,0)},this.takeSnapshot=()=>{const r=[];if(this.itemSizeCache.size===0)return r;const o=this.getMeasurements();for(const s of o)s&&this.itemSizeCache.has(s.key)&&r.push({index:s.index,key:s.key,start:s.start,size:s.size,end:s.end,lane:s.lane});return r},this._scrollToOffset=(r,{adjustments:o,behavior:s})=>{this._intendedScrollOffset=r+(o??0),this.options.scrollToFn(r,{behavior:s,adjustments:o},this)},this.measure=()=>{this.pendingMin=null,this.itemSizeCache.clear(),this.laneAssignments.clear(),this.itemSizeCacheVersion++,this.notify(!1)},this.setOptions(n)}applyScrollAdjustment(n,r){n!==0&&(Wh()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?this._iosDeferredAdjustment+=n:(this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=n,behavior:r}),this.scrollOffset!==null&&(this.scrollOffset+=this.scrollAdjustments,this.scrollAdjustments=0)))}scheduleScrollReconcile(){if(!this.targetWindow){this.scrollState=null;return}this.rafId==null&&(this.rafId=this.targetWindow.requestAnimationFrame(()=>{this.rafId=null,this.reconcileScroll()}))}reconcileScroll(){if(!this.scrollState||!this.scrollElement)return;if(this.now()-this.scrollState.startedAt>5e3){this.scrollState=null;return}const o=this.scrollState.index!=null?this.getOffsetForIndex(this.scrollState.index,this.scrollState.align):void 0,s=o?o[0]:this.scrollState.lastTargetOffset,l=1,u=s!==this.scrollState.lastTargetOffset;if(!u&&N$(s,this.getScrollOffset())){if(this.scrollState.stableFrames++,this.scrollState.stableFrames>=l){this.getScrollOffset()!==s&&this._scrollToOffset(s,{adjustments:void 0,behavior:"auto"}),this.scrollState=null;return}}else if(this.scrollState.stableFrames=0,u){const d=this.getSize()||600,p=Math.abs(s-this.getScrollOffset()),h=this.scrollState.behavior==="smooth"&&p>d;this.scrollState.lastTargetOffset=s,h||(this.scrollState.behavior="auto"),this._scrollToOffset(s,{adjustments:void 0,behavior:h?"smooth":"auto"})}this.scheduleScrollReconcile()}}const AC=(e,n,r,o)=>{for(;e<=n;){const s=(e+n)/2|0,l=r(s);if(lo)n=s-1;else return s}return e>0?e-1:0};function B$(e,n,r){let o=0;for(;o<=n;){const s=(o+n)/2|0,l=e[s*2];if(lr)n=s-1;else return s}return o>0?o-1:0}function q$(e,n,r,o,s){const l=e.length-1;if(e.length<=o)return{startIndex:0,endIndex:l};if(o===1&&s!==null){const h=B$(s,l,r);let y=h;const v=r+n;for(;ye[h].start,r),p=d;if(o===1)for(;p1){const h=Array(o).fill(0);for(;pv=0&&y.some(v=>v>=r);){const v=e[d];y[v.lane]=v.start,d--}d=Math.max(0,d-d%o),p=Math.min(l,p+(o-1-p%o))}return{startIndex:d,endIndex:p}}const em=typeof document<"u"?w.useLayoutEffect:w.useEffect;function G$({useFlushSync:e=!0,directDomUpdates:n=!1,directDomUpdatesMode:r="transform",...o}){const s=w.useReducer(h=>h+1,0)[1],l=w.useRef({enabled:n,mode:r,container:null,lastSize:null,lastPositions:new WeakMap,prevRange:null});l.current.enabled=n,l.current.mode=r;const u=h=>{const y=l.current;if(!y.enabled||!y.container)return;const v=h.getTotalSize();if(v!==y.lastSize){y.lastSize=v;const T=h.options.horizontal?"width":"height";y.container.style[T]=`${v}px`}const b=!!h.options.horizontal,x=y.mode==="transform",C=b?"left":"top",_=h.options.scrollMargin,E=h.getVirtualItems();for(const T of E){const O=T.start-_,A=h.elementsCache.get(T.key);A&&y.lastPositions.get(A)!==O&&(y.lastPositions.set(A,O),x?A.style.transform=b?`translate3d(${O}px, 0, 0)`:`translate3d(0, ${O}px, 0)`:A.style[C]=`${O}px`)}},d={...o,onChange:(h,y)=>{var v;const b=l.current;let x=!0;if(b.enabled){u(h);const C=h.range,_=b.prevRange;x=!_||_.isScrolling!==h.isScrolling||_.startIndex!==C?.startIndex||_.endIndex!==C?.endIndex,x&&(b.prevRange=C?{startIndex:C.startIndex,endIndex:C.endIndex,isScrolling:h.isScrolling}:null)}x&&(e&&y?Ao.flushSync(s):s()),(v=o.onChange)==null||v.call(o,h,y)}},[p]=w.useState(()=>{const h=new H$(d);return Object.assign(h,{containerRef:y=>{const v=l.current;if(v.container=y,v.lastSize=null,y&&v.enabled){const b=h.getTotalSize();v.lastSize=b;const x=h.options.horizontal?"width":"height";y.style[x]=`${b}px`}}})});return p.setOptions(d),em(()=>p._didMount(),[]),em(()=>p._willUpdate()),em(()=>{u(p)}),p}function Z$(e){return G$({observeElementRect:L$,observeElementOffset:V$,scrollToFn:U$,...e})}function K$(e,n){const r=[],o=(s,l)=>{for(const u of s)r.push({node:u,depth:l}),u.dir&&n.has(u.path)&&o(u.children||[],l+1)};return o(e?.children||[],0),r}function Y$(e){const{root:n,expanded:r,onToggle:o,currentPath:s,listingShowing:l,onOpen:u}=e,d=w.useRef(null),p=w.useMemo(()=>K$(n,r),[n,r]),h=Z$({count:p.length,getScrollElement:()=>d.current,estimateSize:()=>window.matchMedia("(max-width: 768px)").matches?44:28,overscan:12,getItemKey:y=>p[y].node.path});return w.useEffect(()=>{if(!s)return;const y=p.findIndex(v=>v.node.path===s);y>=0&&h.scrollToIndex(y,{align:"auto"})},[s,p]),m.jsx("nav",{id:"tree","aria-label":"Files",ref:d,children:m.jsx("div",{style:{height:h.getTotalSize(),position:"relative"},children:h.getVirtualItems().map(y=>{const{node:v,depth:b}=p[y.index],x=v.dir?r.has(v.path):!1,C=()=>{if(v.dir&&s===v.path&&l){o(v.path);return}u(v.path),v.dir||mr()};return m.jsxs("div",{className:"row "+(v.dir?"dir":"file")+(s===v.path?" active":"")+(v.dir&&!x?" collapsed":""),"data-path":v.path,tabIndex:0,role:"button",title:v.name,"aria-expanded":v.dir?x:void 0,style:{position:"absolute",top:0,left:0,right:0,transform:`translateY(${y.start}px)`,paddingLeft:8+b*13},onClick:C,onKeyDown:_=>{(_.key==="Enter"||_.key===" ")&&(_.preventDefault(),C())},children:[Array.from({length:b},(_,E)=>m.jsx("span",{className:"tguide",style:{left:8+E*13+5},"aria-hidden":"true"},E)),m.jsx("span",{className:"chev",onClick:_=>{v.dir&&(_.stopPropagation(),o(v.path))},children:m.jsx(yt,{name:"chevd"})}),m.jsx("span",{className:"ticon",children:m.jsx(yt,{name:v.dir?"folder":"doc"})}),m.jsx("span",{className:"label",children:v.name})]},y.key)})})})}function Q$(e){const n=e.split("/"),r=[];let o="";for(let s=0;s{o=o?o+"/"+s:s;const u=o,d=l===r.length-1;return m.jsxs("span",{children:[l>0&&m.jsx("span",{className:"crumb-sep",children:"/"}),d?m.jsx("span",{children:s}):m.jsx("span",{className:"crumb-seg",title:u,onClick:()=>n(u),children:s})]},u)})})}function iw(e){if(e==="")return[];const n=e.split(` diff --git a/internal/webapp/static/index.html b/internal/webapp/static/index.html index 5a55785..62b6793 100644 --- a/internal/webapp/static/index.html +++ b/internal/webapp/static/index.html @@ -5,7 +5,7 @@ BearDrive - + diff --git a/internal/webapp/store_test.go b/internal/webapp/store_test.go index e7d6642..45e2189 100644 --- a/internal/webapp/store_test.go +++ b/internal/webapp/store_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/google/uuid" "github.com/runbear-io/beardrive/internal/remote" ) @@ -56,7 +57,10 @@ func TestProjectAPI(t *testing.T) { if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil { t.Fatal(err) } - if !out.Created || out.Project.Name != "my-app" || !strings.HasPrefix(out.Project.ID, "p-") { + // New ids are UUIDs (and must satisfy the route validator, which also + // still accepts the legacy p-xxxxxxxx ids old hubs minted). + if !out.Created || out.Project.Name != "my-app" || + uuid.Validate(out.Project.ID) != nil || !projectIDRe.MatchString(out.Project.ID) { t.Fatalf("create = %+v", out) } id := out.Project.ID diff --git a/web/docs/src/content/docs/guides/agent-artifacts.md b/web/docs/src/content/docs/guides/agent-artifacts.md index 186c8e4..8d52ee5 100644 --- a/web/docs/src/content/docs/guides/agent-artifacts.md +++ b/web/docs/src/content/docs/guides/agent-artifacts.md @@ -13,7 +13,7 @@ sign-in and org membership, and a **public link** that needs no account. ```console $ bdrive url wiki/report.html -https://drive.example.com/p-1a2b3c4d/wiki/report.html +https://drive.example.com/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d/wiki/report.html ``` Computed locally with no network call, always shows the latest synced content, diff --git a/web/docs/src/content/docs/manual/setup-by-hand.md b/web/docs/src/content/docs/manual/setup-by-hand.md index 1064a10..abd74bf 100644 --- a/web/docs/src/content/docs/manual/setup-by-hand.md +++ b/web/docs/src/content/docs/manual/setup-by-hand.md @@ -43,7 +43,7 @@ Once per project. $ cd ~/workspace && bdrive init initialized /Users/snow/workspace server: https://your-hub - project: workspace (p-7f3a2c91) + project: workspace (7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4) claude hooks registered → /Users/snow/.claude/settings.json daemon: running (pid 55434, scan 3s, remote sync 10s) ``` diff --git a/web/docs/src/content/docs/reference/migration.md b/web/docs/src/content/docs/reference/migration.md index 11d1ef6..72515fd 100644 --- a/web/docs/src/content/docs/reference/migration.md +++ b/web/docs/src/content/docs/reference/migration.md @@ -65,9 +65,9 @@ bdrive import team-wiki.tar.gz ``` ``` -imported into "team-wiki" (p-4e1a9b02, created on https://your-hub.example): 3 journal(s), 128 blob(s), 42.7 MB +imported into "team-wiki" (4e1a9b02-9c8d-4e7f-b6a5-3c2d1e0f9a8b, created on https://your-hub.example): 3 journal(s), 128 blob(s), 42.7 MB -connect a folder to it: bdrive init --project p-4e1a9b02 +connect a folder to it: bdrive init --project 4e1a9b02-9c8d-4e7f-b6a5-3c2d1e0f9a8b ``` Import creates the project (named from the archive; `--name` overrides), @@ -80,7 +80,7 @@ On each device that should follow the project to its new home: ```sh bdrive login https://your-hub.example -cd ~/team-wiki && bdrive init --project p-4e1a9b02 +cd ~/team-wiki && bdrive init --project 4e1a9b02-9c8d-4e7f-b6a5-3c2d1e0f9a8b ``` Because the journals were copied byte-for-byte, a reconnecting device's local diff --git a/web/docs/src/content/docs/reference/project-files.md b/web/docs/src/content/docs/reference/project-files.md index 09cb997..ea71985 100644 --- a/web/docs/src/content/docs/reference/project-files.md +++ b/web/docs/src/content/docs/reference/project-files.md @@ -15,7 +15,7 @@ list — still honored, never written now). ```jsonc // .bdrive/config.json { "id": "m-5a10b713", "volume": "notes", - "remote": "https://drive.example.com/p/p-7f3a2c91" } + "remote": "https://drive.example.com/p/7f3a2c91-4d5e-4b8a-9c17-2ad0f6b3e9c4" } ``` Written by `bdrive init` and safe to hand-edit — a running daemon picks changes diff --git a/web/docs/src/content/docs/start/setup.md b/web/docs/src/content/docs/start/setup.md index 46e123b..fc02f61 100644 --- a/web/docs/src/content/docs/start/setup.md +++ b/web/docs/src/content/docs/start/setup.md @@ -16,7 +16,8 @@ you want synced, and paste: ``` Follow https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md -to set up BearDrive project on . Ask me which folder to sync. +to set up BearDrive project on . Ask me which folder to +sync (the project is named ""). ``` The agent fetches that page and works through it — install the CLI, sign in @@ -26,6 +27,11 @@ thing; the agent handles every deviation — already installed, no Homebrew, browser sign-in, wrong folder. On BearDrive Cloud, drop `on ` — sign-in defaults to beardrive.ai. +The project name is in the prompt because the agent recommends a folder of +the same name — so `handbook` on the hub is `handbook/` on everyone's disk. +Starting from nothing (no project id, no name), it recommends `shared/` and +names the new project `shared`. + The hooks step is the durable part: once they are registered, every later session in every folder syncs automatically, with nothing to remember. diff --git a/web/docs/src/content/docs/use-cases/multi-device.md b/web/docs/src/content/docs/use-cases/multi-device.md index a9e5453..b8d2f8a 100644 --- a/web/docs/src/content/docs/use-cases/multi-device.md +++ b/web/docs/src/content/docs/use-cases/multi-device.md @@ -20,7 +20,7 @@ nothing about the first. one, connect the *same project* rather than making a new one — the agent needs the project id, which the hub shows on the project's home page: -> Set up BearDrive here, connecting to project `p-79d0a07c`. +> Set up BearDrive here, connecting to project `79d0a07c-1b2c-4d3e-8f90-a1b2c3d4e5f6`. The folder does not have to match across machines. State is keyed by a stable project id, never a path, so `~/work` on one and `~/Documents/work` on another