@oodarun/cli 0.1.17 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard-dist/assets/AdminApp-DzKKN2IA.js +6 -0
- package/dashboard-dist/assets/{AdminLogin-DPuKez-W.js → AdminLogin-BYZ4BJQb.js} +1 -1
- package/dashboard-dist/assets/{App-Dc5SAGN3.js → App-BLInVSOO.js} +1 -1
- package/dashboard-dist/assets/InternalDashboard-BOnJXxi7.js +1 -0
- package/dashboard-dist/assets/{SiteAuth-zqMzPUk6.js → SiteAuth-COKQhwhP.js} +1 -1
- package/dashboard-dist/assets/api-nNV-WJu1.js +1 -0
- package/dashboard-dist/assets/index-D6_514CX.css +1 -0
- package/dashboard-dist/assets/{index-e3u3oOC5.js → index-j26_mgI3.js} +2 -2
- package/dashboard-dist/assets/router-BvUnq6R0.js +1 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/cli.js +110 -23
- package/package.json +1 -1
- package/dashboard-dist/assets/AdminApp-eGVdfeZo.js +0 -6
- package/dashboard-dist/assets/InternalDashboard-oJnYMgak.js +0 -1
- package/dashboard-dist/assets/api--5oZGh0X.js +0 -1
- package/dashboard-dist/assets/index-CrjhrzUZ.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as e,r as d}from"./index-j26_mgI3.js";function j(t,s){const n=((t==null?void 0:t.trim())||s).split(/[\s@.]+/).filter(Boolean);return n.length===0?"?":n.length===1?n[0].slice(0,2).toUpperCase():(n[0][0]+n[1][0]).toUpperCase()}function w(t){const s=t.trim().split(/\s+/).filter(Boolean);return s.length===0?"?":s.length===1?s[0].slice(0,2).toUpperCase():(s[0][0]+s[1][0]).toUpperCase()}function y({user:t,onAccount:s,onLogout:l}){const[n,o]=d.useState(!1),x=d.useRef(null);return d.useEffect(()=>{if(!n)return;const a=m=>{x.current&&!x.current.contains(m.target)&&o(!1)},r=m=>{m.key==="Escape"&&o(!1)};return document.addEventListener("mousedown",a),document.addEventListener("keydown",r),()=>{document.removeEventListener("mousedown",a),document.removeEventListener("keydown",r)}},[n]),e.jsxs("div",{className:"relative",ref:x,children:[e.jsxs("button",{onClick:()=>o(a=>!a),className:"flex w-full items-center gap-2 px-2 py-2 hover:bg-border/50 transition-colors","aria-haspopup":"menu","aria-expanded":n,children:[e.jsx("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center bg-ink text-surface text-xs font-medium",children:j(t.name,t.email)}),e.jsxs("span",{className:"min-w-0 flex-1 text-left",children:[e.jsx("span",{className:"block text-sm font-medium text-ink truncate",children:t.name||t.email}),t.name&&e.jsx("span",{className:"block text-xs text-ink-faint truncate",children:t.email})]}),e.jsx("svg",{className:"h-3 w-3 shrink-0 text-ink-faint",viewBox:"0 0 12 12",fill:"none",children:e.jsx("path",{d:"M3 7.5L6 4.5L9 7.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),n&&e.jsxs("div",{role:"menu",className:"absolute bottom-full left-0 right-0 mb-1 border border-border bg-surface shadow-sm z-20",children:[s&&e.jsx("button",{role:"menuitem",onClick:()=>{o(!1),s()},className:"block w-full text-left px-3 py-2 text-sm text-ink hover:bg-border/50 transition-colors",children:"Account"}),e.jsx("button",{role:"menuitem",onClick:()=>{o(!1),l()},className:"block w-full text-left px-3 py-2 text-sm text-ink-muted hover:bg-border/50 transition-colors",children:"Sign out"})]})]})}function f({label:t,active:s,onClick:l}){return e.jsx("button",{onClick:l,className:`block w-full text-left px-2 py-1 text-sm transition-colors ${s?"text-ink font-medium":"text-ink-muted hover:text-ink"}`,children:t})}function g({brand:t,brandAvatar:s,onBrandClick:l,nav:n,activeKey:o,onNavigate:x,activeChildKey:a,onChildNavigate:r,user:m,onAccount:b,onLogout:h,children:k}){return e.jsxs("div",{className:"min-h-screen bg-surface text-ink",children:[e.jsxs("aside",{className:"fixed inset-y-0 left-0 w-56 border-r border-border bg-surface flex flex-col",children:[e.jsx("button",{onClick:l,disabled:!l,className:`flex items-center gap-2 px-4 h-14 border-b border-border ${l?"hover:bg-border/40 transition-colors cursor-pointer":"cursor-default"}`,children:e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-5"})}),e.jsxs("nav",{className:"flex-1 p-2 overflow-y-auto",children:[e.jsxs("div",{className:"px-3 pt-3 pb-2 flex items-center gap-2",children:[s&&e.jsx("span",{className:"flex h-5 w-5 shrink-0 items-center justify-center bg-ink text-surface text-[10px] font-medium",children:w(t)}),e.jsx("span",{className:"text-sm font-medium text-ink truncate",children:t})]}),e.jsx("div",{className:"space-y-0.5",children:n.map(c=>{const p=o===c.key;return e.jsxs("div",{children:[e.jsx("button",{onClick:()=>x(c.key),className:`block w-full text-left px-3 py-2 text-sm font-medium transition-colors ${p?"bg-ink text-surface":"text-ink-muted hover:text-ink hover:bg-border/50"}`,children:c.label}),c.children&&p&&e.jsx("div",{className:"mt-0.5 ml-3 pl-2 border-l border-border space-y-0.5",children:c.children.map(i=>i.children?e.jsxs("div",{children:[e.jsx(f,{label:i.label,active:a===i.key,onClick:()=>r==null?void 0:r(i.key)}),e.jsx("div",{className:"ml-3 space-y-0.5",children:i.children.map(u=>e.jsx(f,{label:u.label,active:a===u.key,onClick:()=>r==null?void 0:r(u.key)},u.key))})]},i.key):e.jsx(f,{label:i.label,active:a===i.key,onClick:()=>r==null?void 0:r(i.key)},i.key))})]},c.key)})})]}),e.jsx("div",{className:"border-t border-border p-2",children:e.jsx(y,{user:m,onAccount:b,onLogout:h})})]}),e.jsx("div",{className:"pl-56",children:e.jsx("main",{className:"max-w-4xl mx-auto px-6 py-8",children:k})})]})}function L(){const[t,s]=d.useState(()=>window.location.pathname);return d.useEffect(()=>{const n=()=>s(window.location.pathname);return window.addEventListener("popstate",n),()=>window.removeEventListener("popstate",n)},[]),{path:t,navigate:(n,o)=>{n!==window.location.pathname&&(o!=null&&o.replace?window.history.replaceState({},"",n):window.history.pushState({},"",n),s(n))}}}function N(){return window.location.hostname==="app.ooda.run"?"":"/admin"}function E(t,s){return(t.startsWith(s)?t.slice(s.length):t).replace(/^\/+/,"").split("/")[0]||""}export{g as D,N as a,E as s,L as u};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
9
9
|
<link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-sans/style.css" rel="stylesheet" />
|
|
10
10
|
<link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-mono/style.css" rel="stylesheet" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-j26_mgI3.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D6_514CX.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/dist/cli.js
CHANGED
|
@@ -298,7 +298,7 @@ createRoot(document.getElementById("root")!).render(
|
|
|
298
298
|
});
|
|
299
299
|
|
|
300
300
|
// src/cli/index.ts
|
|
301
|
-
import
|
|
301
|
+
import path12 from "path";
|
|
302
302
|
import readline2 from "readline";
|
|
303
303
|
import { select as select3, confirm, Separator as Separator3 } from "@inquirer/prompts";
|
|
304
304
|
|
|
@@ -1304,9 +1304,9 @@ function failLogin(json, message) {
|
|
|
1304
1304
|
}
|
|
1305
1305
|
process.exitCode = 1;
|
|
1306
1306
|
}
|
|
1307
|
-
function whoamiCmd(opts) {
|
|
1307
|
+
async function whoamiCmd(opts) {
|
|
1308
1308
|
const orgId = getOrgId();
|
|
1309
|
-
const token =
|
|
1309
|
+
const token = await ensureFreshAccessToken();
|
|
1310
1310
|
if (!orgId || !token) {
|
|
1311
1311
|
if (opts.json) {
|
|
1312
1312
|
console.log(JSON.stringify({ ok: false, authenticated: false }));
|
|
@@ -3773,14 +3773,14 @@ async function pullChangesFromProject(projectName, token, projectRoot, localProj
|
|
|
3773
3773
|
}
|
|
3774
3774
|
execSync3(`git checkout -b "${localBranch}"`, localOpts);
|
|
3775
3775
|
try {
|
|
3776
|
-
const
|
|
3776
|
+
const fs10 = await import("fs");
|
|
3777
3777
|
const os2 = await import("os");
|
|
3778
|
-
const
|
|
3779
|
-
const patchFile =
|
|
3780
|
-
|
|
3778
|
+
const path13 = await import("path");
|
|
3779
|
+
const patchFile = path13.join(os2.tmpdir(), `ooda-patch-${Date.now()}.patch`);
|
|
3780
|
+
fs10.writeFileSync(patchFile, patchContent, "utf-8");
|
|
3781
3781
|
execSync3(`git am "${patchFile}"`, localOpts);
|
|
3782
3782
|
try {
|
|
3783
|
-
|
|
3783
|
+
fs10.unlinkSync(patchFile);
|
|
3784
3784
|
} catch {
|
|
3785
3785
|
}
|
|
3786
3786
|
} catch (amError) {
|
|
@@ -5669,15 +5669,15 @@ function buildPublishBody(opts) {
|
|
|
5669
5669
|
// src/cli/publish.ts
|
|
5670
5670
|
var MAX_SLUG_ATTEMPTS = 5;
|
|
5671
5671
|
async function publishLocalDir(opts) {
|
|
5672
|
-
const { projectDir, slugOverride, json } = opts;
|
|
5672
|
+
const { projectDir, slugOverride, force, json } = opts;
|
|
5673
5673
|
if (!isOrgMode()) {
|
|
5674
5674
|
fail(json, "Publishing requires an organisation login. Run `ooda` and log in first.");
|
|
5675
5675
|
return;
|
|
5676
5676
|
}
|
|
5677
5677
|
const orgId = getOrgId();
|
|
5678
|
-
const jwt =
|
|
5678
|
+
const jwt = await ensureFreshAccessToken();
|
|
5679
5679
|
if (!orgId || !jwt) {
|
|
5680
|
-
fail(json, "
|
|
5680
|
+
fail(json, "Not signed in (or your session expired). Run `ooda login` first.");
|
|
5681
5681
|
return;
|
|
5682
5682
|
}
|
|
5683
5683
|
const apiBase = process.env.OODA_API_BASE || "https://api.ooda.run";
|
|
@@ -5705,11 +5705,21 @@ async function publishLocalDir(opts) {
|
|
|
5705
5705
|
return;
|
|
5706
5706
|
}
|
|
5707
5707
|
let candidate = base;
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5708
|
+
let takenInOrg = /* @__PURE__ */ new Set();
|
|
5709
|
+
try {
|
|
5710
|
+
takenInOrg = new Set((await listSites(auth)).map((s) => s.slug));
|
|
5711
|
+
} catch {
|
|
5712
|
+
}
|
|
5713
|
+
const isOurs = (slug) => config.slug === slug;
|
|
5714
|
+
if (takenInOrg.has(candidate) && !isOurs(candidate) && !force) {
|
|
5715
|
+
if (allowSuffix) {
|
|
5716
|
+
candidate = appendSuffix(base, randomSlugSuffix());
|
|
5717
|
+
} else {
|
|
5718
|
+
fail(
|
|
5719
|
+
json,
|
|
5720
|
+
`A site "${candidate}" already exists in your org and isn't this project's. Publishing would overwrite it \u2014 choose a different --slug, or pass --force to overwrite on purpose.`
|
|
5721
|
+
);
|
|
5722
|
+
return;
|
|
5713
5723
|
}
|
|
5714
5724
|
}
|
|
5715
5725
|
if (!json) {
|
|
@@ -5804,8 +5814,8 @@ var ACCESS_MODES = ["public", "password", "login"];
|
|
|
5804
5814
|
async function runSitesCommand(args) {
|
|
5805
5815
|
if (!isOrgMode()) return fail2(args.json, "Managing sites requires an organisation login. Run `ooda` and log in first.");
|
|
5806
5816
|
const orgId = getOrgId();
|
|
5807
|
-
const jwt =
|
|
5808
|
-
if (!orgId || !jwt) return fail2(args.json, "
|
|
5817
|
+
const jwt = await ensureFreshAccessToken();
|
|
5818
|
+
if (!orgId || !jwt) return fail2(args.json, "Not signed in (or your session expired). Run `ooda login` first.");
|
|
5809
5819
|
const apiBase = process.env.OODA_API_BASE || "https://api.ooda.run";
|
|
5810
5820
|
const auth = { apiBase, orgId, jwt };
|
|
5811
5821
|
const sub = args.subcommand || "list";
|
|
@@ -5950,6 +5960,7 @@ publish [path]
|
|
|
5950
5960
|
build folder. The CLI finds the build output inside it (dist, build, out,
|
|
5951
5961
|
.output/public, .next/static). Requires an org login.
|
|
5952
5962
|
--slug <slug> Override the slug (default: ooda.json name, else folder name)
|
|
5963
|
+
--force Overwrite an existing same-org site at this slug (otherwise refused)
|
|
5953
5964
|
--json Machine-readable JSON output
|
|
5954
5965
|
|
|
5955
5966
|
sites access <slug>
|
|
@@ -5980,8 +5991,79 @@ Examples:
|
|
|
5980
5991
|
ooda sites delete my-app --json`;
|
|
5981
5992
|
}
|
|
5982
5993
|
|
|
5994
|
+
// src/cli/update-check.ts
|
|
5995
|
+
import fs9 from "fs";
|
|
5996
|
+
import path11 from "path";
|
|
5997
|
+
var PKG = "@oodarun/cli";
|
|
5998
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
5999
|
+
var CACHE_FILE = "update-check.json";
|
|
6000
|
+
var FETCH_TIMEOUT_MS = 1500;
|
|
6001
|
+
function compareSemver(a, b) {
|
|
6002
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
6003
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
6004
|
+
for (let i = 0; i < 3; i++) {
|
|
6005
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
6006
|
+
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
6007
|
+
}
|
|
6008
|
+
return 0;
|
|
6009
|
+
}
|
|
6010
|
+
function shouldNotify(current, latest) {
|
|
6011
|
+
if (!latest || current === "0.0.0") return false;
|
|
6012
|
+
return compareSemver(latest, current) > 0;
|
|
6013
|
+
}
|
|
6014
|
+
function cachePath() {
|
|
6015
|
+
return path11.join(getConfigDir(), CACHE_FILE);
|
|
6016
|
+
}
|
|
6017
|
+
function readCache() {
|
|
6018
|
+
try {
|
|
6019
|
+
return JSON.parse(fs9.readFileSync(cachePath(), "utf-8"));
|
|
6020
|
+
} catch {
|
|
6021
|
+
return null;
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
function writeCache(cache) {
|
|
6025
|
+
try {
|
|
6026
|
+
fs9.writeFileSync(cachePath(), JSON.stringify(cache), { mode: 384 });
|
|
6027
|
+
} catch {
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
async function fetchLatest() {
|
|
6031
|
+
try {
|
|
6032
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, {
|
|
6033
|
+
headers: { Accept: "application/vnd.npm.install-v1+json" },
|
|
6034
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
6035
|
+
});
|
|
6036
|
+
if (!res.ok) return null;
|
|
6037
|
+
const data = await res.json();
|
|
6038
|
+
return data.version ?? null;
|
|
6039
|
+
} catch {
|
|
6040
|
+
return null;
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
async function notifyIfOutdated(current, now = Date.now()) {
|
|
6044
|
+
try {
|
|
6045
|
+
if (current === "0.0.0") return;
|
|
6046
|
+
const cache = readCache();
|
|
6047
|
+
let latest = cache?.latest ?? null;
|
|
6048
|
+
if (!cache || now - cache.lastCheck > CHECK_INTERVAL_MS) {
|
|
6049
|
+
latest = await fetchLatest();
|
|
6050
|
+
writeCache({ lastCheck: now, latest });
|
|
6051
|
+
}
|
|
6052
|
+
if (shouldNotify(current, latest)) {
|
|
6053
|
+
process.stderr.write(
|
|
6054
|
+
`
|
|
6055
|
+
Update available: ${PKG} ${current} \u2192 ${latest}
|
|
6056
|
+
Run: npm i -g ${PKG}@latest
|
|
6057
|
+
|
|
6058
|
+
`
|
|
6059
|
+
);
|
|
6060
|
+
}
|
|
6061
|
+
} catch {
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
|
|
5983
6065
|
// src/cli/index.ts
|
|
5984
|
-
var CLI_VERSION = "0.1.
|
|
6066
|
+
var CLI_VERSION = "0.1.20";
|
|
5985
6067
|
function formatMutationError(result) {
|
|
5986
6068
|
const parts = [];
|
|
5987
6069
|
if (result.status !== void 0) parts.push(String(result.status));
|
|
@@ -6061,6 +6143,7 @@ function parseArgs(argv) {
|
|
|
6061
6143
|
i++;
|
|
6062
6144
|
} else if (arg === "--clear-password") flags.clearPassword = true;
|
|
6063
6145
|
else if (arg === "--clear-mode") flags.clearMode = true;
|
|
6146
|
+
else if (arg === "--force") flags.force = true;
|
|
6064
6147
|
else if (arg === "--json") flags.json = true;
|
|
6065
6148
|
else if (!arg.startsWith("--")) positionals.push(arg);
|
|
6066
6149
|
}
|
|
@@ -6072,6 +6155,7 @@ function parseArgs(argv) {
|
|
|
6072
6155
|
} else if (command === "publish") {
|
|
6073
6156
|
args.publishTarget = positionals[0];
|
|
6074
6157
|
args.publishSlug = flags.slug;
|
|
6158
|
+
args.publishForce = Boolean(flags.force);
|
|
6075
6159
|
} else if (command === "sites") {
|
|
6076
6160
|
args.sites = {
|
|
6077
6161
|
subcommand: positionals[0],
|
|
@@ -6509,6 +6593,9 @@ async function directConnect(projectName) {
|
|
|
6509
6593
|
async function main() {
|
|
6510
6594
|
const args = parseArgs(process.argv);
|
|
6511
6595
|
const cwd = process.cwd();
|
|
6596
|
+
if (args.command !== "help" && !args.json && process.stderr.isTTY) {
|
|
6597
|
+
await notifyIfOutdated(CLI_VERSION);
|
|
6598
|
+
}
|
|
6512
6599
|
if (args.command === "help") {
|
|
6513
6600
|
console.log(buildHelpText(CLI_VERSION));
|
|
6514
6601
|
process.exit(0);
|
|
@@ -6523,15 +6610,15 @@ async function main() {
|
|
|
6523
6610
|
if (target && isGitHubTarget(target)) {
|
|
6524
6611
|
await deployFromGitHubFlow(target, apiToken, claudeToken);
|
|
6525
6612
|
} else {
|
|
6526
|
-
const deployPath = target ?
|
|
6613
|
+
const deployPath = target ? path12.resolve(target) : cwd;
|
|
6527
6614
|
await deployCurrentDir(deployPath, apiToken, claudeToken);
|
|
6528
6615
|
}
|
|
6529
6616
|
process.exit(0);
|
|
6530
6617
|
}
|
|
6531
6618
|
if (args.command === "publish") {
|
|
6532
6619
|
await ensureAuth({ requireClaudeToken: false });
|
|
6533
|
-
const dir = args.publishTarget ?
|
|
6534
|
-
await publishLocalDir({ projectDir: dir, slugOverride: args.publishSlug, json: args.json });
|
|
6620
|
+
const dir = args.publishTarget ? path12.resolve(args.publishTarget) : cwd;
|
|
6621
|
+
await publishLocalDir({ projectDir: dir, slugOverride: args.publishSlug, force: args.publishForce, json: args.json });
|
|
6535
6622
|
process.exit(process.exitCode ?? 0);
|
|
6536
6623
|
}
|
|
6537
6624
|
if (args.command === "sites") {
|
|
@@ -6544,7 +6631,7 @@ async function main() {
|
|
|
6544
6631
|
process.exit(process.exitCode ?? 0);
|
|
6545
6632
|
}
|
|
6546
6633
|
if (args.command === "whoami") {
|
|
6547
|
-
whoamiCmd({ json: args.json });
|
|
6634
|
+
await whoamiCmd({ json: args.json });
|
|
6548
6635
|
process.exit(process.exitCode ?? 0);
|
|
6549
6636
|
}
|
|
6550
6637
|
if (args.command === "logout") {
|
package/package.json
CHANGED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{r as n,j as e}from"./index-e3u3oOC5.js";import{m as Y,a as Q,b as W,A as X}from"./AdminLogin-DPuKez-W.js";import{b as L,d as _,e as Z,g as ee,a as te,c as K,s as se}from"./api--5oZGh0X.js";function ne({orgId:s,role:a="admin"}){const[i,c]=n.useState([]),[f,h]=n.useState(!0),[j,u]=n.useState(null),p=a==="admin",g=async()=>{h(!0);try{const o=p?await L(s,"/users"):await _(s,"/members");if(!o.ok){u("Failed to load members");return}const r=await o.json();c(r.users||[])}catch{u("Could not reach the server")}finally{h(!1)}};n.useEffect(()=>{g()},[s]);const b=async o=>{if(!confirm(`Remove ${o} from this organization?`))return;(await L(s,`/users/${encodeURIComponent(o)}`,{method:"DELETE"})).ok&&c(t=>t.filter(x=>x.email!==o))};return f?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading members..."}):j?e.jsx("p",{className:"text-sm text-red-600",children:j}):e.jsxs("div",{children:[e.jsxs("h2",{className:"text-lg font-medium text-ink mb-4",children:["Members",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:i.length})]}),i.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No members yet."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:i.map(o=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:o.name||o.email}),e.jsx("p",{className:"text-xs text-ink-faint",children:o.email})]}),o.role&&e.jsx("span",{className:`text-xs px-2 py-0.5 ${o.role==="admin"?"bg-ink text-surface":"bg-border text-ink-muted"}`,children:o.role})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",children:new Date(o.joinedAt).toLocaleDateString()}),p&&e.jsx("button",{onClick:()=>b(o.email),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Remove"})]})]},o.email))})]})}function O(s){return s.status==="pending"&&s.expiresAt&&new Date(s.expiresAt).getTime()<Date.now()?"expired":s.status}function ae({orgId:s}){const[a,i]=n.useState([]),[c,f]=n.useState(!0),[h,j]=n.useState(null),[u,p]=n.useState(""),[g,b]=n.useState("member"),[o,r]=n.useState(!1),[t,x]=n.useState(null),l=async()=>{f(!0);try{const d=await L(s,"/invites");if(!d.ok){j("Failed to load invites");return}const S=await d.json();i(S.invites||[])}catch{j("Could not reach the server")}finally{f(!1)}};n.useEffect(()=>{l()},[s]);const k=async d=>{d.preventDefault(),x(null);const S=u.split(/[,\n]/).map(R=>R.trim()).filter(Boolean);if(S.length===0){x("Enter at least one email address");return}r(!0);try{const R=await L(s,"/invites",{method:"POST",body:JSON.stringify({emails:S,role:g})});if(!R.ok){const I=await R.json();x(I.error||"Failed to create invites");return}p(""),l()}catch{x("Could not reach the server")}finally{r(!1)}},C=async d=>{if(!confirm(`Revoke invite for ${d}?`))return;(await L(s,`/invites/${encodeURIComponent(d)}`,{method:"DELETE"})).ok&&l()},v=a.filter(d=>O(d)==="pending"),A=a.filter(d=>O(d)==="expired"),M=a.filter(d=>O(d)==="accepted"),N=a.filter(d=>O(d)==="revoked"),T=async d=>{r(!0);try{(await L(s,"/invites",{method:"POST",body:JSON.stringify({emails:[d],role:"member"})})).ok&&l()}catch{}finally{r(!1)}},D=d=>{switch(d){case"pending":return"bg-yellow-100 text-yellow-800";case"accepted":return"bg-green-100 text-green-800";case"revoked":return"bg-red-100 text-red-800";case"expired":return"bg-orange-100 text-orange-800";default:return"bg-border text-ink-muted"}};return e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-4",children:"Invite people"}),e.jsxs("form",{onSubmit:k,className:"space-y-3",children:[e.jsx("div",{children:e.jsx("textarea",{value:u,onChange:d=>p(d.target.value),placeholder:"Email addresses (comma or newline separated)",rows:3,className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent resize-none font-mono"})}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("select",{value:g,onChange:d=>b(d.target.value),className:"px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink",children:[e.jsx("option",{value:"member",children:"Member"}),e.jsx("option",{value:"admin",children:"Admin"})]}),e.jsx("button",{type:"submit",disabled:o,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:o?"Sending...":"Send invites"})]}),t&&e.jsx("p",{className:"text-sm text-red-600",children:t})]})]}),c?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading invites..."}):h?e.jsx("p",{className:"text-sm text-red-600",children:h}):e.jsxs("div",{children:[e.jsxs("h2",{className:"text-lg font-medium text-ink mb-4",children:["Invites",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:a.length})]}),a.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No invites yet."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:[...v,...A,...M,...N].map(d=>{const S=O(d);return e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:d.email}),e.jsx("p",{className:"text-xs text-ink-faint",children:new Date(d.createdAt).toLocaleDateString()})]}),e.jsx("span",{className:`text-xs px-2 py-0.5 ${D(S)}`,children:S}),e.jsx("span",{className:`text-xs px-2 py-0.5 ${d.role==="admin"?"bg-ink text-surface":"bg-border text-ink-muted"}`,children:d.role})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[S==="expired"&&e.jsx("button",{onClick:()=>T(d.email),disabled:o,className:"text-xs text-ink hover:text-ink/70 transition-colors disabled:opacity-50",children:"Re-send"}),S==="pending"&&e.jsx("button",{onClick:()=>C(d.email),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Revoke"})]})]},d.id)})})]})]})}function re(s){const a=Math.max(0,Math.floor(Date.now()/1e3-s));return a<60?`${a}s ago`:a<3600?`${Math.floor(a/60)}m ago`:a<86400?`${Math.floor(a/3600)}h ago`:`${Math.floor(a/86400)}d ago`}function ie(s){try{return atob(s.logTailBase64)}catch{return""}}function B(s){const a=ie(s).trim();if(!a)return"";const i=a.split(`
|
|
2
|
-
`).filter(c=>c.trim());return i[i.length-1]||""}function H(s){const a=Date.now()-new Date(s).getTime(),i=Math.floor(a/6e4);if(i<1)return"just now";if(i<60)return`${i}m ago`;const c=Math.floor(i/60);return c<24?`${c}h ago`:`${Math.floor(c/24)}d ago`}function oe(s){const a=s.toLowerCase();return["running","started","ready"].includes(a)?"bg-green-100 text-green-800":["stopped","suspended"].includes(a)?"bg-red-100 text-red-800":a==="sleeping"?"bg-gray-100 text-gray-600":"bg-yellow-100 text-yellow-800"}function le({orgId:s,role:a="admin"}){const[i,c]=n.useState([]),[f,h]=n.useState(!0),[j,u]=n.useState(null),p=a==="admin",g=p?L:_,b=async()=>{h(!0);try{const t=await g(s,"/projects");if(!t.ok){u("Failed to load projects");return}const x=await t.json();c(x.projects||[])}catch{u("Could not reach the server")}finally{h(!1)}};n.useEffect(()=>{b()},[s]);const o=async t=>{(await g(s,`/projects/${encodeURIComponent(t)}/stop`,{method:"POST"})).ok&&c(l=>l.map(k=>k.name===t?{...k,status:"stopped"}:k))},r=async t=>{if(!confirm(`Delete project "${t}"? This will destroy the running environment.`))return;(await g(s,`/projects/${encodeURIComponent(t)}`,{method:"DELETE"})).ok&&c(l=>l.filter(k=>k.name!==t))};return f?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading projects..."}):j?e.jsx("p",{className:"text-sm text-red-600",children:j}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Projects",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:i.length})]}),e.jsx("button",{onClick:b,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),i.length===0?e.jsxs("div",{className:"border border-border py-12 text-center",children:[e.jsx("p",{className:"text-sm text-ink-muted",children:"No projects created yet"}),e.jsx("p",{className:"text-xs text-ink-faint mt-1",children:"Projects will appear here when members deploy"})]}):e.jsx("div",{className:"border border-border divide-y divide-border",children:i.map(t=>{const x=p||t.isOwn,l=t.status&&["running","started","ready"].includes(t.status.toLowerCase());return e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:t.name}),t.createdByName&&e.jsxs("p",{className:"text-xs text-ink-faint",children:[t.createdByName,t.isOwn&&!p&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"})]})]}),t.status&&e.jsx("span",{className:`text-xs px-2 py-0.5 ${oe(t.status)}`,children:t.status}),t.devServerStatus&&e.jsx("span",{className:"text-xs px-2 py-0.5 bg-red-100 text-red-800 cursor-help",title:`Dev server auto-disabled ${re(t.devServerStatus.disabledAt)} after ${t.devServerStatus.fails} rapid crashes.${B(t.devServerStatus)?`
|
|
3
|
-
|
|
4
|
-
Last error: ${B(t.devServerStatus).slice(0,300)}`:""}
|
|
5
|
-
|
|
6
|
-
The owner needs to reconnect with npx @oodarun/cli and run /start-server after fixing the underlying error.`,children:"dev server disabled"})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[t.lastActiveAt?e.jsxs("span",{className:"text-xs text-ink-muted",title:`Last active: ${t.lastActiveAt}`,children:["active ",H(t.lastActiveAt)]}):e.jsxs("span",{className:"text-xs text-ink-faint",title:t.createdAt,children:["created ",H(t.createdAt)]}),x&&l&&e.jsx("button",{onClick:()=>o(t.name),className:"text-xs text-amber-600 hover:text-amber-800 transition-colors",children:"Stop"}),x&&e.jsx("button",{onClick:()=>r(t.name),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Delete"})]})]},t.name)})})]})}function ce({orgId:s,site:a,apiFetch:i,onSaved:c}){const[f,h]=n.useState(a.accessMode??"inherit"),[j,u]=n.useState(!1),[p,g]=n.useState(""),[b,o]=n.useState(null),[r,t]=n.useState(!1),[x,l]=n.useState(null),k=f==="password"||f==="inherit"&&a.effectiveMode==="password",C=f!==(a.accessMode??"inherit")||j,v=async()=>{l(null);const N=await i(s,`/sites/${encodeURIComponent(a.slug)}/password`);if(!N.ok){l("Could not reveal password");return}const T=await N.json();o(T.password??"(none set)")},A=async()=>{b&&b!=="(none set)"&&(await navigator.clipboard.writeText(b),l("Copied"))},M=async()=>{t(!0),l(null);try{const N=W({mode:f,setPassword:j,password:p});if(!(await i(s,`/sites/${encodeURIComponent(a.slug)}`,{method:"PATCH",body:JSON.stringify(N)})).ok){l("Save failed");return}u(!1),g(""),o(null),l("Saved"),c()}finally{t(!1)}};return e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx("select",{value:f,onChange:N=>h(N.target.value),className:"text-xs border border-border bg-surface px-2 py-1 text-ink",children:Q.map(N=>e.jsx("option",{value:N.value,children:N.value==="inherit"?`Inherit (${Y(a.effectiveMode)})`:N.label},N.value))}),k&&e.jsx(e.Fragment,{children:j?e.jsx("input",{type:"text",value:p,onChange:N=>g(N.target.value),placeholder:"New password (blank to clear)",className:"text-xs border border-border bg-surface px-2 py-1 text-ink"}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:v,className:"text-xs text-ink-muted hover:text-ink border border-border px-2 py-1",children:"Reveal"}),b&&e.jsxs(e.Fragment,{children:[e.jsx("code",{className:"text-xs text-ink bg-surface-muted px-2 py-1",children:b}),e.jsx("button",{onClick:A,className:"text-xs text-ink-muted hover:text-ink",children:"Copy"})]}),e.jsx("button",{onClick:()=>u(!0),className:"text-xs text-ink-muted hover:text-ink",children:"Change"})]})}),C&&e.jsx("button",{onClick:M,disabled:r,className:"text-xs bg-ink text-surface px-2 py-1 disabled:opacity-50",children:r?"Saving…":"Save"}),x&&e.jsx("span",{className:"text-xs text-ink-faint",children:x})]})}function de(s){const a=Date.now()-new Date(s).getTime(),i=Math.floor(a/6e4);if(i<1)return"just now";if(i<60)return`${i}m ago`;const c=Math.floor(i/60);return c<24?`${c}h ago`:`${Math.floor(c/24)}d ago`}function xe({orgId:s,role:a="admin"}){const[i,c]=n.useState([]),[f,h]=n.useState(!0),[j,u]=n.useState(null),p=a==="admin",g=_,b=async()=>{h(!0);try{const r=await g(s,"/sites");if(!r.ok){u("Failed to load sites");return}const t=await r.json();c(t.sites||[])}catch{u("Could not reach the server")}finally{h(!1)}};n.useEffect(()=>{b()},[s]);const o=async r=>{if(!confirm(`Unpublish "${r}"? This will remove the site from ooda.run.`))return;(await g(s,`/sites/${encodeURIComponent(r)}`,{method:"DELETE"})).ok&&c(x=>x.filter(l=>l.slug!==r))};return f?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading sites..."}):j?e.jsx("p",{className:"text-sm text-red-600",children:j}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Published Sites",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:i.length})]}),e.jsx("button",{onClick:b,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),i.length===0?e.jsxs("div",{className:"border border-border py-12 text-center",children:[e.jsx("p",{className:"text-sm text-ink-muted",children:"No sites published yet"}),e.jsx("p",{className:"text-xs text-ink-faint mt-1",children:"Published sites will appear here"})]}):e.jsx("div",{className:"border border-border divide-y divide-border",children:i.map(r=>{const t=p||r.isOwn;return e.jsxs("div",{className:"flex items-start justify-between px-4 py-3",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm font-medium text-ink",children:[r.slug,e.jsxs("span",{className:"ml-2 text-xs font-normal text-ink-faint border border-border px-1.5 py-0.5",children:[Y(r.effectiveMode),r.accessMode===null&&" · inherited"]})]}),e.jsx("p",{className:"text-xs text-ink-faint",children:r.url}),r.publishedByName&&e.jsxs("p",{className:"text-xs text-ink-faint mt-0.5",children:["by ",r.publishedByName,r.isOwn&&!p&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"})]}),t&&e.jsx(ce,{orgId:s,site:r,apiFetch:g,onSaved:b})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",title:r.publishedAt,children:de(r.publishedAt)}),e.jsx("a",{href:r.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-ink-muted hover:text-ink border border-border px-2 py-1 transition-colors",children:"Open"}),t&&e.jsx("button",{onClick:()=>o(r.slug),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Unpublish"})]})]},r.slug)})})]})}const me=[{value:"public",label:"Public — anyone with the link"},{value:"password",label:"Password — shared password"},{value:"login",label:"Ooda login — members of this org"}];function ue({orgId:s}){const[a,i]=n.useState(null),[c,f]=n.useState(!0),[h,j]=n.useState(!1),[u,p]=n.useState(null),[g,b]=n.useState(null),[o,r]=n.useState(""),[t,x]=n.useState(""),[l,k]=n.useState(""),[C,v]=n.useState(60),[A,M]=n.useState([]),[N,T]=n.useState("public"),[D,d]=n.useState(""),[S,R]=n.useState(!1),I=async()=>{var m,y;f(!0),p(null);try{const w=await L(s,"/settings");if(!w.ok){p("Failed to load settings");return}const P=await w.json();i(P);const E=P.claude;if(E){r(((m=E.env)==null?void 0:m.ANTHROPIC_API_KEY)||""),x(((y=E.env)==null?void 0:y.ANTHROPIC_BASE_URL)||""),k(E.apiKeyHelper||""),v(Math.round((E.apiKeyHelperTtlMs||36e5)/6e4));const $=new Set(["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL"]),V=Object.entries(E.env||{}).filter(([U])=>!$.has(U)).map(([U,G])=>({key:U,value:G}));M(V)}P.siteAccess&&(T(P.siteAccess.defaultMode),d(P.siteAccess.defaultPassword??"")),R(!1)}catch{p("Could not reach the server")}finally{f(!1)}};n.useEffect(()=>{I()},[s]);const J=async()=>{j(!0),p(null),b(null);const m={};o&&(m.ANTHROPIC_API_KEY=o),t&&(m.ANTHROPIC_BASE_URL=t);for(const w of A)w.key.trim()&&(m[w.key.trim()]=w.value);const y={};Object.keys(m).length>0&&(y.env=m),l.trim()&&(y.apiKeyHelper=l.trim(),y.apiKeyHelperTtlMs=C*6e4);try{const w={claude:Object.keys(y).length>0?y:null};if(S&&(w.siteAccess={defaultMode:N,defaultPassword:N==="password"&&D?D:null}),!(await L(s,"/settings",{method:"PUT",body:JSON.stringify(w)})).ok){p("Failed to save settings");return}b("Settings saved"),setTimeout(()=>b(null),3e3)}catch{p("Could not reach the server")}finally{j(!1)}},z=()=>{M(m=>[...m,{key:"",value:""}])},q=m=>{M(y=>y.filter((w,P)=>P!==m))},F=(m,y,w)=>{M(P=>P.map((E,$)=>$===m?{...E,[y]:w}:E))};return c?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading settings..."}):u&&!a?e.jsx("p",{className:"text-sm text-red-600",children:u}):e.jsxs("div",{className:"space-y-8",children:[e.jsxs("section",{children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-1",children:"Claude Configuration"}),e.jsx("p",{className:"text-xs text-ink-faint mb-4",children:"Configure how Claude Code authenticates on cloud sandboxes in this organization."}),e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Anthropic API Key"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Encrypted at rest. Consider using an API key helper for automatic rotation."}),e.jsx("input",{type:"password",value:o,onChange:m=>r(m.target.value),placeholder:"sk-ant-api03-...",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Base URL"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Custom Anthropic API endpoint (leave blank for default)."}),e.jsx("input",{type:"text",value:t,onChange:m=>x(m.target.value),placeholder:"https://api.anthropic.com",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"API Key Helper"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Path to a script that prints a valid API key to stdout. Used for token rotation."}),e.jsx("input",{type:"text",value:l,onChange:m=>k(m.target.value),placeholder:"/usr/local/bin/token-helper.sh",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"}),l&&e.jsxs("div",{className:"mt-2",children:[e.jsx("label",{className:"block text-xs text-ink-muted mb-1",children:"Refresh interval (minutes)"}),e.jsx("input",{type:"number",value:C,onChange:m=>v(parseInt(m.target.value,10)||60),min:1,className:"w-24 text-sm px-3 py-1.5 border border-border bg-surface text-ink focus:outline-none focus:border-ink"})]})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Environment Variables"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Additional env vars injected into project sessions."}),A.map((m,y)=>e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx("input",{type:"text",value:m.key,onChange:w=>F(y,"key",w.target.value),placeholder:"KEY",className:"flex-1 text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink font-mono"}),e.jsx("input",{type:"text",value:m.value,onChange:w=>F(y,"value",w.target.value),placeholder:"value",className:"flex-[2] text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink font-mono"}),e.jsx("button",{onClick:()=>q(y),className:"text-xs text-red-500 hover:text-red-700 px-2",children:"Remove"})]},y)),e.jsx("button",{onClick:z,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"+ Add variable"})]})]})]}),e.jsxs("section",{children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-1",children:"Published site access"}),e.jsx("p",{className:"text-xs text-ink-faint mb-4",children:"Default access policy for this org's published sites. Each site can override this. The password is encrypted at rest."}),e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Default access"}),e.jsx("select",{value:N,onChange:m=>{T(m.target.value),R(!0)},className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink focus:outline-none focus:border-ink",children:me.map(m=>e.jsx("option",{value:m.value,children:m.label},m.value))})]}),N==="password"&&e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Default password"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Shared by every site that inherits the org default. Sites can set their own."}),e.jsx("input",{type:"text",value:D,onChange:m=>{d(m.target.value),R(!0)},placeholder:"Set a default password",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:J,disabled:h,className:"text-sm font-medium px-4 py-1.5 bg-ink text-surface hover:opacity-90 transition-opacity disabled:opacity-50",children:h?"Saving...":"Save changes"}),g&&e.jsx("span",{className:"text-xs text-green-600",children:g}),u&&e.jsx("span",{className:"text-xs text-red-600",children:u})]})]})}const he=[["projects","Projects"],["sites","Published Sites"],["members","Members"],["invites","Invites"],["settings","Settings"]],fe=[["projects","Projects"],["sites","Published Sites"],["members","Members"]];function pe({orgId:s,orgName:a,user:i,role:c,onLogout:f}){const[h,j]=n.useState("projects"),u=c==="admin",p=u?he:fe;return e.jsxs("div",{className:"min-h-screen bg-surface",children:[e.jsxs("header",{className:"border-b border-border px-6 py-4 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-5"}),e.jsx("span",{className:"text-ink-faint",children:"/"}),e.jsx("span",{className:"text-sm font-medium text-ink",children:a})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",children:i.email}),e.jsx("button",{onClick:f,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Sign out"})]})]}),e.jsx("div",{className:"border-b border-border px-6",children:e.jsx("nav",{className:"flex gap-6",children:p.map(([g,b])=>e.jsx("button",{onClick:()=>j(g),className:`py-3 text-sm font-medium border-b-2 transition-colors ${h===g?"border-ink text-ink":"border-transparent text-ink-muted hover:text-ink"}`,children:b},g))})}),e.jsxs("main",{className:"max-w-4xl mx-auto px-6 py-8",children:[h==="projects"&&e.jsx(le,{orgId:s,role:c}),h==="sites"&&e.jsx(xe,{orgId:s,role:c}),h==="members"&&e.jsx(ne,{orgId:s,role:c}),h==="invites"&&u&&e.jsx(ae,{orgId:s}),h==="settings"&&u&&e.jsx(ue,{orgId:s})]})]})}function be({token:s,onDone:a}){const[i,c]=n.useState(""),[f,h]=n.useState(""),[j,u]=n.useState(null),[p,g]=n.useState([]),[b,o]=n.useState(!1),[r,t]=n.useState(!1),x=async l=>{if(l.preventDefault(),u(null),g([]),i!==f){u("Passwords do not match");return}o(!0);try{const k=await Z(s,i);if(!k.ok){u(k.error||"Reset failed"),g(k.errors||[]);return}t(!0)}catch{u("Could not reach the server")}finally{o(!1)}};return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-sm p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:"Choose a new password"})]}),r?e.jsxs("div",{className:"space-y-4 text-center",children:[e.jsx("p",{className:"text-sm text-ink",children:"Your password has been reset."}),e.jsx("button",{onClick:a,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Sign in"})]}):e.jsxs("form",{onSubmit:x,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"password",className:"block text-sm font-medium text-ink-muted mb-1",children:"New password"}),e.jsx("input",{id:"password",type:"password",value:i,onChange:l=>c(l.target.value),required:!0,autoComplete:"new-password",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"confirm",className:"block text-sm font-medium text-ink-muted mb-1",children:"Confirm password"}),e.jsx("input",{id:"confirm",type:"password",value:f,onChange:l=>h(l.target.value),required:!0,autoComplete:"new-password",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),j&&e.jsxs("div",{className:"text-sm text-red-600",children:[e.jsx("p",{children:j}),p.length>0&&e.jsx("ul",{className:"mt-1 list-disc list-inside text-xs text-red-500",children:p.map(l=>e.jsx("li",{children:l},l))})]}),e.jsx("button",{type:"submit",disabled:b,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:b?"...":"Reset password"})]})]})})}function ke(){const[s,a]=n.useState(null),[i,c]=n.useState([]),[f,h]=n.useState(null),[j,u]=n.useState(!0);n.useEffect(()=>{(async()=>{if(!ee()){u(!1);return}const x=await te();if(x){a(x.user);const l=localStorage.getItem("ooda-selected-org"),k=localStorage.getItem("ooda-selected-org-name"),C=x.orgs.find(v=>v.orgId===l);if(C)c(x.orgs.map(v=>({...v,orgName:v.orgId===l&&k||v.orgId}))),h({...C,orgName:k||C.orgId});else if(x.orgs.length>0){const v=x.orgs.map(A=>({...A,orgName:A.orgId}));c(v),h(v[0]),localStorage.setItem("ooda-selected-org",v[0].orgId),localStorage.setItem("ooda-selected-org-name",v[0].orgName)}}else K();u(!1)})()},[]);const p=(t,x,l,k)=>{se(l,k),a(t),c(x);const v=x.find(A=>A.role==="admin")||x[0];v&&(h(v),localStorage.setItem("ooda-selected-org",v.orgId),localStorage.setItem("ooda-selected-org-name",v.orgName))},g=()=>{K(),localStorage.removeItem("ooda-selected-org"),localStorage.removeItem("ooda-selected-org-name"),a(null),c([]),h(null)},b=window.location.pathname!=="/reset-password"?null:new URLSearchParams(window.location.search).get("token");if(b)return e.jsx(be,{token:b,onDone:()=>{window.location.href="/"}});if(j)return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading..."})});if(!s||!f)return e.jsx(X,{onLogin:p});const o=i.find(t=>t.orgId===f.orgId),r=(o==null?void 0:o.role)||"member";return e.jsx(pe,{orgId:f.orgId,orgName:f.orgName,user:s,role:r,onLogout:g})}export{ke as AdminApp};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r,j as e}from"./index-e3u3oOC5.js";import{g as A,a as E,c as y,i as j}from"./api--5oZGh0X.js";function g(l){const m=Date.now()-new Date(l).getTime(),n=Math.floor(m/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const c=Math.floor(n/60);return c<24?`${c}h ago`:`${Math.floor(c/24)}d ago`}function O({onCreated:l,onCancel:m}){const[n,c]=r.useState(""),[o,x]=r.useState(""),[d,t]=r.useState(""),[i,a]=r.useState([]),[u,h]=r.useState(null),[p,b]=r.useState(!1),[N,w]=r.useState(null),k=()=>{const s=d.trim().toLowerCase();!s||!s.includes("@")||i.includes(s)||(a([...i,s]),t(""))},C=s=>{a(i.filter(f=>f!==s))},S=async s=>{if(s.preventDefault(),i.length===0){h("Add at least one admin email");return}h(null),b(!0);try{const f=await j("/orgs",{method:"POST",body:JSON.stringify({orgId:n,orgName:o||n,adminEmails:i})}),v=await f.json();if(!f.ok){h(v.error||"Failed to create org");return}w(v)}catch{h("Could not reach the server")}finally{b(!1)}};return N?e.jsxs("div",{className:"border border-border p-6 mb-6 bg-white",children:[e.jsx("h3",{className:"text-sm font-medium text-ink mb-4",children:"Organisation created"}),e.jsxs("p",{className:"text-sm text-ink-muted mb-3",children:[e.jsx("span",{className:"font-medium text-ink",children:o||n})," ",e.jsxs("span",{className:"text-ink-faint",children:["(",n,")"]})]}),e.jsx("div",{className:"space-y-1 mb-4",children:N.invites.map(s=>e.jsxs("p",{className:"text-sm text-ink-muted",children:[s.email," — ",s.emailSent?"invite sent":"invite created (email not sent)"]},s.email))}),e.jsx("button",{onClick:l,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Done"})]}):e.jsxs("form",{onSubmit:S,className:"border border-border p-6 mb-6 bg-white",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h3",{className:"text-sm font-medium text-ink",children:"Create organisation"}),e.jsx("button",{type:"button",onClick:m,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Cancel"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"orgId",className:"block text-xs font-medium text-ink-muted mb-1",children:"Org ID (slug)"}),e.jsx("input",{id:"orgId",type:"text",value:n,onChange:s=>c(s.target.value.toLowerCase().replace(/[^a-z0-9-]/g,"-")),required:!0,placeholder:"wise-workshop",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"orgName",className:"block text-xs font-medium text-ink-muted mb-1",children:"Display name"}),e.jsx("input",{id:"orgName",type:"text",value:o,onChange:s=>x(s.target.value),placeholder:n||"Wise Workshop",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]})]}),e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"block text-xs font-medium text-ink-muted mb-1",children:"Admin emails"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{type:"email",value:d,onChange:s=>t(s.target.value),onKeyDown:s=>{s.key==="Enter"&&(s.preventDefault(),k())},placeholder:"admin@example.com",className:"flex-1 px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsx("button",{type:"button",onClick:k,className:"px-3 py-2 border border-border text-sm text-ink-muted hover:text-ink hover:border-ink transition-colors",children:"Add"})]}),i.length>0&&e.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:i.map(s=>e.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-1 bg-surface-alt text-sm text-ink",children:[s,e.jsx("button",{type:"button",onClick:()=>C(s),className:"text-ink-faint hover:text-ink ml-1",children:"×"})]},s))})]}),u&&e.jsx("p",{className:"text-sm text-red-600 mb-4",children:u}),e.jsx("button",{type:"submit",disabled:p||!n||i.length===0,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:p?"Creating...":"Create organisation"})]})}function I(){const[l,m]=r.useState([]),[n,c]=r.useState(!0),[o,x]=r.useState(null),[d,t]=r.useState(!1),i=async()=>{c(!0);try{const a=await j("/orgs");if(!a.ok){x(a.status===401?"Not authorized (requires internal admin)":"Failed to load orgs");return}const u=await a.json();m(u.orgs||[])}catch{x("Could not reach the server")}finally{c(!1)}};return r.useEffect(()=>{i()},[]),n?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading orgs..."}):o?e.jsx("p",{className:"text-sm text-red-600",children:o}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Organisations",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:l.length})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:()=>t(!0),className:"px-3 py-1.5 bg-ink text-surface text-xs font-medium hover:bg-ink/80 transition-colors",children:"Create org"}),e.jsx("button",{onClick:i,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]})]}),d&&e.jsx(O,{onCreated:()=>{t(!1),i()},onCancel:()=>t(!1)}),l.length===0?e.jsx("div",{className:"border border-border py-12 text-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"No organisations yet"})}):e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"grid grid-cols-6 gap-4 px-4 py-2 text-xs font-medium text-ink-muted bg-surface-alt",children:[e.jsx("span",{className:"col-span-2",children:"Name"}),e.jsx("span",{children:"Projects"}),e.jsx("span",{children:"Members"}),e.jsx("span",{children:"Limit"}),e.jsx("span",{children:"Created"})]}),l.map(a=>e.jsxs("div",{className:"grid grid-cols-6 gap-4 px-4 py-3 items-center",children:[e.jsxs("div",{className:"col-span-2",children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:a.name}),e.jsx("p",{className:"text-xs text-ink-faint",children:a.id})]}),e.jsx("span",{className:"text-sm text-ink",children:a.projectCount}),e.jsx("span",{className:"text-sm text-ink",children:a.memberCount}),e.jsx("span",{className:"text-sm text-ink-muted",children:a.maxProjects}),e.jsx("span",{className:"text-xs text-ink-faint",title:a.createdAt,children:g(a.createdAt)})]},a.id))]})]})}function L(){const[l,m]=r.useState([]),[n,c]=r.useState(!0),[o,x]=r.useState(null),d=async()=>{c(!0);try{const t=await j("/projects");if(!t.ok){x(t.status===401?"Not authorized (requires internal admin)":"Failed to load projects");return}const i=await t.json();m(i.projects||[])}catch{x("Could not reach the server")}finally{c(!1)}};return r.useEffect(()=>{d()},[]),n?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading projects..."}):o?e.jsx("p",{className:"text-sm text-red-600",children:o}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["All Projects",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:l.length})]}),e.jsx("button",{onClick:d,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),l.length===0?e.jsx("div",{className:"border border-border py-12 text-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"No projects across any org"})}):e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"grid grid-cols-5 gap-4 px-4 py-2 text-xs font-medium text-ink-muted bg-surface-alt",children:[e.jsx("span",{children:"Project"}),e.jsx("span",{children:"Org"}),e.jsx("span",{children:"Owner"}),e.jsx("span",{children:"Last Active"}),e.jsx("span",{children:"Created"})]}),l.map(t=>e.jsxs("div",{className:"grid grid-cols-5 gap-4 px-4 py-3 items-center",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:t.name}),t.previewUrl&&e.jsx("a",{href:t.previewUrl,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-blue-600 hover:underline truncate block",children:"preview"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-ink",children:t.orgName||t.orgId}),t.orgName&&e.jsx("p",{className:"text-xs text-ink-faint",children:t.orgId})]}),e.jsx("span",{className:"text-sm text-ink-muted truncate",children:t.ownerEmail||"—"}),e.jsx("span",{className:"text-xs text-ink-muted",title:t.lastActiveAt||"",children:t.lastActiveAt?g(t.lastActiveAt):"—"}),e.jsx("span",{className:"text-xs text-ink-faint",title:t.createdAt,children:g(t.createdAt)})]},`${t.orgId}/${t.name}`))]})]})}const D=[["orgs","Organisations"],["projects","All Projects"]];function F(){const[l,m]=r.useState(null),[n,c]=r.useState(!1),[o,x]=r.useState(!0),[d,t]=r.useState("orgs"),i=async()=>(await j("/orgs")).ok;r.useEffect(()=>{(async()=>{if(!A()){x(!1);return}const h=await E();h?(m(h.user),c(await i())):y(),x(!1)})()},[]);const a=()=>{y(),m(null)};return o?e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading..."})}):!l||!n?e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"404 — Not found"})}):e.jsxs("div",{className:"min-h-screen bg-surface",children:[e.jsxs("header",{className:"border-b border-border px-6 py-4 flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-5"}),e.jsx("span",{className:"text-ink-faint",children:"/"}),e.jsx("span",{className:"text-sm font-medium text-ink",children:"Internal"})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",children:l.email}),e.jsx("button",{onClick:a,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Sign out"})]})]}),e.jsx("div",{className:"border-b border-border px-6",children:e.jsx("nav",{className:"flex gap-6",children:D.map(([u,h])=>e.jsx("button",{onClick:()=>t(u),className:`py-3 text-sm font-medium border-b-2 transition-colors ${d===u?"border-ink text-ink":"border-transparent text-ink-muted hover:text-ink"}`,children:h},u))})}),e.jsxs("main",{className:"max-w-5xl mx-auto px-6 py-8",children:[d==="orgs"&&e.jsx(I,{}),d==="projects"&&e.jsx(L,{})]})]})}export{F as InternalDashboard};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const n="https://api.ooda.run",c="ooda-access-token",i="ooda-refresh-token";function o(){return localStorage.getItem(c)}function h(){return localStorage.getItem(i)}function f(a,e){localStorage.setItem(c,a),localStorage.setItem(i,e)}function u(){localStorage.removeItem(c),localStorage.removeItem(i)}async function d(){const a=h();if(!a)return!1;const e=await fetch(`${n}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:a})});if(!e.ok)return!1;const t=await e.json();return f(t.accessToken,t.refreshToken),!0}async function l(){const a=o();if(!a)return null;let e=await fetch(`${n}/auth/me`,{headers:{Authorization:`Bearer ${a}`}});if(e.status===401){if(!await d())return null;e=await fetch(`${n}/auth/me`,{headers:{Authorization:`Bearer ${o()}`}})}return e.ok?e.json():null}async function g(a){await fetch(`${n}/auth/forgot-password`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:a})})}async function y(a,e){const t=await fetch(`${n}/auth/reset-password`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:a,password:e})}),r=await t.json();return{ok:t.ok,...r}}async function k(a,e,t){const r=o(),s=new Headers(t==null?void 0:t.headers);return r&&s.set("Authorization",`Bearer ${r}`),s.set("Content-Type","application/json"),fetch(`${n}/org/${a}/admin${e}`,{...t,headers:s})}async function T(a,e){const t=o(),r=new Headers(e==null?void 0:e.headers);return t&&r.set("Authorization",`Bearer ${t}`),r.set("Content-Type","application/json"),fetch(`${n}/int${a}`,{...e,headers:r})}async function $(a,e,t){const r=o(),s=new Headers(t==null?void 0:t.headers);return r&&s.set("Authorization",`Bearer ${r}`),s.set("Content-Type","application/json"),fetch(`${n}/org/${a}/dashboard${e}`,{...t,headers:s})}export{n as A,l as a,k as b,u as c,$ as d,y as e,g as f,o as g,T as i,d as r,f as s};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:"Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-mono:"Geist Mono", ui-monospace, "SFMono-Regular", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-800:oklch(47% .157 37.304);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-800:oklch(44.8% .119 151.328);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-600:oklch(44.6% .03 256.802);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-4xl:56rem;--container-5xl:64rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-normal:0em;--tracking-widest:.1em;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface:#ebf1e5;--color-ink:#272725;--color-ink-muted:#5a5a56;--color-ink-faint:#8a8a84;--color-border:#cdd4c7}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.fixed{position:fixed}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.right-0{right:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.col-span-2{grid-column:span 2/span 2}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-2{height:calc(var(--spacing) * 2)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-12{height:calc(var(--spacing) * 12)}.h-full{height:100%}.max-h-60{max-height:calc(var(--spacing) * 60)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.min-h-screen{min-height:100vh}.w-2{width:calc(var(--spacing) * 2)}.w-24{width:calc(var(--spacing) * 24)}.w-40{width:calc(var(--spacing) * 40)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-\[2\]{flex:2}.flex-shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--color-border)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-border{border-color:var(--color-border)}.border-border\/30{border-color:#cdd4c74d}@supports (color:color-mix(in lab,red,red)){.border-border\/30{border-color:color-mix(in oklab,var(--color-border) 30%,transparent)}}.border-ink{border-color:var(--color-ink)}.border-transparent{border-color:#0000}.bg-border{background-color:var(--color-border)}.bg-border\/50{background-color:#cdd4c780}@supports (color:color-mix(in lab,red,red)){.bg-border\/50{background-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-ink{background-color:var(--color-ink)}.bg-orange-100{background-color:var(--color-orange-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-surface{background-color:var(--color-surface)}.bg-surface\/95{background-color:#ebf1e5f2}@supports (color:color-mix(in lab,red,red)){.bg-surface\/95{background-color:color-mix(in oklab,var(--color-surface) 95%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-yellow-500{background-color:var(--color-yellow-500)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-20{padding-top:calc(var(--spacing) * 20)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-600{color:var(--color-amber-600)}.text-blue-600{color:var(--color-blue-600)}.text-gray-600{color:var(--color-gray-600)}.text-green-400{color:var(--color-green-400)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-green-800{color:var(--color-green-800)}.text-ink{color:var(--color-ink)}.text-ink-faint{color:var(--color-ink-faint)}.text-ink-muted{color:var(--color-ink-muted)}.text-orange-800{color:var(--color-orange-800)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-800{color:var(--color-red-800)}.text-surface{color:var(--color-surface)}.text-surface\/60{color:#ebf1e599}@supports (color:color-mix(in lab,red,red)){.text-surface\/60{color:color-mix(in oklab,var(--color-surface) 60%,transparent)}}.text-yellow-800{color:var(--color-yellow-800)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.placeholder\:text-ink-faint::placeholder{color:var(--color-ink-faint)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media(hover:hover){.hover\:border-border:hover{border-color:var(--color-border)}.hover\:border-ink:hover{border-color:var(--color-ink)}.hover\:border-ink-faint:hover{border-color:var(--color-ink-faint)}.hover\:bg-border:hover{background-color:var(--color-border)}.hover\:bg-border\/30:hover{background-color:#cdd4c74d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-border\/30:hover{background-color:color-mix(in oklab,var(--color-border) 30%,transparent)}}.hover\:bg-green-100:hover{background-color:var(--color-green-100)}.hover\:bg-ink\/80:hover{background-color:#272725cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-ink\/80:hover{background-color:color-mix(in oklab,var(--color-ink) 80%,transparent)}}.hover\:text-amber-800:hover{color:var(--color-amber-800)}.hover\:text-ink:hover{color:var(--color-ink)}.hover\:text-ink\/70:hover{color:#272725b3}@supports (color:color-mix(in lab,red,red)){.hover\:text-ink\/70:hover{color:color-mix(in oklab,var(--color-ink) 70%,transparent)}}.hover\:text-red-700:hover{color:var(--color-red-700)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-ink:focus{border-color:var(--color-ink)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-ink:focus{--tw-ring-color:var(--color-ink)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{background-color:var(--color-gray-50)}.disabled\:text-ink-muted:disabled{color:var(--color-ink-muted)}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@keyframes pulse{50%{opacity:.5}}
|