@agimon-ai/po-template-elegant 0.0.0-alpha.2 → 0.0.0-alpha.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.
@@ -1,13 +1,13 @@
1
1
  import { defineWebPlugin, defineWebTemplate } from "@agimon-ai/po-core/web";
2
- import { DEFAULT_REPOSITORY_SETTINGS_SECTION, DEFAULT_SETTINGS_SECTION, DashboardRendererProvider, HOST_SLOTS, findTransientTab, pluginActivityGroups, refreshWebPluginCompositions, sessionsStore, setDockOpen, settingsSection, transientTabsStore, uiStore, updateWorkspaceAdmission, useActiveSession, useActiveSessionMeta, useDashboardRoute, useDashboardState, useNoSessions, usePluginSlotProps, useSessionMcp, useWebPluginRegistry, watchDashboardTranscript, webTabs, workspaceAdmissionStore, workspacesStore } from "@agimon-ai/po-web-dashboard";
3
- import { ActivityDock, AppearanceSettings, CommandPalette, Composer, ContributedSettings, DialogOverlay, ImageSettings, NotificationSettings, PairingApprovalDialog, PluginSettings, PluginSurface, ProviderSettings, RefusedCard, RemoteAccessDialog, RemoteControlSettings, RepositoryWorkspace, SelectionBar, SessionActivity, SessionMcp, SessionRailDialogs, SessionTranscriptView, SettingsMenu, SettingsPanelHost, ThreadView, Timeline, TopBar, WelcomePanel, useSessionRail } from "@agimon-ai/po-web-dashboard/views";
2
+ import { DEFAULT_REPOSITORY_SETTINGS_SECTION, DEFAULT_SETTINGS_SECTION, DashboardRendererProvider, HOST_SLOTS, admitDashboardWorkspace, answerLogin, cancelLogin, createPlainSession, findTransientTab, hasSessionProtocol, listDirectory, listPoFolders, listProviders, pluginActivityGroups, readLogin, refreshWebPluginCompositions, sessionsStore, setDockOpen, settingsSection, startLogin, submitComposerDraft, transientTabsStore, uiStore, updateComposerState, updateWorkspaceAdmission, useActiveSession, useActiveSessionMeta, useDashboardRoute, useDashboardState, useNoSessions, usePluginSlotProps, useSessionMcp, useWebPluginRegistry, watchDashboardTranscript, webTabs, workspaceAdmissionStore, workspacesStore } from "@agimon-ai/po-web-dashboard";
3
+ import { ActivityDock, AppearanceSettings, CommandPalette, Composer, ContributedSettings, DialogOverlay, ImageSettings, LoginFlowDialog, NotificationSettings, PairingApprovalDialog, PluginSettings, PluginSurface, ProviderSettings, RefusedCard, RemoteAccessDialog, RemoteControlSettings, RepositoryWorkspace, SelectionBar, SessionActivity, SessionMcp, SessionRailDialogs, SessionTranscriptView, SettingsMenu, SettingsPanelHost, ThreadView, Timeline, TopBar, WelcomePanel, useSessionRail } from "@agimon-ai/po-web-dashboard/views";
4
4
  import { useStore } from "@tanstack/react-store";
5
- import { useEffect, useRef, useState } from "react";
6
- import { ActivityIcon, AlertIcon, Avatar, AvatarFallback, AvatarImage, BranchIcon, Button, ChevronUpIcon, CloseIcon, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Dot, Drawer, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, FolderIcon, ForkIcon, GearIcon, Input, Kbd, KebabIcon, LoaderIcon, NavTab, OptionRow, PlusIcon, ShieldIcon, cn } from "@agimon-ai/po-web-components";
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
+ import { ActivityIcon, AlertIcon, ArrowRightIcon, Avatar, AvatarFallback, AvatarImage, BranchIcon, Button, Checkbox, ChevronUpIcon, CloseIcon, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Dot, Drawer, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, FolderIcon, ForkIcon, GearIcon, Input, Kbd, KebabIcon, LoaderIcon, LockIcon, NavTab, OptionRow, PlusIcon, RadioGroup, RadioGroupItem, SendIcon, ShieldIcon, Skeleton, Textarea, cn } from "@agimon-ai/po-web-components";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Link, useNavigate } from "@tanstack/react-router";
9
9
  //#region src/extensions/(frontend)/template/_components/ElegantFolderBrowser.tsx
10
- function folderName$1(path) {
10
+ function folderName$2(path) {
11
11
  return path.slice(path.lastIndexOf("/") + 1) || path;
12
12
  }
13
13
  /** Walks the server's folders inline: up, into a child, or pick the current folder. */
@@ -31,7 +31,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
31
31
  }, [target, listDirectory]);
32
32
  return /* @__PURE__ */ jsxs("div", {
33
33
  "data-testid": "folder-browser",
34
- className: "flex flex-col gap-1 rounded-lg border border-doom-border-soft bg-doom-panel/40 p-1.5",
34
+ className: "flex flex-col gap-1 rounded-lg border border-po-border-soft bg-po-panel/40 p-1.5",
35
35
  children: [
36
36
  /* @__PURE__ */ jsxs("div", {
37
37
  className: "flex items-center gap-1 px-1",
@@ -47,7 +47,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
47
47
  children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-3 w-3" })
48
48
  }),
49
49
  /* @__PURE__ */ jsx("span", {
50
- className: "min-w-0 flex-1 truncate text-sm text-doom-dim",
50
+ className: "min-w-0 flex-1 truncate text-sm text-po-dim",
51
51
  title: listing?.path,
52
52
  children: listing?.path ?? "loading…"
53
53
  }),
@@ -62,7 +62,7 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
62
62
  ]
63
63
  }),
64
64
  error ? /* @__PURE__ */ jsx("p", {
65
- className: "px-2 py-1 text-sm text-doom-red",
65
+ className: "px-2 py-1 text-sm text-po-red",
66
66
  children: error
67
67
  }) : null,
68
68
  /* @__PURE__ */ jsxs("div", {
@@ -70,14 +70,14 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
70
70
  "aria-label": "folders",
71
71
  className: "max-h-40 overflow-y-auto",
72
72
  children: [listing !== null && listing.directories.length === 0 ? /* @__PURE__ */ jsx("p", {
73
- className: "px-2 py-1 text-sm text-doom-dim",
73
+ className: "px-2 py-1 text-sm text-po-dim",
74
74
  children: "no folders here"
75
75
  }) : null, listing?.directories.map((directory) => /* @__PURE__ */ jsx(OptionRow, {
76
76
  density: "compact",
77
77
  "data-testid": "folder-browser-entry",
78
78
  onClick: () => setTarget(directory),
79
79
  className: "w-full px-2.5 py-1 ",
80
- children: folderName$1(directory)
80
+ children: folderName$2(directory)
81
81
  }, directory))]
82
82
  })
83
83
  ]
@@ -87,9 +87,9 @@ function ElegantFolderBrowser({ start, listDirectory, onSelect }) {
87
87
  //#region src/extensions/(frontend)/template/_components/ElegantAddWorkspaceDialog.tsx
88
88
  const SUGGESTION_DEBOUNCE_MS = 120;
89
89
  const NO_HIGHLIGHT = -1;
90
- const TRAILING_SEPARATORS = /\/+$/u;
91
- function folderName(path) {
92
- const trimmed = path.trim().replace(TRAILING_SEPARATORS, "");
90
+ const TRAILING_SEPARATORS$1 = /\/+$/u;
91
+ function folderName$1(path) {
92
+ const trimmed = path.trim().replace(TRAILING_SEPARATORS$1, "");
93
93
  return trimmed.slice(trimmed.lastIndexOf("/") + 1);
94
94
  }
95
95
  /** Adds a workspace by name, by folder, or both; a name alone gets a new default folder. */
@@ -104,7 +104,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
104
104
  const [suggestions, setSuggestions] = useState([]);
105
105
  const [highlight, setHighlight] = useState(NO_HIGHLIGHT);
106
106
  const pathInput = useRef(null);
107
- const shownName = nameEdited ? name : folderName(path);
107
+ const shownName = nameEdited ? name : folderName$1(path);
108
108
  useEffect(() => {
109
109
  const typed = path.trim();
110
110
  if (typed === "") return;
@@ -128,7 +128,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
128
128
  changePath(`${directory}/`);
129
129
  pathInput.current?.focus();
130
130
  };
131
- const trimmedPath = path.trim().replace(TRAILING_SEPARATORS, "") || (path.trim() === "" ? "" : "/");
131
+ const trimmedPath = path.trim().replace(TRAILING_SEPARATORS$1, "") || (path.trim() === "" ? "" : "/");
132
132
  const canSubmit = !busy && (trimmedPath !== "" || shownName.trim() !== "");
133
133
  const submit = async () => {
134
134
  if (!canSubmit) return;
@@ -149,7 +149,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
149
149
  htmlFor: "add-workspace-name",
150
150
  className: "flex flex-col gap-1",
151
151
  children: [/* @__PURE__ */ jsx("span", {
152
- className: "text-base font-medium text-doom-dim",
152
+ className: "text-base font-medium text-po-dim",
153
153
  children: "name"
154
154
  }), /* @__PURE__ */ jsx(Input, {
155
155
  id: "add-workspace-name",
@@ -170,9 +170,9 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
170
170
  htmlFor: "add-workspace-root",
171
171
  className: "flex flex-col gap-1",
172
172
  children: [/* @__PURE__ */ jsxs("span", {
173
- className: "text-base font-medium text-doom-dim",
173
+ className: "text-base font-medium text-po-dim",
174
174
  children: ["folder ", /* @__PURE__ */ jsx("span", {
175
- className: "text-doom-dim",
175
+ className: "text-po-dim",
176
176
  children: "(optional; type a path or browse)"
177
177
  })]
178
178
  }), /* @__PURE__ */ jsxs("span", {
@@ -219,7 +219,7 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
219
219
  role: "listbox",
220
220
  "aria-label": "matching directories",
221
221
  "data-testid": "add-workspace-suggestions",
222
- className: "max-h-40 overflow-y-auto rounded-lg border border-doom-border-soft bg-doom-panel/40 p-1.5",
222
+ className: "max-h-40 overflow-y-auto rounded-lg border border-po-border-soft bg-po-panel/40 p-1.5",
223
223
  children: suggestions.map((directory, index) => /* @__PURE__ */ jsx(OptionRow, {
224
224
  density: "compact",
225
225
  active: index === highlight,
@@ -242,11 +242,11 @@ function ElegantAddWorkspaceDialog({ suggestedPaths, actions }) {
242
242
  }) : null,
243
243
  trimmedPath === "" && shownName.trim() !== "" ? /* @__PURE__ */ jsxs("p", {
244
244
  "data-testid": "add-workspace-default-hint",
245
- className: "text-sm text-doom-dim",
245
+ className: "text-sm text-po-dim",
246
246
  children: ["creates ~/.po/workspace/", shownName.trim()]
247
247
  }) : null,
248
248
  error ? /* @__PURE__ */ jsx("pre", {
249
- className: "max-h-28 overflow-y-auto rounded border border-doom-edge-red bg-doom-tint-red/40 px-2.5 py-2 text-sm whitespace-pre-wrap text-doom-red",
249
+ className: "max-h-28 overflow-y-auto rounded border border-po-edge-red bg-po-tint-red/40 px-2.5 py-2 text-sm whitespace-pre-wrap text-po-red",
250
250
  children: error
251
251
  }) : null,
252
252
  /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
@@ -286,12 +286,12 @@ function ElegantPendingSetup({ sessionId, setup, actions }) {
286
286
  };
287
287
  return /* @__PURE__ */ jsxs("div", {
288
288
  "data-testid": `pending-session-${setup.id}`,
289
- className: "ml-9 flex flex-col gap-0.5 rounded-lg border border-dashed border-doom-border-soft px-3 py-2",
289
+ className: "ml-9 flex flex-col gap-0.5 rounded-lg border border-dashed border-po-border-soft px-3 py-2",
290
290
  children: [
291
291
  /* @__PURE__ */ jsxs("div", {
292
292
  className: "flex items-center justify-between gap-2",
293
293
  children: [/* @__PURE__ */ jsx("span", {
294
- className: "truncate text-base font-semibold text-doom-hi",
294
+ className: "truncate text-base font-semibold text-po-hi",
295
295
  children: setup.name
296
296
  }), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
297
297
  asChild: true,
@@ -310,17 +310,17 @@ function ElegantPendingSetup({ sessionId, setup, actions }) {
310
310
  }) })] })]
311
311
  }),
312
312
  /* @__PURE__ */ jsx("p", {
313
- className: setup.failed ? "text-sm text-doom-red" : "text-sm text-doom-dim",
313
+ className: setup.failed ? "text-sm text-po-red" : "text-sm text-po-dim",
314
314
  children: setup.status
315
315
  }),
316
316
  setup.recovery ? /* @__PURE__ */ jsx("p", {
317
317
  role: setup.failed ? "alert" : void 0,
318
- className: "text-sm text-doom-dim",
318
+ className: "text-sm text-po-dim",
319
319
  children: setup.recovery
320
320
  }) : null,
321
321
  error ? /* @__PURE__ */ jsx("p", {
322
322
  role: "alert",
323
- className: "text-sm text-doom-red",
323
+ className: "text-sm text-po-red",
324
324
  children: error
325
325
  }) : null
326
326
  ]
@@ -342,7 +342,7 @@ function ElegantSessionCard({ session, actions }) {
342
342
  };
343
343
  const { active } = session;
344
344
  const error = removeError || session.error;
345
- const tileClass = active ? "rounded-lg border border-doom-edge-green bg-doom-tint-green px-3 hover:bg-doom-tint-green" : "rounded-lg border border-transparent px-3 hover:bg-doom-panel";
345
+ const tileClass = active ? "rounded-lg border border-po-edge-green bg-po-tint-green px-3 hover:bg-po-tint-green" : "rounded-lg border border-transparent px-3 hover:bg-po-panel";
346
346
  const failed = session.status.startsWith("failed") || session.status.includes(" failed");
347
347
  const running = session.status.startsWith("running");
348
348
  const commitRename = () => {
@@ -370,7 +370,7 @@ function ElegantSessionCard({ session, actions }) {
370
370
  src: session.profile.avatarUrl,
371
371
  alt: ""
372
372
  }) : null, /* @__PURE__ */ jsx(AvatarFallback, {
373
- className: "bg-doom-tint-green text-xs font-semibold text-doom-green",
373
+ className: "bg-po-tint-green text-xs font-semibold text-po-green",
374
374
  children: session.profile?.initials ?? "PO"
375
375
  })]
376
376
  }), /* @__PURE__ */ jsxs("span", {
@@ -380,27 +380,27 @@ function ElegantSessionCard({ session, actions }) {
380
380
  children: [
381
381
  session.nested && session.provenance === "workflow-session" ? /* @__PURE__ */ jsx(ActivityIcon, {
382
382
  "aria-label": "workflow session",
383
- className: `mt-1 size-3 shrink-0 ${active ? "text-doom-green" : "text-doom-faint"}`
383
+ className: `mt-1 size-3 shrink-0 ${active ? "text-po-green" : "text-po-faint"}`
384
384
  }) : session.nested && session.provenance ? /* @__PURE__ */ jsx(ForkIcon, {
385
385
  "aria-label": session.provenance === "worktree" ? "automatic per-conversation worktree" : session.provenance,
386
- className: `mt-1 size-3 shrink-0 ${active ? "text-doom-green" : "text-doom-faint"}`
386
+ className: `mt-1 size-3 shrink-0 ${active ? "text-po-green" : "text-po-faint"}`
387
387
  }) : null,
388
388
  /* @__PURE__ */ jsx("span", {
389
- className: "min-w-0 flex-1 text-base font-semibold break-words text-doom-hi",
389
+ className: "min-w-0 flex-1 text-base font-semibold break-words text-po-hi",
390
390
  children: session.name || "Untitled"
391
391
  }),
392
392
  session.ordinal <= 9 ? /* @__PURE__ */ jsx("span", {
393
393
  title: `press ${String(session.ordinal)} to focus`,
394
- className: "grid size-5 shrink-0 place-items-center rounded-full bg-doom-panel text-2xs text-doom-dim transition-opacity group-focus-within:opacity-0 group-hover:opacity-0",
394
+ className: "grid size-5 shrink-0 place-items-center rounded-full bg-po-panel text-2xs text-po-dim transition-opacity group-focus-within:opacity-0 group-hover:opacity-0",
395
395
  children: session.ordinal
396
396
  }) : null
397
397
  ]
398
398
  }), /* @__PURE__ */ jsxs("span", {
399
- className: `flex min-w-0 items-start gap-1.5 text-sm leading-snug ${failed ? "text-doom-red" : running ? "text-doom-yellow" : active ? "text-doom-text" : "text-doom-dim"}`,
399
+ className: `flex min-w-0 items-start gap-1.5 text-sm leading-snug ${failed ? "text-po-red" : running ? "text-po-yellow" : active ? "text-po-text" : "text-po-dim"}`,
400
400
  children: [session.awaitingInput ? /* @__PURE__ */ jsx(AlertIcon, {
401
401
  "data-testid": "session-awaiting-input",
402
402
  "aria-label": "Waiting for your input",
403
- className: "mt-0.5 size-3 shrink-0 text-doom-magenta"
403
+ className: "mt-0.5 size-3 shrink-0 text-po-magenta"
404
404
  }) : running ? /* @__PURE__ */ jsx(LoaderIcon, {
405
405
  "aria-hidden": true,
406
406
  className: "mt-0.5 size-3 shrink-0 animate-spin"
@@ -417,22 +417,22 @@ function ElegantSessionCard({ session, actions }) {
417
417
  }),
418
418
  session.git ? /* @__PURE__ */ jsxs("span", {
419
419
  "data-testid": "session-branch",
420
- className: "flex min-w-0 items-center gap-1.5 pl-10.5 text-sm text-doom-dim",
420
+ className: "flex min-w-0 items-center gap-1.5 pl-10.5 text-sm text-po-dim",
421
421
  children: [
422
- /* @__PURE__ */ jsx(BranchIcon, { className: `size-3 shrink-0 ${active ? "text-doom-green" : ""}` }),
422
+ /* @__PURE__ */ jsx(BranchIcon, { className: `size-3 shrink-0 ${active ? "text-po-green" : ""}` }),
423
423
  /* @__PURE__ */ jsx("span", {
424
424
  className: "truncate font-mono",
425
425
  children: session.git.branch
426
426
  }),
427
427
  session.git.dirty ? /* @__PURE__ */ jsx("span", {
428
- className: "shrink-0 text-doom-yellow",
428
+ className: "shrink-0 text-po-yellow",
429
429
  children: "modified"
430
430
  }) : null
431
431
  ]
432
432
  }) : null,
433
433
  error ? /* @__PURE__ */ jsx("span", {
434
434
  "data-testid": "session-error",
435
- className: "line-clamp-3 text-sm break-words text-doom-red",
435
+ className: "line-clamp-3 text-sm break-words text-po-red",
436
436
  children: error
437
437
  }) : null
438
438
  ] });
@@ -466,7 +466,7 @@ function ElegantSessionCard({ session, actions }) {
466
466
  size: "icon",
467
467
  "data-testid": `session-menu-${session.id}`,
468
468
  title: "session actions",
469
- className: "text-doom-dim hover:text-doom-hi",
469
+ className: "text-po-dim hover:text-po-hi",
470
470
  children: /* @__PURE__ */ jsx(KebabIcon, { className: "h-3 w-3" })
471
471
  })
472
472
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
@@ -552,7 +552,7 @@ function ElegantSessionCard({ session, actions }) {
552
552
  children: [/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: "remove session" }) }), /* @__PURE__ */ jsxs(DialogBody, { children: [/* @__PURE__ */ jsxs(DialogDescription, { children: [
553
553
  "this stops ",
554
554
  /* @__PURE__ */ jsx("span", {
555
- className: "font-semibold text-doom-hi",
555
+ className: "font-semibold text-po-hi",
556
556
  children: session.name || "untitled"
557
557
  }),
558
558
  " and removes it from the list. anything it is running ends now, but its saved history remains available to resume."
@@ -603,19 +603,19 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
603
603
  className: "flex flex-col gap-1.5",
604
604
  children: [
605
605
  /* @__PURE__ */ jsxs("div", {
606
- className: "flex min-w-0 items-start gap-2.5 rounded-md px-2 py-1 transition-colors hover:bg-doom-panel/60",
606
+ className: "flex min-w-0 items-start gap-2.5 rounded-md px-2 py-1 transition-colors hover:bg-po-panel/60",
607
607
  children: [
608
608
  /* @__PURE__ */ jsx(FolderIcon, {
609
609
  "aria-hidden": true,
610
- className: "mt-0.5 size-4 shrink-0 text-doom-dim"
610
+ className: "mt-0.5 size-4 shrink-0 text-po-dim"
611
611
  }),
612
612
  /* @__PURE__ */ jsxs("div", {
613
613
  className: "flex min-w-0 flex-1 flex-col",
614
614
  children: [/* @__PURE__ */ jsx("p", {
615
- className: "truncate text-base font-semibold text-doom-hi",
615
+ className: "truncate text-base font-semibold text-po-hi",
616
616
  children: name
617
617
  }), /* @__PURE__ */ jsx("p", {
618
- className: "truncate font-mono text-sm text-doom-dim",
618
+ className: "truncate font-mono text-sm text-po-dim",
619
619
  title: root,
620
620
  children: root
621
621
  })]
@@ -630,7 +630,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
630
630
  "aria-label": `New session in ${name}`,
631
631
  disabled: !available,
632
632
  onClick: () => actions.createSession(id),
633
- className: "text-doom-faint hover:text-doom-hi",
633
+ className: "text-po-faint hover:text-po-hi",
634
634
  children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
635
635
  }), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
636
636
  asChild: true,
@@ -640,7 +640,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
640
640
  "data-testid": `workspace-menu-${id}`,
641
641
  title: "Workspace actions",
642
642
  "aria-label": `${name} actions`,
643
- className: "text-doom-faint hover:text-doom-hi",
643
+ className: "text-po-faint hover:text-po-hi",
644
644
  children: /* @__PURE__ */ jsx(KebabIcon, { className: "size-3.5" })
645
645
  })
646
646
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
@@ -668,7 +668,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
668
668
  ]
669
669
  }),
670
670
  !available ? /* @__PURE__ */ jsx("p", {
671
- className: "px-9 text-sm text-doom-red",
671
+ className: "px-9 text-sm text-po-red",
672
672
  children: "Workspace unavailable"
673
673
  }) : null,
674
674
  workspace.sessions.length > 0 ? /* @__PURE__ */ jsx("div", {
@@ -678,7 +678,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
678
678
  actions
679
679
  }, session.id))
680
680
  }) : available ? /* @__PURE__ */ jsx("p", {
681
- className: "px-9 pb-1 text-sm text-doom-dim",
681
+ className: "px-9 pb-1 text-sm text-po-dim",
682
682
  children: "No sessions yet. Start or resume one."
683
683
  }) : null,
684
684
  /* @__PURE__ */ jsx(Dialog, {
@@ -692,7 +692,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
692
692
  /* @__PURE__ */ jsxs(DialogDescription, { children: [
693
693
  "this unregisters ",
694
694
  /* @__PURE__ */ jsx("span", {
695
- className: "font-semibold text-doom-hi",
695
+ className: "font-semibold text-po-hi",
696
696
  children: name
697
697
  }),
698
698
  " from Po only. files at",
@@ -702,7 +702,7 @@ function ElegantWorkspaceGroup({ workspace, actions }) {
702
702
  ] }),
703
703
  removeError ? /* @__PURE__ */ jsx("p", {
704
704
  "data-testid": `workspace-delete-error-${id}`,
705
- className: "text-sm text-doom-red",
705
+ className: "text-sm text-po-red",
706
706
  children: removeError
707
707
  }) : null,
708
708
  /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
@@ -748,7 +748,7 @@ function ElegantRail({ rail, onClose }) {
748
748
  className: "size-9 rounded-lg"
749
749
  }), /* @__PURE__ */ jsx("span", {
750
750
  "aria-hidden": "true",
751
- className: "text-2xl font-semibold text-doom-hi",
751
+ className: "text-2xl font-semibold text-po-hi",
752
752
  children: "Po"
753
753
  })]
754
754
  }), /* @__PURE__ */ jsxs("span", {
@@ -759,7 +759,7 @@ function ElegantRail({ rail, onClose }) {
759
759
  "data-testid": "remote-access-open",
760
760
  "aria-label": `Remote access is ${remote.status}`,
761
761
  onClick: actions.openRemoteAccess,
762
- className: `gap-1.5 rounded-md ${remote.status === "failed" ? "" : "bg-doom-panel"}`,
762
+ className: `gap-1.5 rounded-md ${remote.status === "failed" ? "" : "bg-po-panel"}`,
763
763
  children: [live ? /* @__PURE__ */ jsx(Dot, {
764
764
  tone: "yellow",
765
765
  pulse: true,
@@ -772,7 +772,7 @@ function ElegantRail({ rail, onClose }) {
772
772
  title: "Hide sessions",
773
773
  "aria-label": "Hide sessions",
774
774
  onClick: onClose,
775
- className: "text-doom-dim",
775
+ className: "text-po-dim",
776
776
  children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-3.5" })
777
777
  })]
778
778
  })]
@@ -780,7 +780,7 @@ function ElegantRail({ rail, onClose }) {
780
780
  /* @__PURE__ */ jsxs("div", {
781
781
  className: "flex items-center justify-between px-5 pt-3 pb-2",
782
782
  children: [/* @__PURE__ */ jsx("h2", {
783
- className: "text-lg font-semibold text-doom-hi",
783
+ className: "text-lg font-semibold text-po-hi",
784
784
  children: "Workspaces"
785
785
  }), /* @__PURE__ */ jsx(Button, {
786
786
  variant: "ghost",
@@ -789,7 +789,7 @@ function ElegantRail({ rail, onClose }) {
789
789
  title: "Add workspace",
790
790
  "aria-label": "Add workspace",
791
791
  onClick: actions.openAddWorkspace,
792
- className: "text-doom-faint hover:text-doom-hi",
792
+ className: "text-po-faint hover:text-po-hi",
793
793
  children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
794
794
  })]
795
795
  }),
@@ -799,16 +799,16 @@ function ElegantRail({ rail, onClose }) {
799
799
  workspace,
800
800
  actions
801
801
  }, workspace.id)), rail.workspaces.length === 0 ? /* @__PURE__ */ jsxs("div", {
802
- className: "flex flex-col gap-3 rounded-lg border border-dashed border-doom-border px-4 py-5",
802
+ className: "flex flex-col gap-3 rounded-lg border border-dashed border-po-border px-4 py-5",
803
803
  children: [/* @__PURE__ */ jsx("p", {
804
- className: "text-sm text-doom-dim",
804
+ className: "text-sm text-po-dim",
805
805
  children: "Add a folder to start working with Po."
806
806
  }), /* @__PURE__ */ jsxs(Button, {
807
807
  variant: "outline",
808
808
  size: "md",
809
809
  "data-testid": "add-workspace-empty",
810
810
  onClick: actions.openAddWorkspace,
811
- className: "justify-start gap-2 bg-doom-panel",
811
+ className: "justify-start gap-2 bg-po-panel",
812
812
  children: [/* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" }), "Add workspace"]
813
813
  })]
814
814
  }) : null]
@@ -816,10 +816,10 @@ function ElegantRail({ rail, onClose }) {
816
816
  rail.pluginContent,
817
817
  /* @__PURE__ */ jsx("div", { className: "flex-1" }),
818
818
  /* @__PURE__ */ jsxs("div", {
819
- className: "sticky bottom-0 mt-auto shrink-0 bg-doom-rail",
819
+ className: "sticky bottom-0 mt-auto shrink-0 bg-po-rail",
820
820
  children: [remote.status === "off" ? null : /* @__PURE__ */ jsxs("div", {
821
821
  "data-testid": "remote-banner",
822
- className: `flex items-center gap-2 border-t border-doom-border-soft px-4 py-2 text-sm ${remote.status === "failed" ? "bg-doom-tint-red text-doom-red" : "bg-doom-tint-yellow text-doom-yellow"}`,
822
+ className: `flex items-center gap-2 border-t border-po-border-soft px-4 py-2 text-sm ${remote.status === "failed" ? "bg-po-tint-red text-po-red" : "bg-po-tint-yellow text-po-yellow"}`,
823
823
  children: [
824
824
  /* @__PURE__ */ jsx(Dot, { tone: remote.status === "failed" ? "red" : "yellow" }),
825
825
  /* @__PURE__ */ jsx("span", {
@@ -842,24 +842,24 @@ function ElegantRail({ rail, onClose }) {
842
842
  })
843
843
  ]
844
844
  }), /* @__PURE__ */ jsxs("div", {
845
- className: "flex flex-col gap-1 border-t border-doom-border-soft px-3 py-3",
845
+ className: "flex flex-col gap-1 border-t border-po-border-soft px-3 py-3",
846
846
  children: [/* @__PURE__ */ jsxs(Button, {
847
847
  variant: "ghost",
848
848
  size: "md",
849
849
  "data-testid": "settings-open",
850
850
  onClick: actions.openSettings,
851
- className: "justify-start gap-2.5 px-2 text-doom-text",
852
- children: [/* @__PURE__ */ jsx(GearIcon, { className: "size-4 text-doom-dim" }), "Settings"]
851
+ className: "justify-start gap-2.5 px-2 text-po-text",
852
+ children: [/* @__PURE__ */ jsx(GearIcon, { className: "size-4 text-po-dim" }), "Settings"]
853
853
  }), /* @__PURE__ */ jsxs("span", {
854
- className: "px-2 text-sm text-doom-dim max-sm:hidden",
854
+ className: "px-2 text-sm text-po-dim max-sm:hidden",
855
855
  children: [
856
856
  /* @__PURE__ */ jsx(Kbd, {
857
- className: "bg-doom-panel",
857
+ className: "bg-po-panel",
858
858
  children: "ctrl+k"
859
859
  }),
860
860
  " commands · ",
861
861
  /* @__PURE__ */ jsx(Kbd, {
862
- className: "bg-doom-panel",
862
+ className: "bg-po-panel",
863
863
  children: "ctrl+t"
864
864
  }),
865
865
  " new session"
@@ -876,7 +876,7 @@ function ElegantRail({ rail, onClose }) {
876
876
  function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen, onNavigationOpenChange, onMobileActivityOpenChange }) {
877
877
  const conversation = view === "conversation" || view === "welcome";
878
878
  return /* @__PURE__ */ jsxs("div", {
879
- className: "relative flex h-full min-w-0 flex-col overflow-hidden bg-doom-bg",
879
+ className: "relative flex h-full min-w-0 flex-col overflow-hidden bg-po-bg",
880
880
  children: [
881
881
  /* @__PURE__ */ jsx(Drawer, {
882
882
  open: navigationOpen,
@@ -886,7 +886,7 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
886
886
  showHeader: false,
887
887
  "data-testid": "session-rail-panel",
888
888
  backdropTestId: "mobile-drawer-backdrop",
889
- className: "w-[min(340px,calc(100vw-48px))] border-doom-border-soft",
889
+ className: "w-[min(340px,calc(100vw-48px))] border-po-border-soft",
890
890
  children: /* @__PURE__ */ jsx(ElegantRail, {
891
891
  rail,
892
892
  onClose: () => onNavigationOpenChange(false)
@@ -909,10 +909,10 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
909
909
  children: slots.composer
910
910
  }),
911
911
  slots.controls == null ? null : /* @__PURE__ */ jsxs("details", {
912
- className: "shrink-0 px-3 pb-3 text-sm text-doom-dim",
912
+ className: "shrink-0 px-3 pb-3 text-sm text-po-dim",
913
913
  children: [/* @__PURE__ */ jsx("summary", {
914
914
  "data-testid": "template-controls-toggle",
915
- className: "cursor-pointer rounded-sm px-1 py-1 focus-visible:outline focus-visible:outline-doom-blue",
915
+ className: "cursor-pointer rounded-sm px-1 py-1 focus-visible:outline focus-visible:outline-po-blue",
916
916
  children: "Session controls"
917
917
  }), slots.controls]
918
918
  })
@@ -937,6 +937,576 @@ function ElegantLayout({ view, slots, rail, navigationOpen, mobileActivityOpen,
937
937
  });
938
938
  }
939
939
  //#endregion
940
+ //#region src/extensions/(frontend)/template/_components/ElegantOnboarding.tsx
941
+ function StepFrame({ step, pending, children, testId }) {
942
+ return /* @__PURE__ */ jsx("div", {
943
+ "data-testid": testId,
944
+ className: "flex min-h-0 flex-1 items-center justify-center overflow-y-auto px-4 py-10",
945
+ children: /* @__PURE__ */ jsxs("section", {
946
+ className: "flex w-full max-w-xl flex-col gap-6",
947
+ children: [children, pending.length > 1 ? /* @__PURE__ */ jsx("ol", {
948
+ "aria-label": "Setup steps",
949
+ className: "flex justify-center gap-2",
950
+ children: pending.map((entry) => /* @__PURE__ */ jsx("li", {
951
+ "aria-current": entry === step ? "step" : void 0,
952
+ className: `size-1.5 rounded-full ${entry === step ? "bg-po-selected" : "bg-po-border-soft"}`
953
+ }, entry))
954
+ }) : null]
955
+ })
956
+ });
957
+ }
958
+ function Heading({ title, description }) {
959
+ return /* @__PURE__ */ jsxs("header", {
960
+ className: "flex flex-col gap-1.5 text-center",
961
+ children: [/* @__PURE__ */ jsx("h1", {
962
+ className: "text-xl font-semibold text-po-hi",
963
+ children: title
964
+ }), /* @__PURE__ */ jsx("p", {
965
+ className: "text-base text-po-dim",
966
+ children: description
967
+ })]
968
+ });
969
+ }
970
+ function ErrorLine({ error }) {
971
+ return error ? /* @__PURE__ */ jsx("p", {
972
+ role: "alert",
973
+ className: "text-sm text-po-red",
974
+ children: error
975
+ }) : null;
976
+ }
977
+ const STEP_COUNT_WORDS = [
978
+ "",
979
+ "One quick step",
980
+ "Two quick steps"
981
+ ];
982
+ /** The first thing a new person sees, only while a setup step is still missing. */
983
+ function ElegantOnboardingWelcome({ pending, onBegin }) {
984
+ return /* @__PURE__ */ jsx(StepFrame, {
985
+ pending: [],
986
+ testId: "onboarding-welcome",
987
+ children: /* @__PURE__ */ jsxs("div", {
988
+ className: "flex flex-col items-center gap-5 py-4 text-center",
989
+ children: [
990
+ /* @__PURE__ */ jsxs("span", {
991
+ className: "flex items-center gap-2.5",
992
+ "aria-label": "Po",
993
+ children: [/* @__PURE__ */ jsx("img", {
994
+ src: "/favicon.svg",
995
+ alt: "",
996
+ "aria-hidden": "true",
997
+ className: "size-10 rounded-lg"
998
+ }), /* @__PURE__ */ jsx("span", {
999
+ "aria-hidden": "true",
1000
+ className: "text-2xl font-semibold text-po-hi",
1001
+ children: "Po"
1002
+ })]
1003
+ }),
1004
+ /* @__PURE__ */ jsxs("div", {
1005
+ className: "flex flex-col gap-1.5",
1006
+ children: [/* @__PURE__ */ jsx("h1", {
1007
+ className: "text-2xl font-semibold text-po-hi",
1008
+ children: "Hi, I'm Po. I'll handle the busywork."
1009
+ }), /* @__PURE__ */ jsxs("p", {
1010
+ className: "text-base text-po-dim",
1011
+ children: [STEP_COUNT_WORDS[pending.length] ?? `${pending.length} quick steps`, " and you can hand me your first task."]
1012
+ })]
1013
+ }),
1014
+ /* @__PURE__ */ jsxs(Button, {
1015
+ variant: "primary",
1016
+ size: "lg",
1017
+ "data-testid": "onboarding-begin",
1018
+ onClick: onBegin,
1019
+ className: "px-6",
1020
+ children: ["Let's begin", /* @__PURE__ */ jsx(ArrowRightIcon, { className: "size-3.5" })]
1021
+ })
1022
+ ]
1023
+ })
1024
+ });
1025
+ }
1026
+ /** Choose and sign in to the provider that runs the models. */
1027
+ function ElegantOnboardingModel({ pending, providers, selectedId, busy, error, onSelect, onConnect, onShowAll }) {
1028
+ return /* @__PURE__ */ jsxs(StepFrame, {
1029
+ step: "model",
1030
+ pending,
1031
+ testId: "onboarding-model",
1032
+ children: [
1033
+ /* @__PURE__ */ jsx(Heading, {
1034
+ title: "Choose who does the thinking",
1035
+ description: "You can connect more providers later in settings."
1036
+ }),
1037
+ /* @__PURE__ */ jsx(RadioGroup, {
1038
+ "aria-label": "Model provider",
1039
+ value: selectedId ?? "",
1040
+ onValueChange: onSelect,
1041
+ className: "flex flex-col gap-2",
1042
+ children: providers.map((provider) => /* @__PURE__ */ jsxs("label", {
1043
+ htmlFor: `onboarding-provider-${provider.id}`,
1044
+ "data-testid": `onboarding-provider-${provider.id}`,
1045
+ className: `flex cursor-pointer items-center gap-3 rounded-lg border px-4 py-3 transition-colors ${provider.id === selectedId ? "border-po-selected bg-po-selected/5" : "border-po-border-soft hover:border-po-green/50"}`,
1046
+ children: [/* @__PURE__ */ jsxs("span", {
1047
+ className: "flex min-w-0 flex-1 flex-col",
1048
+ children: [/* @__PURE__ */ jsx("span", {
1049
+ className: "text-base font-semibold text-po-hi",
1050
+ children: provider.name
1051
+ }), /* @__PURE__ */ jsx("span", {
1052
+ className: "text-sm text-po-dim",
1053
+ children: provider.note
1054
+ })]
1055
+ }), /* @__PURE__ */ jsx(RadioGroupItem, {
1056
+ id: `onboarding-provider-${provider.id}`,
1057
+ value: provider.id
1058
+ })]
1059
+ }, provider.id))
1060
+ }),
1061
+ /* @__PURE__ */ jsx(Button, {
1062
+ variant: "ghost",
1063
+ size: "sm",
1064
+ onClick: onShowAll,
1065
+ className: "self-start",
1066
+ children: "Show every provider"
1067
+ }),
1068
+ /* @__PURE__ */ jsx(ErrorLine, { error }),
1069
+ /* @__PURE__ */ jsxs("div", {
1070
+ className: "flex items-center justify-between gap-3",
1071
+ children: [/* @__PURE__ */ jsxs("span", {
1072
+ className: "flex items-center gap-1.5 text-sm text-po-dim",
1073
+ children: [/* @__PURE__ */ jsx(LockIcon, { className: "size-3.5" }), "Your keys stay on this machine."]
1074
+ }), /* @__PURE__ */ jsx(Button, {
1075
+ variant: "primary",
1076
+ size: "lg",
1077
+ "data-testid": "onboarding-connect",
1078
+ disabled: selectedId === null || busy,
1079
+ onClick: onConnect,
1080
+ children: busy ? "Connecting…" : "Connect"
1081
+ })]
1082
+ })
1083
+ ]
1084
+ });
1085
+ }
1086
+ function addLabel(count) {
1087
+ if (count === 0) return "Add workspace";
1088
+ return count === 1 ? "Add 1 workspace" : `Add ${count} workspaces`;
1089
+ }
1090
+ /** Admit folders Po found, a new named workspace, or a browsed folder. */
1091
+ function ElegantOnboardingWorkspace({ pending, scanning, found, name, busy, error, browser, onToggle, onNameChange, onBrowse, onAdd }) {
1092
+ const count = found.filter((folder) => folder.checked).length + (name.trim() === "" ? 0 : 1);
1093
+ const showFound = scanning || found.length > 0;
1094
+ return /* @__PURE__ */ jsxs(StepFrame, {
1095
+ step: "workspace",
1096
+ pending,
1097
+ testId: "onboarding-workspace",
1098
+ children: [
1099
+ /* @__PURE__ */ jsx(Heading, {
1100
+ title: "Where should I work?",
1101
+ description: found.length > 0 ? "I found these folders with Po settings on this machine." : "Name a new workspace, or pick a folder you already have."
1102
+ }),
1103
+ showFound ? /* @__PURE__ */ jsxs("div", {
1104
+ className: "flex flex-col rounded-lg border border-po-border-soft",
1105
+ children: [/* @__PURE__ */ jsx("span", {
1106
+ className: "border-b border-po-border-soft px-4 py-2 text-sm text-po-dim",
1107
+ children: scanning ? "Looking for folders with Po settings…" : "Found on this machine"
1108
+ }), scanning ? /* @__PURE__ */ jsxs("output", {
1109
+ "aria-busy": true,
1110
+ className: "flex flex-col gap-3 px-4 py-3",
1111
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-44" })]
1112
+ }) : /* @__PURE__ */ jsx("ul", {
1113
+ "data-testid": "onboarding-found",
1114
+ children: found.map((folder) => /* @__PURE__ */ jsx("li", {
1115
+ className: "border-b border-po-border-soft last:border-b-0",
1116
+ children: /* @__PURE__ */ jsxs("label", {
1117
+ className: "flex cursor-pointer items-center gap-3 px-4 py-2.5",
1118
+ children: [/* @__PURE__ */ jsx("span", {
1119
+ className: "min-w-0 flex-1 truncate font-mono text-sm text-po-text",
1120
+ children: folder.path
1121
+ }), /* @__PURE__ */ jsx(Checkbox, {
1122
+ "aria-label": `Add ${folder.path}`,
1123
+ checked: folder.checked,
1124
+ onCheckedChange: (checked) => onToggle(folder.path, checked === true)
1125
+ })]
1126
+ })
1127
+ }, folder.path))
1128
+ })]
1129
+ }) : null,
1130
+ showFound ? /* @__PURE__ */ jsxs("div", {
1131
+ className: "flex items-center gap-3 text-sm text-po-dim",
1132
+ children: [
1133
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-po-border-soft" }),
1134
+ "or",
1135
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-po-border-soft" })
1136
+ ]
1137
+ }) : null,
1138
+ /* @__PURE__ */ jsxs("label", {
1139
+ htmlFor: "onboarding-workspace-name",
1140
+ className: "flex flex-col gap-1.5",
1141
+ children: [
1142
+ /* @__PURE__ */ jsx("span", {
1143
+ className: "text-base font-medium text-po-text",
1144
+ children: "Name a new workspace"
1145
+ }),
1146
+ /* @__PURE__ */ jsxs("span", {
1147
+ className: "flex items-center gap-2",
1148
+ children: [/* @__PURE__ */ jsx(Input, {
1149
+ id: "onboarding-workspace-name",
1150
+ "data-testid": "onboarding-workspace-name",
1151
+ value: name,
1152
+ placeholder: "Notes",
1153
+ onChange: (event) => onNameChange(event.target.value),
1154
+ className: "min-w-0 flex-1"
1155
+ }), /* @__PURE__ */ jsx(Button, {
1156
+ variant: "outline",
1157
+ size: "md",
1158
+ "data-testid": "onboarding-browse",
1159
+ onClick: onBrowse,
1160
+ children: "Browse folders"
1161
+ })]
1162
+ }),
1163
+ /* @__PURE__ */ jsxs("span", {
1164
+ className: "font-mono text-sm text-po-dim",
1165
+ children: ["~/.po/workspace/", name.trim() || "Notes"]
1166
+ })
1167
+ ]
1168
+ }),
1169
+ browser,
1170
+ /* @__PURE__ */ jsx(ErrorLine, { error }),
1171
+ /* @__PURE__ */ jsx(Button, {
1172
+ variant: "primary",
1173
+ size: "lg",
1174
+ "data-testid": "onboarding-add-workspaces",
1175
+ disabled: count === 0 || busy,
1176
+ onClick: onAdd,
1177
+ className: "self-end",
1178
+ children: busy ? "Adding…" : addLabel(count)
1179
+ })
1180
+ ]
1181
+ });
1182
+ }
1183
+ /** Setup is done and nothing has started yet: the first task goes straight into a new session. */
1184
+ function ElegantOnboardingReady({ model, root, draft, busy, error, suggestions, onDraftChange, onSend }) {
1185
+ return /* @__PURE__ */ jsxs(StepFrame, {
1186
+ pending: [],
1187
+ testId: "welcome",
1188
+ children: [
1189
+ /* @__PURE__ */ jsxs("header", {
1190
+ className: "flex flex-col gap-1.5",
1191
+ children: [/* @__PURE__ */ jsx("h1", {
1192
+ className: "text-2xl font-semibold text-po-hi",
1193
+ children: "Ready when you are."
1194
+ }), /* @__PURE__ */ jsxs("p", {
1195
+ className: "text-base text-po-dim",
1196
+ children: [
1197
+ "Po is connected to ",
1198
+ model,
1199
+ " and working in ",
1200
+ /* @__PURE__ */ jsx("span", {
1201
+ className: "font-mono text-po-text",
1202
+ children: root
1203
+ }),
1204
+ "."
1205
+ ]
1206
+ })]
1207
+ }),
1208
+ /* @__PURE__ */ jsxs("div", {
1209
+ className: "flex flex-col gap-2 rounded-lg border border-po-border bg-po-bg p-3 focus-within:border-po-green/60",
1210
+ children: [/* @__PURE__ */ jsx(Textarea, {
1211
+ "data-testid": "onboarding-first-task",
1212
+ "aria-label": "Your first task",
1213
+ value: draft,
1214
+ placeholder: "Tell Po what you'd like done…",
1215
+ onChange: (event) => onDraftChange(event.target.value),
1216
+ onKeyDown: (event) => {
1217
+ if (event.key === "Enter" && !event.shiftKey && draft.trim() !== "") {
1218
+ event.preventDefault();
1219
+ onSend();
1220
+ }
1221
+ },
1222
+ className: "min-h-20 resize-none border-0 bg-transparent p-1 text-lg focus-visible:ring-0"
1223
+ }), /* @__PURE__ */ jsx(Button, {
1224
+ variant: "primary",
1225
+ size: "icon-md",
1226
+ "aria-label": "Start this task",
1227
+ "data-testid": "onboarding-send",
1228
+ disabled: draft.trim() === "" || busy,
1229
+ onClick: onSend,
1230
+ className: "self-end",
1231
+ children: /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
1232
+ })]
1233
+ }),
1234
+ /* @__PURE__ */ jsx("div", {
1235
+ className: "grid gap-2 sm:grid-cols-3",
1236
+ children: suggestions.map((suggestion) => /* @__PURE__ */ jsx(Button, {
1237
+ variant: "outline",
1238
+ size: "card",
1239
+ onClick: () => onDraftChange(suggestion),
1240
+ children: /* @__PURE__ */ jsx("span", {
1241
+ className: "text-base text-po-text",
1242
+ children: suggestion
1243
+ })
1244
+ }, suggestion))
1245
+ }),
1246
+ /* @__PURE__ */ jsx(ErrorLine, { error }),
1247
+ /* @__PURE__ */ jsxs("span", {
1248
+ className: "flex flex-wrap items-center justify-end gap-1.5 border-t border-po-border-soft pt-4 text-sm text-po-dim",
1249
+ children: [
1250
+ /* @__PURE__ */ jsx(Kbd, { children: "ctrl+t" }),
1251
+ " new session · ",
1252
+ /* @__PURE__ */ jsx(Kbd, { children: "ctrl+k" }),
1253
+ " commands"
1254
+ ]
1255
+ })
1256
+ ]
1257
+ });
1258
+ }
1259
+ //#endregion
1260
+ //#region src/extensions/(frontend)/template/_components/ElegantOnboardingFlow.tsx
1261
+ /** Shown first, in this order; every other provider waits behind "Show every provider". */
1262
+ const FEATURED_PROVIDERS = [
1263
+ "anthropic",
1264
+ "openai-codex",
1265
+ "github-copilot",
1266
+ "google",
1267
+ "openrouter"
1268
+ ];
1269
+ const SUGGESTIONS = [
1270
+ "Tour this codebase for me",
1271
+ "Find and fix failing tests",
1272
+ "Draft a README update"
1273
+ ];
1274
+ const FLOW_POLL_MS = 500;
1275
+ const ATTACH_TIMEOUT_MS = 3e4;
1276
+ const TRAILING_SEPARATORS = /\/+$/u;
1277
+ function folderName(path) {
1278
+ const trimmed = path.trim().replace(TRAILING_SEPARATORS, "");
1279
+ return trimmed.slice(trimmed.lastIndexOf("/") + 1);
1280
+ }
1281
+ /**
1282
+ * Sends the session's composer draft once the session is attached and its protocol is bound,
1283
+ * which only happens after the session page takes focus. Sends once, never retries, so an
1284
+ * unacknowledged send cannot repeat. A session that never gets ready keeps the text in its
1285
+ * composer for the person to send.
1286
+ */
1287
+ function submitWhenReady(sessionId) {
1288
+ const started = Date.now();
1289
+ const timer = setInterval(() => {
1290
+ const ready = sessionsStore.state.byId[sessionId]?.attach === "attached" && hasSessionProtocol(sessionId);
1291
+ if (!ready && Date.now() - started < ATTACH_TIMEOUT_MS) return;
1292
+ clearInterval(timer);
1293
+ if (ready) submitComposerDraft(sessionId, "submit");
1294
+ }, FLOW_POLL_MS);
1295
+ }
1296
+ function ModelStep({ pending, models, onConnected }) {
1297
+ const [showAll, setShowAll] = useState(false);
1298
+ const signable = models.filter((provider) => provider.methods.length > 0);
1299
+ const featured = FEATURED_PROVIDERS.flatMap((id) => signable.filter((provider) => provider.id === id));
1300
+ const shown = showAll || featured.length === 0 ? signable : featured;
1301
+ const [selectedId, setSelectedId] = useState(shown[0]?.id ?? null);
1302
+ const [flow, setFlow] = useState(null);
1303
+ const [starting, setStarting] = useState(false);
1304
+ const [error, setError] = useState("");
1305
+ const flowId = flow?.id;
1306
+ const running = flow?.status === "running";
1307
+ useEffect(() => {
1308
+ if (flowId === void 0 || !running) return;
1309
+ let stopped = false;
1310
+ let timer;
1311
+ const poll = async () => {
1312
+ const result = await readLogin(flowId);
1313
+ if (stopped) return;
1314
+ if ("error" in result) {
1315
+ setFlow((current) => current?.id === flowId ? {
1316
+ ...current,
1317
+ status: "failed",
1318
+ error: result.error
1319
+ } : current);
1320
+ return;
1321
+ }
1322
+ setFlow(result.flow);
1323
+ if (result.flow.status === "succeeded") onConnected();
1324
+ else if (result.flow.status === "running") timer = setTimeout(() => void poll(), FLOW_POLL_MS);
1325
+ };
1326
+ timer = setTimeout(() => void poll(), FLOW_POLL_MS);
1327
+ return () => {
1328
+ stopped = true;
1329
+ if (timer !== void 0) clearTimeout(timer);
1330
+ };
1331
+ }, [
1332
+ flowId,
1333
+ running,
1334
+ onConnected
1335
+ ]);
1336
+ const connect = async () => {
1337
+ const provider = signable.find((candidate) => candidate.id === selectedId);
1338
+ const method = provider?.methods.find((candidate) => candidate.type === "oauth") ?? provider?.methods[0];
1339
+ if (provider === void 0 || method === void 0 || starting || running) return;
1340
+ setError("");
1341
+ setStarting(true);
1342
+ const result = await startLogin(provider.id, method.type);
1343
+ setStarting(false);
1344
+ if ("flow" in result) setFlow(result.flow);
1345
+ else setError(result.error);
1346
+ };
1347
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ElegantOnboardingModel, {
1348
+ pending,
1349
+ providers: shown.map((provider) => ({
1350
+ id: provider.id,
1351
+ name: provider.name,
1352
+ note: provider.methods.map((method) => method.label).join(" or ")
1353
+ })),
1354
+ selectedId,
1355
+ busy: starting || running,
1356
+ ...error === "" ? {} : { error },
1357
+ onSelect: setSelectedId,
1358
+ onConnect: () => void connect(),
1359
+ onShowAll: () => setShowAll(true)
1360
+ }), flow ? /* @__PURE__ */ jsx(LoginFlowDialog, {
1361
+ flow,
1362
+ onAnswer: (promptId, value) => void answerLogin(flow.id, promptId, value).then((result) => {
1363
+ if ("flow" in result) setFlow(result.flow);
1364
+ else setError(result.error);
1365
+ }),
1366
+ onCancel: () => void cancelLogin(flow.id).then((result) => setFlow("flow" in result ? result.flow : null)),
1367
+ onClose: () => {
1368
+ if (flow.status === "failed") setError(flow.error ?? "The sign-in did not finish. Try again whenever you like.");
1369
+ setFlow(null);
1370
+ }
1371
+ }) : null] });
1372
+ }
1373
+ function WorkspaceStep({ pending }) {
1374
+ const [scanning, setScanning] = useState(true);
1375
+ const [found, setFound] = useState([]);
1376
+ const [name, setName] = useState("");
1377
+ const [browsing, setBrowsing] = useState(false);
1378
+ const [error, setError] = useState("");
1379
+ const busy = useStore(workspaceAdmissionStore, (state) => state.pending);
1380
+ useEffect(() => {
1381
+ let stale = false;
1382
+ listPoFolders().then((paths) => {
1383
+ if (stale) return;
1384
+ setFound(paths.map((path, index) => ({
1385
+ path,
1386
+ checked: index === 0
1387
+ })));
1388
+ setScanning(false);
1389
+ });
1390
+ return () => {
1391
+ stale = true;
1392
+ };
1393
+ }, []);
1394
+ const pick = (path) => {
1395
+ setFound((current) => current.some((folder) => folder.path === path) ? current.map((folder) => folder.path === path ? {
1396
+ ...folder,
1397
+ checked: true
1398
+ } : folder) : [...current, {
1399
+ path,
1400
+ checked: true
1401
+ }]);
1402
+ setBrowsing(false);
1403
+ };
1404
+ const add = async () => {
1405
+ setError("");
1406
+ const admissions = [...found.filter((folder) => folder.checked).map((folder) => ({
1407
+ name: folderName(folder.path),
1408
+ path: folder.path
1409
+ })), ...name.trim() === "" ? [] : [{ name: name.trim() }]];
1410
+ for (const admission of admissions) {
1411
+ const result = await admitDashboardWorkspace(admission);
1412
+ if (result !== void 0) {
1413
+ setError(result.error);
1414
+ return;
1415
+ }
1416
+ }
1417
+ };
1418
+ return /* @__PURE__ */ jsx(ElegantOnboardingWorkspace, {
1419
+ pending,
1420
+ scanning,
1421
+ found,
1422
+ name,
1423
+ busy,
1424
+ ...error === "" ? {} : { error },
1425
+ ...browsing ? { browser: /* @__PURE__ */ jsx(ElegantFolderBrowser, {
1426
+ listDirectory,
1427
+ onSelect: pick
1428
+ }) } : {},
1429
+ onToggle: (path, checked) => setFound((current) => current.map((folder) => folder.path === path ? {
1430
+ ...folder,
1431
+ checked
1432
+ } : folder)),
1433
+ onNameChange: setName,
1434
+ onBrowse: () => setBrowsing((open) => !open),
1435
+ onAdd: () => void add()
1436
+ });
1437
+ }
1438
+ function ReadyStep({ model }) {
1439
+ const navigate = useNavigate();
1440
+ const workspace = useStore(workspacesStore, (state) => state.byId[state.selectedId ?? state.order[0] ?? ""]);
1441
+ const [draft, setDraft] = useState("");
1442
+ const [busy, setBusy] = useState(false);
1443
+ const [error, setError] = useState("");
1444
+ if (workspace === void 0) return null;
1445
+ const send = async () => {
1446
+ const text = draft.trim();
1447
+ if (text === "" || busy) return;
1448
+ setError("");
1449
+ setBusy(true);
1450
+ const outcome = await createPlainSession(workspace.id);
1451
+ if (!("sessionId" in outcome)) {
1452
+ setBusy(false);
1453
+ setError(outcome.error);
1454
+ return;
1455
+ }
1456
+ updateComposerState(outcome.sessionId, (state) => ({
1457
+ ...state,
1458
+ draft: text,
1459
+ caret: text.length
1460
+ }));
1461
+ submitWhenReady(outcome.sessionId);
1462
+ await navigate({
1463
+ to: "/session/$sessionId",
1464
+ params: { sessionId: outcome.sessionId }
1465
+ });
1466
+ };
1467
+ return /* @__PURE__ */ jsx(ElegantOnboardingReady, {
1468
+ model,
1469
+ root: workspace.root,
1470
+ draft,
1471
+ busy,
1472
+ ...error === "" ? {} : { error },
1473
+ suggestions: SUGGESTIONS,
1474
+ onDraftChange: setDraft,
1475
+ onSend: () => void send()
1476
+ });
1477
+ }
1478
+ /**
1479
+ * First run in place of the empty welcome: only the setup steps still missing, then the
1480
+ * first task. Finished steps are read from the hub, so nothing new is persisted.
1481
+ */
1482
+ function ElegantOnboardingFlow() {
1483
+ const updateRequired = useStore(sessionsStore, (state) => state.updateRequired);
1484
+ const hydrated = useStore(workspacesStore, (state) => state.hydrated);
1485
+ const hasWorkspace = useStore(workspacesStore, (state) => state.order.length > 0);
1486
+ const [providers, setProviders] = useState(null);
1487
+ const [steps, setSteps] = useState(null);
1488
+ const reload = useCallback(() => {
1489
+ listProviders().then((result) => setProviders("providers" in result ? result.providers : "unavailable"));
1490
+ }, []);
1491
+ useEffect(reload, [reload]);
1492
+ if (updateRequired) return /* @__PURE__ */ jsx(WelcomePanel, {});
1493
+ if (providers === null || !hydrated) return null;
1494
+ const models = providers === "unavailable" ? [] : providers.filter((provider) => provider.kind !== "po-feature");
1495
+ const connected = models.find((provider) => provider.authenticated !== void 0);
1496
+ const pending = [...providers === "unavailable" || connected !== void 0 ? [] : ["model"], ...hasWorkspace ? [] : ["workspace"]];
1497
+ if (steps === null && pending.length > 0) return /* @__PURE__ */ jsx(ElegantOnboardingWelcome, {
1498
+ pending,
1499
+ onBegin: () => setSteps(pending)
1500
+ });
1501
+ if (pending[0] === "model") return /* @__PURE__ */ jsx(ModelStep, {
1502
+ pending: steps ?? pending,
1503
+ models,
1504
+ onConnected: reload
1505
+ });
1506
+ if (pending[0] === "workspace") return /* @__PURE__ */ jsx(WorkspaceStep, { pending: steps ?? pending });
1507
+ return /* @__PURE__ */ jsx(ReadyStep, { model: connected?.name ?? "your model" });
1508
+ }
1509
+ //#endregion
940
1510
  //#region src/extensions/(frontend)/template/_components/ElegantConversation.tsx
941
1511
  function ElegantConversation() {
942
1512
  useWebPluginRegistry();
@@ -1010,18 +1580,19 @@ function ElegantConversation() {
1010
1580
  }),
1011
1581
  notices: transferLabel === null ? null : /* @__PURE__ */ jsxs("output", {
1012
1582
  "data-testid": "voice-transfer-transition",
1013
- className: "border-b border-doom-cyan/30 bg-doom-cyan/10 px-4 py-2 text-center text-base font-medium text-doom-cyan",
1583
+ className: "border-b border-po-cyan/30 bg-po-cyan/10 px-4 py-2 text-center text-base font-medium text-po-cyan",
1014
1584
  children: [
1015
1585
  "Transferring voice to ",
1016
1586
  transferLabel,
1017
1587
  "..."
1018
1588
  ]
1019
1589
  }),
1020
- content: mcpView ? /* @__PURE__ */ jsx(SessionMcp, { state: mcp }, sessionId) : tab ? /* @__PURE__ */ jsx(tab.panel, { ...slotProps }) : noSessions ? /* @__PURE__ */ jsx(WelcomePanel, {}) : /* @__PURE__ */ jsx(Timeline, {}),
1590
+ content: mcpView ? /* @__PURE__ */ jsx(SessionMcp, { state: mcp }, sessionId) : tab ? /* @__PURE__ */ jsx(tab.panel, { ...slotProps }) : noSessions ? /* @__PURE__ */ jsx(ElegantOnboardingFlow, {}) : /* @__PURE__ */ jsx(Timeline, {}),
1021
1591
  composer: mcpView ? null : tab ? tab.retainComposer === true ? /* @__PURE__ */ jsx(Composer, { composerContext }) : null : noSessions ? null : /* @__PURE__ */ jsx(Composer, {}),
1022
1592
  controls: !mcpView && !tab && !noSessions && dormantMeta === null ? /* @__PURE__ */ jsx(SelectionBar, {}) : null,
1023
1593
  activity: /* @__PURE__ */ jsx(ActivityDock, {
1024
1594
  mcp,
1595
+ tabId,
1025
1596
  onClose: closeActivity,
1026
1597
  onOpenContent: () => setMobileActivityOpen(false)
1027
1598
  })
@@ -1070,21 +1641,21 @@ function ElegantSettings() {
1070
1641
  ]);
1071
1642
  return /* @__PURE__ */ jsxs("div", {
1072
1643
  "data-testid": "settings",
1073
- className: "flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-doom-bg",
1644
+ className: "flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-po-bg",
1074
1645
  children: [/* @__PURE__ */ jsxs("header", {
1075
- className: "grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-2 gap-y-2 border-b border-doom-border px-3 py-2 sm:h-14 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] sm:px-6 sm:py-0",
1646
+ className: "grid shrink-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-2 gap-y-2 border-b border-po-border px-3 py-2 sm:h-14 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] sm:px-6 sm:py-0",
1076
1647
  children: [
1077
1648
  /* @__PURE__ */ jsx("h1", {
1078
- className: "order-1 min-w-0 truncate text-xl font-semibold text-doom-hi sm:order-none",
1649
+ className: "order-1 min-w-0 truncate text-xl font-semibold text-po-hi sm:order-none",
1079
1650
  children: "Settings"
1080
1651
  }),
1081
1652
  /* @__PURE__ */ jsxs("nav", {
1082
- className: "order-3 col-span-2 flex w-full items-center gap-1 rounded-lg bg-doom-panel p-1 sm:order-none sm:col-span-1 sm:w-auto",
1653
+ className: "order-3 col-span-2 flex w-full items-center gap-1 rounded-lg bg-po-panel p-1 sm:order-none sm:col-span-1 sm:w-auto",
1083
1654
  "aria-label": "settings workspace",
1084
1655
  children: [/* @__PURE__ */ jsx(NavTab, {
1085
1656
  asChild: true,
1086
1657
  active: workspace === "general",
1087
- className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-doom-green sm:flex-none",
1658
+ className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-po-green sm:flex-none",
1088
1659
  "aria-current": workspace === "general" ? "true" : void 0,
1089
1660
  children: /* @__PURE__ */ jsx(Link, {
1090
1661
  to: "/settings/$section",
@@ -1096,7 +1667,7 @@ function ElegantSettings() {
1096
1667
  }), /* @__PURE__ */ jsx(NavTab, {
1097
1668
  asChild: true,
1098
1669
  active: workspace === "repository",
1099
- className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-doom-green sm:flex-none",
1670
+ className: "min-h-8 flex-1 justify-center rounded-md px-4 focus-visible:ring-2 focus-visible:ring-po-green sm:flex-none",
1100
1671
  "aria-current": workspace === "repository" ? "true" : void 0,
1101
1672
  children: /* @__PURE__ */ jsx(Link, {
1102
1673
  to: "/settings/$section",