@wopr-network/platform-ui-core 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,21 @@
1
1
  {
2
2
  "name": "@wopr-network/platform-ui-core",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Brand-agnostic AI agent platform UI — deploy as any brand via env vars",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/wopr-network/platform-ui-core.git"
8
8
  },
9
9
  "license": "UNLICENSED",
10
+ "exports": {
11
+ ".": "./src/lib/index.ts",
12
+ "./app/*": "./src/app/*",
13
+ "./components/*": "./src/components/*",
14
+ "./hooks/*": "./src/hooks/*",
15
+ "./lib/*": "./src/lib/*",
16
+ "./globals.css": "./src/app/globals.css",
17
+ "./proxy": "./src/proxy.ts"
18
+ },
10
19
  "publishConfig": {
11
20
  "registry": "https://registry.npmjs.org",
12
21
  "access": "public"
@@ -20,8 +29,7 @@
20
29
  "tailwind.config.ts",
21
30
  "biome.json",
22
31
  "vitest.config.ts",
23
- ".env.wopr",
24
- ".env.paperclip"
32
+ ".env.wopr"
25
33
  ],
26
34
  "dependencies": {
27
35
  "@hookform/resolvers": "^5.2.2",
@@ -67,11 +67,9 @@ import {
67
67
  renameInstance,
68
68
  restoreSnapshot,
69
69
  toggleInstancePlugin,
70
- updateInstanceBudget,
71
70
  updateInstanceConfig,
72
71
  updateInstanceSecrets,
73
72
  } from "@/lib/api";
74
- import { getBrandConfig } from "@/lib/brand-config";
75
73
  import { toUserMessage } from "@/lib/errors";
76
74
  import { cn } from "@/lib/utils";
77
75
 
@@ -118,10 +116,6 @@ export function InstanceDetailClient({ instanceId }: { instanceId: string }) {
118
116
  const [renaming, setRenaming] = useState(false);
119
117
  const [renameValue, setRenameValue] = useState("");
120
118
  const [renameSaving, setRenameSaving] = useState(false);
121
- const [budgetCents, setBudgetCents] = useState<number>(0);
122
- const [budgetSaving, setBudgetSaving] = useState(false);
123
- const [budgetError, setBudgetError] = useState<string | null>(null);
124
-
125
119
  useEffect(() => {
126
120
  if (!configText.trim()) return;
127
121
  try {
@@ -193,7 +187,6 @@ export function InstanceDetailClient({ instanceId }: { instanceId: string }) {
193
187
  const data = await getInstance(instanceId);
194
188
  setInstance(data);
195
189
  setConfigText(JSON.stringify(data.config, null, 2));
196
- if (data.budgetCents !== undefined) setBudgetCents(data.budgetCents);
197
190
  } catch (err) {
198
191
  setError(toUserMessage(err, "Failed to load instance"));
199
192
  } finally {
@@ -306,19 +299,6 @@ export function InstanceDetailClient({ instanceId }: { instanceId: string }) {
306
299
  }
307
300
  }
308
301
 
309
- async function handleSaveBudget() {
310
- setBudgetSaving(true);
311
- setBudgetError(null);
312
- try {
313
- await updateInstanceBudget(instanceId, budgetCents);
314
- await load();
315
- } catch (err) {
316
- setBudgetError(toUserMessage(err, "Failed to update budget"));
317
- } finally {
318
- setBudgetSaving(false);
319
- }
320
- }
321
-
322
302
  async function handleCreateSnapshot() {
323
303
  setSnapshotsError(null);
324
304
  setCreating(true);
@@ -496,16 +476,6 @@ export function InstanceDetailClient({ instanceId }: { instanceId: string }) {
496
476
  </Badge>
497
477
  )}
498
478
  <span>{instance.provider}</span>
499
- {instance.subdomain && (
500
- <a
501
- href={`https://${instance.subdomain}.${getBrandConfig().domain}`}
502
- target="_blank"
503
- rel="noopener noreferrer"
504
- className="font-mono text-xs text-terminal hover:underline"
505
- >
506
- {instance.subdomain}.{getBrandConfig().domain}
507
- </a>
508
- )}
509
479
  </div>
510
480
  </div>
511
481
  <div className="flex gap-2">
@@ -599,48 +569,6 @@ export function InstanceDetailClient({ instanceId }: { instanceId: string }) {
599
569
  <MetricCard title="Active Sessions" value={String(instance.sessions.length)} />
600
570
  <MetricCard title="Created" value={new Date(instance.createdAt).toLocaleDateString()} />
601
571
  </div>
602
-
603
- {/* Budget management — shown when backend provides budget data */}
604
- {instance.budgetCents !== undefined && (
605
- <Card className="mt-4">
606
- <CardHeader className="pb-3">
607
- <CardTitle className="text-sm font-medium">Spending Budget</CardTitle>
608
- </CardHeader>
609
- <CardContent className="space-y-4">
610
- <div className="flex items-center justify-between">
611
- <span className="text-2xl font-bold font-mono">
612
- ${(budgetCents / 100).toFixed(2)}
613
- </span>
614
- <span className="text-xs text-muted-foreground">per month</span>
615
- </div>
616
- <input
617
- type="range"
618
- min={0}
619
- max={10000}
620
- step={100}
621
- value={budgetCents}
622
- onChange={(e) => setBudgetCents(Number(e.target.value))}
623
- className="w-full accent-terminal"
624
- aria-label="Budget slider"
625
- />
626
- <div className="flex items-center justify-between text-xs text-muted-foreground">
627
- <span>$0</span>
628
- <span>$100</span>
629
- </div>
630
- {budgetError && <p className="text-sm text-destructive">{budgetError}</p>}
631
- <div className="flex justify-end">
632
- <Button
633
- size="sm"
634
- variant="terminal"
635
- onClick={handleSaveBudget}
636
- disabled={budgetSaving || budgetCents === instance.budgetCents}
637
- >
638
- {budgetSaving ? "Saving..." : "Update Budget"}
639
- </Button>
640
- </div>
641
- </CardContent>
642
- </Card>
643
- )}
644
572
  </TabsContent>
645
573
 
646
574
  {/* Health Tab */}
@@ -25,7 +25,7 @@ const panelVariants = {
25
25
  opacity: 1,
26
26
  y: 0,
27
27
  scale: 1,
28
- transition: { type: "spring", damping: 25, stiffness: 300 },
28
+ transition: { type: "spring" as const, damping: 25, stiffness: 300 },
29
29
  },
30
30
  exit: { opacity: 0, y: 20, scale: 0.95, transition: { duration: 0.15 } },
31
31
  };
package/src/lib/api.ts CHANGED
@@ -61,8 +61,6 @@ export interface Instance {
61
61
  plugins: PluginInfo[];
62
62
  uptime: number | null;
63
63
  createdAt: string;
64
- subdomain?: string;
65
- nodeId?: string;
66
64
  }
67
65
 
68
66
  export interface PluginInfo {
@@ -95,8 +93,6 @@ export interface InstanceDetail extends Instance {
95
93
  memoryMb: number;
96
94
  cpuPercent: number;
97
95
  };
98
- budgetCents?: number;
99
- perAgentCents?: number;
100
96
  }
101
97
 
102
98
  // --- API client ---
@@ -323,7 +319,6 @@ export async function getInstance(id: string): Promise<InstanceDetail> {
323
319
  id,
324
320
  })) as BotStatusResponse;
325
321
  const uptimeMs = bot.uptime ? new Date(bot.uptime).getTime() : NaN;
326
- const extra = bot as Record<string, unknown>;
327
322
  return {
328
323
  id: bot.id,
329
324
  name: bot.name,
@@ -333,8 +328,6 @@ export async function getInstance(id: string): Promise<InstanceDetail> {
333
328
  plugins: parsePluginsFromEnv(bot.env as Record<string, string> | undefined),
334
329
  uptime: Number.isNaN(uptimeMs) ? null : Math.floor((Date.now() - uptimeMs) / 1000),
335
330
  createdAt: (bot.createdAt as string | undefined) ?? new Date().toISOString(),
336
- subdomain: (extra.subdomain as string | undefined) ?? undefined,
337
- nodeId: (extra.nodeId as string | undefined) ?? undefined,
338
331
  config: bot.env ?? {},
339
332
  channelDetails: [],
340
333
  sessions: [],
@@ -342,8 +335,6 @@ export async function getInstance(id: string): Promise<InstanceDetail> {
342
335
  memoryMb: bot.stats?.memoryUsageMb ?? 0,
343
336
  cpuPercent: bot.stats?.cpuPercent ?? 0,
344
337
  },
345
- budgetCents: typeof extra.budgetCents === "number" ? extra.budgetCents : undefined,
346
- perAgentCents: typeof extra.perAgentCents === "number" ? extra.perAgentCents : undefined,
347
338
  };
348
339
  }
349
340
 
@@ -471,18 +462,6 @@ export async function updateInstanceConfig(id: string, env: Record<string, strin
471
462
  });
472
463
  }
473
464
 
474
- /** PUT /api/provision/budget — Update instance spending budget. */
475
- export async function updateInstanceBudget(
476
- id: string,
477
- budgetCents: number,
478
- perAgentCents?: number,
479
- ): Promise<void> {
480
- await apiFetch("/provision/budget", {
481
- method: "PUT",
482
- body: JSON.stringify({ instanceId: id, budgetCents, perAgentCents }),
483
- });
484
- }
485
-
486
465
  /** PATCH /fleet/bots/:id — Rename a bot instance. */
487
466
  export async function renameInstance(id: string, name: string): Promise<void> {
488
467
  await fleetFetch(`/bots/${id}`, {
package/.env.paperclip DELETED
@@ -1,18 +0,0 @@
1
- # Paperclip Brand Configuration
2
- # Copy to .env.local to deploy as Paperclip
3
- NEXT_PUBLIC_BRAND_PRODUCT_NAME="Paperclip"
4
- NEXT_PUBLIC_BRAND_NAME="Paperclip"
5
- NEXT_PUBLIC_BRAND_DOMAIN="runpaperclip.com"
6
- NEXT_PUBLIC_BRAND_APP_DOMAIN="app.runpaperclip.com"
7
- NEXT_PUBLIC_BRAND_TAGLINE="AI agents that run your business."
8
- NEXT_PUBLIC_BRAND_EMAIL_PRIVACY="privacy@runpaperclip.com"
9
- NEXT_PUBLIC_BRAND_EMAIL_LEGAL="legal@runpaperclip.com"
10
- NEXT_PUBLIC_BRAND_EMAIL_SUPPORT="support@runpaperclip.com"
11
- NEXT_PUBLIC_BRAND_DEFAULT_IMAGE="ghcr.io/wopr-network/wopr:latest"
12
- NEXT_PUBLIC_BRAND_STORAGE_PREFIX="paperclip"
13
- NEXT_PUBLIC_BRAND_EVENT_PREFIX="paperclip"
14
- NEXT_PUBLIC_BRAND_ENV_PREFIX="PAPERCLIP"
15
- NEXT_PUBLIC_BRAND_TOOL_PREFIX="paperclip"
16
- NEXT_PUBLIC_BRAND_TENANT_COOKIE="paperclip_tenant_id"
17
- NEXT_PUBLIC_BRAND_COMPANY_LEGAL="Paperclip AI Inc."
18
- NEXT_PUBLIC_BRAND_PRICE="$5/month"