oomi-ai 0.2.39 → 0.2.40
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/README.md +5 -3
- package/lib/personaRuntimeManager.js +21 -17
- package/lib/personaRuntimeProcess.js +392 -49
- package/lib/scaffold.js +14 -14
- package/openclaw.plugin.json +1 -1
- package/package.json +10 -8
- package/templates/persona-app/package.json +6 -4
- package/templates/persona-app/src/App.css +564 -79
- package/templates/persona-app/src/App.tsx +2 -2
- package/templates/persona-app/src/main.tsx +13 -0
- package/templates/persona-app/src/pages/HomePage.tsx +120 -39
- package/templates/persona-app/src/pages/ScenePage.tsx +2 -15
- package/templates/persona-app/src/persona/notes.ts +3 -1
- package/templates/persona-app/src/spatial.ts +82 -0
- package/templates/persona-app/template.json +1 -1
- package/templates/persona-app/vendor/webspatial/FORK.md +6 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/LICENSE +21 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.d.ts +906 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js +75 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.d.ts +906 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js +3131 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/core-sdk/package.json +45 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/LICENSE +21 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.d.ts +365 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js +4296 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.d.ts +82 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js +66 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.d.ts +2 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js +18 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.d.ts +5 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js +66 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.d.ts +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js +18 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.d.ts +365 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js +4336 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js.map +1 -0
- package/templates/persona-app/vendor/webspatial/react-sdk/package.json +94 -0
- package/templates/persona-app/vite.config.ts +13 -0
|
@@ -6,8 +6,8 @@ export default function App() {
|
|
|
6
6
|
return (
|
|
7
7
|
<Router basename={__XR_ENV_BASE__}>
|
|
8
8
|
<Routes>
|
|
9
|
-
<Route
|
|
10
|
-
<Route path="
|
|
9
|
+
<Route index element={<HomePage />} />
|
|
10
|
+
<Route path="scene" element={<ScenePage />} />
|
|
11
11
|
</Routes>
|
|
12
12
|
</Router>
|
|
13
13
|
);
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { StrictMode } from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { snapdom } from "@zumer/snapdom";
|
|
4
|
+
import html2canvas from "html2canvas";
|
|
3
5
|
import "./index.css";
|
|
4
6
|
import App from "./App";
|
|
5
7
|
|
|
8
|
+
// WebSpatial AndroidXR uses DOM capture to turn enable-xr surfaces into native panels.
|
|
9
|
+
// Expose both libraries globally so the SDK can pick the fast path when available.
|
|
10
|
+
(window as Window & {
|
|
11
|
+
snapdom?: typeof snapdom;
|
|
12
|
+
html2canvas?: typeof html2canvas;
|
|
13
|
+
}).snapdom = snapdom;
|
|
14
|
+
(window as Window & {
|
|
15
|
+
snapdom?: typeof snapdom;
|
|
16
|
+
html2canvas?: typeof html2canvas;
|
|
17
|
+
}).html2canvas = html2canvas;
|
|
18
|
+
|
|
6
19
|
createRoot(document.getElementById("root")!).render(
|
|
7
20
|
<StrictMode>
|
|
8
21
|
<App />
|
|
@@ -1,70 +1,151 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect } from "react";
|
|
2
2
|
import { Link } from "react-router-dom";
|
|
3
3
|
import "../App.css";
|
|
4
4
|
import { personaConfig } from "../persona/config";
|
|
5
5
|
import { personaNotes } from "../persona/notes";
|
|
6
|
+
import {
|
|
7
|
+
WEBSPATIAL_FORK_COMMIT,
|
|
8
|
+
configurePersonaScene,
|
|
9
|
+
detectSpatialEnvironment,
|
|
10
|
+
openPersonaScene,
|
|
11
|
+
xrStyle,
|
|
12
|
+
} from "../spatial";
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const previewCards = [
|
|
15
|
+
{
|
|
16
|
+
tone: "ocean",
|
|
17
|
+
title: "Focused surface",
|
|
18
|
+
body: "Use the persona site as a real operator board, planner, studio, or dashboard instead of another chat clone.",
|
|
19
|
+
depth: 34,
|
|
20
|
+
material: "translucent",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
tone: "coral",
|
|
24
|
+
title: "Depth-authored cards",
|
|
25
|
+
body: "Key controls should declare their own depth and material so AndroidXR reads them as layered surfaces.",
|
|
26
|
+
depth: 84,
|
|
27
|
+
material: "thin",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
tone: "violet",
|
|
31
|
+
title: "Persistent handoff",
|
|
32
|
+
body: "Let Oomi keep the live conversation thread while the persona page stays focused on structured work.",
|
|
33
|
+
depth: 140,
|
|
34
|
+
material: "thick",
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
type HomePageProps = {
|
|
39
|
+
sceneMode?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function HomePage({ sceneMode = false }: HomePageProps) {
|
|
43
|
+
const environment = detectSpatialEnvironment();
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
configurePersonaScene();
|
|
47
|
+
}, []);
|
|
18
48
|
|
|
19
49
|
return (
|
|
20
|
-
<main className="persona-shell">
|
|
50
|
+
<main className="persona-shell" enable-xr-monitor={sceneMode || undefined}>
|
|
21
51
|
<section className="persona-header">
|
|
22
|
-
<div className="persona-panel persona-hero">
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
52
|
+
<div className="persona-panel persona-hero" enable-xr style={xrStyle(22, "translucent")}>
|
|
53
|
+
<div>
|
|
54
|
+
<p className="persona-eyebrow">{sceneMode ? "Spatial Persona Surface" : "WebSpatial Persona"}</p>
|
|
55
|
+
<h1 className="persona-title">{personaConfig.name}</h1>
|
|
56
|
+
<p className="persona-description">{personaConfig.description}</p>
|
|
57
|
+
</div>
|
|
26
58
|
|
|
27
59
|
<div className="persona-actions">
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
{!sceneMode ? (
|
|
61
|
+
<>
|
|
62
|
+
<button className="persona-button" onClick={openPersonaScene} enable-xr style={xrStyle(52, "regular")}>
|
|
63
|
+
Launch Spatial Surface
|
|
64
|
+
</button>
|
|
65
|
+
<Link className="persona-link" to="/scene" target="_blank" enable-xr style={xrStyle(92, "thin")}>
|
|
66
|
+
Open Spatial Preview
|
|
67
|
+
</Link>
|
|
68
|
+
</>
|
|
69
|
+
) : (
|
|
70
|
+
<Link className="persona-button" to="/" enable-xr style={xrStyle(52, "regular")}>
|
|
71
|
+
Return To Browser View
|
|
72
|
+
</Link>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div className="persona-preview-strip">
|
|
77
|
+
{previewCards.map(card => (
|
|
78
|
+
<article
|
|
79
|
+
key={card.title}
|
|
80
|
+
className="persona-preview-card"
|
|
81
|
+
data-tone={card.tone}
|
|
82
|
+
enable-xr
|
|
83
|
+
style={xrStyle(card.depth, card.material)}
|
|
84
|
+
>
|
|
85
|
+
<h3>{card.title}</h3>
|
|
86
|
+
<p>{card.body}</p>
|
|
87
|
+
</article>
|
|
88
|
+
))}
|
|
34
89
|
</div>
|
|
35
90
|
</div>
|
|
36
91
|
|
|
37
|
-
<aside className="persona-panel persona-runtime">
|
|
92
|
+
<aside className="persona-panel persona-runtime" enable-xr style={xrStyle(72, "thin")}>
|
|
38
93
|
<p className="persona-eyebrow">Runtime</p>
|
|
39
94
|
<div className="runtime-list">
|
|
40
|
-
<div
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
95
|
+
<div className="runtime-row">
|
|
96
|
+
<span className="runtime-label">Slug</span>
|
|
97
|
+
<span className="runtime-value">{personaConfig.slug}</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div className="runtime-row">
|
|
100
|
+
<span className="runtime-label">SDK</span>
|
|
101
|
+
<span className="runtime-value">@webspatial/react-sdk {environment.sdkVersion}</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div className="runtime-row">
|
|
104
|
+
<span className="runtime-label">Bridge</span>
|
|
105
|
+
<span className="runtime-value">{environment.hasBridge ? "available" : "waiting"}</span>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="runtime-row">
|
|
108
|
+
<span className="runtime-label">Native</span>
|
|
109
|
+
<span className="runtime-value">{environment.nativeVersion ?? "browser fallback"}</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="runtime-row">
|
|
112
|
+
<span className="runtime-label">Fork</span>
|
|
113
|
+
<span className="runtime-value">{WEBSPATIAL_FORK_COMMIT.slice(0, 7)}</span>
|
|
114
|
+
</div>
|
|
44
115
|
</div>
|
|
45
116
|
</aside>
|
|
46
117
|
</section>
|
|
47
118
|
|
|
48
119
|
<section className="persona-grid">
|
|
49
|
-
<article className="persona-panel persona-card">
|
|
50
|
-
<h2>
|
|
120
|
+
<article className="persona-panel persona-card" enable-xr style={xrStyle(34, "translucent")}>
|
|
121
|
+
<h2>What Good XR Feels Like</h2>
|
|
122
|
+
<p>
|
|
123
|
+
Treat the generated persona site like a spatial work surface. The XR route should keep
|
|
124
|
+
the actual persona shell intact, then layer depth, materials, and anchored surfaces on
|
|
125
|
+
top instead of swapping in a disconnected demo board.
|
|
126
|
+
</p>
|
|
51
127
|
<p>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
128
|
+
{sceneMode
|
|
129
|
+
? "This route is the AndroidXR work surface. It should feel like the same persona site, just spatialized."
|
|
130
|
+
: "This home route exists for browser parity and one-click launch into the spatial work surface."}
|
|
55
131
|
</p>
|
|
56
|
-
|
|
132
|
+
</article>
|
|
133
|
+
|
|
134
|
+
<article className="persona-panel persona-card" enable-xr style={xrStyle(74, "thin")}>
|
|
135
|
+
<h2>Editing Notes</h2>
|
|
136
|
+
<ul className="persona-note-list">
|
|
57
137
|
{personaNotes.map(note => (
|
|
58
138
|
<li key={note}>{note}</li>
|
|
59
139
|
))}
|
|
60
140
|
</ul>
|
|
61
141
|
</article>
|
|
62
142
|
|
|
63
|
-
<article className="persona-panel persona-card persona-scene-card" enable-xr>
|
|
64
|
-
<h2>Scene
|
|
65
|
-
<p
|
|
66
|
-
|
|
67
|
-
|
|
143
|
+
<article className="persona-panel persona-card persona-scene-card" enable-xr style={xrStyle(118, "regular")}>
|
|
144
|
+
<h2>Scene Contract</h2>
|
|
145
|
+
<p>
|
|
146
|
+
The page should import WebSpatial helpers, self-configure the scene, and keep using
|
|
147
|
+
explicit <code>enable-xr</code>, <code>--xr-back</code>, and
|
|
148
|
+
<code> --xr-background-material</code> values on important surfaces.
|
|
68
149
|
</p>
|
|
69
150
|
</article>
|
|
70
151
|
</section>
|
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import { personaConfig } from "../persona/config";
|
|
1
|
+
import { HomePage } from "./HomePage";
|
|
3
2
|
|
|
4
3
|
export function ScenePage() {
|
|
5
|
-
return
|
|
6
|
-
<main className="scene-shell">
|
|
7
|
-
<section className="persona-panel scene-panel">
|
|
8
|
-
<p className="persona-eyebrow">Scene</p>
|
|
9
|
-
<h1>{personaConfig.name}</h1>
|
|
10
|
-
<p>{personaConfig.description}</p>
|
|
11
|
-
<p>
|
|
12
|
-
This route is intentionally separate so WebSpatial scene launching has a dedicated
|
|
13
|
-
surface. Extend this page with persona-specific spatial UI.
|
|
14
|
-
</p>
|
|
15
|
-
</section>
|
|
16
|
-
</main>
|
|
17
|
-
);
|
|
4
|
+
return <HomePage sceneMode />;
|
|
18
5
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const personaNotes = [
|
|
2
2
|
"Keep persona-specific logic inside src/persona/ unless Oomi explicitly instructs otherwise.",
|
|
3
|
-
"Preserve the WebSpatial router basename and scene-launch flow.",
|
|
3
|
+
"Preserve the WebSpatial router basename, the scene self-init helper, and the scene-launch flow.",
|
|
4
|
+
"Keep using the vendored AndroidXR-enabled WebSpatial fork instead of switching back to the stock npm packages.",
|
|
5
|
+
"Author key surfaces with explicit enable-xr, --xr-back, and --xr-background-material values so the page reads as spatial instead of flat.",
|
|
4
6
|
"Do not remove public/oomi.runtime.json, public/oomi.health.json, or public/manifest.webmanifest.",
|
|
5
7
|
];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
import { initScene, version as webSpatialSdkVersion } from "@webspatial/react-sdk";
|
|
3
|
+
|
|
4
|
+
export const PERSONA_SCENE_NAME = "personaScene";
|
|
5
|
+
export const WEBSPATIAL_FORK_REPOSITORY = "https://github.com/zill4/webspatial-sdk";
|
|
6
|
+
export const WEBSPATIAL_FORK_COMMIT = "b2746721e4fe6b4f86dac0ea55938074eea00cda";
|
|
7
|
+
|
|
8
|
+
type SpatialWindow = Window & {
|
|
9
|
+
webspatialBridge?: unknown;
|
|
10
|
+
__WebSpatialData?: {
|
|
11
|
+
getNativeVersion?: () => string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type SpatialEnvironmentSnapshot = {
|
|
16
|
+
isWebSpatial: boolean;
|
|
17
|
+
sdkVersion: string;
|
|
18
|
+
nativeVersion: string | null;
|
|
19
|
+
hasBridge: boolean;
|
|
20
|
+
hasWebSpatialData: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type XrStyle = CSSProperties & {
|
|
24
|
+
"--xr-back"?: number | string;
|
|
25
|
+
"--xr-background-material"?: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function xrStyle(back: number, material: string): XrStyle {
|
|
29
|
+
return {
|
|
30
|
+
"--xr-back": `${back}px`,
|
|
31
|
+
"--xr-background-material": material,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function detectSpatialEnvironment(): SpatialEnvironmentSnapshot {
|
|
36
|
+
const typedWindow = window as SpatialWindow;
|
|
37
|
+
const userAgent = navigator.userAgent;
|
|
38
|
+
const userAgentVersion = userAgent.match(/WebSpatial\/([\d.]+)/)?.[1] ?? null;
|
|
39
|
+
const nativeVersion = (() => {
|
|
40
|
+
try {
|
|
41
|
+
return typedWindow.__WebSpatialData?.getNativeVersion?.() ?? userAgentVersion;
|
|
42
|
+
} catch {
|
|
43
|
+
return userAgentVersion;
|
|
44
|
+
}
|
|
45
|
+
})();
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
isWebSpatial: userAgent.includes("WebSpatial/"),
|
|
49
|
+
sdkVersion: webSpatialSdkVersion,
|
|
50
|
+
nativeVersion,
|
|
51
|
+
hasBridge: typeof typedWindow.webspatialBridge !== "undefined",
|
|
52
|
+
hasWebSpatialData: typeof typedWindow.__WebSpatialData !== "undefined",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function configurePersonaScene() {
|
|
57
|
+
initScene(
|
|
58
|
+
PERSONA_SCENE_NAME,
|
|
59
|
+
previous => ({
|
|
60
|
+
...previous,
|
|
61
|
+
defaultSize: {
|
|
62
|
+
width: 1440,
|
|
63
|
+
height: 960,
|
|
64
|
+
},
|
|
65
|
+
resizability: {
|
|
66
|
+
minWidth: 960,
|
|
67
|
+
minHeight: 720,
|
|
68
|
+
maxWidth: 1800,
|
|
69
|
+
maxHeight: 1280,
|
|
70
|
+
},
|
|
71
|
+
worldAlignment: "gravityAligned",
|
|
72
|
+
worldScaling: "automatic",
|
|
73
|
+
baseplateVisibility: "hidden",
|
|
74
|
+
}),
|
|
75
|
+
{ type: "window" },
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function openPersonaScene() {
|
|
80
|
+
configurePersonaScene();
|
|
81
|
+
window.open(`${__XR_ENV_BASE__}/scene`, PERSONA_SCENE_NAME);
|
|
82
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
This persona template vendors the AndroidXR-capable WebSpatial runtime packages from:
|
|
2
|
+
|
|
3
|
+
- Repository: https://github.com/zill4/webspatial-sdk
|
|
4
|
+
- Commit: 8904ac8fec48fe49ee14d1739237bd1afb2894fe
|
|
5
|
+
|
|
6
|
+
Oomi uses these vendored packages for persona runtimes so OpenClaw installs the AndroidXR-enabled fork instead of the stock npm release.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Spatial Web
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|