@fungi.computer/tourtois 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -2
  3. package/dist/AgentMcpServers.d.ts +34 -0
  4. package/dist/AgentMcpServers.js +124 -0
  5. package/dist/AppAccessConsent.d.ts +23 -0
  6. package/dist/AppAccessConsent.js +122 -0
  7. package/dist/AppCallPermissions.d.ts +9 -0
  8. package/dist/AppCallPermissions.js +21 -0
  9. package/dist/AppDesktopSettings.d.ts +11 -0
  10. package/dist/AppDesktopSettings.js +102 -0
  11. package/dist/AppPane.d.ts +37 -0
  12. package/dist/AppPane.js +184 -0
  13. package/dist/AppWorkbench.d.ts +44 -0
  14. package/dist/AppWorkbench.js +575 -0
  15. package/dist/AvatarPicker.d.ts +7 -0
  16. package/dist/AvatarPicker.js +78 -0
  17. package/dist/AvatarPreview.d.ts +10 -0
  18. package/dist/AvatarPreview.js +6 -0
  19. package/dist/DesktopMenuBar.d.ts +18 -0
  20. package/dist/DesktopMenuBar.js +23 -0
  21. package/dist/FocusedAppMenus.d.ts +2 -0
  22. package/dist/FocusedAppMenus.js +10 -0
  23. package/dist/Keys.d.ts +131 -0
  24. package/dist/Keys.js +201 -0
  25. package/dist/MushroomMark.d.ts +2 -0
  26. package/dist/MushroomMark.js +5 -0
  27. package/dist/SettingsHome.d.ts +18 -0
  28. package/dist/SettingsHome.js +48 -0
  29. package/dist/SettingsNavigation.d.ts +17 -0
  30. package/dist/SettingsNavigation.js +153 -0
  31. package/dist/SystemSettings.d.ts +24 -0
  32. package/dist/SystemSettings.js +177 -0
  33. package/dist/TeamDesktop.d.ts +36 -0
  34. package/dist/TeamDesktop.js +39 -0
  35. package/dist/WorkbenchAppBar.d.ts +5 -0
  36. package/dist/WorkbenchAppBar.js +12 -0
  37. package/dist/app-authority.d.ts +150 -0
  38. package/dist/app-authority.js +41 -0
  39. package/dist/app-directory-reconciliation.d.ts +14 -0
  40. package/dist/app-directory-reconciliation.js +72 -0
  41. package/dist/app-directory.d.ts +206 -0
  42. package/dist/app-directory.js +21 -0
  43. package/dist/app-icon.d.ts +9 -0
  44. package/dist/app-icon.js +27 -0
  45. package/dist/app-launch.d.ts +53 -0
  46. package/dist/app-launch.js +204 -0
  47. package/dist/app-menus.d.ts +6 -0
  48. package/dist/app-menus.js +81 -0
  49. package/dist/app-open-url.d.ts +8 -0
  50. package/dist/app-open-url.js +63 -0
  51. package/dist/app-surface.d.ts +62 -0
  52. package/dist/app-surface.js +10 -0
  53. package/dist/app-windows.d.ts +107 -0
  54. package/dist/app-windows.js +21 -0
  55. package/dist/chrome.css +153 -0
  56. package/dist/command-dialogs.d.ts +42 -0
  57. package/dist/command-dialogs.js +194 -0
  58. package/dist/desktop/Desktop.d.ts +34 -0
  59. package/dist/desktop/Desktop.js +275 -0
  60. package/dist/desktop/consent.d.ts +4 -0
  61. package/dist/desktop/consent.js +64 -0
  62. package/dist/desktop/gill-frame.d.ts +14 -0
  63. package/dist/desktop/gill-frame.js +41 -0
  64. package/dist/desktop/gill-param-picker.d.ts +15 -0
  65. package/dist/desktop/gill-param-picker.js +145 -0
  66. package/dist/desktop/launcher-gill.d.ts +20 -0
  67. package/dist/desktop/launcher-gill.js +49 -0
  68. package/dist/desktop/own-launchers.d.ts +9 -0
  69. package/dist/desktop/own-launchers.js +9 -0
  70. package/dist/desktop/row-gill.d.ts +24 -0
  71. package/dist/desktop/row-gill.js +136 -0
  72. package/dist/desktop-api.d.ts +63 -0
  73. package/dist/desktop-api.js +31 -0
  74. package/dist/desktop-client.d.ts +19 -0
  75. package/dist/desktop-client.js +127 -0
  76. package/dist/desktop-layout.d.ts +117 -0
  77. package/dist/desktop-layout.js +305 -0
  78. package/dist/desktop-visibility.d.ts +8 -0
  79. package/dist/desktop-visibility.js +5 -0
  80. package/dist/layers.d.ts +5 -0
  81. package/dist/layers.js +31 -0
  82. package/dist/main.d.ts +2 -0
  83. package/dist/main.js +17 -0
  84. package/dist/member-avatar-cache.d.ts +15 -0
  85. package/dist/member-avatar-cache.js +69 -0
  86. package/dist/member-avatar.d.ts +39 -0
  87. package/dist/member-avatar.js +88 -0
  88. package/dist/menu-bar.d.ts +5 -0
  89. package/dist/menu-bar.js +5 -0
  90. package/dist/model.d.ts +6 -0
  91. package/dist/model.js +13 -0
  92. package/dist/oyster-platform-controls.d.ts +4 -0
  93. package/dist/oyster-platform-controls.js +107 -0
  94. package/dist/platform-controls.d.ts +84 -0
  95. package/dist/platform-controls.js +266 -0
  96. package/dist/queries.d.ts +7 -0
  97. package/dist/queries.js +7 -0
  98. package/dist/session-registry.d.ts +16 -0
  99. package/dist/session-registry.js +69 -0
  100. package/dist/session-selection.d.ts +6 -0
  101. package/dist/session-selection.js +22 -0
  102. package/dist/settings-leave-guard.d.ts +5 -0
  103. package/dist/settings-leave-guard.js +9 -0
  104. package/dist/settings-navigation.css +129 -0
  105. package/dist/settings-routes.d.ts +118 -0
  106. package/dist/settings-routes.js +216 -0
  107. package/dist/settings-sections.d.ts +74 -0
  108. package/dist/settings-sections.js +17 -0
  109. package/dist/shell-commands.d.ts +15 -0
  110. package/dist/shell-commands.js +95 -0
  111. package/dist/shell-host.d.ts +52 -0
  112. package/dist/shell-host.js +224 -0
  113. package/dist/shell-module.d.ts +12 -0
  114. package/dist/shell-module.js +17 -0
  115. package/dist/shell-release.d.ts +3 -0
  116. package/dist/shell-release.js +4 -0
  117. package/dist/shell.css +858 -0
  118. package/dist/shell.d.ts +6 -0
  119. package/dist/shell.js +83 -0
  120. package/dist/spa.css +11 -0
  121. package/dist/status-bar.d.ts +9 -0
  122. package/dist/status-bar.js +51 -0
  123. package/dist/team-directory.d.ts +3 -0
  124. package/dist/team-directory.js +6 -0
  125. package/dist/use-window-motion.d.ts +3 -0
  126. package/dist/use-window-motion.js +37 -0
  127. package/dist/useAppOpenUrlHandoff.d.ts +11 -0
  128. package/dist/useAppOpenUrlHandoff.js +62 -0
  129. package/dist/useAppWindowManager.d.ts +323 -0
  130. package/dist/useAppWindowManager.js +47 -0
  131. package/dist/useDirectoryCommands.d.ts +12 -0
  132. package/dist/useDirectoryCommands.js +80 -0
  133. package/dist/workbench.d.ts +3 -0
  134. package/dist/workbench.js +2 -0
  135. package/package.json +222 -3
@@ -0,0 +1,184 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { IconButton } from "@fungi.computer/caps/components/icon-button";
3
+ import { AppStatusBar, StatusBarPicker, } from "@fungi.computer/caps/blocks/app-status-bar";
4
+ import { Sigil } from "@fungi.computer/sigils";
5
+ import { WindowActions, WindowBody, WindowFrame, WindowHeader, } from "@fungi.computer/caps/components/window";
6
+ import { Settings, ShieldCheck } from "lucide-react";
7
+ import { WindowStatusItem } from "./status-bar.js";
8
+ import { useLayer, useMaosaicoItem, useMaosaicoLayout, } from "@fungi.computer/maosaico";
9
+ import { AppError, } from "@fungi.computer/agar";
10
+ import { useEffect, useRef, useState } from "react";
11
+ import { AppIcon } from "./app-icon.js";
12
+ import { useWindowMotion } from "./use-window-motion.js";
13
+ import { backHint } from "./shell-commands.js";
14
+ import { createAppWindowManager, } from "./app-windows.js";
15
+ import { launchComputerId } from "./app-launch.js";
16
+ const windowStatusLabel = (projection) => {
17
+ if (projection.status === "error")
18
+ return `${projection.launch.title} unavailable`;
19
+ if (projection.status === "loading")
20
+ return `${projection.launch.title} opening…`;
21
+ return projection.launch.title;
22
+ };
23
+ /** The focused window's App-level settings; its Computer lives in its status bar. */
24
+ export function FocusedWindowControls({ app, onOpenSettings, onOpenPermissions, projection, }) {
25
+ if (!app)
26
+ return null;
27
+ return (_jsxs("div", { className: "tourtois-focused-controls", role: "group", "aria-label": `${projection.launch.title} settings`, children: [_jsx(IconButton, { size: "responsive", "aria-label": `Permissions for ${projection.launch.title}`, title: "App permissions", icon: _jsx(ShieldCheck, {}), onClick: onOpenPermissions }), _jsx(IconButton, { size: "responsive", "aria-label": `Settings for ${projection.launch.title}`, title: "App settings", icon: _jsx(Settings, {}), onClick: onOpenSettings })] }));
28
+ }
29
+ export function AppPane({ projection, icon, manager, onError, index, focusWindow, afterHide, onBack, onSelectComputer, }) {
30
+ const containerRef = useRef(null);
31
+ const [computerPickerOpen, setComputerPickerOpen] = useState(false);
32
+ useEffect(() => {
33
+ if (projection.launch.computers === undefined)
34
+ return;
35
+ return manager.registerComputerChoice(projection.windowId, () => {
36
+ setComputerPickerOpen(true);
37
+ });
38
+ }, [
39
+ manager,
40
+ projection.windowId,
41
+ projection.generation,
42
+ projection.launch.computers,
43
+ ]);
44
+ useEffect(() => {
45
+ if (containerRef.current)
46
+ containerRef.current.inert = projection.status !== "ready";
47
+ }, [projection.status]);
48
+ const binding = useMaosaicoItem({
49
+ id: projection.windowId,
50
+ frame: {
51
+ x: 24 + index * 40,
52
+ y: 24 + index * 32,
53
+ width: 600,
54
+ height: 480,
55
+ },
56
+ minima: { width: 320, height: 360 },
57
+ }, { participating: projection.status !== "minimized" });
58
+ const layout = useMaosaicoLayout();
59
+ const element = useWindowMotion(binding, layout.interacting);
60
+ const zoomed = layout.zoomedId === projection.windowId;
61
+ const zoom = () => {
62
+ layout.zoom(zoomed ? null : projection.windowId);
63
+ focusWindow(projection.windowId);
64
+ };
65
+ const close = () => {
66
+ void manager
67
+ .close(projection.windowId)
68
+ .then(() => {
69
+ // The App may veto a close to protect unsaved work.
70
+ if (!manager
71
+ .read()
72
+ .windows.some((item) => item.windowId === projection.windowId))
73
+ afterHide(projection.windowId);
74
+ })
75
+ .catch((cause) => {
76
+ console.error("App workbench operation failed", cause);
77
+ onError("App could not be closed.");
78
+ });
79
+ };
80
+ useEffect(() => {
81
+ const parent = containerRef.current;
82
+ if (!parent)
83
+ return;
84
+ parent.appendChild(projection.container);
85
+ manager.attach(projection.windowId);
86
+ return () => {
87
+ projection.container.remove();
88
+ };
89
+ }, [manager, projection.container, projection.windowId]);
90
+ return (_jsxs(WindowFrame, { ref: element, className: "tourtois-pane tourtois-app-pane", "aria-label": projection.launch.title, active: binding.active, floating: layout.mode === "floating" && !zoomed, "data-window-id": projection.windowId, "data-app-id": projection.launch.appId, "data-installation-id": projection.launch.installationId ?? undefined, "data-surface-id": projection.launch.surfaceId, "data-release-id": projection.launch.releaseId, hidden: projection.status === "minimized" || !binding.visible, onFocusCapture: () => {
91
+ binding.focus();
92
+ }, onPointerDownCapture: () => {
93
+ binding.focus();
94
+ },
95
+ // The mouse back button over this window's chrome is its App's Back;
96
+ // inside the App, Agar maps it the same way.
97
+ onMouseUp: (event) => {
98
+ if (event.button !== 3 || projection.navigation?.canGoBack !== true)
99
+ return;
100
+ event.preventDefault();
101
+ onBack(projection.windowId);
102
+ }, style: binding.stackingStyle, children: [_jsx(WindowHeader, { title: projection.launch.title, ...(projection.navigation?.title === undefined
103
+ ? {}
104
+ : { subtitle: projection.navigation.title }), density: layout.mode === "tiled" ? "compact" : "regular", icon: _jsx(AppIcon, { roles: projection.launch.roles, icon: icon }), ...(projection.navigation?.canGoBack === true
105
+ ? {
106
+ back: {
107
+ label: `Back in ${projection.launch.title}`,
108
+ hint: backHint(),
109
+ onBack: () => {
110
+ onBack(projection.windowId);
111
+ },
112
+ },
113
+ }
114
+ : {}), handleProps: {
115
+ ...binding.props,
116
+ onClick: binding.focus,
117
+ onDoubleClick: zoom,
118
+ }, actions: _jsx(_Fragment, { children: _jsx(WindowActions, { title: projection.launch.title, maximized: zoomed, ...(layout.mode === "tiled" &&
119
+ layout.order[0] !== projection.windowId
120
+ ? {
121
+ onPromote: () => {
122
+ const main = layout.order[0];
123
+ if (main)
124
+ layout.swap(projection.windowId, main);
125
+ focusWindow(projection.windowId);
126
+ },
127
+ }
128
+ : {}), onToggleMaximize: zoom, onMinimize: () => {
129
+ void manager
130
+ .minimize(projection.windowId)
131
+ .then(() => {
132
+ afterHide(projection.windowId);
133
+ })
134
+ .catch((cause) => {
135
+ console.error("App workbench operation failed", cause);
136
+ onError("App could not be minimized.");
137
+ });
138
+ }, onClose: close }) }) }), projection.status === "loading" ? (_jsxs("div", { className: "tourtois-app-loading", role: "status", children: [_jsx(AppIcon, { roles: projection.launch.roles, icon: icon }), _jsxs("div", { children: [_jsxs("strong", { children: ["Opening ", projection.launch.title, "\u2026"] }), _jsx("span", { children: "Preparing this App for your workspace." })] })] })) : null, projection.status === "error" &&
139
+ !(projection.error instanceof AppError &&
140
+ projection.error.code === "DISCONNECTED") ? (_jsx("p", { className: "tourtois-window-status", role: "status", children: windowStatusLabel(projection) })) : null, _jsx(WindowBody, { ref: containerRef, className: "tourtois-pane-body", hidden: projection.status === "error" }), _jsx(WindowStatusBar, { projection: projection, computerPickerOpen: computerPickerOpen, onComputerPickerOpenChange: setComputerPickerOpen, onSelectComputer: (computerId) => {
141
+ onSelectComputer(projection.windowId, computerId);
142
+ }, surface: () => containerRef.current, onAction: (action) => {
143
+ void manager
144
+ .activateStatus(projection.windowId, action)
145
+ .catch((cause) => {
146
+ console.error("App workbench operation failed", cause);
147
+ onError("App could not handle that action.");
148
+ });
149
+ } })] }));
150
+ }
151
+ /**
152
+ * One window's status bar, owned by the shell like its title bar: the
153
+ * window's Computer first (only the person changes it, here), then the items
154
+ * the App declared as data. The shell renders every item with Caps pieces and
155
+ * hands the person's use back to the App. A window with neither has no bar.
156
+ */
157
+ export function WindowStatusBar({ projection, onSelectComputer, onAction, surface, computerPickerOpen, onComputerPickerOpenChange, }) {
158
+ const popover = useLayer("popover");
159
+ const { computers, title } = projection.launch;
160
+ const items = projection.statusItems;
161
+ if (computers === undefined && items.length === 0)
162
+ return null;
163
+ const anchorFor = (key) => {
164
+ const origin = surface?.()?.getBoundingClientRect();
165
+ if (!origin)
166
+ return undefined;
167
+ const rect = key.getBoundingClientRect();
168
+ return {
169
+ start: Math.max(0, rect.left - origin.left),
170
+ width: Math.max(0, rect.width),
171
+ };
172
+ };
173
+ const render = (item) => (_jsx(WindowStatusItem, { item: item, container: popover, onAction: onAction, anchorFor: anchorFor }, item.id));
174
+ const end = items.filter((item) => item.end === true);
175
+ const start = items.filter((item) => item.end !== true);
176
+ return (_jsx(AppStatusBar, { className: "tourtois-window-status-bar", "aria-label": `${title} status`, attachment: computers === undefined ? undefined : (_jsx(StatusBarPicker, { ...(computerPickerOpen === undefined
177
+ ? {}
178
+ : { open: computerPickerOpen }), ...(onComputerPickerOpenChange === undefined
179
+ ? {}
180
+ : { onOpenChange: onComputerPickerOpenChange }), noun: "Computer", pluralNoun: "Computers", accessibleLabel: `Choose Computer for ${title}`, icon: _jsx(Sigil, { name: "computer", size: 16 }), options: computers.map((computer) => ({
181
+ id: computer.computerId,
182
+ label: computer.name,
183
+ })), value: launchComputerId(projection.launch.href), emptyMessage: "No Computers are granted to this App", disabled: projection.status === "loading", onSelect: onSelectComputer })), end: end.length === 0 ? undefined : end.map(render), children: start.length === 0 ? undefined : start.map(render) }));
184
+ }
@@ -0,0 +1,44 @@
1
+ import type { DesktopMethods } from "./desktop-api.js";
2
+ import type { AppOpenInput } from "@fungi.computer/agar/apps";
3
+ import { type AppBarItem } from "@fungi.computer/caps/blocks/app-bar";
4
+ import { type ReactNode, type RefObject } from "react";
5
+ import type { WorkbenchDirectory } from "@fungi.computer/oyster/shell/workbench-directory";
6
+ import { type ComputerOption } from "./app-launch.js";
7
+ import type { PlatformControls } from "./platform-controls.js";
8
+ import type { AppStorage } from "@fungi.computer/agar/storage";
9
+ import type { DesktopGillTransport } from "./desktop/row-gill.js";
10
+ import type { SettingsLocation } from "./settings-routes.js";
11
+ export type AppWorkbenchProps = Readonly<{
12
+ teamId: string;
13
+ teamName: string;
14
+ initialComputerId: string | null;
15
+ computers: readonly ComputerOption[];
16
+ computersUnavailable: boolean;
17
+ paneLayerRef: RefObject<HTMLDivElement>;
18
+ phone: boolean;
19
+ extraPanes?: (context: {
20
+ activeId: string | null;
21
+ order: readonly string[];
22
+ focus: (id: string) => void;
23
+ }) => ReactNode;
24
+ initialFocusId?: string;
25
+ onLayoutChange?: ((tiled: boolean) => void) | undefined;
26
+ extraLaunchers?: readonly AppBarItem[];
27
+ settingsLaunchers?: readonly Readonly<{
28
+ id: string;
29
+ label: string;
30
+ icon?: ReactNode;
31
+ location: SettingsLocation;
32
+ }>[];
33
+ systemMenuItems?: ReactNode;
34
+ /** Read the Team's App directory through the host's `directory()` port. */
35
+ directoryReader: () => Promise<WorkbenchDirectory>;
36
+ /** Take the host address's App-open handoff once, instead of this URL's. */
37
+ takeAppOpenRequest?: () => Promise<AppOpenInput | null>;
38
+ /** Team administration, rendered by the host with the owner's authority. */
39
+ platform: PlatformControls;
40
+ desktopStorage: AppStorage;
41
+ desktopMethods: DesktopMethods;
42
+ gills: DesktopGillTransport;
43
+ }>;
44
+ export declare function AppWorkbench({ paneLayerRef, phone, teamId, teamName, initialComputerId, computers, computersUnavailable, extraPanes, initialFocusId, onLayoutChange, extraLaunchers, settingsLaunchers, systemMenuItems, directoryReader, takeAppOpenRequest, platform, desktopStorage, desktopMethods, gills, }: AppWorkbenchProps): import("react/jsx-runtime").JSX.Element;