oomi-ai 0.2.49 → 0.3.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.
Files changed (88) hide show
  1. package/README.md +227 -463
  2. package/agent_instructions.md +244 -234
  3. package/bin/oomi-ai.js +4028 -5797
  4. package/bin/sessionBridgeState.js +78 -78
  5. package/lib/openclawPaths.js +70 -71
  6. package/lib/openclawProfile.js +216 -216
  7. package/lib/personaApiClient.js +133 -303
  8. package/lib/spokenMetadata.js +137 -137
  9. package/openclaw.extension.js +341 -341
  10. package/openclaw.plugin.json +17 -17
  11. package/package.json +59 -59
  12. package/persona-app/README.md +27 -0
  13. package/persona-app/registry/v1.json +63 -0
  14. package/persona-app/schema/persona-app.v1.schema.json +90 -0
  15. package/skills/oomi/SKILL.md +165 -182
  16. package/skills/oomi/agent_instructions.md +99 -80
  17. package/lib/channelPluginClient.js +0 -119
  18. package/lib/openclawDevGateway.js +0 -384
  19. package/lib/personaJobExecutor.js +0 -139
  20. package/lib/personaJobPoller.js +0 -112
  21. package/lib/personaPortAllocator.js +0 -36
  22. package/lib/personaRuntimeManager.js +0 -496
  23. package/lib/personaRuntimeProcess.js +0 -924
  24. package/lib/personaRuntimeRegistry.js +0 -67
  25. package/lib/personaRuntimeSupervisor.js +0 -330
  26. package/lib/scaffold.js +0 -108
  27. package/lib/template.js +0 -45
  28. package/skills/oomi/config.json +0 -3
  29. package/skills/oomi/scripts/get_avatar_capabilities.py +0 -40
  30. package/skills/oomi/scripts/get_data.py +0 -49
  31. package/skills/oomi/scripts/install_agent_instructions.py +0 -78
  32. package/skills/oomi/scripts/send_goal.py +0 -53
  33. package/skills/oomi/scripts/sync.py +0 -46
  34. package/skills/oomi/setup.py +0 -41
  35. package/templates/persona-app/.env.example +0 -8
  36. package/templates/persona-app/README.md +0 -47
  37. package/templates/persona-app/eslint.config.js +0 -28
  38. package/templates/persona-app/index.html +0 -18
  39. package/templates/persona-app/oomi.runtime.json +0 -13
  40. package/templates/persona-app/package.json +0 -44
  41. package/templates/persona-app/persona/brief.md +0 -14
  42. package/templates/persona-app/persona.json +0 -14
  43. package/templates/persona-app/public/manifest.webmanifest +0 -8
  44. package/templates/persona-app/public/oomi.health.json +0 -6
  45. package/templates/persona-app/src/App.css +0 -379
  46. package/templates/persona-app/src/App.tsx +0 -17
  47. package/templates/persona-app/src/index.css +0 -53
  48. package/templates/persona-app/src/main.tsx +0 -23
  49. package/templates/persona-app/src/pages/HomePage.tsx +0 -127
  50. package/templates/persona-app/src/pages/ScenePage.tsx +0 -158
  51. package/templates/persona-app/src/persona/config.ts +0 -6
  52. package/templates/persona-app/src/persona/notes.ts +0 -9
  53. package/templates/persona-app/src/spatial.ts +0 -82
  54. package/templates/persona-app/src/vite-env.d.ts +0 -3
  55. package/templates/persona-app/template.json +0 -13
  56. package/templates/persona-app/tsconfig.app.json +0 -23
  57. package/templates/persona-app/tsconfig.json +0 -7
  58. package/templates/persona-app/tsconfig.node.json +0 -21
  59. package/templates/persona-app/vendor/webspatial/FORK.md +0 -6
  60. package/templates/persona-app/vendor/webspatial/core-sdk/LICENSE +0 -21
  61. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.d.ts +0 -906
  62. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js +0 -75
  63. package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js.map +0 -1
  64. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.d.ts +0 -906
  65. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js +0 -3131
  66. package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js.map +0 -1
  67. package/templates/persona-app/vendor/webspatial/core-sdk/package.json +0 -45
  68. package/templates/persona-app/vendor/webspatial/react-sdk/LICENSE +0 -21
  69. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.d.ts +0 -365
  70. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js +0 -4167
  71. package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js.map +0 -1
  72. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.d.ts +0 -82
  73. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js +0 -66
  74. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js.map +0 -1
  75. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.d.ts +0 -2
  76. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js +0 -18
  77. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js.map +0 -1
  78. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.d.ts +0 -5
  79. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js +0 -66
  80. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js.map +0 -1
  81. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.d.ts +0 -1
  82. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js +0 -18
  83. package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js.map +0 -1
  84. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.d.ts +0 -365
  85. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js +0 -4207
  86. package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js.map +0 -1
  87. package/templates/persona-app/vendor/webspatial/react-sdk/package.json +0 -94
  88. package/templates/persona-app/vite.config.ts +0 -31
@@ -1,78 +0,0 @@
1
- import argparse
2
- import os
3
- import sys
4
-
5
- DEFAULT_MARKER_START = "<oomi-agent-instructions>"
6
- DEFAULT_MARKER_END = "</oomi-agent-instructions>"
7
-
8
-
9
- def read_file(path: str) -> str:
10
- with open(path, "r") as f:
11
- return f.read()
12
-
13
-
14
- def write_file(path: str, content: str) -> None:
15
- with open(path, "w") as f:
16
- f.write(content)
17
-
18
-
19
- def get_default_agents_file() -> str:
20
- # Prefer explicit workspace env, otherwise use repo root if detected
21
- workspace = os.environ.get("OPENCLAW_WORKSPACE") or os.environ.get("OPENCLAW_HOME")
22
- if workspace:
23
- return os.path.join(workspace, "AGENTS.md")
24
- return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", "AGENTS.md"))
25
-
26
-
27
- def build_block(instructions: str, marker_start: str, marker_end: str) -> str:
28
- return f"{marker_start}\n{instructions.strip()}\n{marker_end}"
29
-
30
-
31
- def install_block(agents_path: str, block: str, marker_start: str, marker_end: str) -> None:
32
- if os.path.exists(agents_path):
33
- existing = read_file(agents_path)
34
- else:
35
- existing = ""
36
-
37
- if marker_start in existing and marker_end in existing:
38
- # Replace existing block
39
- pre = existing.split(marker_start)[0]
40
- post = existing.split(marker_end)[1]
41
- content = f"{pre}{block}{post}"
42
- else:
43
- # Append block
44
- spacer = "\n\n" if existing and not existing.endswith("\n\n") else ""
45
- content = f"{existing}{spacer}{block}\n"
46
-
47
- write_file(agents_path, content)
48
-
49
-
50
- def main() -> None:
51
- parser = argparse.ArgumentParser(description="Install Oomi agent instructions into AGENTS.md.")
52
- parser.add_argument(
53
- "--agents-file",
54
- default=get_default_agents_file(),
55
- help="Path to AGENTS.md (defaults to OPENCLAW_WORKSPACE/AGENTS.md or repo AGENTS.md).",
56
- )
57
- parser.add_argument(
58
- "--instructions-file",
59
- default=os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "agent_instructions.md")),
60
- help="Path to instructions markdown file.",
61
- )
62
- parser.add_argument("--marker-start", default=DEFAULT_MARKER_START, help="Start marker.")
63
- parser.add_argument("--marker-end", default=DEFAULT_MARKER_END, help="End marker.")
64
- args = parser.parse_args()
65
-
66
- if not os.path.exists(args.instructions_file):
67
- print(f"Instructions file not found: {args.instructions_file}", file=sys.stderr)
68
- sys.exit(1)
69
-
70
- instructions = read_file(args.instructions_file)
71
- block = build_block(instructions, args.marker_start, args.marker_end)
72
- install_block(args.agents_file, block, args.marker_start, args.marker_end)
73
-
74
- print(f"Installed Oomi instructions into {args.agents_file}")
75
-
76
-
77
- if __name__ == "__main__":
78
- main()
@@ -1,53 +0,0 @@
1
- import urllib.request
2
- import urllib.error
3
- import json
4
- import argparse
5
- import os
6
- import sys
7
-
8
- # Load config
9
- try:
10
- config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.json')
11
- with open(config_path, 'r') as f:
12
- config = json.load(f)
13
- BASE_URL = config.get('api_url', 'http://localhost:3000/api/skill')
14
- except:
15
- BASE_URL = 'http://localhost:3000/api/skill'
16
-
17
- API_URL = f"{BASE_URL}/goal"
18
-
19
- def send_goal(goal_type, value, message=None):
20
- payload = {
21
- "type": goal_type,
22
- "value": value,
23
- "message": message
24
- }
25
-
26
- try:
27
- req = urllib.request.Request(
28
- API_URL,
29
- data=json.dumps(payload).encode('utf-8'),
30
- headers={'Content-Type': 'application/json'}
31
- )
32
-
33
- with urllib.request.urlopen(req) as response:
34
- result = json.loads(response.read().decode())
35
-
36
- print(json.dumps(result, indent=2))
37
-
38
- except urllib.error.URLError as e:
39
- print(json.dumps({
40
- "error": f"Failed to send goal: {str(e)}",
41
- "hint": "Is the Next.js app running on localhost:3000?"
42
- }))
43
- sys.exit(1)
44
-
45
- if __name__ == "__main__":
46
- parser = argparse.ArgumentParser(description="Set a goal in Oomi")
47
- parser.add_argument("--type", required=True, help="Type of goal (e.g. steps, sleep)")
48
- parser.add_argument("--value", required=True, type=float, help="Goal target value")
49
- parser.add_argument("--message", help="Optional motivational message")
50
-
51
- args = parser.parse_args()
52
-
53
- send_goal(args.type, args.value, args.message)
@@ -1,46 +0,0 @@
1
- import urllib.request
2
- import urllib.error
3
- import json
4
- import os
5
- import sys
6
-
7
- # Load config
8
- try:
9
- config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config.json')
10
- with open(config_path, 'r') as f:
11
- config = json.load(f)
12
- BASE_URL = config.get('api_url', 'http://localhost:3000/api/skill')
13
- except:
14
- BASE_URL = 'http://localhost:3000/api/skill'
15
-
16
- API_URL = f"{BASE_URL}/sync"
17
-
18
- def sync_context():
19
- # In a real scenario, this might read from stdin or a file provided by the agent
20
- # For now, we send a dummy context
21
- payload = {
22
- "agent_id": "nemu-agent",
23
- "context_summary": "User is actively working on coding tasks.",
24
- "suggested_mode": "working"
25
- }
26
-
27
- try:
28
- req = urllib.request.Request(
29
- API_URL,
30
- data=json.dumps(payload).encode('utf-8'),
31
- headers={'Content-Type': 'application/json'}
32
- )
33
-
34
- with urllib.request.urlopen(req) as response:
35
- result = json.loads(response.read().decode())
36
-
37
- print(json.dumps(result, indent=2))
38
-
39
- except urllib.error.URLError as e:
40
- print(json.dumps({
41
- "error": f"Failed to sync: {str(e)}"
42
- }))
43
- sys.exit(1)
44
-
45
- if __name__ == "__main__":
46
- sync_context()
@@ -1,41 +0,0 @@
1
- import json
2
- import os
3
- import sys
4
-
5
- CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'config.json')
6
-
7
- def setup():
8
- print("Oomi Skill Setup")
9
- print("================")
10
-
11
- # Load existing config or defaults
12
- config = {"api_url": "http://localhost:3000/api/skill"}
13
- if os.path.exists(CONFIG_FILE):
14
- try:
15
- with open(CONFIG_FILE, 'r') as f:
16
- config.update(json.load(f))
17
- except:
18
- pass
19
-
20
- # Prompt user
21
- print(f"\nCurrent API URL: {config.get('api_url')}")
22
- new_url = input("Enter new API URL (press Enter to keep current): ").strip()
23
-
24
- if new_url:
25
- # Remove trailing slash if present
26
- if new_url.endswith('/'):
27
- new_url = new_url[:-1]
28
- config['api_url'] = new_url
29
-
30
- # Save
31
- try:
32
- with open(CONFIG_FILE, 'w') as f:
33
- json.dump(config, f, indent=2)
34
- print(f"\nConfiguration saved to {CONFIG_FILE}")
35
- print("Setup complete!")
36
- except Exception as e:
37
- print(f"\nError saving configuration: {e}")
38
- sys.exit(1)
39
-
40
- if __name__ == "__main__":
41
- setup()
@@ -1,8 +0,0 @@
1
- XR_DEV_SERVER=http://localhost:4789/webspatial/avp/
2
- XR_PRE_SERVER=
3
- XR_PROD_SERVER=
4
- XR_BUNDLE_ID=
5
- XR_TEAM_ID=
6
- XR_VERSION=
7
- XR_DEV_NAME=
8
- XR_DEV_PASSWORD=
@@ -1,47 +0,0 @@
1
- # __OOMI_PERSONA_NAME__
2
-
3
- This project was scaffolded by `oomi personas scaffold`.
4
-
5
- ## Purpose
6
-
7
- This app is intended to run inside the Oomi client as a managed persona surface with an XR-first WebSpatial scaffold.
8
-
9
- ## Editable Zones
10
-
11
- Only customize files in these zones unless Oomi explicitly changes the scaffold contract:
12
-
13
- - `src/persona/`
14
- - `persona/`
15
-
16
- ## XR Scaffold Contract
17
-
18
- The scaffold is considered healthy only when all of the following stay true:
19
-
20
- - the index route defaults to `ScenePage` in XR mode and keeps a valid browser route for non-spatial use
21
- - `ScenePage` calls `configurePersonaScene()` on mount
22
- - `ScenePage` logs `detectSpatialEnvironment()` so developers can verify the runtime is actually live
23
- - multiple meaningful surfaces use `enable-xr` and `xrStyle()`
24
- - `html.is-spatial` keeps the shell background transparent
25
- - `src/main.tsx` still exposes `snapdom` and `html2canvas` on `window`
26
- - the vendored WebSpatial fork metadata in `vendor/webspatial/FORK.md` stays intact
27
-
28
- ## Runtime Contract
29
-
30
- - Template version: `__OOMI_TEMPLATE_VERSION__`
31
- - Health document: `/oomi.health.json`
32
- - Runtime metadata document: `/oomi.runtime.json`
33
- - Manifest: `/manifest.webmanifest`
34
- - Default dev port: `4789`
35
-
36
- ## Local Development
37
-
38
- ```bash
39
- npm install
40
- npm run dev:avp
41
- ```
42
-
43
- ## Notes
44
-
45
- - Preserve the WebSpatial/Vite shell, the runtime metadata files in `public/`, and the XR-specific route split between browser and scene modes.
46
- - Treat the scene route as the real XR workspace, not as a flat homepage with one outer `enable-xr` wrapper.
47
- - Customize persona behavior in `src/persona/`.
@@ -1,28 +0,0 @@
1
- import js from "@eslint/js";
2
- import globals from "globals";
3
- import reactHooks from "eslint-plugin-react-hooks";
4
- import reactRefresh from "eslint-plugin-react-refresh";
5
- import tseslint from "typescript-eslint";
6
-
7
- export default tseslint.config(
8
- { ignores: ["dist"] },
9
- {
10
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
11
- files: ["**/*.{ts,tsx}"],
12
- languageOptions: {
13
- ecmaVersion: 2020,
14
- globals: globals.browser,
15
- },
16
- plugins: {
17
- "react-hooks": reactHooks,
18
- "react-refresh": reactRefresh,
19
- },
20
- rules: {
21
- ...reactHooks.configs.recommended.rules,
22
- "react-refresh/only-export-components": [
23
- "warn",
24
- { allowConstantExport: true },
25
- ],
26
- },
27
- },
28
- );
@@ -1,18 +0,0 @@
1
- <!DOCTYPE html>
2
- <%- XR_ENV === 'avp' ? `
3
- <html lang="en" class="is-spatial">
4
- ` : `
5
- <html lang="en">
6
- ` %>
7
- <head>
8
- <meta charset="UTF-8" />
9
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10
- <link rel="manifest" href="/manifest.webmanifest" />
11
- <title>__OOMI_PERSONA_NAME__</title>
12
- </head>
13
- <body>
14
- <div id="root"></div>
15
- <script type="module" src="/src/main.tsx"></script>
16
- </body>
17
- </html>
18
- </html>
@@ -1,13 +0,0 @@
1
- {
2
- "templateVersion": "__OOMI_TEMPLATE_VERSION__",
3
- "appKind": "oomi-persona-app",
4
- "healthPath": "/webspatial/avp/oomi.health.json",
5
- "defaultPort": 4789,
6
- "supportsRuntimeRegistration": true,
7
- "renderMode": "webspatial",
8
- "entryDocument": "/index.html",
9
- "editableZones": [
10
- "src/persona",
11
- "persona"
12
- ]
13
- }
@@ -1,44 +0,0 @@
1
- {
2
- "name": "oomi-persona-__OOMI_PERSONA_SLUG__",
3
- "version": "0.0.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "install:clean": "npm install",
8
- "dev": "vite --host 0.0.0.0 --port 4789 --strictPort",
9
- "dev:avp": "cross-env XR_ENV=avp vite --host 0.0.0.0 --port 4789 --strictPort",
10
- "build": "vite build && cross-env XR_ENV=avp vite build",
11
- "preview": "vite preview --host 0.0.0.0 --port 4789 --strictPort",
12
- "lint": "eslint ."
13
- },
14
- "dependencies": {
15
- "@webspatial/core-sdk": "file:./vendor/webspatial/core-sdk",
16
- "@webspatial/react-sdk": "file:./vendor/webspatial/react-sdk",
17
- "@zumer/snapdom": "^1.9.14",
18
- "html2canvas": "^1.4.1",
19
- "react": "^19.0.0",
20
- "react-dom": "^19.0.0",
21
- "react-router-dom": "^7.4.0",
22
- "three": "^0.170.0"
23
- },
24
- "devDependencies": {
25
- "@eslint/js": "^9.21.0",
26
- "@types/react": "^19.0.10",
27
- "@types/react-dom": "^19.0.4",
28
- "@vitejs/plugin-react": "^4.3.4",
29
- "@webspatial/builder": "^1.2.1",
30
- "@webspatial/platform-visionos": "^1.2.1",
31
- "@webspatial/vite-plugin": "^0.1.7",
32
- "cross-env": "^7.0.3",
33
- "dotenv-cli": "^8.0.0",
34
- "eslint": "^9.21.0",
35
- "eslint-plugin-react-hooks": "^5.1.0",
36
- "eslint-plugin-react-refresh": "^0.4.19",
37
- "globals": "^15.15.0",
38
- "typescript": "~5.7.2",
39
- "typescript-eslint": "^8.24.1",
40
- "vite": "^6.2.0",
41
- "vite-plugin-html": "^3.2.2"
42
- },
43
- "packageManager": "pnpm@10.6.4"
44
- }
@@ -1,14 +0,0 @@
1
- # Persona Brief
2
-
3
- Name: __OOMI_PERSONA_NAME__
4
- Slug: __OOMI_PERSONA_SLUG__
5
-
6
- ## User Intent
7
-
8
- __OOMI_PERSONA_DESCRIPTION__
9
-
10
- ## Notes For The Agent
11
-
12
- - Start from the scaffolded shell.
13
- - Keep the runtime and health documents intact.
14
- - Add persona-specific data flows inside `src/persona/` or `persona/`.
@@ -1,14 +0,0 @@
1
- {
2
- "id": "__OOMI_PERSONA_SLUG__",
3
- "name": "__OOMI_PERSONA_NAME__",
4
- "summary": "__OOMI_PERSONA_DESCRIPTION__",
5
- "status": "inactive",
6
- "type": "persona",
7
- "templateType": "persona-app",
8
- "promptTemplateVersion": "__OOMI_TEMPLATE_VERSION__",
9
- "capabilities": [],
10
- "dataSources": [],
11
- "tags": [
12
- "managed"
13
- ]
14
- }
@@ -1,8 +0,0 @@
1
- {
2
- "xr_main_scene": {
3
- "default_size": {
4
- "width": 860,
5
- "height": 1100
6
- }
7
- }
8
- }
@@ -1,6 +0,0 @@
1
- {
2
- "ok": true,
3
- "status": "healthy",
4
- "appKind": "oomi-persona-app",
5
- "templateVersion": "__OOMI_TEMPLATE_VERSION__"
6
- }