From 7dd5d097fe3a3a9b1ec32d93d425c9fc66e0f04f Mon Sep 17 00:00:00 2001 From: "Snow Lee (Sungwon)" Date: Tue, 11 Aug 2026 00:52:46 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20one=20answer=20on=20Windows=20support?= =?UTF-8?q?=20=E2=80=94=20macOS=20and=20Linux=20only=20(BEA-77)=20(#126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Can my Windows teammate join?" got three answers from three official surfaces: README's feature list said macOS & Linux, its CLI table documented an HKCU Run entry on Windows, and the hub's Installation page named no OS at all. Windows autostart is real code that cannot run — internal/store's flock and internal/daemon's Kill/Setsid are unix-only, so GOOS=windows does not build. The fix is the docs, not the port: every Windows claim comes out of README, web/docs and `bdrive autostart`'s own help, and the Installation page gains one line naming the supported systems. No Go source is deleted; internal/autostart/autostart_windows.go stays compiled-but-dormant for whenever the port happens. --- README.md | 2 +- cmd/bdrive/autostart_help_test.go | 27 +++++++++++++++++++ cmd/bdrive/resume.go | 7 +++-- .../frontend/src/components/ConnectGuide.tsx | 1 + .../{index-CM4CrIy-.js => index-xRtrzl4p.js} | 2 +- internal/webapp/static/index.html | 2 +- web/docs/src/content/docs/manual/hooks.md | 4 --- web/docs/src/content/docs/reference/cli.md | 2 +- 8 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 cmd/bdrive/autostart_help_test.go rename internal/webapp/static/assets/{index-CM4CrIy-.js => index-xRtrzl4p.js} (99%) diff --git a/README.md b/README.md index 6ff6f46..18fc011 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ hub's own storage, never something a syncing client points at directly: | `bdrive logout` | Sign this device out — revoke this device's token on the hub and clear it locally (`--forget` also drops the remembered server) | | `bdrive init [folder]` | Create/connect a project and start syncing — the mount is always exactly the folder named. Interactive on a TTY, flags (`--name/--project/--server/--only/--template/--yes`) for scripts; `--template docs\|wiki\|para` starts the project from a structure (directories plus the `AGENTS.md` that explains them) instead of an empty folder; registers agent sync hooks and the login autostart in each platform's user config (`--no-hooks` skips the hooks), prints the project link; re-run to resume | | `bdrive resume` | Restart the sync daemon for every project on this device that isn't paused — after a reboot, a crash, or a manual kill. Idempotent; this is what the login agent runs | -| `bdrive autostart [install\|uninstall]` | Show, add, or remove the login registration that runs `bdrive resume` after a reboot — a launchd user agent on macOS, a systemd user unit on Linux, an HKCU Run entry on Windows. `bdrive init` installs it; `--no-autostart` skips it | +| `bdrive autostart [install\|uninstall]` | Show, add, or remove the login registration that runs `bdrive resume` after a reboot — a launchd user agent on macOS, a systemd user unit on Linux. `bdrive init` installs it; `--no-autostart` skips it | | `bdrive stop [folder]` | Stop syncing, including agent sync hooks (files stay; `bdrive init` resumes) | | `bdrive scope [add\|rm ]` | Show or change which subfolders sync — edits the managed block of `.bdriveignore` rules that `init --only` writes, so no one hand-writes negation syntax. The daemon picks changes up in seconds; `rm` deletes nothing, locally or on the hub. `--explain` lists every path in the folder split into what syncs and what does not, so you can verify what leaves this machine (pure read — no daemon, no lock, no network) | | `bdrive forget ...` | Stop syncing a path *and* remove it from the hub — adds the rule to `.bdriveignore` (which syncs) and prunes in one step. Local files are never touched, here or on teammates' devices | diff --git a/cmd/bdrive/autostart_help_test.go b/cmd/bdrive/autostart_help_test.go new file mode 100644 index 0000000..caeb272 --- /dev/null +++ b/cmd/bdrive/autostart_help_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "strings" + "testing" + + "github.com/spf13/cobra" +) + +// Windows autostart code exists but cannot run — internal/store and +// internal/daemon do not build for Windows — so no help text may promise it. +// BEA-77: three surfaces gave three different answers to "can my Windows +// teammate join?". +func TestAutostartHelpNamesNoWindows(t *testing.T) { + var walk func(*cobra.Command) + walk = func(c *cobra.Command) { + for _, s := range []string{c.Short, c.Long} { + if strings.Contains(s, "Windows") { + t.Errorf("%q help mentions Windows: %s", c.Name(), s) + } + } + for _, sub := range c.Commands() { + walk(sub) + } + } + walk(autostartCmd()) +} diff --git a/cmd/bdrive/resume.go b/cmd/bdrive/resume.go index 45f3678..04e0368 100644 --- a/cmd/bdrive/resume.go +++ b/cmd/bdrive/resume.go @@ -114,8 +114,7 @@ reboot. It runs ` + "`bdrive resume`" + `, so it covers every project this devic — one registration per machine, not one per project. macOS uses a launchd user agent, Linux a systemd user unit (systemd must be the -init system), Windows a per-user Run entry. All are user-level: no sudo, -nothing machine-wide. +init system). Both are user-level: no sudo, nothing machine-wide. ` + "`bdrive init`" + ` installs it for you; these subcommands are for checking, retrying, or opting out.`, @@ -123,7 +122,7 @@ retrying, or opting out.`, RunE: func(cmd *cobra.Command, args []string) error { path, err := autostart.Path() if errors.Is(err, autostart.ErrUnsupported) { - fmt.Println("autostart: not available here (needs macOS, Windows, or Linux with systemd)") + fmt.Println("autostart: not available here (needs macOS, or Linux with systemd)") fmt.Println(" after a reboot, run `bdrive resume` (or `bdrive init` in a project) to start syncing again") return nil } @@ -145,7 +144,7 @@ retrying, or opting out.`, RunE: func(cmd *cobra.Command, args []string) error { res, err := autostart.Install() if errors.Is(err, autostart.ErrUnsupported) { - fmt.Println("autostart: not available here (needs macOS, Windows, or Linux with systemd) — run `bdrive resume` after a reboot") + fmt.Println("autostart: not available here (needs macOS, or Linux with systemd) — run `bdrive resume` after a reboot") return nil } if err != nil { diff --git a/internal/webapp/frontend/src/components/ConnectGuide.tsx b/internal/webapp/frontend/src/components/ConnectGuide.tsx index 23019b8..c9138a1 100644 --- a/internal/webapp/frontend/src/components/ConnectGuide.tsx +++ b/internal/webapp/frontend/src/components/ConnectGuide.tsx @@ -71,6 +71,7 @@ export function ConnectGuide({ project, existing }: { project: Project; existing The agent installs the CLI, signs this machine in, and registers the sync hooks — asking before anything it changes.

+

Runs on macOS and Linux. Windows is not supported yet.

What exactly happens
    diff --git a/internal/webapp/static/assets/index-CM4CrIy-.js b/internal/webapp/static/assets/index-xRtrzl4p.js similarity index 99% rename from internal/webapp/static/assets/index-CM4CrIy-.js rename to internal/webapp/static/assets/index-xRtrzl4p.js index cb25097..12ea574 100644 --- a/internal/webapp/static/assets/index-CM4CrIy-.js +++ b/internal/webapp/static/assets/index-xRtrzl4p.js @@ -115,7 +115,7 @@ Error generating stack: `+c.message+` 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 m=e.external.registry.get(u[0])?.id;if(n!==u[0]&&m){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 CC(e,n){const r=e.seen.get(n);if(!r)throw new Error("Unprocessed schema. This is a bug in Zod.");const i=d=>{const p=e.seen.get(d);if(p.ref===null)return;const m=p.def??p.schema,y={...m},v=p.ref;if(p.ref=null,v){i(v);const x=e.seen.get(v),S=x.schema;if(S.$ref&&(e.target==="draft-07"||e.target==="draft-04"||e.target==="openapi-3.0")?(m.allOf=m.allOf??[],m.allOf.push(S)):Object.assign(m,S),Object.assign(m,y),d._zod.parent===v)for(const E in m)E==="$ref"||E==="allOf"||E in y||delete m[E];if(S.$ref&&x.def)for(const E in m)E==="$ref"||E==="allOf"||E in x.def&&JSON.stringify(m[E])===JSON.stringify(x.def[E])&&delete m[E]}const b=d._zod.parent;if(b&&b!==v){i(b);const x=e.seen.get(b);if(x?.schema.$ref&&(m.$ref=x.schema.$ref,x.def))for(const S in m)S==="$ref"||S==="allOf"||S in x.def&&JSON.stringify(m[S])===JSON.stringify(x.def[S])&&delete m[S]}e.override({zodSchema:d,jsonSchema:m,path:p.path??[]})};for(const d of[...e.seen.entries()].reverse())i(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:ju(n,"input",e.processors),output:ju(n,"output",e.processors)}},enumerable:!1,writable:!1}),d}catch{throw new Error("Error converting schema to JSON.")}}function pn(e,n){const r=n??{seen:new Set};if(r.seen.has(e))return!1;r.seen.add(e);const i=e._zod.def;if(i.type==="transform")return!0;if(i.type==="array")return pn(i.element,r);if(i.type==="set")return pn(i.valueType,r);if(i.type==="lazy")return pn(i.getter(),r);if(i.type==="promise"||i.type==="optional"||i.type==="nonoptional"||i.type==="nullable"||i.type==="readonly"||i.type==="default"||i.type==="prefault")return pn(i.innerType,r);if(i.type==="intersection")return pn(i.left,r)||pn(i.right,r);if(i.type==="record"||i.type==="map")return pn(i.keyType,r)||pn(i.valueType,r);if(i.type==="pipe")return e._zod.traits.has("$ZodCodec")?!0:pn(i.in,r)||pn(i.out,r);if(i.type==="object"){for(const s in i.shape)if(pn(i.shape[s],r))return!0;return!1}if(i.type==="union"){for(const s of i.options)if(pn(s,r))return!0;return!1}if(i.type==="tuple"){for(const s of i.items)if(pn(s,r))return!0;return!!(i.rest&&pn(i.rest,r))}return!1}const LL=(e,n={})=>r=>{const i=SC({...r,processors:n});return cn(e,i),_C(i,e),CC(i,e)},ju=(e,n,r={})=>i=>{const{libraryOptions:s,target:l}=i??{},u=SC({...s??{},target:l,io:n,processors:r});return cn(e,u),_C(u,e),CC(u,e)},$L={guid:"uuid",url:"uri",datetime:"date-time",json_string:"json-string",regex:""},IL=(e,n,r,i)=>{const s=r;s.type="string";const{minimum:l,maximum:u,format:d,patterns:p,contentEncoding:m}=e._zod.bag;if(typeof l=="number"&&(s.minLength=l),typeof u=="number"&&(s.maxLength=u),d&&(s.format=$L[d]??d,s.format===""&&delete s.format,d==="time"&&delete s.format),m&&(s.contentEncoding=m),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}))])}},PL=(e,n,r,i)=>{r.type="boolean"},FL=(e,n,r,i)=>{r.not={}},VL=(e,n,r,i)=>{},UL=(e,n,r,i)=>{const s=e._zod.def,l=lC(s.entries);l.every(u=>typeof u=="number")&&(r.type="number"),l.every(u=>typeof u=="string")&&(r.type="string"),r.enum=l},HL=(e,n,r,i)=>{if(n.unrepresentable==="throw")throw new Error("Custom types cannot be represented in JSON Schema")},BL=(e,n,r,i)=>{if(n.unrepresentable==="throw")throw new Error("Transforms cannot be represented in JSON Schema")},qL=(e,n,r,i)=>{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=cn(l.element,n,{...i,path:[...i.path,"items"]})},GL=(e,n,r,i)=>{const s=r,l=e._zod.def;s.type="object",s.properties={};const u=l.shape;for(const m in u)s.properties[m]=cn(u[m],n,{...i,path:[...i.path,"properties",m]});const d=new Set(Object.keys(u)),p=new Set([...d].filter(m=>{const y=l.shape[m]._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=cn(l.catchall,n,{...i,path:[...i.path,"additionalProperties"]})):n.io==="output"&&(s.additionalProperties=!1)},ZL=(e,n,r,i)=>{const s=e._zod.def,l=s.inclusive===!1,u=s.options.map((d,p)=>cn(d,n,{...i,path:[...i.path,l?"oneOf":"anyOf",p]}));l?r.oneOf=u:r.anyOf=u},KL=(e,n,r,i)=>{const s=e._zod.def,l=cn(s.left,n,{...i,path:[...i.path,"allOf",0]}),u=cn(s.right,n,{...i,path:[...i.path,"allOf",1]}),d=m=>"allOf"in m&&Object.keys(m).length===1,p=[...d(l)?l.allOf:[l],...d(u)?u.allOf:[u]];r.allOf=p},YL=(e,n,r,i)=>{const s=e._zod.def,l=cn(s.innerType,n,i),u=n.seen.get(e);n.target==="openapi-3.0"?(u.ref=s.innerType,r.nullable=!0):r.anyOf=[l,{type:"null"}]},QL=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);const l=n.seen.get(e);l.ref=s.innerType},XL=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);const l=n.seen.get(e);l.ref=s.innerType,r.default=JSON.parse(JSON.stringify(s.defaultValue))},JL=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);const l=n.seen.get(e);l.ref=s.innerType,n.io==="input"&&(r._prefault=JSON.parse(JSON.stringify(s.defaultValue)))},WL=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);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},e8=(e,n,r,i)=>{const s=e._zod.def,l=s.in._zod.traits.has("$ZodTransform"),u=n.io==="input"?l?s.out:s.in:s.out;cn(u,n,i);const d=n.seen.get(e);d.ref=u},t8=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);const l=n.seen.get(e);l.ref=s.innerType,r.readOnly=!0},EC=(e,n,r,i)=>{const s=e._zod.def;cn(s.innerType,n,i);const l=n.seen.get(e);l.ref=s.innerType};function Zm(){return Zm=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(Zm({},b,{path:[].concat(s.path,b.path)}))})}),n){var m=r[d].types,y=m&&m[s.code];r[d]=rg(d,n,r,l,y?[].concat(y,s.message):s.message)}e.shift()};e.length;)i();return r}function fg(e,n,r){if(r===void 0&&(r={}),(function(i){return"_def"in i&&typeof i._def=="object"&&"typeName"in i._def})(e))return function(i,s,l){try{return Promise.resolve(Gx(function(){return Promise.resolve(e[r.mode==="sync"?"parse":"parseAsync"](i,n)).then(function(u){return l.shouldUseNativeValidation&&Bm({},l),{errors:{},values:r.raw?Object.assign({},i):u}})},function(u){if((function(d){return Array.isArray(d?.issues)})(u))return{values:{},errors:Ax(n8(u.errors,!l.shouldUseNativeValidation&&l.criteriaMode==="all"),l)};throw u}))}catch(u){return Promise.reject(u)}};if((function(i){return"_zod"in i&&typeof i._zod=="object"})(e))return function(i,s,l){try{return Promise.resolve(Gx(function(){return Promise.resolve((r.mode==="sync"?i5:o5)(e,i,n)).then(function(u){return l.shouldUseNativeValidation&&Bm({},l),{errors:{},values:r.raw?Object.assign({},i):u}})},function(u){if((function(d){return d instanceof ug})(u))return{values:{},errors:Ax(r8(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 a8=de("ZodISODateTime",(e,n)=>{d6.init(e,n),Ct.init(e,n)});function i8(e){return mL(a8,e)}const o8=de("ZodISODate",(e,n)=>{f6.init(e,n),Ct.init(e,n)});function s8(e){return pL(o8,e)}const l8=de("ZodISOTime",(e,n)=>{h6.init(e,n),Ct.init(e,n)});function c8(e){return gL(l8,e)}const u8=de("ZodISODuration",(e,n)=>{m6.init(e,n),Ct.init(e,n)});function d8(e){return vL(u8,e)}const f8=(e,n)=>{ug.init(e,n),e.name="ZodError",Object.defineProperties(e,{format:{value:r=>a5(e,r)},flatten:{value:r=>r5(e,r)},addIssue:{value:r=>{e.issues.push(r),e.message=JSON.stringify(e.issues,qm,2)}},addIssues:{value:r=>{e.issues.push(...r),e.message=JSON.stringify(e.issues,qm,2)}},isEmpty:{get(){return e.issues.length===0}}})},ar=de("ZodError",f8,{Parent:Error}),h8=id(ar),m8=od(ar),p8=sd(ar),g8=ld(ar),v8=c5(ar),y8=u5(ar),b8=d5(ar),x8=f5(ar),w8=h5(ar),S8=m5(ar),_8=p5(ar),C8=g5(ar),Zx=new WeakMap;function ud(e,n,r){const i=Object.getPrototypeOf(e);let s=Zx.get(i);if(s||(s=new Set,Zx.set(i,s)),!s.has(n)){s.add(n);for(const l in r){const u=r[l];Object.defineProperty(i,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 Ft=de("ZodType",(e,n)=>(Pt.init(e,n),Object.assign(e["~standard"],{jsonSchema:{input:ju(e,"input"),output:ju(e,"output")}}),e.toJSONSchema=LL(e,{}),e.def=n,e.type=n.type,Object.defineProperty(e,"_def",{value:n}),e.parse=(r,i)=>h8(e,r,i,{callee:e.parse}),e.safeParse=(r,i)=>p8(e,r,i),e.parseAsync=async(r,i)=>m8(e,r,i,{callee:e.parseAsync}),e.safeParseAsync=async(r,i)=>g8(e,r,i),e.spa=e.safeParseAsync,e.encode=(r,i)=>v8(e,r,i),e.decode=(r,i)=>y8(e,r,i),e.encodeAsync=async(r,i)=>b8(e,r,i),e.decodeAsync=async(r,i)=>x8(e,r,i),e.safeEncode=(r,i)=>w8(e,r,i),e.safeDecode=(r,i)=>S8(e,r,i),e.safeEncodeAsync=async(r,i)=>_8(e,r,i),e.safeDecodeAsync=async(r,i)=>C8(e,r,i),ud(e,"ZodType",{check(...r){const i=this.def;return this.clone(Xa(i,{checks:[...i.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,i){return Ja(this,r,i)},brand(){return this},register(r,i){return r.add(this,i),this},refine(r,i){return this.check(v$(r,i))},superRefine(r,i){return this.check(y$(r,i))},overwrite(r){return this.check(Ko(r))},optional(){return Xx(this)},exactOptional(){return a$(this)},nullable(){return Jx(this)},nullish(){return Xx(Jx(this))},nonoptional(r){return u$(this,r)},array(){return K8(this)},or(r){return X8([this,r])},and(r){return W8(this,r)},transform(r){return Wx(this,n$(r))},default(r){return s$(this,r)},prefault(r){return c$(this,r)},catch(r){return f$(this,r)},pipe(r){return Wx(this,r)},readonly(){return p$(this)},describe(r){const i=this.clone();return Ys.add(i,{description:r}),i},meta(...r){if(r.length===0)return Ys.get(this);const i=this.clone();return Ys.add(i,r[0]),i},isOptional(){return this.safeParse(void 0).success},isNullable(){return this.safeParse(null).success},apply(r){return r(this)}}),Object.defineProperty(e,"description",{get(){return Ys.get(e)?.description},configurable:!0}),e)),RC=de("_ZodString",(e,n)=>{dg.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(i,s,l)=>IL(e,i,s);const r=e._zod.bag;e.format=r.format??null,e.minLength=r.minimum??null,e.maxLength=r.maximum??null,ud(e,"_ZodString",{regex(...i){return this.check(wL(...i))},includes(...i){return this.check(CL(...i))},startsWith(...i){return this.check(EL(...i))},endsWith(...i){return this.check(RL(...i))},min(...i){return this.check(Ru(...i))},max(...i){return this.check(xC(...i))},length(...i){return this.check(wC(...i))},nonempty(...i){return this.check(Ru(1,...i))},lowercase(i){return this.check(SL(i))},uppercase(i){return this.check(_L(i))},trim(){return this.check(TL())},normalize(...i){return this.check(jL(...i))},toLowerCase(){return this.check(OL())},toUpperCase(){return this.check(AL())},slugify(){return this.check(ML())}})}),E8=de("ZodString",(e,n)=>{dg.init(e,n),RC.init(e,n),e.email=r=>e.check(Z6(R8,r)),e.url=r=>e.check(J6(j8,r)),e.jwt=r=>e.check(hL(U8,r)),e.emoji=r=>e.check(W6(T8,r)),e.guid=r=>e.check(qx(Kx,r)),e.uuid=r=>e.check(K6(nu,r)),e.uuidv4=r=>e.check(Y6(nu,r)),e.uuidv6=r=>e.check(Q6(nu,r)),e.uuidv7=r=>e.check(X6(nu,r)),e.nanoid=r=>e.check(eL(O8,r)),e.guid=r=>e.check(qx(Kx,r)),e.cuid=r=>e.check(tL(A8,r)),e.cuid2=r=>e.check(nL(M8,r)),e.ulid=r=>e.check(rL(N8,r)),e.base64=r=>e.check(uL(P8,r)),e.base64url=r=>e.check(dL(F8,r)),e.xid=r=>e.check(aL(D8,r)),e.ksuid=r=>e.check(iL(z8,r)),e.ipv4=r=>e.check(oL(k8,r)),e.ipv6=r=>e.check(sL(L8,r)),e.cidrv4=r=>e.check(lL($8,r)),e.cidrv6=r=>e.check(cL(I8,r)),e.e164=r=>e.check(fL(V8,r)),e.datetime=r=>e.check(i8(r)),e.date=r=>e.check(s8(r)),e.time=r=>e.check(c8(r)),e.duration=r=>e.check(d8(r))});function cu(e){return G6(E8,e)}const Ct=de("ZodStringFormat",(e,n)=>{xt.init(e,n),RC.init(e,n)}),R8=de("ZodEmail",(e,n)=>{n6.init(e,n),Ct.init(e,n)}),Kx=de("ZodGUID",(e,n)=>{e6.init(e,n),Ct.init(e,n)}),nu=de("ZodUUID",(e,n)=>{t6.init(e,n),Ct.init(e,n)}),j8=de("ZodURL",(e,n)=>{r6.init(e,n),Ct.init(e,n)}),T8=de("ZodEmoji",(e,n)=>{a6.init(e,n),Ct.init(e,n)}),O8=de("ZodNanoID",(e,n)=>{i6.init(e,n),Ct.init(e,n)}),A8=de("ZodCUID",(e,n)=>{o6.init(e,n),Ct.init(e,n)}),M8=de("ZodCUID2",(e,n)=>{s6.init(e,n),Ct.init(e,n)}),N8=de("ZodULID",(e,n)=>{l6.init(e,n),Ct.init(e,n)}),D8=de("ZodXID",(e,n)=>{c6.init(e,n),Ct.init(e,n)}),z8=de("ZodKSUID",(e,n)=>{u6.init(e,n),Ct.init(e,n)}),k8=de("ZodIPv4",(e,n)=>{p6.init(e,n),Ct.init(e,n)}),L8=de("ZodIPv6",(e,n)=>{g6.init(e,n),Ct.init(e,n)}),$8=de("ZodCIDRv4",(e,n)=>{v6.init(e,n),Ct.init(e,n)}),I8=de("ZodCIDRv6",(e,n)=>{y6.init(e,n),Ct.init(e,n)}),P8=de("ZodBase64",(e,n)=>{b6.init(e,n),Ct.init(e,n)}),F8=de("ZodBase64URL",(e,n)=>{w6.init(e,n),Ct.init(e,n)}),V8=de("ZodE164",(e,n)=>{S6.init(e,n),Ct.init(e,n)}),U8=de("ZodJWT",(e,n)=>{C6.init(e,n),Ct.init(e,n)}),H8=de("ZodBoolean",(e,n)=>{E6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>PL(e,r,i)});function Yx(e){return yL(H8,e)}const B8=de("ZodUnknown",(e,n)=>{R6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>VL()});function Qx(){return bL(B8)}const q8=de("ZodNever",(e,n)=>{j6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>FL(e,r,i)});function G8(e){return xL(q8,e)}const Z8=de("ZodArray",(e,n)=>{T6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>qL(e,r,i,s),e.element=n.element,ud(e,"ZodArray",{min(r,i){return this.check(Ru(r,i))},nonempty(r){return this.check(Ru(1,r))},max(r,i){return this.check(xC(r,i))},length(r,i){return this.check(wC(r,i))},unwrap(){return this.element}})});function K8(e,n){return NL(Z8,e,n)}const Y8=de("ZodObject",(e,n)=>{A6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>GL(e,r,i,s),ct(e,"shape",()=>n.shape),ud(e,"ZodObject",{keyof(){return e$(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:G8()})},strip(){return this.clone({...this._zod.def,catchall:void 0})},extend(r){return X4(this,r)},safeExtend(r){return J4(this,r)},merge(r){return W4(this,r)},pick(r){return Y4(this,r)},omit(r){return Q4(this,r)},partial(...r){return e5(jC,this,r[0])},required(...r){return t5(TC,this,r[0])}})});function hg(e,n){const r={type:"object",shape:e??{},...Le(n)};return new Y8(r)}const Q8=de("ZodUnion",(e,n)=>{M6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>ZL(e,r,i,s),e.options=n.options});function X8(e,n){return new Q8({type:"union",options:e,...Le(n)})}const J8=de("ZodIntersection",(e,n)=>{N6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>KL(e,r,i,s)});function W8(e,n){return new J8({type:"intersection",left:e,right:n})}const Km=de("ZodEnum",(e,n)=>{D6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(i,s,l)=>UL(e,i,s),e.enum=n.entries,e.options=Object.values(n.entries);const r=new Set(Object.keys(n.entries));e.extract=(i,s)=>{const l={};for(const u of i)if(r.has(u))l[u]=n.entries[u];else throw new Error(`Key ${u} not found in enum`);return new Km({...n,checks:[],...Le(s),entries:l})},e.exclude=(i,s)=>{const l={...n.entries};for(const u of i)if(r.has(u))delete l[u];else throw new Error(`Key ${u} not found in enum`);return new Km({...n,checks:[],...Le(s),entries:l})}});function e$(e,n){const r=Array.isArray(e)?Object.fromEntries(e.map(i=>[i,i])):e;return new Km({type:"enum",entries:r,...Le(n)})}const t$=de("ZodTransform",(e,n)=>{z6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>BL(e,r),e._zod.parse=(r,i)=>{if(i.direction==="backward")throw new sC(e.constructor.name);r.addIssue=l=>{if(typeof l=="string")r.issues.push(fl(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(fl(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 n$(e){return new t$({type:"transform",transform:e})}const jC=de("ZodOptional",(e,n)=>{bC.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>EC(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function Xx(e){return new jC({type:"optional",innerType:e})}const r$=de("ZodExactOptional",(e,n)=>{k6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>EC(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function a$(e){return new r$({type:"optional",innerType:e})}const i$=de("ZodNullable",(e,n)=>{L6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>YL(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function Jx(e){return new i$({type:"nullable",innerType:e})}const o$=de("ZodDefault",(e,n)=>{$6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>XL(e,r,i,s),e.unwrap=()=>e._zod.def.innerType,e.removeDefault=e.unwrap});function s$(e,n){return new o$({type:"default",innerType:e,get defaultValue(){return typeof n=="function"?n():uC(n)}})}const l$=de("ZodPrefault",(e,n)=>{I6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>JL(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function c$(e,n){return new l$({type:"prefault",innerType:e,get defaultValue(){return typeof n=="function"?n():uC(n)}})}const TC=de("ZodNonOptional",(e,n)=>{P6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>QL(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function u$(e,n){return new TC({type:"nonoptional",innerType:e,...Le(n)})}const d$=de("ZodCatch",(e,n)=>{F6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>WL(e,r,i,s),e.unwrap=()=>e._zod.def.innerType,e.removeCatch=e.unwrap});function f$(e,n){return new d$({type:"catch",innerType:e,catchValue:typeof n=="function"?n:()=>n})}const h$=de("ZodPipe",(e,n)=>{V6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>e8(e,r,i,s),e.in=n.in,e.out=n.out});function Wx(e,n){return new h$({type:"pipe",in:e,out:n})}const m$=de("ZodReadonly",(e,n)=>{U6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>t8(e,r,i,s),e.unwrap=()=>e._zod.def.innerType});function p$(e){return new m$({type:"readonly",innerType:e})}const g$=de("ZodCustom",(e,n)=>{H6.init(e,n),Ft.init(e,n),e._zod.processJSONSchema=(r,i,s)=>HL(e,r)});function v$(e,n={}){return DL(g$,e,n)}function y$(e,n){return zL(e,n)}const b$=/\.(md|markdown)$/i,x$=/\.(png|jpe?g|gif|svg|webp|ico|bmp|avif)$/i,OC=/\.html?$/i,AC=/\.pdf$/i,w$=/\.(csv|tsv)$/i,S$=/\.(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 mg(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 f.jsx("div",{"data-slot":"table-container",className:"relative w-full overflow-x-auto",children:f.jsx("table",{"data-slot":"table",className:Xe("w-full caption-bottom text-sm",e),...n})})}function R$({className:e,...n}){return f.jsx("thead",{"data-slot":"table-header",className:Xe("[&_tr]:border-b",e),...n})}function j$({className:e,...n}){return f.jsx("tbody",{"data-slot":"table-body",className:Xe("[&_tr:last-child]:border-0",e),...n})}function ew({className:e,...n}){return f.jsx("tr",{"data-slot":"table-row",className:Xe("border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",e),...n})}function tw({className:e,...n}){return f.jsx("th",{"data-slot":"table-head",className:Xe("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 T$({className:e,...n}){return f.jsx("td",{"data-slot":"table-cell",className:Xe("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",e),...n})}function O$({header:e}){const n=e.column.getIsSorted();return e.column.getCanSort()?f.jsx(tw,{"data-sort":n||void 0,"aria-sort":n==="asc"?"ascending":n==="desc"?"descending":"none",children:f.jsxs("button",{type:"button",className:"th-sort",onClick:e.column.getToggleSortingHandler(),children:[Fm(e.column.columnDef.header,e.getContext()),n==="asc"?" ↑":n==="desc"?" ↓":""]})}):f.jsx(tw,{children:Fm(e.column.columnDef.header,e.getContext())})}function DC({table:e,className:n}){return f.jsx("div",{className:"admin-list admin-card-table"+(n?" "+n:""),children:f.jsxs(E$,{className:"admin-table",children:[f.jsx(R$,{children:e.getHeaderGroups().map(r=>f.jsx(ew,{children:r.headers.map(i=>f.jsx(O$,{header:i},i.id))},r.id))}),f.jsx(j$,{children:e.getRowModel().rows.map(r=>f.jsx(ew,{className:"admin-item",children:r.getVisibleCells().map(i=>f.jsx(T$,{children:Fm(i.column.columnDef.cell,i.getContext())},i.id))},r.id))})]})})}function zC(e){return e?"expires "+new Date(e).toLocaleDateString():"no expiry"}function A$(e){if(e.opens===void 0)return null;if(e.opens===0)return"not opened yet";const n=`${e.opens} open${e.opens===1?"":"s"}`;return e.last_opened?`${n} · last opened ${new Date(e.last_opened).toLocaleDateString()}`:n}function kC(e,n){const r=[];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(zC(e.expires));const i=A$(e);return i&&r.push(i),r.join(" · ")}const LC="Opens count how many times a file has been read through a public link. Repeat opens by the same reader within 10 minutes count once.";function $C({shares:e,onChanged:n,showProject:r=!1,canRevoke:i=!0,empty:s="No public shares."}){const[l,u]=w.useState([]),d=w.useMemo(()=>k_(),[]),p=w.useMemo(()=>[d.accessor("path",{header:"Path",cell:y=>f.jsx("a",{className:"ai-main mono",title:y.getValue(),...ul(Wu(y.getValue(),y.row.original.project)),children:y.getValue()})}),d.accessor(y=>kC(y,r),{id:"detail",header:r?"Project":"Shared",cell:y=>f.jsx("span",{className:"ai-tag",children:y.getValue()})}),d.display({id:"actions",header:"",cell:y=>i?f.jsx("button",{className:"ai-del","aria-label":`Revoke the share of ${y.row.original.path}`,onClick:()=>IC(y.row.original,n),children:"Revoke"}):null})],[d,n,r,i]),m=Z_({data:e,columns:p,state:{sorting:l},onSortingChange:u,getCoreRowModel:q_(),getSortedRowModel:G_()});return e.length===0?f.jsx("div",{className:"admin-list",children:f.jsx("div",{className:"admin-empty",children:s})}):f.jsx(DC,{table:m,className:"shares-table"})}async function IC(e,n){if(await _l("Revoke share link",`Revoke the public link to “${e.path}”? Anyone with the URL will lose access.`,"Revoke",!0))try{await tr("DELETE","/api/shares/"+e.token),Ke("Share revoked."),n()}catch(r){Ke(r.message,!0)}}const M$=hg({name:cu().trim().min(1,"Give the organization a name.").max(60,"Keep it under 60 characters.")});function N$({org:e,projects:n,myEmail:r}){const i=Ai(),s=e.role==="owner",l=()=>i.invalidateQueries({queryKey:["orgs"]}),u=()=>i.invalidateQueries({queryKey:["invites",e.id]}),d=()=>i.invalidateQueries({queryKey:["orgShares",e.id]}),p=ag({resolver:fg(M$),values:{name:e.name}}),{data:m}=Zt({queryKey:["invites",e.id],queryFn:()=>ln(`/api/orgs/${e.id}/invites`),enabled:s,select:b=>b.invites||[]}),{data:y}=Zt({queryKey:["orgShares",e.id],queryFn:()=>ln(`/api/orgs/${e.id}/shares`),enabled:s,select:b=>b.shares||[]}),v=n.filter(b=>b.org===e.id);return f.jsxs("div",{className:"admin",children:[f.jsx("h1",{id:"org-title",children:e.name}),!s&&f.jsx("p",{className:"role-chip-row",children:f.jsx("span",{className:"ai-tag role-chip",children:"Member"})}),!s&&f.jsx("p",{className:"admin-sub",children:"Only owners can rename this organization, manage members, or issue invite links."}),s&&f.jsxs("form",{className:"admin-row",onSubmit:p.handleSubmit(async({name:b})=>{try{await tr("PATCH","/api/orgs/"+e.id,{name:b}),Ke("Renamed."),l()}catch(x){Ke(x.message,!0)}}),children:[f.jsx("label",{className:"admin-lbl",htmlFor:"org-rename",children:"Organization name"}),f.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")}),f.jsx(vt,{variant:"subtle",id:"org-rename-btn",type:"submit",disabled:!p.formState.isDirty,children:"Rename org"}),p.formState.errors.name&&f.jsx("span",{id:"org-rename-err",role:"alert",className:"field-err",children:p.formState.errors.name.message})]}),f.jsx("h3",{children:"Members"}),f.jsx(D$,{org:e,owner:s,myEmail:r,onChanged:l}),f.jsx("h3",{children:"Projects"}),f.jsxs("div",{className:"admin-list",children:[v.length===0&&f.jsx("div",{className:"admin-empty",children:"No projects yet."}),v.map(b=>f.jsx("div",{className:"admin-item",children:f.jsx("span",{className:"ai-main",title:b.name,children:b.name})},b.id))]}),s&&f.jsxs(f.Fragment,{children:[f.jsxs("div",{className:"admin-h",children:[f.jsx("h3",{children:"Invite links"}),f.jsx(vt,{variant:"primary",onClick:async()=>{try{const b=await Si(`/api/orgs/${e.id}/invites`),x=await Bo(b.url);Ke(x?"Invite link copied to clipboard.":"Invite created — copy it from the list below."),u()}catch(b){Ke(b.message,!0)}},children:"New invite"})]}),f.jsxs("div",{className:"admin-list",children:[m&&m.length===0&&f.jsx("div",{className:"admin-empty",children:"No active invite links."}),(m||[]).map(b=>f.jsxs("div",{className:"admin-item",children:[f.jsx("button",{type:"button",className:"ai-main mono ai-copy","aria-label":`Copy invite link ${b.url}`,title:b.url,onClick:()=>Bo(b.url).then(x=>Ke(x?"Copied.":"Select and copy the link.")),children:b.url}),f.jsx("span",{className:"ai-tag",children:(b.creator?"by "+b.creator+" · ":"")+(b.uses?b.uses+" joined · ":"unused · ")+"expires "+new Date(b.expires).toLocaleDateString()}),f.jsx("button",{className:"ai-del","aria-label":`Revoke invite ${b.token.slice(0,8)}`,onClick:async()=>{if(await _l("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 tr("DELETE",`/api/orgs/${e.id}/invites/${b.token}`),Ke("Revoked."),u()}catch(x){Ke(x.message,!0)}},children:"Revoke"})]},b.token))]}),f.jsx("h3",{children:"Public share links"}),f.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."}),f.jsx($C,{shares:y||[],onChanged:d,showProject:!0})]})]})}function D$({org:e,owner:n,myEmail:r,onChanged:i}){const[s,l]=w.useState([{id:"email",desc:!1}]),u=w.useMemo(()=>k_(),[]),d=w.useMemo(()=>[u.accessor("email",{id:"email",header:"Member",cell:m=>{const y=!!r&&m.getValue().toLowerCase()===r.toLowerCase();return f.jsx("span",{className:"ai-main",title:m.getValue(),children:m.getValue()+(y?" (you)":"")})}}),u.accessor("role",{id:"role",header:"Role",cell:m=>{const y=m.row.original,v=!!r&&y.email.toLowerCase()===r.toLowerCase();return!n||v?f.jsx("span",{className:"ai-tag role-static",children:y.role}):f.jsxs("span",{className:"role-cell",children:[f.jsxs("select",{"aria-label":`Role for ${y.email}`,value:y.role,onChange:async b=>{try{await tr("PATCH",`/api/orgs/${e.id}/members/${encodeURIComponent(y.email)}`,{role:b.target.value}),Ke("Role updated.")}catch(x){Ke(x.message,!0)}i()},children:[f.jsx("option",{value:"owner",children:"owner"}),f.jsx("option",{value:"member",children:"member"})]}),f.jsx("button",{className:"ai-del","aria-label":`Remove ${y.email}`,onClick:async()=>{if(await _l("Remove member",`Remove ${y.email} from ${e.name}?`,"Remove",!0))try{await tr("DELETE",`/api/orgs/${e.id}/members/${encodeURIComponent(y.email)}`),Ke("Removed."),i()}catch(b){Ke(b.message,!0)}},children:"Remove"})]})}})],[u,e.id,e.name,n,r]),p=Z_({data:e.members,columns:d,state:{sorting:s},onSortingChange:l,getCoreRowModel:q_(),getSortedRowModel:G_()});return f.jsx(DC,{table:p})}const z$=hg({require_verification:Yx(),require_approval:Yx()});function k$(){const e=Ai(),{data:n,error:r}=Zt({queryKey:["admin","policy"],queryFn:()=>ln("/api/admin/policy")}),{data:i}=T_(!0),s=ag({resolver:fg(z$),values:n?{require_verification:n.require_verification&&n.mailer,require_approval:n.require_approval}:{require_verification:!1,require_approval:!1}});if(w.useEffect(()=>{r&&Ke(r.message,!0)},[r]),!n)return null;const l=async(u,d,p)=>{try{await Si(`/api/admin/pending/${u}/${d}`),Ke((d==="approve"?"Approved ":"Denied ")+p),e.invalidateQueries({queryKey:["admin","pending"]})}catch(m){Ke(m.message,!0)}};return f.jsxs("div",{className:"admin",children:[f.jsx("h1",{children:"Signup & access"}),f.jsx("p",{className:"admin-sub",children:"Who can create an account on this hub, and how new accounts are vetted."}),f.jsx("h3",{children:"New-account vetting"}),f.jsxs("form",{onSubmit:s.handleSubmit(async u=>{try{await Si("/api/admin/policy",u),Ke("Signup policy saved."),e.invalidateQueries({queryKey:["admin","policy"]})}catch(d){Ke(d.message,!0)}}),children:[f.jsxs("div",{className:"admin-list",children:[f.jsx(nw,{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")}),f.jsx(nw,{label:"Require admin approval",desc:"New accounts wait for a hub admin to approve them before they gain access.",inputProps:s.register("require_approval")})]}),f.jsx(vt,{variant:"primary",type:"submit",style:{marginTop:14},disabled:!s.formState.isDirty,children:"Save policy"})]}),f.jsx("h3",{children:"Who can sign up"}),f.jsxs("div",{className:"admin-list",children:[f.jsxs("div",{className:"admin-item",children:[f.jsx("span",{className:"ai-main",children:"Allowed email domains"}),f.jsx("span",{className:"ai-tag",children:n.allowed_domains&&n.allowed_domains.length?n.allowed_domains.map(u=>"@"+u).join(", "):"any"})]}),f.jsxs("div",{className:"admin-item",children:[f.jsx("span",{className:"ai-main",children:"Self-signup"}),f.jsx("span",{className:"ai-tag",children:n.allow_signup?"open":"invite-only"})]}),f.jsxs("div",{className:"admin-item",children:[f.jsx("span",{className:"ai-main",children:"Hub admins"}),f.jsx("span",{className:"ai-tag",children:n.admins&&n.admins.length?n.admins.join(", "):"none"})]})]}),f.jsx("p",{className:"admin-sub",children:"Domains and admins are set in the server config file (they can't be widened from the browser)."}),f.jsx("h3",{children:"Pending signups"}),f.jsxs("div",{className:"admin-list",children:[(!i||i.length===0)&&f.jsx("div",{className:"admin-empty",children:"No one is waiting for approval."}),(i||[]).map(u=>f.jsxs("div",{className:"admin-item",children:[f.jsx("span",{className:"ai-main",children:(u.name?u.name+" · ":"")+u.email}),f.jsx(vt,{variant:"primary",onClick:()=>l(u.id,"approve",u.email),children:"Approve"}),f.jsx("button",{className:"ai-del",onClick:()=>l(u.id,"deny",u.email),children:"Deny"})]},u.id))]})]})}function nw({label:e,desc:n,disabled:r,inputProps:i}){return f.jsxs("label",{className:"admin-item toggle",style:r?{opacity:.55}:void 0,children:[f.jsxs("span",{className:"ai-main",children:[f.jsx("div",{className:"tg-label",children:e}),f.jsx("div",{className:"tg-desc",children:n})]}),f.jsx("input",{type:"checkbox",disabled:r,...i})]})}function L$({...e}){return f.jsx(f1,{"data-slot":"select",...e})}function $$({...e}){return f.jsx(g1,{"data-slot":"select-value",...e})}function I$({className:e,size:n="default",children:r,...i}){return f.jsxs(m1,{"data-slot":"select-trigger","data-size":n,className:Xe("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),...i,children:[r,f.jsx(v1,{asChild:!0,children:f.jsx(Bp,{className:"size-4 opacity-50"})})]})}function P$({className:e,children:n,position:r="item-aligned",align:i="center",...s}){return f.jsx(b1,{children:f.jsxs(x1,{"data-slot":"select-content",className:Xe("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:i,...s,children:[f.jsx(V$,{}),f.jsx(E1,{className:Xe("p-1",r==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"),children:n}),f.jsx(U$,{})]})})}function F$({className:e,children:n,...r}){return f.jsxs(O1,{"data-slot":"select-item",className:Xe("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:[f.jsx("span",{"data-slot":"select-item-indicator",className:"absolute right-2 flex size-3.5 items-center justify-center",children:f.jsx(N1,{children:f.jsx(m_,{className:"size-4"})})}),f.jsx(A1,{children:n})]})}function V$({className:e,...n}){return f.jsx(D1,{"data-slot":"select-scroll-up-button",className:Xe("flex cursor-default items-center justify-center py-1",e),...n,children:f.jsx(uz,{className:"size-4"})})}function U$({className:e,...n}){return f.jsx(z1,{"data-slot":"select-scroll-down-button",className:Xe("flex cursor-default items-center justify-center py-1",e),...n,children:f.jsx(Bp,{className:"size-4"})})}const rw=["#5b8def","#f5a623","#4cc38a","#e0679b","#8b7bf0","#3ec8c8","#e6934a"];function hl(e){let n=0;for(const r of e)n=n*31+r.charCodeAt(0)>>>0;return rw[n%rw.length]}function aw({projects:e,currentId:n,menu:r,onNew:i}){const s=e.find(l=>l.id===n);return f.jsxs("nav",{id:"projects","aria-label":"Projects",children:[f.jsxs("div",{className:"nav-head",children:[f.jsx("span",{children:"Projects"}),f.jsx("button",{className:"nav-add",title:"New project","aria-label":"New project",onClick:i,children:"+"})]}),f.jsx("div",{className:"proj-row",children:f.jsxs(L$,{value:n||"",onValueChange:l=>{l&&l!==n&&(rn("/"+l),pr())},children:[f.jsxs(I$,{id:"project-select","aria-label":`Switch project — current: ${s?.name??"none"}`,title:s?.name,className:"proj-trigger",children:[s&&f.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:hl(s.name)},children:f.jsx($o,{name:s.icon})}),s?f.jsx("span",{"data-slot":"select-value",children:s.name}):f.jsx($$,{placeholder:"Select a project"})]}),f.jsx(P$,{className:"proj-menu",position:"popper",sideOffset:4,children:e.map(l=>f.jsxs(F$,{value:l.id,children:[f.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:hl(l.name)},children:f.jsx($o,{name:l.icon})}),l.name]},l.id))})]})}),r&&f.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(([l,u,d,p])=>f.jsx("li",{children:f.jsxs("div",{id:"nav-"+l,className:"row"+(r.active===l?" active":""),role:"button",tabIndex:0,onClick:p,onKeyDown:m=>{(m.key==="Enter"||m.key===" ")&&(m.preventDefault(),p())},children:[f.jsx(dt,{name:d}),f.jsx("span",{className:"label",children:u})]})},l))})]})}function PC({...e}){return f.jsx(UM,{"data-slot":"dropdown-menu",...e})}function FC({...e}){return f.jsx(HM,{"data-slot":"dropdown-menu-trigger",...e})}function VC({className:e,sideOffset:n=4,...r}){return f.jsx(BM,{children:f.jsx(qM,{"data-slot":"dropdown-menu-content",sideOffset:n,className:Xe("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 zo({className:e,inset:n,variant:r="default",...i}){return f.jsx(ZM,{"data-slot":"dropdown-menu-item","data-inset":n,"data-variant":r,className:Xe("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),...i})}function tm({className:e,inset:n,...r}){return f.jsx(GM,{"data-slot":"dropdown-menu-label","data-inset":n,className:Xe("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",e),...r})}const H$="https://github.com/runbear-io/beardrive";function B$(){return f.jsx("svg",{viewBox:"0 0 16 16",className:"gh-mark",fill:"currentColor","aria-hidden":"true",children:f.jsx("path",{d:"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"})})}function q$({me:e,org:n,admin:r,orgActive:i,billing:s}){const l=e.name||e.email,[u,d]=w.useState(!1),p=n?ul(n.manage_url):null,m=s?ul(s.url):null;return f.jsxs("footer",{id:"accountbar",children:[f.jsxs("a",{className:"gh-star",href:H$,target:"_blank",rel:"noreferrer",children:[f.jsx(B$,{}),f.jsx("span",{children:"Star on GitHub"}),f.jsx("span",{className:"ext","aria-hidden":"true",children:"↗"}),f.jsx("span",{className:"sr-only",children:" (opens in a new tab)"})]}),f.jsxs(PC,{modal:!1,open:u,onOpenChange:d,children:[f.jsx(FC,{asChild:!0,children:f.jsxs("button",{id:"account-btn",className:i?"active":void 0,"aria-label":"Account menu",children:[f.jsx("span",{className:"avatar",style:{background:hl(e.email)},"aria-hidden":"true",children:(l.trim()[0]||"?").toUpperCase()}),f.jsxs("span",{className:"acct",children:[f.jsx("b",{children:l}),e.name&&f.jsx("small",{children:e.email})]}),f.jsx(dt,{name:"chev"})]})}),f.jsxs(VC,{id:"account-menu",side:"top",align:"start",sideOffset:6,className:"acct-menu",children:[n&&f.jsxs(f.Fragment,{children:[f.jsx(tm,{className:"menu-sec",children:"Organization"}),f.jsx(zo,{asChild:!0,children:f.jsxs("a",{id:"menu-org-settings","aria-current":i?"page":void 0,...p,onClick:y=>{p?.onClick?.(y),d(!1)},children:[f.jsx(dt,{name:"gear"}),f.jsxs("span",{children:[f.jsx("b",{children:n.name})," Settings"]}),!n.manage_url.startsWith("/")&&f.jsxs(f.Fragment,{children:[f.jsx("span",{className:"ext","aria-hidden":"true",children:"↗"}),f.jsx("span",{className:"sr-only",children:" (opens in a new tab)"})]})]})}),s&&f.jsx(zo,{asChild:!0,children:f.jsxs("a",{id:"menu-billing",...m,onClick:y=>{m?.onClick?.(y),d(!1)},children:[f.jsx(dt,{name:"card"}),f.jsx("span",{children:"Billing"}),f.jsx("span",{className:"ps-chip plan-chip",children:s.plan})]})})]}),r&&f.jsxs(f.Fragment,{children:[f.jsx(tm,{className:"menu-sec",children:"Hub"}),f.jsxs(zo,{id:"menu-hub-admin",onSelect:r.onClick,children:[f.jsx(dt,{name:"shield"}),f.jsxs("span",{children:["Signup & access",r.pending?` · ${r.pending}`:""]})]})]}),f.jsx(tm,{className:"menu-sec",children:"Account"}),f.jsx(zo,{asChild:!0,children:f.jsxs("a",{id:"signout",href:"/auth/logout",children:[f.jsx(dt,{name:"power"}),f.jsx("span",{children:"Log out"})]})})]})]})]})}function $a({className:e,...n}){return f.jsx("div",{"data-slot":"card",className:Xe("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",e),...n})}function Ia({className:e,...n}){return f.jsx("div",{"data-slot":"card-header",className:Xe("@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 Pa({className:e,...n}){return f.jsx("div",{"data-slot":"card-title",className:Xe("leading-none font-semibold",e),...n})}function Po({className:e,...n}){return f.jsx("div",{"data-slot":"card-description",className:Xe("text-muted-foreground text-sm",e),...n})}function Fa({className:e,...n}){return f.jsx("div",{"data-slot":"card-content",className:Xe("px-6",e),...n})}function ta({className:e,orientation:n="horizontal",decorative:r=!0,...i}){return f.jsx(CN,{"data-slot":"separator",decorative:r,orientation:n,className:Xe("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),...i})}function G$({url:e}){const n=Zt({queryKey:["billing"],queryFn:()=>ln(e)});if(n.isLoading)return f.jsx("div",{className:"empty",children:"Loading…"});if(n.error||!n.data)return f.jsxs("div",{className:"empty",children:[f.jsx("h3",{children:"Billing is unavailable"}),f.jsx("p",{children:n.error?.message||"Try again shortly."})]});const r=n.data;return f.jsxs("div",{className:"project-settings",id:"billing-view",children:[f.jsxs("h2",{children:["Billing",f.jsx("span",{className:"ps-chip plan-chip",children:r.plan.name})]}),f.jsxs($a,{children:[f.jsxs(Ia,{children:[f.jsxs(Pa,{children:[r.plan.name," plan",r.plan.status?` (${r.plan.status})`:""]}),f.jsxs(Po,{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"]})]}),f.jsx(ta,{}),f.jsx(Fa,{children:f.jsx("div",{className:"usage-bar",children:f.jsx("div",{style:{width:`${r.usage.pct}%`}})})})]}),r.owner?f.jsx("div",{className:"plan-grid",children:r.plans.map(i=>f.jsxs($a,{children:[f.jsxs(Ia,{children:[f.jsx(Pa,{children:i.name}),f.jsx(Po,{children:i.blurb})]}),f.jsx(ta,{}),f.jsxs(Fa,{children:[f.jsxs("p",{className:"plan-price",children:[i.price,f.jsx("small",{children:" / user / month"})]}),f.jsxs("form",{method:"post",action:r.checkout_url,children:[f.jsx("input",{type:"hidden",name:"plan",value:i.id}),f.jsx(vt,{type:"submit",disabled:i.current,variant:i.current?"subtle":"default",children:i.current?"Current plan":`Upgrade to ${i.name}`})]})]})]},i.id))}):f.jsx("p",{className:"muted-note",children:"Only an organization owner can change the plan."}),r.owner&&r.has_customer&&f.jsxs($a,{children:[f.jsxs(Ia,{children:[f.jsx(Pa,{children:"Manage subscription"}),f.jsx(Po,{children:"Change seats, update the card, download invoices, or cancel."})]}),f.jsx(ta,{}),f.jsx(Fa,{children:f.jsx("form",{method:"post",action:r.portal_url,children:f.jsx(vt,{type:"submit",variant:"subtle",children:"Open the billing portal"})})})]})]})}function uu({className:e,type:n,...r}){return f.jsx("input",{type:n,"data-slot":"input",className:Xe("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 nm({className:e,...n}){return f.jsx(YM,{"data-slot":"label",className:Xe("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 Z$({className:e,...n}){return f.jsx("textarea",{"data-slot":"textarea",className:Xe("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 iw={read:1,write:2,admin:3};function wi(e,n){return(iw[e||""]||0)>=(iw[n]||0)}const Ym=280,K$=hg({name:cu().trim().min(1,"Give the project a name.").max(120,"Keep the name under 120 characters."),description:cu().max(Ym,`Keep the description under ${Ym} characters.`),icon:cu()});function Y$({project:e,org:n,onDeleted:r}){const i=O_(),s=wi(e.perm,"admin"),l=ag({resolver:fg(K$),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 m=>{const y=l.formState.dirtyFields,v={};if(y.name&&(v.name=m.name.trim()),y.description&&(v.description=m.description),y.icon&&(v.icon=m.icon),Object.keys(v).length!==0)try{await tr("PATCH","/api/projects/"+e.id,v),Ke("Saved."),l.reset({...m,name:m.name.trim()}),await i()}catch(b){Ke(b.message,!0)}});return f.jsxs("div",{className:"project-settings",children:[f.jsxs("h2",{children:[e.name,!wi(e.perm,"write")&&f.jsx("span",{className:"ps-chip",children:"Read-only"})]}),f.jsxs($a,{children:[f.jsxs(Ia,{children:[f.jsx(Pa,{children:"General"}),f.jsx(Po,{children:"Name, description and icon for this project."})]}),f.jsx(ta,{}),f.jsx(Fa,{children:f.jsxs("form",{className:"ps-form",onSubmit:p,children:[f.jsxs("div",{className:"ps-field",children:[f.jsx(nm,{htmlFor:"ps-icon-btn",children:"Icon"}),f.jsxs("div",{className:"ps-icon-row",children:[f.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:hl(e.name)},children:f.jsx($o,{name:u})}),f.jsxs(PC,{children:[f.jsx(FC,{asChild:!0,children:f.jsx(vt,{id:"ps-icon-btn",type:"button",variant:"subtle",disabled:!s,children:"Change"})}),f.jsxs(VC,{align:"start",className:"ps-icon-grid",children:[f.jsx(zo,{className:"ps-icon-cell"+(u===""?" active":""),title:"Default","aria-label":"Default icon",onSelect:()=>l.setValue("icon","",{shouldDirty:!0}),children:f.jsx($o,{})}),Object.keys(Nm).map(m=>f.jsx(zo,{className:"ps-icon-cell"+(u===m?" active":""),title:m,"aria-label":m,onSelect:()=>l.setValue("icon",m,{shouldDirty:!0}),children:f.jsx($o,{name:m})},m))]})]})]})]}),f.jsxs("div",{className:"ps-field",children:[f.jsx(nm,{htmlFor:"ps-name",children:"Name"}),f.jsx(uu,{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&&f.jsx("span",{id:"ps-name-err",role:"alert",className:"field-err",children:l.formState.errors.name.message})]}),f.jsxs("div",{className:"ps-field",children:[f.jsxs(nm,{htmlFor:"ps-desc",children:["Description ",f.jsx("span",{className:"ps-opt",children:"(optional)"})]}),f.jsx(Z$,{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")}),f.jsxs("div",{className:"ps-meta",children:[l.formState.errors.description?f.jsx("span",{id:"ps-desc-err",role:"alert",className:"field-err",children:l.formState.errors.description.message}):f.jsx("span",{}),f.jsxs("span",{className:"ps-count",children:[d.length," / ",Ym]})]})]}),s&&f.jsxs(f.Fragment,{children:[f.jsx(ta,{}),f.jsx("div",{className:"ps-actions",children:f.jsx(vt,{id:"ps-save",type:"submit",variant:"primary",disabled:!l.formState.isDirty||l.formState.isSubmitting,children:"Save changes"})})]})]})})]}),f.jsxs($a,{children:[f.jsx(Ia,{children:f.jsx(Pa,{children:"About"})}),f.jsx(ta,{}),f.jsx(Fa,{children:f.jsxs("dl",{className:"ps-facts",children:[f.jsx("dt",{children:"Project id"}),f.jsx("dd",{children:f.jsx("code",{children:e.id})}),n&&f.jsxs(f.Fragment,{children:[f.jsx("dt",{children:"Workspace"}),f.jsx("dd",{children:n.name})]}),e.created&&f.jsxs(f.Fragment,{children:[f.jsx("dt",{children:"Created"}),f.jsx("dd",{children:new Date(e.created).toLocaleDateString()})]})]})})]}),f.jsx(J$,{project:e,org:n}),f.jsx(Q$,{project:e}),s&&f.jsxs($a,{className:"ps-danger",children:[f.jsx(Ia,{children:f.jsx(Pa,{children:"Danger zone"})}),f.jsx(ta,{}),f.jsxs(Fa,{children:[f.jsx("p",{children:"Deleting removes the project from this hub. Its files stay in storage. This can't be undone."}),f.jsx(vt,{variant:"danger",onClick:async()=>{if(await R_(`Delete “${e.name}”?`,"This can't be undone. Type the project name to confirm:","","Delete project",{match:e.name,danger:!0})!==null)try{await tr("DELETE","/api/projects/"+e.id),Ke(`Deleted “${e.name}”.`),await r()}catch(y){Ke(y.message,!0)}},children:"Delete project"})]})]})]})}function Q$({project:e}){const n=Ai(),{data:r,error:i}=j_(e.id);return i?null:f.jsxs($a,{children:[f.jsxs(Ia,{children:[f.jsx(Pa,{children:"Public links"}),f.jsxs(Po,{children:["Files in this project that anyone with the URL can read — no account needed.",(r||[]).some(s=>s.opens!==void 0)&&f.jsxs(f.Fragment,{children:[" ",LC]})]})]}),f.jsx(ta,{}),f.jsx(Fa,{children:f.jsx($C,{shares:r||[],canRevoke:wi(e.perm,"write"),onChanged:()=>n.invalidateQueries({queryKey:["shares",e.id]}),empty:"No public links."})})]})}const Qm=[{value:"admin",label:"Admin"},{value:"write",label:"Write"},{value:"read",label:"Read"},{value:"none",label:"No access"}],X$=Object.fromEntries(Qm.map(e=>[e.value,e.label]));function J$({project:e,org:n}){const r=Ai(),{data:i,error:s}=j3(e.id),l=wi(e.perm,"admin"),u=()=>{r.invalidateQueries({queryKey:["permissions",e.id]}),r.invalidateQueries({queryKey:["projects"]})},d=async(x,S)=>{try{await x(),Ke(S)}catch(_){Ke(_.message,!0)}u()};if(s||!i)return null;const p=i,m=`/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 R_("Add an exception","Email of a workspace member. They get Read access; change it in the table.","","Add");x===null||!x.trim()||await d(()=>tr("PUT",`${m}/${encodeURIComponent(x.trim())}`,{level:"read"}),"Added.")};return f.jsxs($a,{className:"ps-people",children:[f.jsxs(Ia,{children:[f.jsx(Pa,{children:"People"}),f.jsx(Po,{children:"Who can see and change this project."})]}),f.jsx(ta,{}),f.jsxs(Fa,{children:[f.jsxs("p",{className:"ps-row",children:[f.jsxs("span",{children:["Everyone in ",n?.name||"this workspace"," can"]}),f.jsx("select",{"aria-label":"Default access for workspace members",disabled:!l,value:p.default,onChange:async x=>{const S=x.target.value;if(S==="none"&&!await _l("Make this project invite-only?","Only people listed below (and workspace owners) will see this project.","Make invite-only")){u();return}await d(()=>tr("PUT",m,{default:S}),"Default access updated.")},children:Qm.filter(x=>x.value!=="admin").map(x=>f.jsx("option",{value:x.value,children:x.label},x.value))})]}),p.default==="none"&&f.jsx("p",{className:"ps-note",children:"This project is invite-only: only the people below and workspace owners can see it."}),f.jsxs("div",{className:"ps-people-head",children:[f.jsx("h4",{children:"Exceptions"}),l&&f.jsx(vt,{type:"button",variant:"subtle",onClick:b,children:"+ Add"})]}),v.length===0?f.jsx("p",{className:"ps-note",children:"No exceptions — everyone gets the access above."}):f.jsx("div",{className:"admin-list",children:v.map(x=>{const S="owner"in x;return f.jsxs("div",{className:"admin-item",children:[f.jsxs("span",{className:"ai-main",title:x.email,children:[x.email,p.creator&&x.email.toLowerCase()===p.creator.toLowerCase()&&f.jsx("span",{className:"ai-tag",children:" (creator)"})]}),S?f.jsx("span",{className:"ai-tag",children:"Workspace owner — always admin"}):f.jsxs("span",{className:"role-cell",children:[f.jsx("select",{"aria-label":`Access for ${x.email}`,disabled:!l,value:x.level,onChange:_=>d(()=>tr("PUT",`${m}/${encodeURIComponent(x.email)}`,{level:_.target.value}),`${x.email} is now ${X$[_.target.value]||_.target.value}.`),children:Qm.map(_=>f.jsx("option",{value:_.value,children:_.label},_.value))}),l&&f.jsx("button",{className:"ai-del","aria-label":`Remove exception for ${x.email}`,onClick:()=>d(()=>tr("DELETE",`${m}/${encodeURIComponent(x.email)}`),"Reverted to the default access."),children:"Remove"})]})]},x.email)})})]})]})}const UC="https://raw.githubusercontent.com/runbear-io/beardrive/main/INSTALL_FOR_AGENTS.md";function HC({project:e,existing:n}){const r=window.location.origin,i=n?'. I already have a folder of notes — ask me which one to sync (the project is named "':'. Ask me which folder to sync (the project is named "',s="Follow "+UC+` to set up BearDrive project `+e.id+" on "+r+i+e.name+'").',l=`brew install runbear-io/tap/beardrive bdrive login `+r+` -bdrive init --project `+e.id;return f.jsxs("div",{className:"guide",children:[f.jsxs("h1",{className:"in-title gd-head",children:[f.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:hl(e.name)},children:f.jsx($o,{name:e.icon})}),e.name]}),e.description&&f.jsx("p",{className:"in-desc",children:e.description}),f.jsxs("div",{className:"gd-body",children:[f.jsx("p",{className:"gd-desc",children:n?"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder you already have:":"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder where you want the files:"}),n&&f.jsx("p",{className:"gd-note",children:"Your files stay exactly where they are. Connecting a folder never moves, renames or overwrites anything in it — it uploads what is there and keeps it in sync."}),f.jsx(Xm,{code:s}),f.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."}),f.jsxs("details",{className:"gd-manual",children:[f.jsx("summary",{children:"What exactly happens"}),f.jsxs("ul",{className:"gd-desc gd-list",children:[f.jsx("li",{children:"Sign-in uses a device code you approve in this browser — the folder itself never holds credentials."}),f.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."}),f.jsx("li",{children:"Codex hooks are off by default: set [features] codex_hooks = true in ~/.codex/config.toml."})]})]}),f.jsxs("details",{className:"gd-manual",children:[f.jsx("summary",{children:"Or run it yourself"}),f.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."}),f.jsx(Xm,{code:l}),f.jsx("p",{className:"gd-desc",children:f.jsx("a",{href:"https://docs.beardrive.ai/manual/install/",target:"_blank",rel:"noreferrer",children:"Full manual setup guide →"})})]})]})]})}function Xm({code:e}){const[n,r]=w.useState("Copy");return f.jsxs("pre",{className:"gd-code",children:[f.jsx("code",{children:e}),f.jsx("button",{className:"gd-copy",onClick:async()=>{r(await Bo(e)?"Copied":"Copy failed"),setTimeout(()=>r("Copy"),1400)},children:n})]})}function W$({onNew:e,canCreate:n}){return f.jsxs("div",{className:"onboard",children:[f.jsx("h1",{children:"Welcome to BearDrive"}),f.jsx("p",{children:"You're signed in, but you're not part of any project yet."}),n&&f.jsxs("div",{className:"ob-card ob-start",children:[f.jsx("h3",{children:"Start a project"}),f.jsx("p",{children:"Name it and pick what it starts from — a structure, or nothing at all. Then connect a folder on any machine and it stays in sync."}),f.jsx(vt,{variant:"primary",id:"ob-new",onClick:e,children:"New project"})]}),f.jsxs("div",{className:"ob-card ob-agent",children:[f.jsx("h3",{children:n?"Or let your agent do it":"Connect a new drive to your project"}),f.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:"}),f.jsx(Xm,{code:"Follow "+UC+` +bdrive init --project `+e.id;return f.jsxs("div",{className:"guide",children:[f.jsxs("h1",{className:"in-title gd-head",children:[f.jsx("span",{className:"proj-mark","aria-hidden":"true",style:{background:hl(e.name)},children:f.jsx($o,{name:e.icon})}),e.name]}),e.description&&f.jsx("p",{className:"in-desc",children:e.description}),f.jsxs("div",{className:"gd-body",children:[f.jsx("p",{className:"gd-desc",children:n?"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder you already have:":"Paste into your coding agent — Claude Code, Cowork, Codex, Gemini CLI, Hermes — in the folder where you want the files:"}),n&&f.jsx("p",{className:"gd-note",children:"Your files stay exactly where they are. Connecting a folder never moves, renames or overwrites anything in it — it uploads what is there and keeps it in sync."}),f.jsx(Xm,{code:s}),f.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."}),f.jsx("p",{className:"gd-desc",children:"Runs on macOS and Linux. Windows is not supported yet."}),f.jsxs("details",{className:"gd-manual",children:[f.jsx("summary",{children:"What exactly happens"}),f.jsxs("ul",{className:"gd-desc gd-list",children:[f.jsx("li",{children:"Sign-in uses a device code you approve in this browser — the folder itself never holds credentials."}),f.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."}),f.jsx("li",{children:"Codex hooks are off by default: set [features] codex_hooks = true in ~/.codex/config.toml."})]})]}),f.jsxs("details",{className:"gd-manual",children:[f.jsx("summary",{children:"Or run it yourself"}),f.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."}),f.jsx(Xm,{code:l}),f.jsx("p",{className:"gd-desc",children:f.jsx("a",{href:"https://docs.beardrive.ai/manual/install/",target:"_blank",rel:"noreferrer",children:"Full manual setup guide →"})})]})]})]})}function Xm({code:e}){const[n,r]=w.useState("Copy");return f.jsxs("pre",{className:"gd-code",children:[f.jsx("code",{children:e}),f.jsx("button",{className:"gd-copy",onClick:async()=>{r(await Bo(e)?"Copied":"Copy failed"),setTimeout(()=>r("Copy"),1400)},children:n})]})}function W$({onNew:e,canCreate:n}){return f.jsxs("div",{className:"onboard",children:[f.jsx("h1",{children:"Welcome to BearDrive"}),f.jsx("p",{children:"You're signed in, but you're not part of any project yet."}),n&&f.jsxs("div",{className:"ob-card ob-start",children:[f.jsx("h3",{children:"Start a project"}),f.jsx("p",{children:"Name it and pick what it starts from — a structure, or nothing at all. Then connect a folder on any machine and it stays in sync."}),f.jsx(vt,{variant:"primary",id:"ob-new",onClick:e,children:"New project"})]}),f.jsxs("div",{className:"ob-card ob-agent",children:[f.jsx("h3",{children:n?"Or let your agent do it":"Connect a new drive to your project"}),f.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:"}),f.jsx(Xm,{code:"Follow "+UC+` to set up a new BearDrive project on `+window.location.origin+". Ask me which folder to sync."}),f.jsx("p",{className:"ob-alt",children:f.jsx("a",{href:"https://docs.beardrive.ai/manual/setup-by-hand/",target:"_blank",rel:"noreferrer",children:"Or start a project manually →"})})]})]})}const BC="__existing__";function eI({templates:e,onCreate:n,onClose:r}){const i=[...e.map(x=>({value:x.name,title:x.title,blurb:x.blurb,rule:!1})),{value:BC,title:"I already have a folder",blurb:"nothing is seeded — connect it and your files stay as they are",rule:!0},{value:"",title:"Empty project",blurb:"just the folder",rule:!1}],[s,l]=w.useState(""),[u,d]=w.useState(i[0].value),[p,m]=w.useState(""),[y,v]=w.useState(!1),b=async()=>{if(!y){if(!s.trim()){m("Give it a name.");return}v(!0);try{await n(s.trim(),u)}finally{v(!1)}}};return f.jsx(Xu,{open:!0,onOpenChange:x=>!x&&r(),children:f.jsxs(Ju,{className:"modal",showCloseButton:!1,children:[f.jsx(wl,{asChild:!0,children:f.jsx("h3",{children:"New project"})}),f.jsx("label",{className:"modal-label",htmlFor:"modal-input",children:"Name"}),f.jsx("input",{className:"modal-input",type:"text",autoComplete:"off",id:"modal-input",autoFocus:!0,value:s,"aria-invalid":!!p,"aria-describedby":p?"modal-input-err":void 0,onChange:x=>{l(x.currentTarget.value),p&&m("")},onKeyDown:x=>x.key==="Enter"&&b()}),p&&f.jsx("span",{id:"modal-input-err",role:"alert",className:"field-err",children:p}),i.length>1&&f.jsxs("fieldset",{className:"start-points",children:[f.jsx("legend",{className:"modal-label",children:"Starting point"}),i.map((x,S)=>f.jsxs("label",{className:"start-point"+(u===x.value?" on":"")+(x.rule?" sp-rule":""),children:[f.jsx("input",{type:"radio",name:"template",value:x.value,checked:u===x.value,onChange:()=>d(x.value)}),f.jsxs("span",{className:"sp-text",children:[f.jsxs("span",{className:"sp-title",children:[x.title,S===0&&f.jsx("span",{className:"sp-rec",children:"Recommended"})]}),f.jsx("span",{className:"sp-blurb",children:x.blurb})]})]},x.value))]}),f.jsxs("div",{className:"modal-actions",children:[f.jsx(vt,{variant:"subtle",onClick:r,children:"Cancel"}),f.jsx(vt,{variant:"primary",onClick:b,disabled:y,children:"Create"})]})]})})}function ow(e,n,r){if(!e)return null;if(!r)return e[n]||null;const i={human:0,agent:0,share:0};for(const[s,l]of Object.entries(e))s.startsWith(n+"/")&&(i.human+=l.human||0,i.agent+=l.agent||0,i.share+=l.share||0);return i.human||i.agent||i.share?i:null}function ka(e){return(e.human||0)+(e.agent||0)+(e.share||0)}function Qs(e){const n=ka(e);if(!n)return"";const r=n+(n===1?" read":" reads");if(!e.agent&&!e.share)return r;const i=[];return e.human&&i.push(e.human+" human"),e.agent&&i.push(e.agent+" agent"),e.share&&i.push(e.share+" shared"),r+" ("+i.join(", ")+")"}function tI(e){const n=ka(e);return n?n<3?1:n<10?2:n<30?3:4:0}function nI(e){const n=ka(e);return n?{agent:(e.agent||0)/n,human:(e.human||0)/n,share:(e.share||0)/n}:{agent:0,human:0,share:0}}function rI(e,n){return e?Object.keys(e).filter(r=>!n.has(r)).sort():[]}const aI=7;function iI(e){if(!e.length)return null;let n=e[0],r=e[0];for(const i of e)ir&&(r=i);return{min:n,max:r}}const oI=(e,n)=>n-el.reads-s.reads).slice(0,lI)){const s=i.path.split("/").pop();let l=i.cx+i.r+4,u="start";l+s.length*cI>n.right&&(l=i.cx-i.r-4,u="end");const d=m=>r.every(y=>Math.abs(y.y-m)>=rm);let p=i.cy;for(;p<=n.bottom&&!d(p);)p+=rm;if(p>n.bottom)for(p=i.cy;p>=n.top&&!d(p);)p-=rm;r.push({path:i.path,name:s,x:l,y:Math.min(n.bottom,Math.max(n.top,p)),anchor:u})}return r}function dI(e,n=!0){const r=Zt({queryKey:["tree",e],queryFn:()=>ln(e+"tree"),enabled:n,refetchInterval:15e3}),i=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,...i,loaded:!!r.data}}function fI(e,n){return Zt({queryKey:["heat",e],queryFn:()=>ln(e+"heat?days=30"),enabled:n,staleTime:6e4,refetchInterval:6e4}).data?.entries??null}function hI(e,n,r){return Zt({queryKey:["history",e,"prefix",n,20],queryFn:()=>ln(e+"history?prefix="+encodeURIComponent(n)+"&n=20"),enabled:r,staleTime:15e3}).data?.entries??null}function mI(e,n,r){const i=new Array(e);return new Proxy(i,{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&&pi[y]!==m))&&(i=d,s=n(...d),r?.onChange&&!(l&&r.skipInitialOnChange)&&r.onChange(s),l=!1),s}return u.updateDeps=d=>{i=d},u}function sw(e,n){if(e===void 0)throw new Error("Unexpected undefined");return e}const pI=(e,n)=>Math.abs(e-n)<1.01,gI=(e,n,r)=>{let i;return function(...s){e.clearTimeout(i),i=e.setTimeout(()=>n.apply(this,s),r)}};let Bs;const am=()=>{if(Bs!==void 0)return Bs;if(typeof navigator>"u")return Bs=!1;if(/iP(hone|od|ad)/.test(navigator.userAgent))return Bs=!0;const e=navigator.maxTouchPoints;return Bs=navigator.platform==="MacIntel"&&e!==void 0&&e>0},lw=e=>{const{offsetWidth:n,offsetHeight:r}=e;return{width:n,height:r}},vI=e=>e,yI=e=>{const n=Math.max(e.startIndex-e.overscan,0),i=Math.min(e.endIndex+e.overscan,e.count-1)-n+1,s=new Array(i);for(let l=0;l{const r=e.scrollElement;if(!r)return;const i=e.targetWindow;if(!i)return;const s=u=>{const{width:d,height:p}=u;n({width:Math.round(d),height:Math.round(p)})};if(s(lw(r)),!i.ResizeObserver)return()=>{};const l=new i.ResizeObserver(u=>{const d=()=>{const p=u[0];if(p?.borderBoxSize){const m=p.borderBoxSize[0];if(m){s({width:m.inlineSize,height:m.blockSize});return}}s(lw(r))};e.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(d):d()});return l.observe(r,{box:"border-box"}),()=>{l.unobserve(r)}},Tu={passive:!0},xI=typeof window>"u"?!0:"onscrollend"in window,wI=(e,n,r)=>{const i=e.scrollElement;if(!i)return;const s=e.targetWindow;if(!s)return;const l=e.options.useScrollendEvent&&xI;let u=0;const d=l?null:gI(s,()=>n(u,!1),e.options.isScrollingResetDelay),p=v=>()=>{u=r(i),d?.(),n(u,v)},m=p(!0),y=p(!1);return i.addEventListener("scroll",m,Tu),l&&i.addEventListener("scrollend",y,Tu),()=>{i.removeEventListener("scroll",m),l&&i.removeEventListener("scrollend",y)}},SI=(e,n)=>wI(e,n,r=>{const{horizontal:i,isRtl:s}=e.options;return i?r.scrollLeft*(s&&-1||1):r.scrollTop}),_I=(e,n,r)=>{if(r.options.useCachedMeasurements){const i=r.indexFromElement(e),s=r.options.getItemKey(i);return r.itemSizeCache.get(s)??r.options.estimateSize(i)}if(n?.borderBoxSize){const i=n.borderBoxSize[0];if(i)return Math.round(i[r.options.horizontal?"inlineSize":"blockSize"])}if(!n){const i=r.indexFromElement(e),s=r.options.getItemKey(i),l=r.itemSizeCache.get(s);if(l!==void 0)return l}return e[r.options.horizontal?"offsetWidth":"offsetHeight"]},CI=(e,{adjustments:n=0,behavior:r},i)=>{var s,l;(l=(s=i.scrollElement)==null?void 0:s.scrollTo)==null||l.call(s,{[i.options.horizontal?"left":"top"]:e+n,behavior:r})},EI=CI;class RI{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,i,s;return((s=(i=(r=this.targetWindow)==null?void 0:r.performance)==null?void 0:i.now)==null?void 0:s.call(i))??Date.now()},this.observer=(()=>{let r=null;const i=()=>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[m,y]of this.elementsCache)if(y===d){this.elementsCache.delete(m);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=i())==null||s.disconnect(),r=null},observe:s=>{var l;return(l=i())==null?void 0:l.observe(s,{box:"border-box"})},unobserve:s=>{var l;return(l=i())==null?void 0:l.unobserve(s)}}})(),this.range=null,this.setOptions=r=>{var i,s;const l={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:vI,rangeExtractor:yI,onChange:()=>{},measureElement:_I,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,m=!1;if(u!==void 0&&u.enabled&&l.enabled&&l.anchorTo==="end"&&this.scrollElement!==null){const b=u.count,x=l.count,S=this.getMeasurements(),_=b>0?((i=S[0])==null?void 0:i.key)??u.getItemKey(0):null,E=b>0?((s=S[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)){m=!0;const T=b>0?this.getVirtualItemForOffset(this.getScrollOffset())??S[0]:null;T&&(d=[T.key,this.getScrollOffset()-T.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,m&&(this.pendingMin=0,this.itemSizeCacheVersion++);let y=!1,v=0;if(d&&this.scrollOffset!==null){const[b,x]=d,S=this.getMeasurements(),{count:_,getItemKey:E}=this.options;let R=0;for(;R<_&&E(R)!==b;)R++;if(R<_){const O=S[R];if(O){const T=O.start+x;T!==this.scrollOffset&&(v=T-this.scrollOffset,this.scrollOffset=T,y=!0)}}}(y||p)&&(this.pendingScrollAnchor=[y?d[0]:null,y?d[1]:0,p,v])},this.notify=r=>{var i,s;(s=(i=this.options).onChange)==null||s.call(i,this,r)},this.maybeNotify=Oo(()=>(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 i=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==i){if(this.cleanup(),!i){this.maybeNotify();return}if(this.scrollElement=i,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,!(!am()||this.targetWindow==null)&&(this._iosJustTouchEnded=!0,this._iosTouchEndTimerId=this.targetWindow.setTimeout(()=>{this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._flushIosDeferredIfReady()},150))};l.addEventListener("touchstart",u,Tu),l.addEventListener("touchend",d,Tu),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&&(am()&&(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(),i=this.getMaxScrollOffset();if(r<0||r>i)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=Oo(()=>[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,i,s,l,u,d,p,m)=>(this.prevLanes!==void 0&&this.prevLanes!==d&&(this.lanesChangedFlag=!0),this.prevLanes=d,this.pendingMin=null,{count:r,paddingStart:i,scrollMargin:s,getItemKey:l,enabled:u,lanes:d,laneAssignmentMode:p,gap:m}),{key:!1}),this.getMeasurements=Oo(()=>[this.getMeasurementOptions(),this.itemSizeCacheVersion],({count:r,paddingStart:i,scrollMargin:s,getItemKey:l,enabled:u,lanes:d,laneAssignmentMode:p,gap:m},y)=>{const v=this.itemSizeCache;if(!u)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>r)for(const R of this.laneAssignments.keys())R>=r&&this.laneAssignments.delete(R);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(R=>{this.itemSizeCache.set(R.key,R.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 R=r*2;let O=this._flatMeasurements;if(!O||O.length0&&I.set(O.subarray(0,b*2)),O=I,this._flatMeasurements=O}let T;if(b===0)T=i+s;else{const I=b-1;T=O[I*2]+O[I*2+1]+m}for(let I=b;I1){z=T;const ge=S[z],fe=ge!==void 0?x[ge]:void 0;I=fe?fe.end+m:i+s}else if(E===d){let ge=0,fe=_[0],Q=S[0];for(let le=1;lethis.options.debug}),this.calculateRange=Oo(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(r,i,s,l)=>r.length===0||i===0?(this.range=null,null):(this.range=TI(r,i,s,l,l===1&&this._flatMeasurements!=null?this._flatMeasurements:null),this.range),{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=Oo(()=>{let r=null,i=null;const s=this.calculateRange();return s&&(r=s.startIndex,i=s.endIndex),this.maybeNotify.updateDeps([this.isScrolling,r,i]),[this.options.rangeExtractor,this.options.overscan,this.options.count,r,i]},(r,i,s,l,u)=>l===null||u===null?[]:r({startIndex:l,endIndex:u,overscan:i,count:s}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=r=>{const i=this.options.indexAttribute,s=r.getAttribute(i);return s?parseInt(s,10):(console.warn(`Missing attribute name '${i}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=r=>{var i;if(!this.scrollState||this.scrollState.behavior!=="smooth")return!0;const s=this.scrollState.index??((i=this.getVirtualItemForOffset(this.scrollState.lastTargetOffset))==null?void 0:i.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 i=this.indexFromElement(r),s=this.options.getItemKey(i),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(i)&&this.resizeItem(i,this.options.measureElement(r,void 0,this))},this.resizeItem=(r,i)=>{var s,l;if(r<0||r>=this.options.count)return;let u,d,p;const m=this._flatMeasurements;if(this.options.lanes===1&&m!==null)p=this.options.getItemKey(r),d=m[r*2],u=m[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=i-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,S=((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,i)=>{const s=[];for(let l=0,u=r.length;lthis.options.debug}),this.getVirtualItemForOffset=r=>{const i=this.getMeasurements();if(i.length===0)return;const s=this._flatMeasurements,l=this.options.lanes===1&&s!=null,u=qC(0,i.length-1,l?d=>s[d*2]:d=>sw(i[d]).start,r);return sw(i[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,i,s=0)=>{if(!this.scrollElement)return 0;const l=this.getSize(),u=this.getScrollOffset();i==="auto"&&(i=r>=u+l?"end":"start"),i==="center"?r+=(s-l)/2:i==="end"&&(r-=l);const d=this.getMaxScrollOffset();return Math.max(Math.min(d,r),0)},this.getOffsetForIndex=(r,i="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(i==="auto")if(u.end>=l+s-this.options.scrollPaddingEnd)i="end";else if(u.start<=l+this.options.scrollPaddingStart)i="start";else return[l,i];if(i==="end"&&r===this.options.count-1)return[this.getMaxScrollOffset(),i];const d=i==="end"?u.end+this.options.scrollPaddingEnd:u.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(d,i,u.size),i]},this.scrollToOffset=(r,{align:i="start",behavior:s="auto"}={})=>{const l=this.getOffsetForAlignment(r,i),u=this.now();this.scrollState={index:null,align:i,behavior:s,startedAt:u,lastTargetOffset:l,stableFrames:0},this._scrollToOffset(l,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollToIndex=(r,{align:i="auto",behavior:s="auto"}={})=>{r=Math.max(0,Math.min(r,this.options.count-1));const l=this.getOffsetForIndex(r,i);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:i="auto"}={})=>{const s=this.getScrollOffset()+r,l=this.now();this.scrollState={index:null,align:"start",behavior:i,startedAt:l,lastTargetOffset:s,stableFrames:0},this._scrollToOffset(s,{adjustments:void 0,behavior:i}),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 i=this.getMeasurements();let s;if(i.length===0)s=this.options.paddingStart;else if(this.options.lanes===1){const l=i.length-1,u=this._flatMeasurements;u!=null?s=u[l*2]+u[l*2+1]:s=((r=i[l])==null?void 0:r.end)??0}else{const l=Array(this.options.lanes).fill(null);let u=i.length-1;for(;u>=0&&l.some(d=>d===null);){const d=i[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 i=this.getMeasurements();for(const s of i)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:i,behavior:s})=>{this._intendedScrollOffset=r+(i??0),this.options.scrollToFn(r,{behavior:s,adjustments:i},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&&(am()&&(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 i=this.scrollState.index!=null?this.getOffsetForIndex(this.scrollState.index,this.scrollState.align):void 0,s=i?i[0]:this.scrollState.lastTargetOffset,l=1,u=s!==this.scrollState.lastTargetOffset;if(!u&&pI(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()),m=this.scrollState.behavior==="smooth"&&p>d;this.scrollState.lastTargetOffset=s,m||(this.scrollState.behavior="auto"),this._scrollToOffset(s,{adjustments:void 0,behavior:m?"smooth":"auto"})}this.scheduleScrollReconcile()}}const qC=(e,n,r,i)=>{for(;e<=n;){const s=(e+n)/2|0,l=r(s);if(li)n=s-1;else return s}return e>0?e-1:0};function jI(e,n,r){let i=0;for(;i<=n;){const s=(i+n)/2|0,l=e[s*2];if(lr)n=s-1;else return s}return i>0?i-1:0}function TI(e,n,r,i,s){const l=e.length-1;if(e.length<=i)return{startIndex:0,endIndex:l};if(i===1&&s!==null){const m=jI(s,l,r);let y=m;const v=r+n;for(;ye[m].start,r),p=d;if(i===1)for(;p1){const m=Array(i).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%i),p=Math.min(l,p+(i-1-p%i))}return{startIndex:d,endIndex:p}}const im=typeof document<"u"?w.useLayoutEffect:w.useEffect;function OI({useFlushSync:e=!0,directDomUpdates:n=!1,directDomUpdatesMode:r="transform",...i}){const s=w.useReducer(m=>m+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=m=>{const y=l.current;if(!y.enabled||!y.container)return;const v=m.getTotalSize();if(v!==y.lastSize){y.lastSize=v;const R=m.options.horizontal?"width":"height";y.container.style[R]=`${v}px`}const b=!!m.options.horizontal,x=y.mode==="transform",S=b?"left":"top",_=m.options.scrollMargin,E=m.getVirtualItems();for(const R of E){const O=R.start-_,T=m.elementsCache.get(R.key);T&&y.lastPositions.get(T)!==O&&(y.lastPositions.set(T,O),x?T.style.transform=b?`translate3d(${O}px, 0, 0)`:`translate3d(0, ${O}px, 0)`:T.style[S]=`${O}px`)}},d={...i,onChange:(m,y)=>{var v;const b=l.current;let x=!0;if(b.enabled){u(m);const S=m.range,_=b.prevRange;x=!_||_.isScrolling!==m.isScrolling||_.startIndex!==S?.startIndex||_.endIndex!==S?.endIndex,x&&(b.prevRange=S?{startIndex:S.startIndex,endIndex:S.endIndex,isScrolling:m.isScrolling}:null)}x&&(e&&y?Mi.flushSync(s):s()),(v=i.onChange)==null||v.call(i,m,y)}},[p]=w.useState(()=>{const m=new RI(d);return Object.assign(m,{containerRef:y=>{const v=l.current;if(v.container=y,v.lastSize=null,y&&v.enabled){const b=m.getTotalSize();v.lastSize=b;const x=m.options.horizontal?"width":"height";y.style[x]=`${b}px`}}})});return p.setOptions(d),im(()=>p._didMount(),[]),im(()=>p._willUpdate()),im(()=>{u(p)}),p}function AI(e){return OI({observeElementRect:bI,observeElementOffset:SI,scrollToFn:EI,...e})}function MI(e,n){const r=[],i=(s,l)=>{for(const u of s)r.push({node:u,depth:l}),u.dir&&n.has(u.path)&&i(u.children||[],l+1)};return i(e?.children||[],0),r}function NI(e){const{root:n,expanded:r,onToggle:i,currentPath:s,listingShowing:l,onOpen:u}=e,d=w.useRef(null),p=w.useMemo(()=>MI(n,r),[n,r]),m=AI({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&&m.scrollToIndex(y,{align:"auto"})},[s,p]),f.jsx("nav",{id:"tree","aria-label":"Files",ref:d,children:f.jsx("div",{style:{height:m.getTotalSize(),position:"relative"},children:m.getVirtualItems().map(y=>{const{node:v,depth:b}=p[y.index],x=v.dir?r.has(v.path):!1,S=()=>{if(v.dir&&s===v.path&&l){i(v.path);return}u(v.path),v.dir||pr()};return f.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:S,onKeyDown:_=>{(_.key==="Enter"||_.key===" ")&&(_.preventDefault(),S())},children:[Array.from({length:b},(_,E)=>f.jsx("span",{className:"tguide",style:{left:8+E*13+5},"aria-hidden":"true"},E)),f.jsx("span",{className:"chev",onClick:_=>{v.dir&&(_.stopPropagation(),i(v.path))},children:f.jsx(dt,{name:"chevd"})}),f.jsx("span",{className:"ticon",children:f.jsx(dt,{name:v.dir?"folder":"doc"})}),f.jsx("span",{className:"label",children:v.name})]},y.key)})})})}function DI(e){const n=e.split("/"),r=[];let i="";for(let s=0;s{i=i?i+"/"+s:s;const u=i,d=l===r.length-1;return f.jsxs("span",{children:[l>0&&f.jsx("span",{className:"crumb-sep",children:"/"}),d?f.jsx("span",{children:s}):f.jsx("span",{className:"crumb-seg",title:u,onClick:()=>n(u),children:s})]},u)})})}function cw(e){if(e==="")return[];const n=e.split(` `);return n[n.length-1]===""&&n.pop(),n}const kI=4e6;function LI(e,n){let r=0;for(;rs.push({op:"-",line:l[v],an:r+v+1}),y=v=>s.push({op:"+",line:u[v],bn:r+v+1});if(d*p>kI){for(let v=0;v=0;S--)for(let _=p-1;_>=0;_--)v[S][_]=l[S]===u[_]?v[S+1][_+1]+1:Math.max(v[S+1][_],v[S][_+1]);let b=0,x=0;for(;b=v[b][x+1]?m(b++):y(x++);for(;bi.op==="+").length,del:r.filter(i=>i.op==="-").length}}const GC=1<<20,II=8192;function PI(e){if(e.byteLength>GC)return{kind:"too-large",size:e.byteLength};if(e.subarray(0,II).includes(0))return{kind:"binary"};try{return{kind:"text",text:new TextDecoder("utf-8",{fatal:!0}).decode(e)}}catch{return{kind:"binary"}}}function Jm(e,n,r,i){let s=e+"blob?sha="+encodeURIComponent(n);return r&&(s+="&name="+encodeURIComponent(r)),i&&(s+="&download=1"),s}async function FI(e){const n=await gj(e),r=Number(n.headers.get("Content-Length"));return r>GC?{kind:"too-large",size:r}:PI(new Uint8Array(await n.arrayBuffer()))}function ZC(e,n,r,i){return Zt({queryKey:n,queryFn:()=>FI(e),enabled:r,...i?{staleTime:1/0,gcTime:1/0}:{},retry:!1})}function uw(e,n,r){return ZC(n?Jm(e,n):"",["blob",e,n],!!n,!0)}function VI(e){return e.slice(e.lastIndexOf("/")+1)}function UI({apiBase:e,path:n,prev:r,cur:i}){const s=VI(n);return f.jsxs("span",{className:"dv-dl",children:[f.jsx("a",{href:Jm(e,r,s,!0),children:"download previous"}),f.jsx("a",{href:Jm(e,i,s,!0),children:"download this version"})]})}function HI({apiBase:e,path:n,prev:r,cur:i}){const s=uw(e,r),l=uw(e,i),u=s.data?.kind==="text"&&l.data?.kind==="text",d=w.useMemo(()=>s.data?.kind==="text"&&l.data?.kind==="text"?$I(s.data.text,l.data.text):null,[s.data,l.data]);if(s.error||l.error)return f.jsx("div",{className:"dv dv-msg",children:"Could not load one of the versions."});if(!s.data||!l.data)return f.jsx("div",{className:"dv dv-msg",children:"Loading changes…"});if(!u){const v=s.data.kind==="too-large"||l.data.kind==="too-large";return f.jsxs("div",{className:"dv dv-msg",children:[v?"Too large to diff — download to compare.":"Binary file — no diff available.",f.jsx(UI,{apiBase:e,path:n,prev:r,cur:i})]})}const{lines:p,add:m,del:y}=d;return f.jsxs("div",{className:"dv",children:[f.jsxs("div",{className:"dv-head",children:[f.jsxs("span",{className:"dv-stat",children:[f.jsxs("span",{className:"dv-add",children:["+",m]})," ",f.jsxs("span",{className:"dv-del",children:["−",y]})]}),m===0&&y===0&&f.jsx("span",{className:"dv-same",children:"No line changes"})]}),f.jsx("div",{className:"dv-body",children:p.map((v,b)=>f.jsxs("div",{className:"dv-line dv-"+(v.op==="="?"ctx":v.op==="+"?"ins":"rm"),children:[f.jsx("span",{className:"dv-n",children:v.an??""}),f.jsx("span",{className:"dv-n",children:v.bn??""}),f.jsx("span",{className:"dv-mark",children:v.op==="="?" ":v.op}),f.jsx("span",{className:"dv-text",children:v.line||" "})]},b))})]})}const BI={add:"added",edit:"edited",delete:"deleted"};function KC({text:e}){return f.jsx(f.Fragment,{children:e.split(/(https?:\/\/\S+)/).map((n,r)=>/^https?:\/\//.test(n)?f.jsx("a",{href:n,target:"_blank",rel:"noopener",children:n},r):n)})}function pg({entry:e,apiBase:n,onOpen:r,diff:i,restore:s,remove:l,restoreSha:u,inRun:d}){const[p,m]=w.useState(!1),[y,v]=w.useState(!1),b=e.kind==="put"?"edit":e.kind,x=dd(e),S=[e.device.name||e.device.id,e.device.os].filter(Boolean).join(" · "),_=b!=="delete",E=!!i&&b!=="delete"&&!!e.blob,R=!!d&&b==="add",O=!!s&&!!u&&!R,T=!!l&&R,z=!!s?.busy&&s.busy===e.path+u,I=!!l?.busy&&l.busy===e.path,F=_&&!!e.blob,V=e.path.split("/").pop()||e.path,U=new Date(e.time).toLocaleString(),pe=n+"blob?sha="+e.blob+"&name="+encodeURIComponent(V)+"&download=1",ge=()=>v(!y),fe=Q=>{Q.target.tagName!=="A"&&_&&r(e.path,e.blob)};return f.jsxs("div",{className:"hentry "+b+(_?" clickable":""),tabIndex:_?0:void 0,role:_?"button":void 0,onClick:fe,onKeyDown:Q=>{_&&(Q.key==="Enter"||Q.key===" ")&&(Q.preventDefault(),r(e.path,e.blob))},children:[f.jsxs("div",{className:"hline",children:[f.jsx("span",{className:"hkind",children:BI[b]||b}),f.jsx("span",{className:"hpath",children:e.path}),f.jsx("span",{className:"htime",children:U})]}),f.jsxs("div",{className:"hmeta",children:[f.jsx("span",{className:"hwho",children:x}),f.jsx("span",{className:"hdev",children:S}),f.jsx("span",{className:"hsize",children:e.size?mg(e.size):""}),O&&f.jsxs("button",{type:"button",className:"hrestore-btn",disabled:z,title:"Put this version of "+e.path+" back as a new change",onClick:Q=>{Q.stopPropagation(),s.onRestore(e.path,u)},onKeyDown:Q=>Q.stopPropagation(),children:[f.jsx(dt,{name:"hist"}),z?"restoring…":"restore"]}),T&&f.jsxs("button",{type:"button",className:"hremove-btn",disabled:I,title:"Remove "+e.path+" — this run created it",onClick:Q=>{Q.stopPropagation(),l.onRemove(e.path)},onKeyDown:Q=>Q.stopPropagation(),children:[f.jsx(dt,{name:"trash"}),I?"removing…":"undo — remove file"]})]}),e.note&&!d&&f.jsx("div",{className:"hnote"+(p?" open":""),tabIndex:0,role:"button",title:p?"Collapse note":"Show full note","aria-expanded":p,onClick:Q=>{Q.stopPropagation(),Q.target.tagName!=="A"&&m(!p)},onKeyDown:Q=>{(Q.key==="Enter"||Q.key===" ")&&(Q.preventDefault(),Q.stopPropagation(),m(!p))},children:f.jsx(KC,{text:e.note})}),(E||F)&&f.jsxs("div",{className:"hactions",children:[E&&(i.prev?f.jsxs("button",{type:"button",className:"hdiff-btn"+(y?" open":""),"aria-expanded":y,onClick:Q=>{Q.stopPropagation(),ge()},onKeyDown:Q=>Q.stopPropagation(),children:[f.jsx(dt,{name:y?"chevd":"chev"}),y?"hide changes":"show changes"]}):f.jsx("div",{className:"hdiff-none",children:"First version — nothing to compare against"})),F&&f.jsxs(f.Fragment,{children:[f.jsxs("button",{type:"button",className:"hver-btn","aria-label":`Open ${V} as of ${U}`,onClick:Q=>{Q.stopPropagation(),r(e.path,e.blob)},onKeyDown:Q=>Q.stopPropagation(),children:[f.jsx(dt,{name:"clock"}),"Open this version"]}),f.jsxs("a",{className:"hver-btn",download:!0,href:pe,"aria-label":`Download ${V} as of ${U}`,onClick:Q=>Q.stopPropagation(),onKeyDown:Q=>{Q.stopPropagation(),Q.key===" "&&(Q.preventDefault(),Q.currentTarget.click())},children:[f.jsx(dt,{name:"download"}),"Download"]})]})]}),E&&i.prev&&y&&f.jsx("div",{onClick:Q=>Q.stopPropagation(),children:f.jsx(HI,{apiBase:i.apiBase,path:e.path,prev:i.prev,cur:e.blob})})]})}function qI(e){const{node:n,heatMap:r,onOpen:i}=e,s=(n.children||[]).slice().sort((m,y)=>Number(y.dir||!1)-Number(m.dir||!1)||m.name.localeCompare(y.name)),l=s.filter(m=>m.dir).length,u=s.length-l,d=[];l&&d.push(l+(l===1?" folder":" folders")),u&&d.push(u+(u===1?" file":" files"));const p=ow(r,n.path,!0);return p&&d.push(Qs(p)+" in 30 days"),f.jsxs("div",{className:"dirlist",children:[f.jsxs("h1",{className:"dl-title",children:[f.jsx("span",{className:"dl-title-icon",children:f.jsx(dt,{name:"folder"})}),f.jsx("span",{children:n.name})]}),f.jsx("p",{className:"dl-sub",children:d.join(" · ")||"Empty folder"}),s.length===0?f.jsx("div",{className:"dl-empty",children:"Nothing in this folder yet."}):f.jsx("div",{className:"dl-items",children:s.map(m=>{let y="";if(m.dir){const b=(m.children||[]).length;y=b+(b===1?" item":" items")}else y=[m.size?mg(m.size):"",m.time?new Date(m.time).toLocaleDateString():""].filter(Boolean).join(" · ");const v=ow(r,m.path,!!m.dir);return v&&(y=Qs(v)+(y?" · "+y:"")),f.jsxs("div",{className:"dl-row",tabIndex:0,role:"button",title:m.path,onClick:()=>i(m.path),onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.preventDefault(),i(m.path))},children:[f.jsx("span",{className:"ticon",children:f.jsx(dt,{name:m.dir?"folder":"doc"})}),f.jsx("span",{className:"dl-name",children:m.name}),v&&f.jsx("span",{className:"heatdot lvl"+tI(v),role:"img","aria-label":Qs(v)+" in 30 days",title:Qs(v)+" in 30 days"}),f.jsx("span",{className:"dl-meta",children:y})]},m.path)})}),e.hub&&f.jsx(GI,{apiBase:e.apiBase,prefix:n.path+"/",onOpen:i,onFullHistory:()=>e.onFullHistory(n.path+"/"),onRendered:e.onRendered})]})}function GI(e){const n=hI(e.apiBase,e.prefix,!0),{onRendered:r}=e;return w.useEffect(()=>{n&&n.length&&r&&r()},[n,r]),!n||n.length===0?null:f.jsxs("div",{className:"dl-history",children:[f.jsx("h3",{className:"dl-h3",children:"Recent changes"}),f.jsx("div",{className:"history dl-hlist",children:n.map((i,s)=>f.jsx(pg,{entry:i,apiBase:e.apiBase,onOpen:e.onOpen},s))}),f.jsx("button",{className:"ai-btn dl-more",onClick:e.onFullHistory,children:"Full history"})]})}const YC=5e3;function ZI(e,n,r=YC){const i=[];let s=[],l="",u=!1,d=0;const p=()=>{s.push(l),l="",i.length BearDrive - + diff --git a/web/docs/src/content/docs/manual/hooks.md b/web/docs/src/content/docs/manual/hooks.md index bde2a79..ff062dc 100644 --- a/web/docs/src/content/docs/manual/hooks.md +++ b/web/docs/src/content/docs/manual/hooks.md @@ -104,7 +104,6 @@ machine-wide: |---|---| | macOS | `~/Library/LaunchAgents/ai.beardrive.daemon.plist` (launchd loads it at login) | | Linux | `~/.config/systemd/user/beardrive.service` plus the `default.target.wants` symlink that enables it (honors `XDG_CONFIG_HOME`) | -| Windows | a `BearDrive` value under `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` — visible in Task Manager's Startup tab, where you can disable it | Linux needs systemd as the init system. Without it — Alpine or another runit/OpenRC distro, WSL1, a slim container — `bdrive autostart` says so rather @@ -119,8 +118,5 @@ happen when it can't ask. Answer no, or run `bdrive autostart uninstall`, and the item goes away; sync then resumes on the next `bdrive resume`, `bdrive init`, or agent turn instead of at login. -On Windows you may see a console window flicker at logon: bdrive is a console -program and `resume` exits in milliseconds. Nothing is wrong. - Either way this is not the only thing that recovers sync: an agent turn in a project syncs it too, so a machine you actually work on catches up on its own. diff --git a/web/docs/src/content/docs/reference/cli.md b/web/docs/src/content/docs/reference/cli.md index 8a20fcb..7e5dc45 100644 --- a/web/docs/src/content/docs/reference/cli.md +++ b/web/docs/src/content/docs/reference/cli.md @@ -13,7 +13,7 @@ One binary, `bdrive` — the CLI, the sync daemon, and the web server. | `bdrive logout` | Sign this device out — revokes this device's token on the hub, then clears it locally. `--forget` also drops the remembered server | | `bdrive init [folder]` | Create or connect a project and start syncing — the mount is always exactly the folder named. Interactive on a TTY; flags (`--name`, `--project`, `--server`, `--only`, `--template`, `--yes`) for scripts. `--template docs\|wiki\|para` starts a new project from a structure instead of an empty folder. Also registers agent sync hooks for detected platforms (`--no-hooks` skips them) and a login item so sync resumes after a reboot (`--no-autostart` skips), and prints the project's hub link. Re-run to resume | | `bdrive resume` | Restart the sync daemon for every project on this device that isn't paused — after a reboot, a crash, or a manual kill. Idempotent, so running it twice is harmless. This is what the login item runs | -| `bdrive autostart [install\|uninstall]` | Show, add, or remove the login registration that runs `bdrive resume` after a reboot: a user LaunchAgent on macOS, a systemd user unit on Linux (needs systemd), a per-user Run entry on Windows. `bdrive init` installs it; `--no-autostart` skips it | +| `bdrive autostart [install\|uninstall]` | Show, add, or remove the login registration that runs `bdrive resume` after a reboot: a user LaunchAgent on macOS, a systemd user unit on Linux (needs systemd). `bdrive init` installs it; `--no-autostart` skips it | | `bdrive stop [folder]` | Stop syncing — daemon and agent sync hooks both pause. Files stay on disk; `bdrive init` resumes | | `bdrive scope [add\|rm ]` | Show or change which subfolders sync — edits the managed block of `.bdriveignore` rules that `init --only` writes. Run from the mount root; the daemon picks changes up in seconds. `rm` stops syncing a folder but deletes nothing, locally or on the hub | | `bdrive scope --explain` | List every path in the folder, split into what syncs and what does not, with counts — the verifiable answer to "what leaves this machine". Pure read: no daemon, no lock, no network |