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,67 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- function ensureDir(dirPath) {
5
- fs.mkdirSync(dirPath, { recursive: true });
6
- }
7
-
8
- function readJsonSafe(filePath) {
9
- if (!fs.existsSync(filePath)) {
10
- return null;
11
- }
12
-
13
- try {
14
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
15
- } catch {
16
- return null;
17
- }
18
- }
19
-
20
- function trimString(value) {
21
- return typeof value === 'string' ? value.trim() : '';
22
- }
23
-
24
- export function resolvePersonaWorkspacePath({ workspaceRoot, slug }) {
25
- const safeRoot = trimString(workspaceRoot);
26
- const safeSlug = trimString(slug);
27
- if (!safeRoot) {
28
- throw new Error('Workspace root is required.');
29
- }
30
- if (!safeSlug) {
31
- throw new Error('Persona slug is required.');
32
- }
33
-
34
- return path.resolve(safeRoot, safeSlug);
35
- }
36
-
37
- export function resolvePersonaRuntimeDir(workspacePath) {
38
- return path.join(workspacePath, '.oomi');
39
- }
40
-
41
- export function resolvePersonaRuntimeStatePath(workspacePath) {
42
- return path.join(resolvePersonaRuntimeDir(workspacePath), 'runtime.json');
43
- }
44
-
45
- export function resolvePersonaRuntimeLogPath(workspacePath) {
46
- return path.join(resolvePersonaRuntimeDir(workspacePath), 'runtime.log');
47
- }
48
-
49
- export function readPersonaRuntimeState(workspacePath) {
50
- return readJsonSafe(resolvePersonaRuntimeStatePath(workspacePath)) || {};
51
- }
52
-
53
- export function writePersonaRuntimeState(workspacePath, state) {
54
- const runtimeDir = resolvePersonaRuntimeDir(workspacePath);
55
- const statePath = resolvePersonaRuntimeStatePath(workspacePath);
56
- ensureDir(runtimeDir);
57
- fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
58
- return state;
59
- }
60
-
61
- export function updatePersonaRuntimeState(workspacePath, partial) {
62
- const current = readPersonaRuntimeState(workspacePath);
63
- return writePersonaRuntimeState(workspacePath, {
64
- ...current,
65
- ...partial,
66
- });
67
- }
@@ -1,330 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- import { resolveOpenclawLegacyPersonasDir } from './openclawPaths.js';
5
- import { createPersonaApiClient } from './personaApiClient.js';
6
- import { launchManagedPersonaRuntime } from './personaRuntimeManager.js';
7
- import { readPersonaRuntimeState, updatePersonaRuntimeState } from './personaRuntimeRegistry.js';
8
- import {
9
- buildLocalPersonaRuntime,
10
- isPersonaWorkspaceProcessRunning,
11
- resolvePersonaDevCommand,
12
- resolvePersonaHealthPath,
13
- } from './personaRuntimeProcess.js';
14
-
15
- function trimString(value) {
16
- return typeof value === 'string' ? value.trim() : '';
17
- }
18
-
19
- function wait(ms) {
20
- return new Promise((resolve) => {
21
- setTimeout(resolve, ms);
22
- });
23
- }
24
-
25
- function listWorkspacePaths(workspaceRoot) {
26
- const roots = [trimString(workspaceRoot), trimString(resolveOpenclawLegacyPersonasDir())]
27
- .filter(Boolean)
28
- .filter((root, index, values) => values.findIndex((candidate) => path.resolve(candidate) === path.resolve(root)) === index)
29
- .filter((root) => fs.existsSync(root));
30
-
31
- const workspacePaths = new Set();
32
- for (const root of roots) {
33
- for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
34
- if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
35
- const candidatePath = path.join(root, entry.name);
36
- let dedupeKey = candidatePath;
37
- try {
38
- dedupeKey = fs.realpathSync(candidatePath);
39
- } catch {
40
- // fall back to the visible path when the real path is unavailable
41
- }
42
- workspacePaths.add(dedupeKey);
43
- }
44
- }
45
-
46
- return Array.from(workspacePaths);
47
- }
48
-
49
- async function healthcheckOk(url) {
50
- const safeUrl = trimString(url);
51
- if (!safeUrl) {
52
- return false;
53
- }
54
-
55
- try {
56
- const response = await fetch(safeUrl, {
57
- method: 'GET',
58
- headers: {
59
- Accept: 'application/json',
60
- },
61
- });
62
- return response.ok;
63
- } catch {
64
- return false;
65
- }
66
- }
67
-
68
- async function reconcileWorkspace({
69
- workspacePath,
70
- workspaceRoot,
71
- client,
72
- logger,
73
- autoRestart,
74
- }) {
75
- const state = readPersonaRuntimeState(workspacePath);
76
- const slug = trimString(state.slug);
77
- if (!slug || trimString(state.status) !== 'running') {
78
- return;
79
- }
80
-
81
- const runtime = {
82
- slug,
83
- endpoint: trimString(state.endpoint || state.entryUrl || state.localEndpoint),
84
- localEndpoint: trimString(state.localEndpoint),
85
- reachableEndpoint: trimString(state.reachableEndpoint),
86
- healthcheckUrl: trimString(state.healthcheckUrl),
87
- transport: trimString(state.transport) || 'local',
88
- localPort: Number.isFinite(Number(state.localPort)) ? Number(state.localPort) : null,
89
- };
90
-
91
- const localRuntime = runtime.localPort
92
- ? buildLocalPersonaRuntime({
93
- localPort: runtime.localPort,
94
- healthPath: resolvePersonaHealthPath({
95
- workspacePath,
96
- fallback: '/oomi.health.json',
97
- }),
98
- })
99
- : null;
100
-
101
- const expectedDevCommand = runtime.localPort
102
- ? resolvePersonaDevCommand({
103
- workspacePath,
104
- localPort: runtime.localPort,
105
- })
106
- : state.devCommand;
107
- const processRunning = isPersonaWorkspaceProcessRunning(state.pid, {
108
- workspacePath,
109
- expectedCommand: expectedDevCommand,
110
- localPort: runtime.localPort,
111
- });
112
-
113
- let effectiveRuntime = runtime;
114
- if (!processRunning) {
115
- if (!autoRestart) {
116
- return;
117
- }
118
-
119
- try {
120
- const launchResult = await launchManagedPersonaRuntime({
121
- slug,
122
- name: trimString(state.name) || slug,
123
- description: trimString(state.description) || trimString(state.name) || slug,
124
- workspaceRoot,
125
- templateVersion: trimString(state.templateVersion) || 'v1',
126
- forceInstall: false,
127
- restart: false,
128
- logFilePath: trimString(state.logFilePath),
129
- entryUrl: '',
130
- transport: 'local',
131
- });
132
-
133
- effectiveRuntime = {
134
- slug,
135
- endpoint: launchResult.runtime.endpoint,
136
- localEndpoint: launchResult.runtime.localEndpoint || launchResult.localRuntime.endpoint,
137
- reachableEndpoint: launchResult.runtime.reachableEndpoint || launchResult.localRuntime.reachableEndpoint,
138
- healthcheckUrl: launchResult.runtime.healthcheckUrl,
139
- transport: launchResult.runtime.transport,
140
- localPort: launchResult.runtime.localPort,
141
- };
142
-
143
- await client.registerRuntime({
144
- slug,
145
- endpoint: effectiveRuntime.endpoint,
146
- healthcheckUrl: effectiveRuntime.healthcheckUrl,
147
- localPort: effectiveRuntime.localPort,
148
- transport: effectiveRuntime.transport,
149
- startedAt: new Date().toISOString(),
150
- });
151
- } catch (error) {
152
- logger.warn?.(
153
- `[persona-runtime] restart failed for ${slug}: ${
154
- error instanceof Error ? error.message : String(error)
155
- }`
156
- );
157
- return;
158
- }
159
- }
160
-
161
- const healthy = await healthcheckOk(effectiveRuntime.healthcheckUrl);
162
- if (!healthy) {
163
- if (!autoRestart) {
164
- return;
165
- }
166
-
167
- try {
168
- const recovered = await launchManagedPersonaRuntime({
169
- slug,
170
- name: trimString(state.name) || slug,
171
- description: trimString(state.description) || trimString(state.name) || slug,
172
- workspaceRoot,
173
- templateVersion: trimString(state.templateVersion) || 'v1',
174
- forceInstall: false,
175
- restart: true,
176
- logFilePath: trimString(state.logFilePath),
177
- entryUrl: '',
178
- transport: 'local',
179
- });
180
-
181
- effectiveRuntime = {
182
- slug,
183
- endpoint: recovered.runtime.endpoint,
184
- localEndpoint: recovered.runtime.localEndpoint || recovered.localRuntime.endpoint,
185
- reachableEndpoint: recovered.runtime.reachableEndpoint || recovered.localRuntime.reachableEndpoint,
186
- healthcheckUrl: recovered.runtime.healthcheckUrl,
187
- transport: recovered.runtime.transport,
188
- localPort: recovered.runtime.localPort,
189
- };
190
-
191
- await client.registerRuntime({
192
- slug,
193
- endpoint: effectiveRuntime.endpoint,
194
- healthcheckUrl: effectiveRuntime.healthcheckUrl,
195
- localPort: effectiveRuntime.localPort,
196
- transport: effectiveRuntime.transport,
197
- startedAt: new Date().toISOString(),
198
- });
199
- } catch (error) {
200
- logger.warn?.(
201
- `[persona-runtime] unhealthy runtime restart failed for ${slug}: ${
202
- error instanceof Error ? error.message : String(error)
203
- }`
204
- );
205
- return;
206
- }
207
- }
208
-
209
- if (!healthy) {
210
- const recoveredHealthy = await healthcheckOk(effectiveRuntime.healthcheckUrl);
211
- if (!recoveredHealthy) {
212
- return;
213
- }
214
- }
215
-
216
- if (localRuntime) {
217
- const refreshedLocalRuntime = buildLocalPersonaRuntime({
218
- localPort: effectiveRuntime.localPort,
219
- healthPath: resolvePersonaHealthPath({
220
- workspacePath,
221
- fallback: '/oomi.health.json',
222
- }),
223
- });
224
- const desiredEndpoint = refreshedLocalRuntime.reachableEndpoint || runtime.endpoint;
225
- const endpointChanged = desiredEndpoint && desiredEndpoint !== effectiveRuntime.endpoint;
226
- const localEndpointChanged = refreshedLocalRuntime.endpoint !== effectiveRuntime.localEndpoint;
227
- const reachableEndpointChanged = refreshedLocalRuntime.reachableEndpoint !== effectiveRuntime.reachableEndpoint;
228
-
229
- if (endpointChanged || localEndpointChanged || reachableEndpointChanged) {
230
- effectiveRuntime = {
231
- ...effectiveRuntime,
232
- endpoint: desiredEndpoint,
233
- localEndpoint: refreshedLocalRuntime.endpoint,
234
- reachableEndpoint: refreshedLocalRuntime.reachableEndpoint,
235
- };
236
- updatePersonaRuntimeState(workspacePath, {
237
- endpoint: desiredEndpoint,
238
- entryUrl: desiredEndpoint,
239
- localEndpoint: refreshedLocalRuntime.endpoint,
240
- reachableEndpoint: refreshedLocalRuntime.reachableEndpoint,
241
- bindHost: refreshedLocalRuntime.bindHost,
242
- reachableHost: refreshedLocalRuntime.reachableHost,
243
- });
244
-
245
- try {
246
- await client.registerRuntime({
247
- slug,
248
- endpoint: effectiveRuntime.endpoint,
249
- healthcheckUrl: effectiveRuntime.healthcheckUrl,
250
- localPort: effectiveRuntime.localPort,
251
- transport: effectiveRuntime.transport,
252
- startedAt: new Date().toISOString(),
253
- });
254
- } catch (error) {
255
- logger.warn?.(
256
- `[persona-runtime] registration refresh failed for ${slug}: ${
257
- error instanceof Error ? error.message : String(error)
258
- }`
259
- );
260
- return;
261
- }
262
- }
263
- }
264
-
265
- try {
266
- await client.heartbeatRuntime({
267
- slug,
268
- endpoint: effectiveRuntime.endpoint,
269
- healthcheckUrl: effectiveRuntime.healthcheckUrl,
270
- localPort: effectiveRuntime.localPort,
271
- transport: effectiveRuntime.transport,
272
- observedAt: new Date().toISOString(),
273
- });
274
- } catch (error) {
275
- logger.warn?.(
276
- `[persona-runtime] heartbeat failed for ${slug}: ${
277
- error instanceof Error ? error.message : String(error)
278
- }`
279
- );
280
- }
281
- }
282
-
283
- export function startPersonaRuntimeSupervisor({
284
- backendUrl,
285
- deviceToken,
286
- workspaceRoot,
287
- fetchImpl = globalThis.fetch,
288
- intervalMs = 30000,
289
- logger = console,
290
- autoRestart = true,
291
- }) {
292
- const client = createPersonaApiClient({
293
- backendUrl,
294
- deviceToken,
295
- fetchImpl,
296
- });
297
-
298
- let stopped = false;
299
- let loopPromise = null;
300
-
301
- async function runLoop() {
302
- while (!stopped) {
303
- const workspaces = listWorkspacePaths(workspaceRoot);
304
- for (const workspacePath of workspaces) {
305
- if (stopped) break;
306
- await reconcileWorkspace({
307
- workspacePath,
308
- workspaceRoot,
309
- client,
310
- logger,
311
- autoRestart,
312
- });
313
- }
314
-
315
- if (stopped) {
316
- break;
317
- }
318
- await wait(intervalMs);
319
- }
320
- }
321
-
322
- loopPromise = runLoop();
323
-
324
- return {
325
- stop() {
326
- stopped = true;
327
- },
328
- completed: loopPromise,
329
- };
330
- }
package/lib/scaffold.js DELETED
@@ -1,108 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- import {
5
- DEFAULT_TEMPLATE_ID,
6
- DEFAULT_TEMPLATE_VERSION,
7
- readTemplateDescriptor,
8
- renderTemplateFile,
9
- resolveTemplateRoot,
10
- } from './template.js';
11
-
12
- function ensureDir(dirPath) {
13
- fs.mkdirSync(dirPath, { recursive: true });
14
- }
15
-
16
- function validatePersonaSlug(slug) {
17
- if (typeof slug !== 'string' || !slug.trim()) {
18
- throw new Error('Persona slug is required.');
19
- }
20
-
21
- const normalized = slug.trim();
22
- if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalized)) {
23
- throw new Error(
24
- 'Persona slug must use lowercase letters, numbers, and single dashes only.',
25
- );
26
- }
27
-
28
- return normalized;
29
- }
30
-
31
- function ensureWritableOutputDir(outDir, force) {
32
- if (!outDir) {
33
- throw new Error('Output directory is required. Use --out <path>.');
34
- }
35
-
36
- if (!fs.existsSync(outDir)) {
37
- ensureDir(outDir);
38
- return;
39
- }
40
-
41
- const entries = fs.readdirSync(outDir);
42
- if (entries.length > 0 && !force) {
43
- throw new Error(`Output directory is not empty: ${outDir}. Use --force to overwrite.`);
44
- }
45
- }
46
-
47
- function copyTemplateTree(sourceRoot, targetRoot, variables) {
48
- const entries = fs.readdirSync(sourceRoot, { withFileTypes: true });
49
- for (const entry of entries) {
50
- if (entry.name === 'template.json') {
51
- continue;
52
- }
53
-
54
- const sourcePath = path.join(sourceRoot, entry.name);
55
- const targetPath = path.join(targetRoot, entry.name);
56
-
57
- if (entry.isDirectory()) {
58
- ensureDir(targetPath);
59
- copyTemplateTree(sourcePath, targetPath, variables);
60
- continue;
61
- }
62
-
63
- const content = fs.readFileSync(sourcePath, 'utf8');
64
- fs.writeFileSync(targetPath, renderTemplateFile(content, variables), 'utf8');
65
- }
66
- }
67
-
68
- export function scaffoldPersonaApp({
69
- slug,
70
- name,
71
- description,
72
- outDir,
73
- templateVersion = DEFAULT_TEMPLATE_VERSION,
74
- templateId = DEFAULT_TEMPLATE_ID,
75
- force = false,
76
- }) {
77
- const safeSlug = validatePersonaSlug(slug);
78
- const safeName = typeof name === 'string' && name.trim() ? name.trim() : safeSlug;
79
- const safeDescription = typeof description === 'string' ? description.trim() : '';
80
- if (!safeDescription) {
81
- throw new Error('Persona description is required. Use --description "<text>".');
82
- }
83
-
84
- const resolvedOutDir = path.resolve(outDir);
85
- const templateRoot = resolveTemplateRoot(templateId, templateVersion);
86
- const descriptor = readTemplateDescriptor(templateRoot);
87
- const variables = {
88
- __OOMI_PERSONA_SLUG__: safeSlug,
89
- __OOMI_PERSONA_NAME__: safeName,
90
- __OOMI_PERSONA_DESCRIPTION__: safeDescription,
91
- __OOMI_TEMPLATE_VERSION__: templateVersion,
92
- };
93
-
94
- ensureWritableOutputDir(resolvedOutDir, force);
95
- copyTemplateTree(templateRoot, resolvedOutDir, variables);
96
-
97
- return {
98
- ok: true,
99
- templateId,
100
- templateVersion,
101
- slug: safeSlug,
102
- outDir: resolvedOutDir,
103
- startCommand: `cd ${resolvedOutDir} && npm install && ${descriptor.startCommand || 'npm run dev'}`,
104
- healthPath: descriptor.healthPath,
105
- editableZones: descriptor.editableZones,
106
- defaultPort: descriptor.defaultPort,
107
- };
108
- }
package/lib/template.js DELETED
@@ -1,45 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
-
5
- export const DEFAULT_TEMPLATE_ID = 'persona-app';
6
- export const DEFAULT_TEMPLATE_VERSION = 'v1';
7
-
8
- const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
9
- const TEMPLATE_ROOT = path.join(PACKAGE_ROOT, 'templates');
10
-
11
- export function readTemplateDescriptor(templateRoot) {
12
- const descriptorPath = path.join(templateRoot, 'template.json');
13
- if (!fs.existsSync(descriptorPath)) {
14
- throw new Error(`Template descriptor not found: ${descriptorPath}`);
15
- }
16
-
17
- return JSON.parse(fs.readFileSync(descriptorPath, 'utf8'));
18
- }
19
-
20
- export function resolveTemplateRoot(
21
- templateId = DEFAULT_TEMPLATE_ID,
22
- version = DEFAULT_TEMPLATE_VERSION,
23
- ) {
24
- const templateRoot = path.join(TEMPLATE_ROOT, templateId);
25
- if (!fs.existsSync(templateRoot)) {
26
- throw new Error(`Unknown template: ${templateId}`);
27
- }
28
-
29
- const descriptor = readTemplateDescriptor(templateRoot);
30
- if (descriptor.version !== version) {
31
- throw new Error(
32
- `Unsupported template version "${version}" for ${templateId}. Available version: ${descriptor.version}`,
33
- );
34
- }
35
-
36
- return templateRoot;
37
- }
38
-
39
- export function renderTemplateFile(content, variables) {
40
- let rendered = content;
41
- for (const [token, value] of Object.entries(variables)) {
42
- rendered = rendered.split(token).join(String(value));
43
- }
44
- return rendered;
45
- }
@@ -1,3 +0,0 @@
1
- {
2
- "api_url": "http://localhost:3000/api/skill"
3
- }
@@ -1,40 +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}/avatar-capabilities"
17
-
18
- def get_avatar_capabilities():
19
- try:
20
- with urllib.request.urlopen(API_URL) as response:
21
- data = json.loads(response.read().decode())
22
-
23
- print(json.dumps({
24
- "summary": "Avatar capabilities retrieved.",
25
- "raw_data": data
26
- }, indent=2))
27
- except urllib.error.URLError as e:
28
- print(json.dumps({
29
- "error": f"Failed to connect to Oomi app: {str(e)}",
30
- "hint": "Is the Next.js app running on localhost:3000?"
31
- }))
32
- sys.exit(1)
33
- except Exception as e:
34
- print(json.dumps({
35
- "error": f"An error occurred: {str(e)}"
36
- }))
37
- sys.exit(1)
38
-
39
- if __name__ == "__main__":
40
- get_avatar_capabilities()
@@ -1,49 +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}/data"
17
-
18
- def get_data():
19
- try:
20
- with urllib.request.urlopen(API_URL) as response:
21
- data = json.loads(response.read().decode())
22
-
23
- # Format output for the agent
24
- summary = (
25
- f"Steps: {data['steps']} / {data['goals']['steps']}\n"
26
- f"Sleep: {data['sleep']}h / {data['goals']['sleep']}h\n"
27
- f"Energy: {data['energy']}/100\n"
28
- f"Mood: {data['mood']}"
29
- )
30
-
31
- print(json.dumps({
32
- "summary": summary,
33
- "raw_data": data
34
- }, indent=2))
35
-
36
- except urllib.error.URLError as e:
37
- print(json.dumps({
38
- "error": f"Failed to connect to Oomi app: {str(e)}",
39
- "hint": "Is the Next.js app running on localhost:3000?"
40
- }))
41
- sys.exit(1)
42
- except Exception as e:
43
- print(json.dumps({
44
- "error": f"An error occurred: {str(e)}"
45
- }))
46
- sys.exit(1)
47
-
48
- if __name__ == "__main__":
49
- get_data()