pi-roundtable-web 0.24.2 → 0.26.0
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/CHANGELOG.md +48 -0
- package/README.md +195 -16
- package/dist/account-zk4efb87.css +102 -0
- package/dist/chunk-account-hw49gd0d.js +1 -0
- package/dist/chunk-action-menu-rm5cyqkj.js +1 -0
- package/dist/chunk-agent-b017vswv.js +1 -0
- package/dist/chunk-arranged-rooms-q5v3dm1r.js +1 -0
- package/dist/chunk-character-creator-5dxcvd16.js +1 -0
- package/dist/chunk-codeeditor-pyt09fwg.js +2 -0
- package/dist/chunk-confirm-521yqmta.js +1 -0
- package/dist/chunk-connectors-hrm06nx8.js +1 -0
- package/dist/chunk-conversations-e26rrf01.js +1 -0
- package/dist/chunk-drag-v41gx2mc.js +1 -0
- package/dist/chunk-entry-jxxb3ath.js +1 -0
- package/dist/chunk-folder-list-b97xk12b.js +1 -0
- package/dist/chunk-folds-b8q7eags.js +1 -0
- package/dist/chunk-gate-8k61stsc.js +1 -0
- package/dist/chunk-group-scene-dx6wt19m.js +1 -0
- package/dist/chunk-group-table-e4jr8r3a.js +1 -0
- package/dist/chunk-host-state-g7e7c0k5.js +1 -0
- package/dist/chunk-host-ui-x7k6n07v.js +939 -0
- package/dist/chunk-index-014rjv9k.js +2 -0
- package/dist/chunk-index-2d0kg096.js +2 -0
- package/dist/chunk-index-2qd81wbx.js +2 -0
- package/dist/chunk-index-2stynxw6.css +1 -0
- package/dist/chunk-index-459drsft.js +2 -0
- package/dist/chunk-index-4mfj596y.js +2 -0
- package/dist/chunk-index-66nskrdj.js +47 -0
- package/dist/chunk-index-awx6nnta.js +2 -0
- package/dist/chunk-index-bbsytycb.js +2 -0
- package/dist/chunk-index-c07p8k0x.js +4 -0
- package/dist/chunk-index-cq1e9xdz.js +2 -0
- package/dist/chunk-index-d1prgfbp.js +2 -0
- package/dist/chunk-index-dhpt8qr9.js +2 -0
- package/dist/chunk-index-e5sd30xy.js +2 -0
- package/dist/chunk-index-g351921r.js +1 -0
- package/dist/chunk-index-hby0ap91.js +2 -0
- package/dist/chunk-index-hssjbr1k.js +2 -0
- package/dist/chunk-index-k2qq1gdj.js +2 -0
- package/dist/chunk-index-ke9ynm0n.js +2 -0
- package/dist/chunk-index-km40bhsz.js +2 -0
- package/dist/chunk-index-kpscvg85.js +2 -0
- package/dist/chunk-index-m0d100mg.js +2 -0
- package/dist/chunk-index-mb72snk9.js +2 -0
- package/dist/chunk-index-mjqqver5.js +4 -0
- package/dist/chunk-index-nqfkwkfp.js +2 -0
- package/dist/chunk-index-nwqk447w.js +2 -0
- package/dist/chunk-index-pcfhpm8v.js +302 -0
- package/dist/chunk-index-q8h8xzbm.js +2 -0
- package/dist/chunk-index-r5vszgfs.js +2 -0
- package/dist/{chunk-index-mpm90318.js → chunk-index-rhtvcbsq.js} +2 -2
- package/dist/chunk-index-rjv7vrwd.js +13 -0
- package/dist/chunk-index-v23m38p6.js +50 -0
- package/dist/chunk-index-va0g7d88.js +1 -0
- package/dist/{chunk-index-6t68gbex.js → chunk-index-wnjp6wv0.js} +2 -2
- package/dist/chunk-index-xgkd15n3.js +2 -0
- package/dist/chunk-index-y8rnq8zf.js +14 -0
- package/dist/chunk-index-z3k18atc.js +2 -0
- package/dist/chunk-lang-css-6bepqpnx.js +1 -0
- package/dist/{chunk-lang-dockerfile-ey0nvhhm.js → chunk-lang-dockerfile-hrav55t7.js} +1 -1
- package/dist/{chunk-lang-go-403qsw9f.js → chunk-lang-go-x9ahv6e5.js} +3 -3
- package/dist/chunk-lang-html-8jc72zt4.js +1 -0
- package/dist/chunk-lang-javascript-2p2qtbnf.js +1 -0
- package/dist/chunk-lang-json-hsemyd0r.js +1 -0
- package/dist/chunk-lang-markdown-zkwb4c9n.js +6 -0
- package/dist/{chunk-lang-python-9jk5a49y.js → chunk-lang-python-tewx7006.js} +2 -2
- package/dist/chunk-lang-rust-0ydx84s1.js +1 -0
- package/dist/{chunk-lang-shell-cgq6q0kj.js → chunk-lang-shell-gq1tmdz4.js} +1 -1
- package/dist/chunk-lang-sql-xt1qyycg.js +2 -0
- package/dist/{chunk-lang-toml-xh45nm68.js → chunk-lang-toml-0hamc5fc.js} +1 -1
- package/dist/chunk-lang-typescript-82xf7z2e.js +1 -0
- package/dist/{chunk-lang-xml-1mh879j9.js → chunk-lang-xml-wf6h5pt2.js} +1 -1
- package/dist/{chunk-lang-yaml-jac98srt.js → chunk-lang-yaml-7vk521h1.js} +1 -1
- package/dist/chunk-layout-actions-zh7bezk7.js +1 -0
- package/dist/chunk-menu-items-1n9qargb.js +2 -0
- package/dist/chunk-notes-t15bh04m.js +1 -0
- package/dist/chunk-notice-bell-w3y0h0sr.js +1 -0
- package/dist/chunk-notices-fa3g7qze.js +1 -0
- package/dist/chunk-onboarding-34v3nr17.js +1 -0
- package/dist/chunk-overview-km5vq375.js +1 -0
- package/dist/chunk-palette-a8txdgd0.js +1 -0
- package/dist/chunk-placement-items-wgaxsbvs.js +1 -0
- package/dist/chunk-profile-ypxdbsk1.js +1 -0
- package/dist/chunk-prompt-history-wm9dsy6s.js +1 -0
- package/dist/chunk-prompts-7mhhq7zs.js +1 -0
- package/dist/chunk-room-confirms-t11a1gsw.js +1 -0
- package/dist/chunk-room-menu-2tm2xtfx.js +1 -0
- package/dist/chunk-rooms-menu-button-wxnsxjwc.js +1 -0
- package/dist/chunk-schedules-2ft6xxyw.js +1 -0
- package/dist/chunk-seat-menu-d3npdtx1.js +1 -0
- package/dist/chunk-sheet-hosts-vngvp7wv.js +1 -0
- package/dist/chunk-skill-editor-65n2hsq4.js +8 -0
- package/dist/chunk-skills-shkdwes8.js +1 -0
- package/dist/chunk-switcher-list-g6hhmr1t.js +1 -0
- package/dist/chunk-table-1b6bsq2y.js +1 -0
- package/dist/chunk-table-seats-vy1qhdks.js +1 -0
- package/dist/chunk-table2d-n26b7gd0.js +1 -0
- package/dist/chunk-table3d-8aysyf56.js +4220 -0
- package/dist/chunk-transcript-355faceq.js +1 -0
- package/dist/chunk-where-j5qdt8a4.js +1 -0
- package/dist/chunk-workspace-vrbs6zx1.js +1 -0
- package/dist/chunk-zh-tw-zeg600bk.js +1 -0
- package/dist/index.html +1 -1
- package/dist/sw.js +1 -1
- package/package.json +5 -4
- package/src/api-types.ts +515 -6
- package/src/app/api-http.ts +66 -0
- package/src/app/app.ts +214 -33
- package/src/app/card-log.ts +6 -0
- package/src/app/desk.ts +47 -22
- package/src/app/files.ts +73 -7
- package/src/app/layout-routes.ts +239 -0
- package/src/app/layout.ts +133 -0
- package/src/app/presence.ts +2 -2
- package/src/app/prompt-routes.ts +167 -0
- package/src/app/protocol.ts +63 -1
- package/src/app/room-log.ts +148 -14
- package/src/app/rooms.ts +23 -0
- package/src/app/routes.ts +278 -156
- package/src/app/skill-doc-routes.ts +122 -0
- package/src/app/socket.ts +309 -77
- package/src/app/sockets.ts +108 -20
- package/src/app/surface.ts +72 -36
- package/src/app/team-routes.ts +457 -0
- package/src/app/threads.ts +14 -0
- package/src/app/uploads.ts +33 -7
- package/src/auth/authenticator.ts +71 -8
- package/src/auth/next.ts +52 -0
- package/src/auth/oidc-pages.ts +60 -0
- package/src/auth/oidc.ts +611 -0
- package/src/auth/sessions.ts +193 -0
- package/src/authz.ts +172 -0
- package/src/console-api.ts +122 -25
- package/src/console-server.ts +70 -6
- package/src/gate.ts +90 -0
- package/src/host/access.ts +161 -0
- package/src/host/cards.ts +99 -0
- package/src/host/context.ts +141 -0
- package/src/host/forms.ts +237 -0
- package/src/host/frames.ts +342 -0
- package/src/host/host-app.ts +176 -0
- package/src/host/host-context.ts +49 -0
- package/src/host/host-routes.ts +363 -0
- package/src/host/pages.ts +266 -0
- package/src/host/reads.ts +155 -0
- package/src/host/retention.ts +41 -0
- package/src/host/room-views.ts +137 -0
- package/src/host/rooms-service.ts +414 -0
- package/src/host/stored-json.ts +13 -0
- package/src/host/views.ts +103 -0
- package/src/i18n/zh-tw.ts +309 -10
- package/src/layout-order.ts +210 -0
- package/src/notices/api.ts +43 -0
- package/src/notices/mount.ts +292 -0
- package/src/notices/service.ts +294 -0
- package/src/notices/store.ts +298 -0
- package/src/notices/urls.ts +38 -0
- package/src/onboarding/api.ts +32 -0
- package/src/onboarding/service.ts +149 -0
- package/src/onboarding/steps.ts +75 -0
- package/src/onboarding/waivers.ts +40 -0
- package/src/options.ts +498 -34
- package/src/profile/api.ts +175 -0
- package/src/profile/links.ts +162 -0
- package/src/push/api.ts +189 -52
- package/src/push/dispatch.ts +156 -0
- package/src/push/drain.ts +139 -0
- package/src/push/mutes.ts +17 -0
- package/src/push/outbox.ts +218 -0
- package/src/push/prefs.ts +118 -0
- package/src/push/sender.ts +7 -2
- package/src/push/triggers.ts +56 -5
- package/src/push/vapid.ts +19 -0
- package/src/push/web-push-transport.ts +106 -0
- package/src/push-sender/index.ts +14 -0
- package/src/push-sender/run.ts +118 -0
- package/src/push-sender/session.ts +54 -0
- package/src/visitors.ts +94 -6
- package/src/web-app.ts +674 -0
- package/src/web-plugin.ts +293 -26
- package/dist/chunk-action-menu-7v5fce2v.js +0 -1
- package/dist/chunk-agent-2rw4ydw2.js +0 -1
- package/dist/chunk-agent-sheet-2q24dkkf.js +0 -3
- package/dist/chunk-character-creator-8q6ympxj.js +0 -1
- package/dist/chunk-codeeditor-fgmq298t.js +0 -2
- package/dist/chunk-connectors-mr53r7fh.js +0 -1
- package/dist/chunk-conversations-4vy2z6w9.js +0 -1
- package/dist/chunk-entry-jg1eem82.js +0 -1
- package/dist/chunk-group-scene-na95b1te.js +0 -1
- package/dist/chunk-index-11rjg8a8.js +0 -1
- package/dist/chunk-index-1y50d6sj.js +0 -2
- package/dist/chunk-index-5y2r0eaj.js +0 -47
- package/dist/chunk-index-7fphxxzd.js +0 -14
- package/dist/chunk-index-80f1zkp6.css +0 -1
- package/dist/chunk-index-87h45frg.js +0 -2
- package/dist/chunk-index-bnwmssyn.js +0 -2
- package/dist/chunk-index-ckgbszwt.js +0 -51
- package/dist/chunk-index-fmjjekhd.js +0 -2
- package/dist/chunk-index-t1m65yn6.js +0 -13
- package/dist/chunk-index-t711t17m.js +0 -2
- package/dist/chunk-index-txv7qvyy.js +0 -2
- package/dist/chunk-index-wr3dg24d.js +0 -2
- package/dist/chunk-index-yx683d5n.js +0 -2
- package/dist/chunk-lang-css-fkdg3x8x.js +0 -1
- package/dist/chunk-lang-html-v8h9g977.js +0 -1
- package/dist/chunk-lang-javascript-ykb2vhaa.js +0 -1
- package/dist/chunk-lang-json-2rze3rpy.js +0 -1
- package/dist/chunk-lang-markdown-6w2htnfc.js +0 -6
- package/dist/chunk-lang-rust-24fggcqx.js +0 -1
- package/dist/chunk-lang-sql-gjywb9ke.js +0 -2
- package/dist/chunk-lang-typescript-qh6rebyb.js +0 -1
- package/dist/chunk-menu-items-zjpyj51b.js +0 -2
- package/dist/chunk-notes-sjba7kw3.js +0 -1
- package/dist/chunk-overview-26r77kb6.js +0 -1
- package/dist/chunk-room-confirms-851184ep.js +0 -1
- package/dist/chunk-room-menu-8y9c026y.js +0 -1
- package/dist/chunk-skills-56s4hdbn.js +0 -1
- package/dist/chunk-table-qykpvp32.js +0 -1
- package/dist/chunk-table2d-k60ressj.js +0 -1
- package/dist/chunk-table3d-bv2ajk39.js +0 -4220
- package/dist/chunk-transcript-vekz1mh6.js +0 -1
- package/dist/chunk-workspace-hevefd0d.js +0 -1
- package/dist/chunk-zh-tw-5r2wjre0.js +0 -1
package/src/web-plugin.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { join } from "node:path";
|
|
2
3
|
import {
|
|
3
4
|
AGENTS,
|
|
@@ -6,10 +7,14 @@ import {
|
|
|
6
7
|
IDENTITY,
|
|
7
8
|
MEMORY,
|
|
8
9
|
MODES,
|
|
10
|
+
PROFILES,
|
|
11
|
+
PROMPTS,
|
|
9
12
|
type RoundtablePlugin,
|
|
10
13
|
SCHEDULES,
|
|
14
|
+
SKILLS,
|
|
11
15
|
} from "pi-roundtable";
|
|
12
16
|
import { DISCORD } from "pi-roundtable/discord";
|
|
17
|
+
import type { PaneName } from "./api-types.ts";
|
|
13
18
|
import { APP_MIGRATIONS, OwnerApp } from "./app/app.ts";
|
|
14
19
|
import { APP_PROTOCOL } from "./app/protocol.ts";
|
|
15
20
|
import { UPLOAD_FRAMING_BYTES } from "./app/uploads.ts";
|
|
@@ -19,8 +24,16 @@ import {
|
|
|
19
24
|
createAuthenticator,
|
|
20
25
|
WEB_CONSOLE_IDENTITY,
|
|
21
26
|
} from "./auth/authenticator.ts";
|
|
22
|
-
import {
|
|
27
|
+
import { discoverProvider, OidcLogin } from "./auth/oidc.ts";
|
|
28
|
+
import { loadSessionKey } from "./auth/session-key.ts";
|
|
29
|
+
import { WebSessions } from "./auth/sessions.ts";
|
|
30
|
+
import {
|
|
31
|
+
type AccessView,
|
|
32
|
+
ConsoleApi,
|
|
33
|
+
type ConsolePorts,
|
|
34
|
+
} from "./console-api.ts";
|
|
23
35
|
import { ConsoleServer } from "./console-server.ts";
|
|
36
|
+
import { Gate } from "./gate.ts";
|
|
24
37
|
import {
|
|
25
38
|
protectedDirs,
|
|
26
39
|
type ResolvedOptions,
|
|
@@ -30,7 +43,11 @@ import {
|
|
|
30
43
|
workspaceRootsOf,
|
|
31
44
|
} from "./options.ts";
|
|
32
45
|
import { loadVapid } from "./push/vapid.ts";
|
|
33
|
-
import { consoleVisitors } from "./visitors.ts";
|
|
46
|
+
import { accessVisitors, consoleVisitors } from "./visitors.ts";
|
|
47
|
+
import { viewerOf, WEB_APP, WebAppRegistry } from "./web-app.ts";
|
|
48
|
+
|
|
49
|
+
/** How often sessions past their limit are deleted: daily. */
|
|
50
|
+
const SESSION_SWEEP_MS = 86_400_000;
|
|
34
51
|
|
|
35
52
|
/** The longest a WebSocket stays open under `password` auth: the session cookie is looked at again after this. */
|
|
36
53
|
const PASSWORD_SOCKET_LIFE_MS = 3_600_000;
|
|
@@ -47,11 +64,16 @@ export function webConsole(options: WebConsoleOptions): RoundtablePlugin {
|
|
|
47
64
|
const { auth } = settings;
|
|
48
65
|
const rooms = settings.panes.includes("rooms");
|
|
49
66
|
const schedules = settings.panes.includes("schedules");
|
|
67
|
+
const migrations = [
|
|
68
|
+
...(rooms ? APP_MIGRATIONS : []),
|
|
69
|
+
...(auth.mode === "oidc" ? [WebSessions.migration] : []),
|
|
70
|
+
];
|
|
50
71
|
return definePlugin({
|
|
51
72
|
name: "web-console",
|
|
52
|
-
...(
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
...(migrations.length > 0 ? { migrations } : {}),
|
|
74
|
+
provides: [WEB_APP],
|
|
75
|
+
// `none` and `password` speak for one principal through this identity; a verifier or a sign-in brings its own.
|
|
76
|
+
...(auth.mode !== "none" && auth.mode !== "password"
|
|
55
77
|
? {}
|
|
56
78
|
: {
|
|
57
79
|
identities: [
|
|
@@ -66,7 +88,10 @@ export function webConsole(options: WebConsoleOptions): RoundtablePlugin {
|
|
|
66
88
|
...(settings.panes.includes("overview") || rooms ? [AGENTS] : []),
|
|
67
89
|
...(rooms ? [MODES] : []),
|
|
68
90
|
...(schedules ? [SCHEDULES] : []),
|
|
69
|
-
|
|
91
|
+
// A list that names the notes pane needs the memory; the default list drops it without one.
|
|
92
|
+
...(settings.panesGiven && settings.panes.includes("notes")
|
|
93
|
+
? [MEMORY]
|
|
94
|
+
: []),
|
|
70
95
|
],
|
|
71
96
|
setup: (context) => build(settings, context),
|
|
72
97
|
});
|
|
@@ -76,6 +101,20 @@ type Context = Parameters<RoundtablePlugin["setup"]>[0];
|
|
|
76
101
|
|
|
77
102
|
async function build(settings: ResolvedOptions, context: Context) {
|
|
78
103
|
const { services, queue, logger, env } = context;
|
|
104
|
+
// What the other plugins register their rooms, pages and steps in: sealed when the web service starts.
|
|
105
|
+
const webApp = new WebAppRegistry(settings.surface);
|
|
106
|
+
services.provide(WEB_APP, webApp);
|
|
107
|
+
const external = settings.push.sender !== "internal";
|
|
108
|
+
const vapidFile = join(settings.dataDir, "web", "vapid.json");
|
|
109
|
+
// An external sender holds the key: the app never makes or reads one, and a leftover file would say it does.
|
|
110
|
+
if (external && existsSync(vapidFile))
|
|
111
|
+
throw new Error(
|
|
112
|
+
`web-console: push.sender is external, but ${vapidFile} exists. The app must not hold a push key: delete the file (devices subscribe again against the sender's key)`,
|
|
113
|
+
);
|
|
114
|
+
if (settings.admission === "access" && env.agentTools === "full")
|
|
115
|
+
logger.warn(
|
|
116
|
+
"web-console: admission is access and the agents carry shell tools. Anyone who can write the database can make a web session, and an agent with a shell can; keep admission owners behind a signing proxy, or run the agent server with tools chat-only",
|
|
117
|
+
);
|
|
79
118
|
const features =
|
|
80
119
|
typeof settings.features === "function"
|
|
81
120
|
? await settings.features(context)
|
|
@@ -108,9 +147,20 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
108
147
|
"web-console: the workspace pane needs a directory to show: the agents' workspace (the agent server provides it) or workspace.roots",
|
|
109
148
|
);
|
|
110
149
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
150
|
+
// The default list shows the notes pane only when the host keeps memory.
|
|
151
|
+
const memory = services.find(MEMORY);
|
|
152
|
+
const withoutNotes = !settings.panesGiven && memory === undefined;
|
|
153
|
+
if (withoutNotes && settings.panes.includes("notes"))
|
|
154
|
+
logger.warn("the notes pane is left out: this host keeps no memory");
|
|
155
|
+
const servable = (pane: PaneName) =>
|
|
156
|
+
(pane !== "workspace" || workspaceRoots.length > 0) &&
|
|
157
|
+
(pane !== "notes" || !withoutNotes);
|
|
158
|
+
const panes = settings.panes.filter(servable);
|
|
159
|
+
const tierPanes = {
|
|
160
|
+
owner: panes,
|
|
161
|
+
admin: settings.tierPanes.admin.filter(servable),
|
|
162
|
+
member: settings.tierPanes.member.filter(servable),
|
|
163
|
+
};
|
|
114
164
|
if (workspaceRoots.length > 0) checkRoots(workspaceRoots, guarded);
|
|
115
165
|
const workspace =
|
|
116
166
|
panes.includes("workspace") && rooms
|
|
@@ -124,27 +174,106 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
124
174
|
// Absent on a host without the registry: the console then lists conversations found by name only.
|
|
125
175
|
const registry = services.find(CONVERSATIONS);
|
|
126
176
|
const identity = services.get(IDENTITY);
|
|
177
|
+
const profiles = services.find(PROFILES);
|
|
178
|
+
if (settings.admission === "access" && !profiles)
|
|
179
|
+
throw new Error(
|
|
180
|
+
"web-console: admission access needs the PROFILES service; a plugin that replaces IDENTITY must provide PROFILES too",
|
|
181
|
+
);
|
|
182
|
+
// An agent's skills are chosen from what the Skills pane lists when the host supplies it, else from the addon's own catalog.
|
|
183
|
+
const skillRegistry = services.find(SKILLS);
|
|
184
|
+
const skills = skillRegistry
|
|
185
|
+
? {
|
|
186
|
+
catalog: () =>
|
|
187
|
+
features?.skills
|
|
188
|
+
? features.skills.catalog()
|
|
189
|
+
: skillRegistry.catalog(),
|
|
190
|
+
attach: (
|
|
191
|
+
agent: string,
|
|
192
|
+
add: readonly string[],
|
|
193
|
+
remove: readonly string[],
|
|
194
|
+
) => skillRegistry.attach(agent, add, remove),
|
|
195
|
+
documents: skillRegistry,
|
|
196
|
+
}
|
|
197
|
+
: undefined;
|
|
198
|
+
// The prompts plugin is always on; a host that replaced it may leave it out.
|
|
199
|
+
const prompts = services.find(PROMPTS);
|
|
127
200
|
const listeners: (() => void)[] = [];
|
|
128
201
|
const changed = () => {
|
|
129
202
|
for (const listener of listeners) listener();
|
|
130
203
|
};
|
|
131
204
|
// A broken page stops startup here, before anything connects.
|
|
132
205
|
const assets = loadAssets(settings.assetDir);
|
|
206
|
+
const gate = new Gate({ registry: webApp });
|
|
207
|
+
const hosted: ConsolePorts["hosted"] = async (visitor) => {
|
|
208
|
+
const viewer = viewerOf(visitor);
|
|
209
|
+
const pages: {
|
|
210
|
+
id: string;
|
|
211
|
+
label: string;
|
|
212
|
+
place: "main" | "settings" | "hidden";
|
|
213
|
+
}[] = [];
|
|
214
|
+
for (const page of webApp.hostPages()) {
|
|
215
|
+
try {
|
|
216
|
+
if (await page.visible(viewer))
|
|
217
|
+
pages.push({
|
|
218
|
+
id: page.id,
|
|
219
|
+
label: page.label,
|
|
220
|
+
place: page.place,
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
logger.warn(
|
|
224
|
+
{ page: page.id, err: error },
|
|
225
|
+
"a page's visibility was not read",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const kinds: { kind: string; label: string }[] = [];
|
|
230
|
+
for (const kind of webApp.kinds()) {
|
|
231
|
+
try {
|
|
232
|
+
if ((await kind.list(viewer, {})) !== undefined)
|
|
233
|
+
kinds.push({ kind: kind.kind, label: kind.label });
|
|
234
|
+
} catch (error) {
|
|
235
|
+
logger.warn(
|
|
236
|
+
{ kind: kind.kind, err: error },
|
|
237
|
+
"a kind of room was not listed",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { pages, kinds };
|
|
242
|
+
};
|
|
243
|
+
const access: AccessView | undefined =
|
|
244
|
+
settings.admission === "access"
|
|
245
|
+
? {
|
|
246
|
+
push: {
|
|
247
|
+
tiers: settings.push.tiers,
|
|
248
|
+
...(settings.push.sender !== "internal"
|
|
249
|
+
? {
|
|
250
|
+
key: settings.push.sender.external.publicKey,
|
|
251
|
+
...(settings.push.sender.external.subscribePath
|
|
252
|
+
? {
|
|
253
|
+
subscribe: settings.push.sender.external.subscribePath,
|
|
254
|
+
}
|
|
255
|
+
: {}),
|
|
256
|
+
}
|
|
257
|
+
: {}),
|
|
258
|
+
},
|
|
259
|
+
gate: (visitor) => gate.required(viewerOf(visitor)),
|
|
260
|
+
}
|
|
261
|
+
: undefined;
|
|
133
262
|
const api = new ConsoleApi({
|
|
134
263
|
title: settings.title,
|
|
135
264
|
timeZone: env.timeZone,
|
|
136
265
|
panes,
|
|
266
|
+
tierPanes,
|
|
267
|
+
...(access ? { access } : {}),
|
|
268
|
+
hosted,
|
|
137
269
|
sessionsDir: settings.sessionsDir,
|
|
138
270
|
...(team ? { team } : {}),
|
|
139
271
|
queue,
|
|
140
272
|
...(connection
|
|
141
273
|
? { channelName: (id: string) => connection.channelInfo(id) }
|
|
142
274
|
: {}),
|
|
143
|
-
...(
|
|
144
|
-
? {
|
|
145
|
-
memoryOf: (principalId: string) =>
|
|
146
|
-
services.get(MEMORY).forSpeaker(principalId),
|
|
147
|
-
}
|
|
275
|
+
...(panes.includes("notes") && memory
|
|
276
|
+
? { memoryOf: (principalId: string) => memory.forSpeaker(principalId) }
|
|
148
277
|
: {}),
|
|
149
278
|
people: identity,
|
|
150
279
|
...(settings.exclude ? { exclude: settings.exclude } : {}),
|
|
@@ -157,16 +286,45 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
157
286
|
characterSkins: env.characterSkins,
|
|
158
287
|
...(settings.routing === "path" ? { mountPath: settings.mount } : {}),
|
|
159
288
|
...(rooms
|
|
160
|
-
? {
|
|
289
|
+
? {
|
|
290
|
+
app: {
|
|
291
|
+
surface: settings.surface,
|
|
292
|
+
protocol: APP_PROTOCOL,
|
|
293
|
+
...(settings.modes ? {} : { modes: false as const }),
|
|
294
|
+
},
|
|
295
|
+
}
|
|
161
296
|
: {}),
|
|
162
297
|
...(settings.presentation ? { presentation: settings.presentation } : {}),
|
|
163
298
|
});
|
|
299
|
+
const identify =
|
|
300
|
+
settings.admission === "access"
|
|
301
|
+
? accessVisitors(identity, { surface: settings.surface, logger })
|
|
302
|
+
: consoleVisitors(identity, {
|
|
303
|
+
logger,
|
|
304
|
+
...(settings.ownerId ? { ownerId: settings.ownerId } : {}),
|
|
305
|
+
});
|
|
306
|
+
// An open socket closes when its session ends; the app is made after the sign-in it hangs on.
|
|
307
|
+
let sessionEnded: (id: string) => void = () => undefined;
|
|
308
|
+
let sweeper: ReturnType<typeof setInterval> | undefined;
|
|
309
|
+
const sessions =
|
|
310
|
+
settings.auth.mode === "oidc"
|
|
311
|
+
? new WebSessions(context.database(), { days: settings.auth.sessionDays })
|
|
312
|
+
: undefined;
|
|
313
|
+
const oidc =
|
|
314
|
+
settings.auth.mode === "oidc" && sessions
|
|
315
|
+
? await startOidc(settings.auth, {
|
|
316
|
+
sessions,
|
|
317
|
+
settings,
|
|
318
|
+
identify,
|
|
319
|
+
logger,
|
|
320
|
+
events: context.events,
|
|
321
|
+
ended: (id) => sessionEnded(id),
|
|
322
|
+
})
|
|
323
|
+
: undefined;
|
|
164
324
|
const authenticator = createAuthenticator({
|
|
165
325
|
auth: settings.auth,
|
|
166
|
-
identify
|
|
167
|
-
|
|
168
|
-
...(settings.ownerId ? { ownerId: settings.ownerId } : {}),
|
|
169
|
-
}),
|
|
326
|
+
identify,
|
|
327
|
+
...(oidc && sessions ? { oidc: { login: oidc, sessions } } : {}),
|
|
170
328
|
origin: settings.origin,
|
|
171
329
|
mount: settings.mount,
|
|
172
330
|
title: settings.title,
|
|
@@ -178,18 +336,25 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
178
336
|
address: context.listener(settings.listener),
|
|
179
337
|
},
|
|
180
338
|
});
|
|
181
|
-
if (rooms && !settings.push.subject)
|
|
339
|
+
if (rooms && !external && !settings.push.subject)
|
|
182
340
|
logger.warn(
|
|
183
341
|
"web push is off: the origin is not https, so set push.subject to a mailto: or https: contact",
|
|
184
342
|
);
|
|
185
|
-
const vapid = rooms
|
|
186
|
-
? await loadVapid(join(settings.dataDir, "web", "vapid.json"))
|
|
187
|
-
: undefined;
|
|
343
|
+
const vapid = rooms && !external ? await loadVapid(vapidFile) : undefined;
|
|
188
344
|
const app =
|
|
189
|
-
rooms && vapid
|
|
345
|
+
rooms && (vapid || external)
|
|
190
346
|
? new OwnerApp({
|
|
347
|
+
...(settings.presentation
|
|
348
|
+
? { presentation: settings.presentation }
|
|
349
|
+
: {}),
|
|
350
|
+
extras: {
|
|
351
|
+
...(profiles ? { profiles } : {}),
|
|
352
|
+
routing: settings.routing,
|
|
353
|
+
onboarding: settings.onboarding,
|
|
354
|
+
push: settings.push,
|
|
355
|
+
},
|
|
191
356
|
push: {
|
|
192
|
-
vapid,
|
|
357
|
+
...(vapid ? { vapid } : {}),
|
|
193
358
|
subject: settings.push.subject,
|
|
194
359
|
preview: settings.push.preview,
|
|
195
360
|
...(settings.push.quietHours
|
|
@@ -209,14 +374,29 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
209
374
|
dataDir: settings.dataDir,
|
|
210
375
|
cardGraceSeconds: settings.cardGraceSeconds,
|
|
211
376
|
uploadMaxBytes: settings.uploadMaxBytes,
|
|
377
|
+
uploadKeepDays: settings.uploadKeepDays,
|
|
378
|
+
events: context.events,
|
|
379
|
+
// The name the person goes by in the app, as the profiles name them.
|
|
380
|
+
...(profiles
|
|
381
|
+
? { nameOf: async (id: string) => (await profiles.of(id)).name }
|
|
382
|
+
: {}),
|
|
383
|
+
roomUrl: (room, message) =>
|
|
384
|
+
`${settings.routing === "path" ? `${settings.mount}/room/` : `${settings.mount}/#/room/`}${encodeURIComponent(room)}${message === undefined ? "" : `?message=${message}`}`,
|
|
212
385
|
authenticator,
|
|
213
386
|
authMode: settings.auth.mode,
|
|
387
|
+
admission: settings.admission,
|
|
388
|
+
registry: webApp,
|
|
389
|
+
gate,
|
|
390
|
+
pushTiers: settings.push.tiers,
|
|
391
|
+
modeSwitches: settings.modes,
|
|
214
392
|
// A password session outlives a logout or a new password on an open socket, so the socket is capped.
|
|
215
393
|
...(settings.auth.mode === "password"
|
|
216
394
|
? { socketLifeMs: PASSWORD_SOCKET_LIFE_MS }
|
|
217
395
|
: {}),
|
|
218
396
|
database: context.database(),
|
|
219
397
|
agents: services.get(AGENTS),
|
|
398
|
+
...(skills ? { skills } : {}),
|
|
399
|
+
...(prompts ? { prompts } : {}),
|
|
220
400
|
...(workspace ? { workspace } : {}),
|
|
221
401
|
modes: services.get(MODES),
|
|
222
402
|
identity,
|
|
@@ -228,7 +408,10 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
228
408
|
logger,
|
|
229
409
|
})
|
|
230
410
|
: undefined;
|
|
231
|
-
if (app)
|
|
411
|
+
if (app) {
|
|
412
|
+
listeners.push(() => app.changed());
|
|
413
|
+
sessionEnded = (id) => app.sessionEnded(id);
|
|
414
|
+
}
|
|
232
415
|
const server = new ConsoleServer({
|
|
233
416
|
mount: settings.mount,
|
|
234
417
|
assets,
|
|
@@ -240,6 +423,8 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
240
423
|
...(settings.presentation ? { presentation: settings.presentation } : {}),
|
|
241
424
|
api,
|
|
242
425
|
...(app ? { app } : {}),
|
|
426
|
+
gate,
|
|
427
|
+
surface: settings.surface,
|
|
243
428
|
subscribe: (listener) => {
|
|
244
429
|
listeners.push(listener);
|
|
245
430
|
queue.onChange(listener);
|
|
@@ -252,10 +437,26 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
252
437
|
{
|
|
253
438
|
name: "web-console",
|
|
254
439
|
start: () => {
|
|
440
|
+
checkRegistered(settings, webApp);
|
|
441
|
+
webApp.seal();
|
|
255
442
|
server.start();
|
|
256
443
|
app?.start();
|
|
444
|
+
if (sessions) {
|
|
445
|
+
const sweep = () =>
|
|
446
|
+
sessions
|
|
447
|
+
.sweep()
|
|
448
|
+
.catch((error: unknown) =>
|
|
449
|
+
logger.warn(
|
|
450
|
+
{ err: error },
|
|
451
|
+
"old web sessions were not deleted",
|
|
452
|
+
),
|
|
453
|
+
);
|
|
454
|
+
sweep();
|
|
455
|
+
sweeper = setInterval(sweep, SESSION_SWEEP_MS);
|
|
456
|
+
}
|
|
257
457
|
},
|
|
258
458
|
stop: () => {
|
|
459
|
+
clearInterval(sweeper);
|
|
259
460
|
app?.stop();
|
|
260
461
|
server.stop();
|
|
261
462
|
},
|
|
@@ -272,3 +473,69 @@ async function build(settings: ResolvedOptions, context: Context) {
|
|
|
272
473
|
dashboard: [`Web console: ${settings.origin}${settings.mount}/`],
|
|
273
474
|
};
|
|
274
475
|
}
|
|
476
|
+
|
|
477
|
+
/** What the host registered, checked when the service starts: every provider onboarding names has its prover. */
|
|
478
|
+
function checkRegistered(settings: ResolvedOptions, webApp: WebAppRegistry) {
|
|
479
|
+
if (
|
|
480
|
+
settings.onboarding.push !== "off" &&
|
|
481
|
+
(!settings.panes.includes("rooms") ||
|
|
482
|
+
(settings.push.sender === "internal" && !settings.push.subject))
|
|
483
|
+
)
|
|
484
|
+
throw new Error(
|
|
485
|
+
"web-console: onboarding.push asks people to turn push on, but push is off here. It needs the rooms pane and a push.subject (or an external sender)",
|
|
486
|
+
);
|
|
487
|
+
for (const provider of Object.keys(settings.onboarding.links))
|
|
488
|
+
if (!webApp.prover(provider))
|
|
489
|
+
throw new Error(
|
|
490
|
+
`web-console: onboarding.links names ${provider}, but no plugin registered a link prover for it (WEB_APP.registerLinkProver)`,
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
interface OidcParts {
|
|
495
|
+
sessions: WebSessions;
|
|
496
|
+
settings: ResolvedOptions;
|
|
497
|
+
identify: Parameters<typeof createAuthenticator>[0]["identify"];
|
|
498
|
+
logger: Context["logger"];
|
|
499
|
+
events: Context["events"];
|
|
500
|
+
ended(id: string): void;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** Reads the provider's discovery document, the client secret and the session key, and makes the sign-in flow. */
|
|
504
|
+
async function startOidc(
|
|
505
|
+
auth: Extract<ResolvedOptions["auth"], { mode: "oidc" }>,
|
|
506
|
+
parts: OidcParts,
|
|
507
|
+
): Promise<OidcLogin> {
|
|
508
|
+
const { settings, logger } = parts;
|
|
509
|
+
let clientSecret: string | undefined;
|
|
510
|
+
if (auth.clientSecretEnv) {
|
|
511
|
+
clientSecret = process.env[auth.clientSecretEnv];
|
|
512
|
+
if (!clientSecret)
|
|
513
|
+
throw new Error(
|
|
514
|
+
`web-console: auth.clientSecretEnv names ${auth.clientSecretEnv}, which is not set`,
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
return new OidcLogin({
|
|
518
|
+
settings: auth,
|
|
519
|
+
metadata: await discoverProvider(auth),
|
|
520
|
+
...(clientSecret ? { clientSecret } : {}),
|
|
521
|
+
sessions: parts.sessions,
|
|
522
|
+
key: loadSessionKey(settings.dataDir, logger),
|
|
523
|
+
origin: settings.origin,
|
|
524
|
+
mount: settings.mount,
|
|
525
|
+
surface: settings.surface,
|
|
526
|
+
routing: settings.routing,
|
|
527
|
+
title: settings.title,
|
|
528
|
+
presentation: settings.presentation,
|
|
529
|
+
identify: parts.identify,
|
|
530
|
+
onSignIn: (info) =>
|
|
531
|
+
parts.events.action?.({
|
|
532
|
+
kind: "sign-in",
|
|
533
|
+
actor: info.speakerId,
|
|
534
|
+
principalId: info.principalId,
|
|
535
|
+
ok: true,
|
|
536
|
+
at: new Date(),
|
|
537
|
+
}),
|
|
538
|
+
onEnded: parts.ended,
|
|
539
|
+
logger,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o,yt,c,r,m,e,i,l,W,pt,En}from"./chunk-index-ckgbszwt.js";var k=()=>typeof matchMedia==="function"&&matchMedia("(max-width: 719px)").matches,x={rtMenu:!0},g=()=>Boolean(window.history.state?.rtMenu),E=8,y=(n)=>n?.isConnected?n:null;function b(n){return n.items.map((t)=>i("button",{type:"button",role:t.checked===void 0?"menuitem":"menuitemcheckbox",...t.checked===void 0?{}:{"aria-checked":t.checked},className:"menu-item menu-link","data-tone":t.tone,onClick:()=>n.onChoose(t),children:[t.icon?e("span",{className:"menu-icon","data-tone":t.tone,children:e(l,{name:t.icon,size:18})}):null,e("span",{className:"menu-text",children:e("strong",{children:t.label})}),t.checked?e(l,{name:"check",size:18,className:"menu-check"}):null]},t.id))}function H({menu:n}){let t=c(void 0);if(n)t.current=n;let u=t.current,f=c(!1),v=c(void 0),p=n?.serial;return o(()=>{if(p===void 0)return;return window.history.pushState(x,"",window.location.href),f.current=!0,()=>{if(f.current)f.current=!1,window.history.back()}},[p]),o(()=>{let h=()=>{if(!f.current||g())return;f.current=!1,pt();let M=v.current;v.current=void 0,M?.()};return window.addEventListener("popstate",h),()=>window.removeEventListener("popstate",h)},[]),e(W,{open:n!==void 0,title:u?.title??"",onClose:pt,restoreFocus:()=>y(u?.source??null),children:u?e("div",{className:"menu action-items",role:"menu","aria-label":u.title,children:e(b,{items:u.items,onChoose:(h)=>{if(!f.current){pt(),h.run();return}v.current=h.run,window.history.back()}})}):null})}function T({menu:n}){let t=c(null),[u,f]=r(n.at),{source:v}=n,p=(s)=>{y(v)?.focus(),pt(),s?.()},h=c(p);h.current=p,yt(()=>{let s=t.current;if(!s)return;let a=s.getBoundingClientRect();f({x:Math.max(E,Math.min(n.at.x,window.innerWidth-a.width-E)),y:Math.max(E,Math.min(n.at.y,window.innerHeight-a.height-E))}),s.querySelector('[role^="menuitem"]')?.focus()},[n.serial]),o(()=>{let s=(d)=>{if(d.target instanceof Node&&t.current?.contains(d.target))return;pt()},a=()=>pt();return document.addEventListener("pointerdown",s,!0),document.addEventListener("wheel",s,{capture:!0,passive:!0}),document.addEventListener("touchmove",s,{capture:!0,passive:!0}),window.addEventListener("resize",a),()=>{document.removeEventListener("pointerdown",s,!0),document.removeEventListener("wheel",s,!0),document.removeEventListener("touchmove",s,!0),window.removeEventListener("resize",a)}},[]);let M=(s)=>{let a=[...t.current?.querySelectorAll('[role^="menuitem"]')??[]],d=a.indexOf(document.activeElement),w=(L)=>{s.preventDefault(),a[(L+a.length)%a.length]?.focus()};switch(s.key){case"Escape":s.preventDefault(),s.stopPropagation(),h.current();return;case"ArrowDown":return w(d+1);case"ArrowUp":return w(d<0?-1:d-1);case"Tab":return w(s.shiftKey?d<0?-1:d-1:d+1);case"Home":return w(0);case"End":return w(-1)}};return e("div",{ref:t,className:"action-popover",role:"menu","aria-label":n.title,tabIndex:-1,style:{left:`${u.x}px`,top:`${u.y}px`},onKeyDown:M,children:e(b,{items:n.items,onChoose:(s)=>p(s.run)})})}function I(){let n=En(),t=c(void 0);if(n&&t.current?.serial!==n.serial)t.current={serial:n.serial,sheet:k()};let u=Boolean(n&&t.current?.sheet);return i(m,{children:[e(H,{menu:u?n:void 0}),n&&!u?e(T,{menu:n},n.serial):null]})}export{I as ActionMenuHost};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o,e,re,f,P,Re}from"./chunk-index-ckgbszwt.js";function g({name:r}){let m=f((i)=>i.listed),t=f((i)=>Object.values(i.rooms).find((n)=>n.view?.kind==="agent"&&n.view.name===r)?.view?.key,r);return o(()=>{if(t)re("room",t,{replace:!0}),Re(r);else if(m)re("rooms",void 0,{replace:!0})},[t,m,r]),e("div",{className:"page",children:e(P,{})})}export{g as AgentPage};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{Q,Ge,ie,o,Oe,q,c,r,t,s,e,i,l,f,ae,W,P,S,y,d,b,vt,on,Cn,An}from"./chunk-index-ckgbszwt.js";import{lt}from"./chunk-index-mpm90318.js";import{st}from"./chunk-index-87h45frg.js";function U(n,m){let a=n.split(`
|
|
2
|
-
`),k=m.split(`
|
|
3
|
-
`),h=0;while(h<a.length&&h<k.length&&a[h]===k[h])h++;let g=0;while(g<a.length-h&&g<k.length-h&&a[a.length-1-g]===k[k.length-1-g])g++;let N=a.slice(h,a.length-g),w=k.slice(h,k.length-g),u=a.slice(0,h).map((v)=>({kind:"same",text:v}));return u.push(...me(N,w)),u.push(...a.slice(a.length-g).map((v)=>({kind:"same",text:v}))),u}function me(n,m){let a=(v)=>v.map((L)=>({kind:"del",text:L})),k=(v)=>v.map((L)=>({kind:"add",text:L}));if(n.length===0)return k(m);if(m.length===0)return a(n);if(n.length*m.length>4000000)return[...a(n),...k(m)];let h=m.length+1,g=new Uint32Array((n.length+1)*h);for(let v=n.length-1;v>=0;v--)for(let L=m.length-1;L>=0;L--)g[v*h+L]=n[v]===m[L]?(g[(v+1)*h+L+1]??0)+1:Math.max(g[(v+1)*h+L]??0,g[v*h+L+1]??0);let N=[],w=0,u=0;while(w<n.length&&u<m.length)if(n[w]===m[u])N.push({kind:"same",text:n[w]}),w++,u++;else if((g[(w+1)*h+u]??0)>=(g[w*h+u+1]??0))N.push({kind:"del",text:n[w]}),w++;else N.push({kind:"add",text:m[u]}),u++;return N.push(...a(n.slice(w)),...k(m.slice(u))),N}function X(n){return{added:n.filter((m)=>m.kind==="add").length,removed:n.filter((m)=>m.kind==="del").length}}var ce=ie(()=>(Q("8q6ympxj"),import("./chunk-character-creator-8q6ympxj.js")).then((n)=>({default:n.CharacterCreator}))),fe=["default","off","minimal","low","medium","high","xhigh"],ee={default:s("Follow the assistant (automatic)"),off:s("Off"),minimal:s("Minimal"),low:s("Low"),medium:s("Medium"),high:s("High"),xhigh:s("Very high")},C="default",E=(n)=>t(ee[n]??n),J=(n)=>({displayName:n.displayName,prompt:n.prompt,model:n.model??C,thinking:n.thinking??C});function Y(n,m){return{...m.displayName!==n.displayName?{displayName:m.displayName}:{},...m.prompt!==n.prompt?{prompt:m.prompt}:{},...m.model!==(n.model??C)?{model:m.model}:{},...m.thinking!==(n.thinking??C)?{thinking:m.thinking}:{}}}function Ee(){let n=An(),m=c(n);if(n)m.current=n;let a=m.current,k=n!==void 0;if(o(()=>{if(!k)return;let h=window.location.href,g=()=>{if(window.location.href!==h)on()};return window.addEventListener("popstate",g),window.addEventListener("hashchange",g),()=>{window.removeEventListener("popstate",g),window.removeEventListener("hashchange",g)}},[k]),!a)return null;return e(W,{open:n!==void 0,title:t("Edit agent"),size:"wide",onClose:on,children:e(ue,{name:a.name,opened:a.id},a.name)})}function ue({name:n,opened:m}){let[a,k]=r(),[h,g]=r([]),[N,w]=r(),[u,v]=r(),[L,R]=r(!1),[te,x]=r(!1),[ne,F]=r(!1),se=vt(a?.room??""),M=c(null),T=a!==void 0,V=f((p)=>a?p.rooms[a.room]?.view?.muted===!0:!1,a?.room??""),[oe,H]=r(!1),O=Oe(),B=Oe(),K=Oe();o(()=>{if(!T||!Cn()?.look)return;M.current?.scrollIntoView({block:"start"}),M.current?.focus({preventScroll:!0})},[T,m]);let _=c({});_.current={profile:a,draft:u},o(()=>{let p=!0;return Promise.all([d.agent(n),d.models()]).then(([D,re])=>{if(!p)return;let{profile:G,draft:I}=_.current,de=G&&I&&Object.keys(Y(G,I)).length>0;k(D),g(re.models),v(de?I:J(D))},(D)=>p&&w(b(D))),()=>{p=!1}},[n,m]);let A=q(()=>a&&u?Y(a,u):{},[a,u]);if(N)return e(S,{message:N});if(!a||!u)return e(P,{});let j=Object.keys(A).length>0,le=Array.from(new Set([C,...h,u.model])),z=async()=>{R(!0);try{let p=await d.updateAgent(n,A);k(p),v(J(p)),x(!1),y(t("Saved."))}catch(p){y(b(p),"danger")}finally{R(!1)}};return i("div",{className:"stack agent-sheet",children:[i("header",{className:"profile-head",children:[e(ae,{spec:a.character,name:a.name,size:72,state:se,label:a.displayName}),i("div",{children:[e("h3",{children:a.displayName}),e("p",{className:"meta",children:t("Runs on {model}, thinking {thinking}",{model:a.effective.model,thinking:E(a.effective.thinking)})})]})]}),e("ul",{className:"menu",children:e("li",{children:i("label",{className:"menu-item menu-toggle",htmlFor:K,children:[e("span",{className:"menu-icon",children:e(l,{name:V?"bell-off":"bell"})}),i("span",{className:"menu-text",children:[e("strong",{children:t("Notifications")}),e("span",{className:"meta",children:t("Push this room's posts to every owner's devices. A card that waits for you is always pushed.")})]}),e(lt,{id:K,checked:!V,label:t("Notifications"),busy:oe,onChange:async(p)=>{H(!0),await st(a.room,!p),H(!1)}})]})})}),te?e(ge,{profile:a,draft:u,saving:L,onBack:()=>x(!1),onSave:z}):i("form",{className:"stack form",onSubmit:(p)=>{if(p.preventDefault(),!j)return;if(A.prompt!==void 0)x(!0);else z()},children:[i("label",{htmlFor:B,children:[t("Name"),e("input",{id:B,value:u.displayName,onChange:(p)=>v({...u,displayName:p.target.value})})]}),i("div",{className:"field",children:[i("div",{className:"field-head",children:[e("label",{htmlFor:O,children:t("Prompt")}),i("button",{type:"button",className:"secondary compact","aria-haspopup":"dialog",onClick:()=>F(!0),children:[e(pe,{}),t("Full screen")]})]}),e("textarea",{id:O,rows:8,value:u.prompt,onChange:(p)=>v({...u,prompt:p.target.value})})]}),e(Z,{label:t("Model"),value:u.model,onChange:(p)=>v({...u,model:p}),options:le.map((p)=>({value:p,label:p===C?t("Follow the assistant"):p}))}),e(Z,{label:t("Thinking level"),value:u.thinking,onChange:(p)=>v({...u,thinking:p}),options:fe.map((p)=>({value:p,label:t(ee[p])}))}),e("div",{className:"actions",children:e("button",{type:"submit",disabled:!j||L,children:L?t("Saving…"):A.prompt!==void 0?t("Review changes"):t("Save")})})]}),i("section",{className:"card stack",ref:M,tabIndex:-1,children:[e("h3",{children:t("Look")}),e("p",{className:"meta",children:t("Class, colors and parts. The picture here, in the rooms and in Discord all follow it.")}),e(Ge,{fallback:e(P,{}),children:e(ce,{name:a.name,displayName:a.displayName,prompt:a.prompt,character:a.character,onSaved:(p)=>k(p)})})]}),e(W,{open:ne,title:t("Prompt"),size:"full",onClose:()=>F(!1),children:e("textarea",{className:"prompt-full","aria-label":t("Prompt"),value:u.prompt,onChange:(p)=>v({...u,prompt:p.target.value})})})]})}var pe=()=>e("svg",{viewBox:"0 0 24 24",width:16,height:16,fill:"none",stroke:"currentColor",strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",children:e("path",{d:"M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5"})});function Z(n){return i("fieldset",{className:"field",children:[e("legend",{children:n.label}),e("div",{className:"option-chips",children:n.options.map((m)=>e("button",{type:"button","aria-pressed":m.value===n.value,className:"option-chip",onClick:()=>n.onChange(m.value),children:m.label},m.value))})]})}var he={same:" ",add:"+",del:"−"};function ge(n){let{profile:m,draft:a}=n,k=c(null);o(()=>k.current?.focus(),[]);let h=q(()=>U(m.prompt,a.prompt),[m.prompt,a.prompt]),g=X(h),N=[];if(a.displayName!==m.displayName)N.push({label:t("Name"),before:m.displayName,after:a.displayName});let w=(u)=>u===C?t("Follow the assistant"):u;if(a.model!==(m.model??C))N.push({label:t("Model"),before:w(m.model??C),after:w(a.model)});if(a.thinking!==(m.thinking??C))N.push({label:t("Thinking level"),before:E(m.thinking??C),after:E(a.thinking)});return i("section",{ref:k,className:"stack review",tabIndex:-1,"aria-label":t("Review changes"),children:[e("h3",{children:t("Review changes")}),N.length?e("ul",{className:"review-fields",children:N.map((u)=>i("li",{children:[e("strong",{children:u.label}),e("span",{className:"review-before",children:u.before}),e("span",{"aria-hidden":"true",children:"→"}),e("span",{className:"review-after",children:u.after})]},u.label))}):null,i("div",{className:"field",children:[i("span",{className:"field-label",children:[t("Prompt")," ·"," ",t("Lines: {added} added, {removed} removed",{added:g.added,removed:g.removed})]}),e("pre",{className:"diff",children:h.map((u,v)=>i("span",{className:"diff-line","data-kind":u.kind,children:[e("span",{className:"diff-mark","aria-hidden":"true",children:he[u.kind]}),u.kind==="add"||u.kind==="del"?i("span",{className:"visually-hidden",children:[u.kind==="add"?t("Added"):t("Removed"),":"," "]}):null,u.text||" "]},v))})]}),i("div",{className:"actions",children:[e("button",{type:"button",className:"secondary",disabled:n.saving,onClick:n.onBack,children:t("Back to editing")}),e("button",{type:"button",disabled:n.saving,onClick:n.onSave,children:n.saving?t("Saving…"):t("Save")})]})]})}export{Ee as AgentSheetHost};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_e,rt,X,Lt,jt}from"./chunk-index-5y2r0eaj.js";import{ce,an,o,Oe,q,c,r,t,s,m,e,i,Ct,bt,ae,W,y,ht,d,b,Pe,Me,ge}from"./chunk-index-ckgbszwt.js";var le={"hat.none":"No hat","hat.goggcap":"Leather cap","hat.tallcap":"Burgundian felt cap","hat.softcap":"Soft cap","hat.hardhat":"Iron skullcap","hat.fcap":"Hunter's cap","hat.winghelm":"Winged helm","hat.helm":"Helm","hat.mortar":"Biretta","hat.beret":"Chaperon","hat.goggles":"Pointed cap","hat.tricorn":"Pilgrim hat","hat.sailor":"Straw hat","hat.kettle":"Kettle hat","hat.cavalier":"Feathered hat","hat.toque":"Linen cook's cap","hair.none":"No hair","beard.none":"No beard","accessory.none":"No accessory","prop.beads":"Prayer beads","prop.marotte":"Marotte","prop.map":"Chart","prop.flask":"Alchemist's phial","prop.telescope":"Astrolabe","prop.wrench":"Dividers","outfit.surplice":"Surplice","outfit.overalls":"Work jerkin","outfit.armor":"Mail hauberk","outfit.apron":"Smith's apron","outfit.chef":"Cook's tunic","outfit.coat":"Doublet","outfit.vest":"Pourpoint","outfit.sailor":"Mariner's tunic","hair.bob":"Bob","hair.bun":"Bun","hair.ponytail":"Ponytail"},U=(a)=>a.charAt(0).toUpperCase()+a.slice(1);function N(a,l){let h=`character.${a}.${l}`,p=t(h);if(p!==h)return p;if(a==="class")return X.classes[l]?.label??U(l);return le[`${a}.${l}`]??U(l)}function V(a){let l=`character.jobs.${a}`,h=t(l);return h!==l?h:X.classes[a]?.jobs??""}var H=[{field:"hat",title:s("Hat"),ids:X.hats},{field:"outfit",title:s("Outfit"),ids:X.outfits},{field:"prop",title:s("Prop"),ids:X.props},{field:"hair",title:s("Hair"),ids:X.hair},{field:"beard",title:s("Beard"),ids:["none",...X.beards]},{field:"accessory",title:s("Accessory"),ids:["none",...X.accessories]}],de=new Set(["class","colors","palette","build","skin","hairColor",...H.map((a)=>a.field)]),Z=Object.keys(X.palettes),x={idle:s("Idle"),thinking:s("Thinking"),working:s("Working"),waiting:s("Waiting for you"),done:s("Done"),error:s("Error"),sleepy:s("Sleepy")},ue={slim:s("Slim"),regular:s("Regular"),stout:s("Stout")};function ee(a){return{class:a.class,outfit:a.outfit,hat:a.hat,prop:a.prop,hair:a.hair,beard:a.beard,accessory:a.accessory,build:a.build,skin:a.skin,hairColor:a.hairColor,colors:{...a.colors}}}var Q=(a)=>JSON.stringify(ee(a)),v=(a)=>a[Math.floor(Math.random()*a.length)];function fe(){return{class:v(_e),outfit:v(X.outfits),hat:v(X.hats),prop:v(X.props),hair:v(X.hair),beard:v(["none",...X.beards]),accessory:v(["none",...X.accessories]),build:v(["slim","regular","stout"]),skin:v([0,1,2,3,4,5]),hairColor:v(X.hairColors),palette:v(Z)}}var te=ce(function(l){return i("button",{type:"button",className:"creator-tile","aria-pressed":l.pressed,title:l.hint?`${l.label} — ${l.hint}`:l.label,onClick:l.onPick,...l.data,children:[e(ae,{spec:l.spec,size:l.size,live:!1}),e("span",{children:l.label})]})});function me(a,l,h){let p=JSON.stringify({...a,[l]:0});return q(()=>h.map((u)=>({...a,[l]:u})),[p,l,h])}function he(){let a=c(null),[l,h]=r();return o(()=>{let p=a.current;if(!p)return;let u=()=>{let S=p.scrollLeft>1,P=p.scrollLeft+p.clientWidth<p.scrollWidth-1;h(S&&P?"both":P?"end":S?"start":void 0)};u(),p.addEventListener("scroll",u,{passive:!0});let g=typeof ResizeObserver>"u"?void 0:new ResizeObserver(u);return g?.observe(p),()=>{p.removeEventListener("scroll",u),g?.disconnect()}},[]),[a,l]}function pe(a){let{part:l}=a,h=me(a.shown,l.field,l.ids),[p,u]=he();return e("div",{className:"creator-strip",ref:p,"data-more":u,children:l.ids.map((g,S)=>e(te,{data:{[`data-${l.field}`]:g},spec:h[S],size:44,label:N(l.field,g),pressed:a.draft[l.field]===g,onPick:()=>a.onPick(g)},g))})}function B(a){return e("button",{type:"button",className:"creator-swatch","aria-pressed":a.pressed,"aria-label":a.label,title:a.label,style:{background:a.background},onClick:a.onPick,...a.data})}function L(a){return i("div",{className:"creator-field","data-field":a.field,children:[a.title?e("h3",{children:a.title}):null,a.children,a.error?e("p",{className:"field-error",role:"alert",children:a.error}):null]})}function He(a){let[l,h]=r(a.character),p=an(l),[u,g]=r({}),[S,P]=r(!1),[T,re]=r("idle"),[K,E]=r(),[R,M]=r(),O=Pe("(max-width: 719px)"),z=c(null),I=Oe(),ie=Me(l),ne=bt(),w=Q(l)!==Q(a.character);o(()=>h(a.character),[a.character]),o(()=>{if(!w)return;let n=(k)=>k.preventDefault(),f=(k)=>{if(k.button!==0||k.metaKey||k.ctrlKey||k.shiftKey||k.altKey)return;let A=k.target instanceof Element?k.target.closest("a"):null;if(!A||A.target||A.hasAttribute("download"))return;if(z.current?.contains(A))return;k.preventDefault(),k.stopPropagation(),E({kind:"link",anchor:A})},F=Ct((k)=>E({kind:"navigate",proceed:k}));return window.addEventListener("beforeunload",n),document.addEventListener("click",f,!0),()=>{F(),window.removeEventListener("beforeunload",n),document.removeEventListener("click",f,!0)}},[w]);let C=(n)=>{g({}),h((f)=>Lt(n,f))},oe=async()=>{P(!0),g({});try{let n=await d.setCharacter(a.name,ee(l));a.onSaved(n),y(t("Saved."))}catch(n){let f=n instanceof ht&&n.field?n.field.split(".")[0]:void 0,F=f&&de.has(f)?f:"*";g({[F]:b(n)})}finally{P(!1)}},se=async()=>{let n=K;if(h(a.character),g({}),n?.kind==="link")setTimeout(()=>n.anchor.click(),0);else if(n?.kind==="navigate")n.proceed()},_=e(L,{field:"class",title:t("Class"),error:u.class,children:e("div",{className:"creator-grid",children:_e.map((n)=>e(be,{id:n,base:p,pressed:l.class===n,onPick:()=>C({class:n,colors:l.colors})},n))})}),j=i(L,{field:"colors",title:t("Colors"),error:u.colors??u.palette,children:[i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Palette")}),Z.map((n)=>{let f=X.palettes[n];return e(B,{data:{"data-palette":n},label:N("palette",n),pressed:l.palette===n,background:`linear-gradient(135deg, ${f.primary} 52%, ${f.trim} 52%)`,onPick:()=>C({palette:n})},n)})]}),e("div",{className:"creator-custom",children:["primary","secondary","trim"].map((n)=>i("label",{children:[e("span",{children:n==="primary"?t("Primary (the accent)"):n==="secondary"?t("Secondary"):t("Trim")}),e("input",{type:"color",value:l.colors[n],onChange:(f)=>C({colors:{[n]:f.target.value}})})]},n))})]}),G=H.map((n)=>e(L,{field:n.field,title:t(n.title),error:u[n.field],children:e(pe,{part:n,draft:l,shown:p,onPick:(f)=>C({[n.field]:f})})},n.field)),J=i(m,{children:[e(L,{field:"build",title:t("Build"),error:u.build,children:i("fieldset",{className:"segmented",children:[e("legend",{className:"visually-hidden",children:t("Build")}),["slim","regular","stout"].map((n)=>i("label",{"data-checked":l.build===n,children:[e("input",{type:"radio",name:`${I}-build`,checked:l.build===n,onChange:()=>C({build:n})}),Y(n)]},n))]})}),e(L,{field:"skin",title:t("Skin tone"),error:u.skin,children:i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Skin tone")}),(ne??X.skins).map((n,f)=>e(B,{data:{"data-skin":String(f)},label:t("Skin tone {n}",{n:f+1}),pressed:l.skin===f,background:n,onPick:()=>C({skin:f})},f))]})}),e(L,{field:"hairColor",title:t("Hair color"),error:u.hairColor,children:i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Hair color")}),X.hairColors.map((n,f)=>e(B,{data:{"data-hair-color":n},label:t("Hair color {n}",{n:f+1}),pressed:l.hairColor===n,background:n,onPick:()=>C({hairColor:n})},n)),e("input",{type:"color","aria-label":t("Hair color"),value:l.hairColor,onChange:(n)=>C({hairColor:n.target.value})})]})})]}),D=[{id:"class",title:t("Class"),summary:N("class",l.class),error:u.class,node:_},{id:"colors",title:t("Colors"),summary:l.palette?N("palette",l.palette):l.colors.primary,error:u.colors??u.palette,node:j},...H.map((n,f)=>({id:n.field,title:t(n.title),summary:N(n.field,l[n.field]),error:u[n.field],node:G[f]})),{id:"body",title:t("Body"),summary:Y(l.build),error:u.build??u.skin??u.hairColor,node:J}];return i("form",{ref:z,className:"creator",style:ie,"aria-labelledby":I,onSubmit:(n)=>{if(n.preventDefault(),w&&!S)oe()},children:[e("h2",{id:I,className:"visually-hidden",children:t("Character of {name}",{name:a.displayName})}),i("div",{className:"creator-preview",children:[e(ae,{spec:l,name:a.name,state:T,size:176,label:t("{name}, {state}",{name:a.displayName,state:t(x[T])})}),e("button",{type:"button",className:"secondary","data-action":"cycle",onClick:()=>re((n)=>rt[(rt.indexOf(n)+1)%rt.length]??"idle"),children:t("Preview states")}),e("span",{className:"meta","aria-live":"polite",children:t(x[T])})]}),i("div",{className:"creator-body",children:[u["*"]?e("p",{className:"field-error",role:"alert","data-field":"*",children:u["*"]}):null,O?e("ul",{className:"creator-sections",children:D.map((n)=>e("li",{children:i("button",{type:"button",className:"creator-section secondary",onClick:()=>M(n.id),children:[e("strong",{children:n.title}),e("span",{className:"meta",children:n.summary}),n.error?e("span",{className:"field-error",role:"alert",children:n.error}):null]})},n.id))}):i(m,{children:[_,j,G,J]}),i("div",{className:"actions creator-actions",children:[e("button",{type:"button",className:"secondary","data-action":"suggest",onClick:()=>{g({}),h(jt({name:a.name,displayName:a.displayName,prompt:a.prompt}))},children:t("Suggest from role")}),e("button",{type:"button",className:"secondary","data-action":"randomize",onClick:()=>C(fe()),children:t("Randomize")}),e("button",{type:"button",className:"secondary","data-action":"cancel",onClick:()=>{if(w)E({kind:"cancel"})},children:t("Cancel")}),e("button",{type:"submit","data-action":"save",disabled:!w||S,children:S?t("Saving…"):t("Save")})]})]}),e(W,{open:O&&R!==void 0,title:D.find((n)=>n.id===R)?.title??"",onClose:()=>M(void 0),children:e("div",{className:"stack",children:D.find((n)=>n.id===R)?.node})}),e(ge,{open:K!==void 0,title:t("Discard your changes?"),confirmLabel:t("Discard"),cancelLabel:t("Keep editing"),tone:"danger",onClose:()=>E(void 0),onConfirm:se,children:e("p",{children:t("The new look for {name} has not been saved.",{name:a.displayName})})})]})}var Y=(a)=>t(ue[a]);function be(a){let l=a.base.colors,h=q(()=>Lt({class:a.id,colors:l}),[a.id,l]);return e(te,{data:{"data-class":a.id},spec:h,size:56,label:N("class",a.id),hint:V(a.id),pressed:a.pressed,onPick:a.onPick})}export{He as CharacterCreator};
|