oomi-ai 0.2.38 → 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 +24 -14
- package/agent_instructions.md +9 -0
- package/bin/oomi-ai.js +1 -1
- package/lib/openclawPaths.js +27 -18
- package/lib/personaRuntimeManager.js +181 -61
- package/lib/personaRuntimeProcess.js +392 -49
- package/lib/personaRuntimeSupervisor.js +20 -7
- 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
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@ OpenClaw channel plugin and bridge tooling for Oomi managed chat and voice.
|
|
|
4
4
|
|
|
5
5
|
## Current Focus
|
|
6
6
|
|
|
7
|
-
`0.2.
|
|
8
|
-
- WebSpatial-based persona scaffolding for generated Oomi apps
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
`0.2.40` keeps the persona automation lane, adds a stable local persona runtime manager, upgrades the Docker dev harness from a package simulator to a real OpenClaw runtime, and introduces a shared OpenClaw profile contract so local onboarding, Docker bootstrap, and future hosted agents use the same setup model:
|
|
8
|
+
- WebSpatial-based persona scaffolding for generated Oomi apps
|
|
9
|
+
- vendored AndroidXR WebSpatial fork sync for persona runtimes, including the npm-safe package metadata needed by OpenClaw installs
|
|
10
|
+
- managed persona runtime installs now detect vendored WebSpatial drift and reinstall automatically so existing workspaces pick up XR runtime fixes
|
|
11
|
+
- a high-level `oomi personas create-managed` command for agent-driven persona creation
|
|
12
|
+
- a stable `oomi personas launch-managed` flow for local persona hosting under `OPENCLAW_WORKSPACE/personas`
|
|
11
13
|
- a matching `oomi personas delete` flow that stops managed runtimes and removes the persona workspace from the OpenClaw machine
|
|
12
14
|
- shared OpenClaw path handling for isolated local or containerized dev roots
|
|
13
15
|
- versioned `oomi openclaw profile init|apply` commands for deterministic local/dev or hosted setup flows
|
|
@@ -288,7 +290,7 @@ The local harness uses the `openrouter-free` preset for direct-provider smoke. I
|
|
|
288
290
|
Use the scaffold flow when OpenClaw needs to build a managed persona app that will live inside Oomi:
|
|
289
291
|
|
|
290
292
|
```bash
|
|
291
|
-
oomi personas scaffold market-analyst --name "Market Analyst" --description "Private app for reviewing my broker positions and risk." --out ~/.openclaw/personas/market-analyst
|
|
293
|
+
oomi personas scaffold market-analyst --name "Market Analyst" --description "Private app for reviewing my broker positions and risk." --out ~/.openclaw/workspace/personas/market-analyst
|
|
292
294
|
```
|
|
293
295
|
|
|
294
296
|
Use:
|
|
@@ -307,7 +309,7 @@ oomi personas delete market-analyst
|
|
|
307
309
|
oomi personas runtime-register market-analyst --local-port 4789
|
|
308
310
|
oomi personas heartbeat market-analyst --local-port 4789
|
|
309
311
|
oomi persona-jobs start pj_123
|
|
310
|
-
oomi persona-jobs succeed pj_123 --workspace-path ~/.openclaw/personas/market-analyst --local-port 4789
|
|
312
|
+
oomi persona-jobs succeed pj_123 --workspace-path ~/.openclaw/workspace/personas/market-analyst --local-port 4789
|
|
311
313
|
oomi persona-jobs fail pj_123 --code JOB_FAILED --message "Scaffold generation failed."
|
|
312
314
|
```
|
|
313
315
|
|
|
@@ -325,14 +327,22 @@ If you want to explicitly host or reuse the persona app on the OpenClaw machine
|
|
|
325
327
|
oomi personas launch-managed cooking-persona --entry-url https://your-relay.example/oomi/cooking-persona
|
|
326
328
|
```
|
|
327
329
|
|
|
328
|
-
This command:
|
|
329
|
-
|
|
330
|
-
- reuses
|
|
331
|
-
- scaffolds only when the workspace is missing
|
|
332
|
-
- installs dependencies only when needed or forced
|
|
333
|
-
- allocates or reuses a free local port
|
|
334
|
-
- starts or reuses the local runtime
|
|
335
|
-
- registers the runtime URL back to Oomi unless `--no-register` is set
|
|
330
|
+
This command:
|
|
331
|
+
|
|
332
|
+
- reuses `OPENCLAW_WORKSPACE/personas/<slug>` as the stable workspace
|
|
333
|
+
- scaffolds only when the workspace is missing
|
|
334
|
+
- installs dependencies only when needed or forced
|
|
335
|
+
- allocates or reuses a free local port
|
|
336
|
+
- starts or reuses the local runtime
|
|
337
|
+
- registers the runtime URL back to Oomi unless `--no-register` is set
|
|
338
|
+
|
|
339
|
+
For existing managed personas that are already open in Oomi, the safe edit flow is:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
oomi personas status <slug> --json
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The agent should use `editableWorkspacePath` from that output as the authoritative directory for reads, edits, and verification. `compatibilityWorkspacePath` is only a fallback for older installs.
|
|
336
346
|
|
|
337
347
|
## Bridge Health States
|
|
338
348
|
|
package/agent_instructions.md
CHANGED
|
@@ -209,6 +209,15 @@ When generating a managed persona app for Oomi:
|
|
|
209
209
|
4. Preserve the scaffolded WebSpatial/Vite shell, `public/oomi.health.json`, `oomi.runtime.json`, and `public/manifest.webmanifest`.
|
|
210
210
|
5. After customization, start the app and register the runtime with Oomi using the current runtime contract.
|
|
211
211
|
|
|
212
|
+
When editing an existing managed persona that is already open in Oomi:
|
|
213
|
+
|
|
214
|
+
1. Do not ask the user to find the app path manually if Oomi already selected the persona tab for you.
|
|
215
|
+
2. First run `oomi personas status <slug> --json`.
|
|
216
|
+
3. Use `editableWorkspacePath` from that command as the authoritative directory for reads, edits, and verification.
|
|
217
|
+
4. Treat `compatibilityWorkspacePath` only as a fallback or migration clue.
|
|
218
|
+
5. Preserve the scaffolded WebSpatial shell and runtime health files unless the user explicitly asks for a deeper structural change.
|
|
219
|
+
6. Do not claim the persona changed unless you have verified the file contents changed in `editableWorkspacePath` or the runtime reflects the update.
|
|
220
|
+
|
|
212
221
|
When executing a structured persona job from Oomi:
|
|
213
222
|
|
|
214
223
|
1. Prefer `oomi persona-jobs execute --message-file <job.json>` when the backend has already produced a machine-readable job payload.
|
package/bin/oomi-ai.js
CHANGED
|
@@ -329,7 +329,7 @@ Common flags:
|
|
|
329
329
|
--health-path PATH Runtime health path (default: /oomi.health.json)
|
|
330
330
|
--healthcheck-url URL Runtime healthcheck URL override
|
|
331
331
|
--transport TEXT Runtime transport label (default: local, relay when --entry-url is used)
|
|
332
|
-
--workspace-root PATH Persona workspace root (default:
|
|
332
|
+
--workspace-root PATH Persona workspace root (default: OPENCLAW_WORKSPACE/personas)
|
|
333
333
|
--restart Restart an existing managed persona runtime before launch
|
|
334
334
|
--started-at ISO Start timestamp override
|
|
335
335
|
--observed-at ISO Heartbeat timestamp override
|
package/lib/openclawPaths.js
CHANGED
|
@@ -15,11 +15,11 @@ export function resolveOpenclawHome() {
|
|
|
15
15
|
return path.join(os.homedir(), '.openclaw');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export function resolveOpenclawWorkspaceRoot() {
|
|
19
|
-
const explicitWorkspace = trimString(process.env.OPENCLAW_WORKSPACE);
|
|
20
|
-
if (explicitWorkspace) {
|
|
21
|
-
return path.resolve(explicitWorkspace);
|
|
22
|
-
}
|
|
18
|
+
export function resolveOpenclawWorkspaceRoot() {
|
|
19
|
+
const explicitWorkspace = trimString(process.env.OPENCLAW_WORKSPACE);
|
|
20
|
+
if (explicitWorkspace) {
|
|
21
|
+
return path.resolve(explicitWorkspace);
|
|
22
|
+
}
|
|
23
23
|
|
|
24
24
|
const openclawHome = resolveOpenclawHome();
|
|
25
25
|
const managedWorkspace = path.join(openclawHome, 'workspace');
|
|
@@ -27,12 +27,16 @@ export function resolveOpenclawWorkspaceRoot() {
|
|
|
27
27
|
return managedWorkspace;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
return openclawHome;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function
|
|
34
|
-
return
|
|
35
|
-
}
|
|
30
|
+
return openclawHome;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function resolveOpenclawLegacyPersonasDir() {
|
|
34
|
+
return resolveOpenclawPath('personas');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function resolveOpenclawPath(...parts) {
|
|
38
|
+
return path.join(resolveOpenclawHome(), ...parts);
|
|
39
|
+
}
|
|
36
40
|
|
|
37
41
|
export function resolveOpenclawConfigCandidates() {
|
|
38
42
|
return [
|
|
@@ -41,13 +45,18 @@ export function resolveOpenclawConfigCandidates() {
|
|
|
41
45
|
];
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
export function resolveOpenclawSkillsDir() {
|
|
45
|
-
return resolveOpenclawPath('skills');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function resolveOpenclawPersonasDir() {
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
export function resolveOpenclawSkillsDir() {
|
|
49
|
+
return resolveOpenclawPath('skills');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveOpenclawPersonasDir() {
|
|
53
|
+
const explicitPersonas = trimString(process.env.OPENCLAW_PERSONAS_DIR);
|
|
54
|
+
if (explicitPersonas) {
|
|
55
|
+
return path.resolve(explicitPersonas);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return path.join(resolveOpenclawWorkspaceRoot(), 'personas');
|
|
59
|
+
}
|
|
51
60
|
|
|
52
61
|
export function resolveOpenclawIdentityPath() {
|
|
53
62
|
return resolveOpenclawPath('identity', 'device.json');
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import { findAvailablePort } from './personaPortAllocator.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
|
|
4
|
+
import { findAvailablePort } from './personaPortAllocator.js';
|
|
5
|
+
import { resolveOpenclawLegacyPersonasDir } from './openclawPaths.js';
|
|
6
|
+
import {
|
|
7
|
+
buildLocalPersonaRuntime,
|
|
8
|
+
defaultPersonaWorkspaceRoot,
|
|
9
|
+
installPersonaWorkspace,
|
|
10
|
+
isPersonaWorkspaceProcessRunning,
|
|
11
|
+
resolvePersonaDevCommand,
|
|
12
|
+
syncLegacyWebSpatialScaffoldFiles,
|
|
13
|
+
syncVendoredWebSpatialPackages,
|
|
14
|
+
startPersonaWorkspace,
|
|
15
|
+
stopPersonaWorkspace,
|
|
16
|
+
waitForPersonaRuntime,
|
|
17
|
+
} from './personaRuntimeProcess.js';
|
|
15
18
|
import {
|
|
16
19
|
readPersonaRuntimeState,
|
|
17
20
|
resolvePersonaRuntimeLogPath,
|
|
@@ -21,9 +24,110 @@ import {
|
|
|
21
24
|
} from './personaRuntimeRegistry.js';
|
|
22
25
|
import { scaffoldPersonaApp } from './scaffold.js';
|
|
23
26
|
|
|
24
|
-
function trimString(value) {
|
|
25
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
26
|
-
}
|
|
27
|
+
function trimString(value) {
|
|
28
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function samePath(a, b) {
|
|
32
|
+
return path.resolve(String(a || '')) === path.resolve(String(b || ''));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function pathExists(targetPath) {
|
|
36
|
+
return Boolean(targetPath) && fs.existsSync(targetPath);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function ensureDir(dirPath) {
|
|
40
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function ensureDirectoryLink(linkPath, targetPath) {
|
|
44
|
+
if (!linkPath || !targetPath || samePath(linkPath, targetPath) || pathExists(linkPath)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ensureDir(path.dirname(linkPath));
|
|
49
|
+
try {
|
|
50
|
+
fs.symlinkSync(
|
|
51
|
+
targetPath,
|
|
52
|
+
linkPath,
|
|
53
|
+
process.platform === 'win32' ? 'junction' : 'dir'
|
|
54
|
+
);
|
|
55
|
+
return true;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveManagedPersonaWorkspacePaths({
|
|
62
|
+
slug,
|
|
63
|
+
workspaceRoot = defaultPersonaWorkspaceRoot(),
|
|
64
|
+
}) {
|
|
65
|
+
const canonicalWorkspaceRoot = path.resolve(workspaceRoot);
|
|
66
|
+
const canonicalWorkspacePath = resolvePersonaWorkspacePath({
|
|
67
|
+
workspaceRoot: canonicalWorkspaceRoot,
|
|
68
|
+
slug,
|
|
69
|
+
});
|
|
70
|
+
const legacyWorkspaceRoot = path.resolve(resolveOpenclawLegacyPersonasDir());
|
|
71
|
+
const legacyWorkspacePath = samePath(canonicalWorkspaceRoot, legacyWorkspaceRoot)
|
|
72
|
+
? ''
|
|
73
|
+
: resolvePersonaWorkspacePath({
|
|
74
|
+
workspaceRoot: legacyWorkspaceRoot,
|
|
75
|
+
slug,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
canonicalWorkspaceRoot,
|
|
80
|
+
canonicalWorkspacePath,
|
|
81
|
+
legacyWorkspaceRoot: legacyWorkspacePath ? legacyWorkspaceRoot : '',
|
|
82
|
+
legacyWorkspacePath,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function resolveManagedPersonaWorkspace({
|
|
87
|
+
slug,
|
|
88
|
+
workspaceRoot = defaultPersonaWorkspaceRoot(),
|
|
89
|
+
}) {
|
|
90
|
+
const paths = resolveManagedPersonaWorkspacePaths({ slug, workspaceRoot });
|
|
91
|
+
ensureDir(paths.canonicalWorkspaceRoot);
|
|
92
|
+
|
|
93
|
+
let migratedFromLegacy = false;
|
|
94
|
+
let canonicalProxyCreated = false;
|
|
95
|
+
let legacyProxyCreated = false;
|
|
96
|
+
|
|
97
|
+
if (!pathExists(paths.canonicalWorkspacePath) && pathExists(paths.legacyWorkspacePath)) {
|
|
98
|
+
try {
|
|
99
|
+
fs.renameSync(paths.legacyWorkspacePath, paths.canonicalWorkspacePath);
|
|
100
|
+
migratedFromLegacy = true;
|
|
101
|
+
} catch {
|
|
102
|
+
canonicalProxyCreated = ensureDirectoryLink(
|
|
103
|
+
paths.canonicalWorkspacePath,
|
|
104
|
+
paths.legacyWorkspacePath
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (pathExists(paths.canonicalWorkspacePath) && paths.legacyWorkspacePath && !pathExists(paths.legacyWorkspacePath)) {
|
|
110
|
+
legacyProxyCreated = ensureDirectoryLink(
|
|
111
|
+
paths.legacyWorkspacePath,
|
|
112
|
+
paths.canonicalWorkspacePath
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const workspacePath = pathExists(paths.canonicalWorkspacePath)
|
|
117
|
+
? paths.canonicalWorkspacePath
|
|
118
|
+
: (pathExists(paths.legacyWorkspacePath) ? paths.legacyWorkspacePath : paths.canonicalWorkspacePath);
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
...paths,
|
|
122
|
+
workspacePath,
|
|
123
|
+
editableWorkspacePath: pathExists(paths.canonicalWorkspacePath)
|
|
124
|
+
? paths.canonicalWorkspacePath
|
|
125
|
+
: workspacePath,
|
|
126
|
+
migratedFromLegacy,
|
|
127
|
+
canonicalProxyCreated,
|
|
128
|
+
legacyProxyCreated,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
27
131
|
|
|
28
132
|
export function slugifyPersonaName(name) {
|
|
29
133
|
const normalized = trimString(name)
|
|
@@ -91,16 +195,18 @@ async function ensureWorkspaceScaffold({
|
|
|
91
195
|
};
|
|
92
196
|
}
|
|
93
197
|
|
|
94
|
-
async function ensureWorkspaceInstall({
|
|
95
|
-
workspacePath,
|
|
96
|
-
forceInstall = false,
|
|
97
|
-
}) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
198
|
+
async function ensureWorkspaceInstall({
|
|
199
|
+
workspacePath,
|
|
200
|
+
forceInstall = false,
|
|
201
|
+
}) {
|
|
202
|
+
const packageSyncChanged = syncVendoredWebSpatialPackages({ workspacePath });
|
|
203
|
+
syncLegacyWebSpatialScaffoldFiles({ workspacePath });
|
|
204
|
+
const nodeModulesPath = path.join(workspacePath, 'node_modules');
|
|
205
|
+
if (!forceInstall && fs.existsSync(nodeModulesPath) && !packageSyncChanged) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
await installPersonaWorkspace({ workspacePath });
|
|
104
210
|
return true;
|
|
105
211
|
}
|
|
106
212
|
|
|
@@ -143,14 +249,15 @@ export async function launchManagedPersonaRuntime({
|
|
|
143
249
|
const safeDescription = trimString(description) || safeName;
|
|
144
250
|
if (!safeName) {
|
|
145
251
|
throw new Error('Persona name is required.');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const safeSlug = trimString(slug) || slugifyPersonaName(safeName);
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
const
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const safeSlug = trimString(slug) || slugifyPersonaName(safeName);
|
|
255
|
+
const workspaceResolution = resolveManagedPersonaWorkspace({
|
|
256
|
+
slug: safeSlug,
|
|
257
|
+
workspaceRoot,
|
|
258
|
+
});
|
|
259
|
+
const workspacePath = workspaceResolution.workspacePath;
|
|
260
|
+
const previousState = readPersonaRuntimeState(workspacePath);
|
|
154
261
|
|
|
155
262
|
const scaffoldInfo = await ensureWorkspaceScaffold({
|
|
156
263
|
slug: safeSlug,
|
|
@@ -238,13 +345,16 @@ export async function launchManagedPersonaRuntime({
|
|
|
238
345
|
devCommand: resolvePersonaDevCommand({ workspacePath, localPort }),
|
|
239
346
|
});
|
|
240
347
|
|
|
241
|
-
return {
|
|
242
|
-
ok: true,
|
|
243
|
-
slug: safeSlug,
|
|
244
|
-
workspacePath,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
348
|
+
return {
|
|
349
|
+
ok: true,
|
|
350
|
+
slug: safeSlug,
|
|
351
|
+
workspacePath,
|
|
352
|
+
editableWorkspacePath: workspaceResolution.editableWorkspacePath,
|
|
353
|
+
compatibilityWorkspacePath: workspaceResolution.legacyWorkspacePath || '',
|
|
354
|
+
migratedFromLegacy: workspaceResolution.migratedFromLegacy,
|
|
355
|
+
scaffolded: scaffoldInfo.scaffolded,
|
|
356
|
+
installed,
|
|
357
|
+
reusedRunningProcess: reusingRunningProcess,
|
|
248
358
|
runtime: registration,
|
|
249
359
|
localRuntime,
|
|
250
360
|
state: runtimeState,
|
|
@@ -256,26 +366,33 @@ export function getManagedPersonaRuntimeStatus({
|
|
|
256
366
|
workspaceRoot = defaultPersonaWorkspaceRoot(),
|
|
257
367
|
}) {
|
|
258
368
|
const safeSlug = trimString(slug);
|
|
259
|
-
if (!safeSlug) {
|
|
260
|
-
throw new Error('Persona slug is required.');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
});
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
369
|
+
if (!safeSlug) {
|
|
370
|
+
throw new Error('Persona slug is required.');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const workspaceResolution = resolveManagedPersonaWorkspace({
|
|
374
|
+
slug: safeSlug,
|
|
375
|
+
workspaceRoot,
|
|
376
|
+
});
|
|
377
|
+
const workspacePath = workspaceResolution.workspacePath;
|
|
378
|
+
const state = readPersonaRuntimeState(workspacePath);
|
|
379
|
+
const pid = Number.isInteger(state.pid) ? state.pid : null;
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
slug: safeSlug,
|
|
383
|
+
workspaceRoot: workspaceResolution.canonicalWorkspaceRoot,
|
|
384
|
+
workspacePath,
|
|
385
|
+
editableWorkspacePath: workspaceResolution.editableWorkspacePath,
|
|
386
|
+
compatibilityWorkspacePath: workspaceResolution.legacyWorkspacePath || '',
|
|
387
|
+
workspaceExists: fs.existsSync(workspacePath),
|
|
388
|
+
runtimeStatePath: resolvePersonaRuntimeStatePath(workspacePath),
|
|
389
|
+
processRunning: pid ? isPersonaWorkspaceProcessRunning(pid) : false,
|
|
390
|
+
migratedFromLegacy: workspaceResolution.migratedFromLegacy,
|
|
391
|
+
canonicalProxyCreated: workspaceResolution.canonicalProxyCreated,
|
|
392
|
+
legacyProxyCreated: workspaceResolution.legacyProxyCreated,
|
|
393
|
+
state,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
279
396
|
|
|
280
397
|
export async function stopManagedPersonaRuntime({
|
|
281
398
|
slug,
|
|
@@ -352,8 +469,11 @@ export async function destroyManagedPersonaRuntime({
|
|
|
352
469
|
slug,
|
|
353
470
|
workspaceRoot,
|
|
354
471
|
});
|
|
355
|
-
ensureWorkspacePathWithinRoot(status.workspacePath, workspaceRoot);
|
|
472
|
+
ensureWorkspacePathWithinRoot(status.workspacePath, status.workspaceRoot || workspaceRoot);
|
|
356
473
|
fs.rmSync(status.workspacePath, { recursive: true, force: true });
|
|
474
|
+
if (status.compatibilityWorkspacePath && pathExists(status.compatibilityWorkspacePath)) {
|
|
475
|
+
fs.rmSync(status.compatibilityWorkspacePath, { recursive: true, force: true });
|
|
476
|
+
}
|
|
357
477
|
|
|
358
478
|
return {
|
|
359
479
|
ok: true,
|