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.
- package/README.md +227 -463
- package/agent_instructions.md +244 -234
- package/bin/oomi-ai.js +4028 -5797
- package/bin/sessionBridgeState.js +78 -78
- package/lib/openclawPaths.js +70 -71
- package/lib/openclawProfile.js +216 -216
- package/lib/personaApiClient.js +133 -303
- package/lib/spokenMetadata.js +137 -137
- package/openclaw.extension.js +341 -341
- package/openclaw.plugin.json +17 -17
- package/package.json +59 -59
- package/persona-app/README.md +27 -0
- package/persona-app/registry/v1.json +63 -0
- package/persona-app/schema/persona-app.v1.schema.json +90 -0
- package/skills/oomi/SKILL.md +165 -182
- package/skills/oomi/agent_instructions.md +99 -80
- package/lib/channelPluginClient.js +0 -119
- package/lib/openclawDevGateway.js +0 -384
- package/lib/personaJobExecutor.js +0 -139
- package/lib/personaJobPoller.js +0 -112
- package/lib/personaPortAllocator.js +0 -36
- package/lib/personaRuntimeManager.js +0 -496
- package/lib/personaRuntimeProcess.js +0 -924
- package/lib/personaRuntimeRegistry.js +0 -67
- package/lib/personaRuntimeSupervisor.js +0 -330
- package/lib/scaffold.js +0 -108
- package/lib/template.js +0 -45
- package/skills/oomi/config.json +0 -3
- package/skills/oomi/scripts/get_avatar_capabilities.py +0 -40
- package/skills/oomi/scripts/get_data.py +0 -49
- package/skills/oomi/scripts/install_agent_instructions.py +0 -78
- package/skills/oomi/scripts/send_goal.py +0 -53
- package/skills/oomi/scripts/sync.py +0 -46
- package/skills/oomi/setup.py +0 -41
- package/templates/persona-app/.env.example +0 -8
- package/templates/persona-app/README.md +0 -47
- package/templates/persona-app/eslint.config.js +0 -28
- package/templates/persona-app/index.html +0 -18
- package/templates/persona-app/oomi.runtime.json +0 -13
- package/templates/persona-app/package.json +0 -44
- package/templates/persona-app/persona/brief.md +0 -14
- package/templates/persona-app/persona.json +0 -14
- package/templates/persona-app/public/manifest.webmanifest +0 -8
- package/templates/persona-app/public/oomi.health.json +0 -6
- package/templates/persona-app/src/App.css +0 -379
- package/templates/persona-app/src/App.tsx +0 -17
- package/templates/persona-app/src/index.css +0 -53
- package/templates/persona-app/src/main.tsx +0 -23
- package/templates/persona-app/src/pages/HomePage.tsx +0 -127
- package/templates/persona-app/src/pages/ScenePage.tsx +0 -158
- package/templates/persona-app/src/persona/config.ts +0 -6
- package/templates/persona-app/src/persona/notes.ts +0 -9
- package/templates/persona-app/src/spatial.ts +0 -82
- package/templates/persona-app/src/vite-env.d.ts +0 -3
- package/templates/persona-app/template.json +0 -13
- package/templates/persona-app/tsconfig.app.json +0 -23
- package/templates/persona-app/tsconfig.json +0 -7
- package/templates/persona-app/tsconfig.node.json +0 -21
- package/templates/persona-app/vendor/webspatial/FORK.md +0 -6
- package/templates/persona-app/vendor/webspatial/core-sdk/LICENSE +0 -21
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.d.ts +0 -906
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js +0 -75
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/iife/index.global.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.d.ts +0 -906
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js +0 -3131
- package/templates/persona-app/vendor/webspatial/core-sdk/dist/index.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/core-sdk/package.json +0 -45
- package/templates/persona-app/vendor/webspatial/react-sdk/LICENSE +0 -21
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.d.ts +0 -365
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js +0 -4167
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/default/index.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.d.ts +0 -82
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js +0 -66
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.d.ts +0 -2
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js +0 -18
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-dev-runtime.web.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.d.ts +0 -5
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js +0 -66
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.d.ts +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js +0 -18
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/jsx/jsx-runtime.web.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.d.ts +0 -365
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js +0 -4207
- package/templates/persona-app/vendor/webspatial/react-sdk/dist/web/index.js.map +0 -1
- package/templates/persona-app/vendor/webspatial/react-sdk/package.json +0 -94
- package/templates/persona-app/vite.config.ts +0 -31
package/lib/openclawProfile.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { generateKeyPairSync } from 'node:crypto';
|
|
4
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { generateKeyPairSync } from 'node:crypto';
|
|
4
|
+
|
|
5
5
|
const OPENCLAW_PROFILE_VERSION = 1;
|
|
6
6
|
const DEFAULT_PROFILE_PRESET = 'oomi-dev-local';
|
|
7
7
|
const DEFAULT_SESSION_KEY = 'agent:main:webchat:channel:oomi';
|
|
8
8
|
const DEFAULT_GATEWAY_PORT = 18789;
|
|
9
9
|
const DEFAULT_PLUGIN_TRUST_MODE = 'auto-discovery';
|
|
10
10
|
const DEFAULT_MODEL_AUTH_MODE = 'oomi-managed';
|
|
11
|
-
|
|
12
|
-
function trimString(value) {
|
|
13
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function ensureDir(dirPath) {
|
|
17
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function readJsonSafe(filePath, fallback = {}) {
|
|
21
|
-
if (!fs.existsSync(filePath)) return fallback;
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
24
|
-
} catch {
|
|
25
|
-
return fallback;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function writeJson(filePath, value) {
|
|
30
|
-
ensureDir(path.dirname(filePath));
|
|
31
|
-
fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n', 'utf8');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function normalizeBoolean(value, fallback = false) {
|
|
35
|
-
if (typeof value === 'boolean') return value;
|
|
36
|
-
const normalized = trimString(value).toLowerCase();
|
|
37
|
-
if (!normalized) return fallback;
|
|
38
|
-
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
39
|
-
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
40
|
-
return fallback;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function normalizePositiveInteger(value, fallback) {
|
|
44
|
-
const numeric = Number.parseInt(String(value || ''), 10);
|
|
45
|
-
if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
|
|
46
|
-
return numeric;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function sanitizeProfileId(value) {
|
|
50
|
-
const normalized = trimString(value)
|
|
51
|
-
.toLowerCase()
|
|
52
|
-
.replace(/[^a-z0-9-]+/g, '-')
|
|
53
|
-
.replace(/^-+|-+$/g, '');
|
|
54
|
-
return normalized || DEFAULT_PROFILE_PRESET;
|
|
55
|
-
}
|
|
56
|
-
|
|
11
|
+
|
|
12
|
+
function trimString(value) {
|
|
13
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function ensureDir(dirPath) {
|
|
17
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function readJsonSafe(filePath, fallback = {}) {
|
|
21
|
+
if (!fs.existsSync(filePath)) return fallback;
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
24
|
+
} catch {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function writeJson(filePath, value) {
|
|
30
|
+
ensureDir(path.dirname(filePath));
|
|
31
|
+
fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n', 'utf8');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function normalizeBoolean(value, fallback = false) {
|
|
35
|
+
if (typeof value === 'boolean') return value;
|
|
36
|
+
const normalized = trimString(value).toLowerCase();
|
|
37
|
+
if (!normalized) return fallback;
|
|
38
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
39
|
+
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
40
|
+
return fallback;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizePositiveInteger(value, fallback) {
|
|
44
|
+
const numeric = Number.parseInt(String(value || ''), 10);
|
|
45
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
|
|
46
|
+
return numeric;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sanitizeProfileId(value) {
|
|
50
|
+
const normalized = trimString(value)
|
|
51
|
+
.toLowerCase()
|
|
52
|
+
.replace(/[^a-z0-9-]+/g, '-')
|
|
53
|
+
.replace(/^-+|-+$/g, '');
|
|
54
|
+
return normalized || DEFAULT_PROFILE_PRESET;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
57
|
function normalizePluginTrustMode(value) {
|
|
58
58
|
return trimString(value) === 'plugins.allow' ? 'plugins.allow' : DEFAULT_PLUGIN_TRUST_MODE;
|
|
59
59
|
}
|
|
@@ -61,87 +61,87 @@ function normalizePluginTrustMode(value) {
|
|
|
61
61
|
function normalizeModelAuthMode(value) {
|
|
62
62
|
return trimString(value) === 'provider-env' ? 'provider-env' : DEFAULT_MODEL_AUTH_MODE;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
function resolveConfigPath(openclawHome, explicitPath = '') {
|
|
66
|
-
const targetPath = trimString(explicitPath);
|
|
67
|
-
if (targetPath) return path.resolve(targetPath);
|
|
68
|
-
|
|
69
|
-
const candidates = [
|
|
70
|
-
path.join(openclawHome, '
|
|
71
|
-
path.join(openclawHome, '
|
|
72
|
-
];
|
|
73
|
-
const existing = candidates.find((candidate) => fs.existsSync(candidate));
|
|
74
|
-
return existing || candidates[1];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function ensureDeviceIdentity(identityPath, deviceId) {
|
|
78
|
-
if (!trimString(deviceId) || fs.existsSync(identityPath)) return false;
|
|
79
|
-
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
|
|
80
|
-
writeJson(identityPath, {
|
|
81
|
-
version: 1,
|
|
82
|
-
deviceId,
|
|
83
|
-
publicKeyPem: publicKey.export({ type: 'spki', format: 'pem' }).toString(),
|
|
84
|
-
privateKeyPem: privateKey.export({ type: 'pkcs8', format: 'pem' }).toString(),
|
|
85
|
-
});
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function clearPluginAllowList(config) {
|
|
90
|
-
const nextConfig = { ...(config || {}) };
|
|
91
|
-
const plugins = typeof nextConfig.plugins === 'object' && nextConfig.plugins ? { ...nextConfig.plugins } : {};
|
|
92
|
-
if (Object.prototype.hasOwnProperty.call(plugins, 'allow')) {
|
|
93
|
-
delete plugins.allow;
|
|
94
|
-
}
|
|
95
|
-
nextConfig.plugins = plugins;
|
|
96
|
-
return nextConfig;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function ensurePluginAllowList(config) {
|
|
100
|
-
const nextConfig = { ...(config || {}) };
|
|
101
|
-
const plugins = typeof nextConfig.plugins === 'object' && nextConfig.plugins ? { ...nextConfig.plugins } : {};
|
|
102
|
-
plugins.allow = ['oomi-ai'];
|
|
103
|
-
nextConfig.plugins = plugins;
|
|
104
|
-
return nextConfig;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function applyGatewayConfig(config, gateway) {
|
|
108
|
-
const nextConfig = { ...(config || {}) };
|
|
109
|
-
const nextGateway = typeof nextConfig.gateway === 'object' && nextConfig.gateway ? { ...nextConfig.gateway } : {};
|
|
110
|
-
nextGateway.port = normalizePositiveInteger(gateway?.port, DEFAULT_GATEWAY_PORT);
|
|
111
|
-
nextGateway.mode = trimString(gateway?.mode) || 'local';
|
|
112
|
-
nextGateway.bind = trimString(gateway?.bind) || 'loopback';
|
|
113
|
-
nextGateway.auth = {
|
|
114
|
-
mode: trimString(gateway?.auth?.mode) || 'token',
|
|
115
|
-
token: trimString(gateway?.auth?.token),
|
|
116
|
-
};
|
|
117
|
-
nextGateway.tailscale = {
|
|
118
|
-
mode: 'off',
|
|
119
|
-
resetOnExit: false,
|
|
120
|
-
};
|
|
121
|
-
nextConfig.gateway = nextGateway;
|
|
122
|
-
return nextConfig;
|
|
123
|
-
}
|
|
124
|
-
|
|
64
|
+
|
|
65
|
+
function resolveConfigPath(openclawHome, explicitPath = '') {
|
|
66
|
+
const targetPath = trimString(explicitPath);
|
|
67
|
+
if (targetPath) return path.resolve(targetPath);
|
|
68
|
+
|
|
69
|
+
const candidates = [
|
|
70
|
+
path.join(openclawHome, 'openclaw.json'),
|
|
71
|
+
path.join(openclawHome, 'clawdbot.json'),
|
|
72
|
+
];
|
|
73
|
+
const existing = candidates.find((candidate) => fs.existsSync(candidate));
|
|
74
|
+
return existing || candidates[1];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function ensureDeviceIdentity(identityPath, deviceId) {
|
|
78
|
+
if (!trimString(deviceId) || fs.existsSync(identityPath)) return false;
|
|
79
|
+
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
|
|
80
|
+
writeJson(identityPath, {
|
|
81
|
+
version: 1,
|
|
82
|
+
deviceId,
|
|
83
|
+
publicKeyPem: publicKey.export({ type: 'spki', format: 'pem' }).toString(),
|
|
84
|
+
privateKeyPem: privateKey.export({ type: 'pkcs8', format: 'pem' }).toString(),
|
|
85
|
+
});
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function clearPluginAllowList(config) {
|
|
90
|
+
const nextConfig = { ...(config || {}) };
|
|
91
|
+
const plugins = typeof nextConfig.plugins === 'object' && nextConfig.plugins ? { ...nextConfig.plugins } : {};
|
|
92
|
+
if (Object.prototype.hasOwnProperty.call(plugins, 'allow')) {
|
|
93
|
+
delete plugins.allow;
|
|
94
|
+
}
|
|
95
|
+
nextConfig.plugins = plugins;
|
|
96
|
+
return nextConfig;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ensurePluginAllowList(config) {
|
|
100
|
+
const nextConfig = { ...(config || {}) };
|
|
101
|
+
const plugins = typeof nextConfig.plugins === 'object' && nextConfig.plugins ? { ...nextConfig.plugins } : {};
|
|
102
|
+
plugins.allow = ['oomi-ai'];
|
|
103
|
+
nextConfig.plugins = plugins;
|
|
104
|
+
return nextConfig;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function applyGatewayConfig(config, gateway) {
|
|
108
|
+
const nextConfig = { ...(config || {}) };
|
|
109
|
+
const nextGateway = typeof nextConfig.gateway === 'object' && nextConfig.gateway ? { ...nextConfig.gateway } : {};
|
|
110
|
+
nextGateway.port = normalizePositiveInteger(gateway?.port, DEFAULT_GATEWAY_PORT);
|
|
111
|
+
nextGateway.mode = trimString(gateway?.mode) || 'local';
|
|
112
|
+
nextGateway.bind = trimString(gateway?.bind) || 'loopback';
|
|
113
|
+
nextGateway.auth = {
|
|
114
|
+
mode: trimString(gateway?.auth?.mode) || 'token',
|
|
115
|
+
token: trimString(gateway?.auth?.token),
|
|
116
|
+
};
|
|
117
|
+
nextGateway.tailscale = {
|
|
118
|
+
mode: 'off',
|
|
119
|
+
resetOnExit: false,
|
|
120
|
+
};
|
|
121
|
+
nextConfig.gateway = nextGateway;
|
|
122
|
+
return nextConfig;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
125
|
function applyOomiChannelConfig(config, oomiChannel) {
|
|
126
|
-
const nextConfig = { ...(config || {}) };
|
|
127
|
-
const channels = typeof nextConfig.channels === 'object' && nextConfig.channels ? { ...nextConfig.channels } : {};
|
|
128
|
-
const oomi = typeof channels.oomi === 'object' && channels.oomi ? { ...channels.oomi } : {};
|
|
129
|
-
const accounts = typeof oomi.accounts === 'object' && oomi.accounts ? { ...oomi.accounts } : {};
|
|
130
|
-
const defaultAccount = typeof accounts.default === 'object' && accounts.default ? { ...accounts.default } : {};
|
|
131
|
-
|
|
132
|
-
accounts.default = {
|
|
133
|
-
enabled: true,
|
|
134
|
-
requestTimeoutMs: normalizePositiveInteger(oomiChannel?.requestTimeoutMs, 15000),
|
|
135
|
-
...defaultAccount,
|
|
136
|
-
backendUrl: trimString(oomiChannel?.backendUrl),
|
|
137
|
-
deviceToken: trimString(oomiChannel?.deviceToken),
|
|
138
|
-
defaultSessionKey: trimString(oomiChannel?.defaultSessionKey) || DEFAULT_SESSION_KEY,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
oomi.defaultAccountId = 'default';
|
|
142
|
-
oomi.accounts = accounts;
|
|
143
|
-
channels.oomi = oomi;
|
|
144
|
-
nextConfig.channels = channels;
|
|
126
|
+
const nextConfig = { ...(config || {}) };
|
|
127
|
+
const channels = typeof nextConfig.channels === 'object' && nextConfig.channels ? { ...nextConfig.channels } : {};
|
|
128
|
+
const oomi = typeof channels.oomi === 'object' && channels.oomi ? { ...channels.oomi } : {};
|
|
129
|
+
const accounts = typeof oomi.accounts === 'object' && oomi.accounts ? { ...oomi.accounts } : {};
|
|
130
|
+
const defaultAccount = typeof accounts.default === 'object' && accounts.default ? { ...accounts.default } : {};
|
|
131
|
+
|
|
132
|
+
accounts.default = {
|
|
133
|
+
enabled: true,
|
|
134
|
+
requestTimeoutMs: normalizePositiveInteger(oomiChannel?.requestTimeoutMs, 15000),
|
|
135
|
+
...defaultAccount,
|
|
136
|
+
backendUrl: trimString(oomiChannel?.backendUrl),
|
|
137
|
+
deviceToken: trimString(oomiChannel?.deviceToken),
|
|
138
|
+
defaultSessionKey: trimString(oomiChannel?.defaultSessionKey) || DEFAULT_SESSION_KEY,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
oomi.defaultAccountId = 'default';
|
|
142
|
+
oomi.accounts = accounts;
|
|
143
|
+
channels.oomi = oomi;
|
|
144
|
+
nextConfig.channels = channels;
|
|
145
145
|
return nextConfig;
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -159,7 +159,7 @@ function removeOomiChannelConfig(config) {
|
|
|
159
159
|
}
|
|
160
160
|
return nextConfig;
|
|
161
161
|
}
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
export function buildOomiDevLocalProfile(options = {}) {
|
|
164
164
|
const profileId = sanitizeProfileId(options.profileId || options.id || DEFAULT_PROFILE_PRESET);
|
|
165
165
|
const pluginTrustMode = normalizePluginTrustMode(options.pluginTrustMode);
|
|
@@ -167,99 +167,99 @@ export function buildOomiDevLocalProfile(options = {}) {
|
|
|
167
167
|
const modelAuthMode = normalizeModelAuthMode(options.modelAuthMode);
|
|
168
168
|
|
|
169
169
|
return {
|
|
170
|
-
version: OPENCLAW_PROFILE_VERSION,
|
|
171
|
-
preset: DEFAULT_PROFILE_PRESET,
|
|
172
|
-
profileId,
|
|
173
|
-
label: trimString(options.label) || 'Oomi Local Dev',
|
|
174
|
-
workspace: {
|
|
175
|
-
root: trimString(options.workspaceRoot),
|
|
176
|
-
},
|
|
177
|
-
device: {
|
|
178
|
-
id: trimString(options.deviceId),
|
|
179
|
-
},
|
|
180
|
-
gateway: {
|
|
181
|
-
port: normalizePositiveInteger(options.gatewayPort, DEFAULT_GATEWAY_PORT),
|
|
182
|
-
mode: 'local',
|
|
183
|
-
bind: 'loopback',
|
|
184
|
-
auth: {
|
|
185
|
-
mode: 'token',
|
|
186
|
-
token: trimString(options.gatewayToken),
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
oomiChannel: {
|
|
190
|
-
enabled: enableOomiChannel,
|
|
191
|
-
backendUrl: trimString(options.backendUrl),
|
|
192
|
-
deviceToken: trimString(options.deviceToken),
|
|
193
|
-
defaultSessionKey: trimString(options.defaultSessionKey) || DEFAULT_SESSION_KEY,
|
|
194
|
-
requestTimeoutMs: normalizePositiveInteger(options.requestTimeoutMs, 15000),
|
|
195
|
-
pluginTrustMode,
|
|
196
|
-
},
|
|
170
|
+
version: OPENCLAW_PROFILE_VERSION,
|
|
171
|
+
preset: trimString(options.preset) || DEFAULT_PROFILE_PRESET,
|
|
172
|
+
profileId,
|
|
173
|
+
label: trimString(options.label) || 'Oomi Local Dev',
|
|
174
|
+
workspace: {
|
|
175
|
+
root: trimString(options.workspaceRoot),
|
|
176
|
+
},
|
|
177
|
+
device: {
|
|
178
|
+
id: trimString(options.deviceId),
|
|
179
|
+
},
|
|
180
|
+
gateway: {
|
|
181
|
+
port: normalizePositiveInteger(options.gatewayPort, DEFAULT_GATEWAY_PORT),
|
|
182
|
+
mode: 'local',
|
|
183
|
+
bind: 'loopback',
|
|
184
|
+
auth: {
|
|
185
|
+
mode: 'token',
|
|
186
|
+
token: trimString(options.gatewayToken),
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
oomiChannel: {
|
|
190
|
+
enabled: enableOomiChannel,
|
|
191
|
+
backendUrl: trimString(options.backendUrl),
|
|
192
|
+
deviceToken: trimString(options.deviceToken),
|
|
193
|
+
defaultSessionKey: trimString(options.defaultSessionKey) || DEFAULT_SESSION_KEY,
|
|
194
|
+
requestTimeoutMs: normalizePositiveInteger(options.requestTimeoutMs, 15000),
|
|
195
|
+
pluginTrustMode,
|
|
196
|
+
},
|
|
197
197
|
model: {
|
|
198
198
|
preset: trimString(options.modelPreset || 'openrouter-free'),
|
|
199
199
|
authMode: modelAuthMode,
|
|
200
200
|
},
|
|
201
201
|
};
|
|
202
202
|
}
|
|
203
|
-
|
|
204
|
-
export function readOpenclawProfile(filePath) {
|
|
205
|
-
const profilePath = path.resolve(filePath);
|
|
206
|
-
return readJsonSafe(profilePath, null);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function writeOpenclawProfile(filePath, profile) {
|
|
210
|
-
const profilePath = path.resolve(filePath);
|
|
211
|
-
writeJson(profilePath, profile);
|
|
212
|
-
return profilePath;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export function applyOpenclawProfile({
|
|
216
|
-
profile,
|
|
217
|
-
openclawHome,
|
|
218
|
-
configPath = '',
|
|
219
|
-
identityPath = '',
|
|
220
|
-
ensureIdentity = true,
|
|
221
|
-
} = {}) {
|
|
222
|
-
if (!profile || typeof profile !== 'object') {
|
|
223
|
-
throw new Error('OpenClaw profile is required.');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const homeRoot = path.resolve(trimString(openclawHome) || process.cwd());
|
|
227
|
-
const resolvedConfigPath = resolveConfigPath(homeRoot, configPath);
|
|
228
|
-
const resolvedIdentityPath = path.resolve(
|
|
229
|
-
trimString(identityPath) || path.join(homeRoot, 'identity', 'device.json')
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
let nextConfig = readJsonSafe(resolvedConfigPath, {});
|
|
233
|
-
nextConfig = applyGatewayConfig(nextConfig, profile.gateway);
|
|
234
|
-
|
|
235
|
-
const pluginTrustMode = normalizePluginTrustMode(profile?.oomiChannel?.pluginTrustMode);
|
|
236
|
-
nextConfig =
|
|
237
|
-
pluginTrustMode === 'plugins.allow'
|
|
238
|
-
? ensurePluginAllowList(nextConfig)
|
|
239
|
-
: clearPluginAllowList(nextConfig);
|
|
240
|
-
|
|
203
|
+
|
|
204
|
+
export function readOpenclawProfile(filePath) {
|
|
205
|
+
const profilePath = path.resolve(filePath);
|
|
206
|
+
return readJsonSafe(profilePath, null);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function writeOpenclawProfile(filePath, profile) {
|
|
210
|
+
const profilePath = path.resolve(filePath);
|
|
211
|
+
writeJson(profilePath, profile);
|
|
212
|
+
return profilePath;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function applyOpenclawProfile({
|
|
216
|
+
profile,
|
|
217
|
+
openclawHome,
|
|
218
|
+
configPath = '',
|
|
219
|
+
identityPath = '',
|
|
220
|
+
ensureIdentity = true,
|
|
221
|
+
} = {}) {
|
|
222
|
+
if (!profile || typeof profile !== 'object') {
|
|
223
|
+
throw new Error('OpenClaw profile is required.');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const homeRoot = path.resolve(trimString(openclawHome) || process.cwd());
|
|
227
|
+
const resolvedConfigPath = resolveConfigPath(homeRoot, configPath);
|
|
228
|
+
const resolvedIdentityPath = path.resolve(
|
|
229
|
+
trimString(identityPath) || path.join(homeRoot, 'identity', 'device.json')
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
let nextConfig = readJsonSafe(resolvedConfigPath, {});
|
|
233
|
+
nextConfig = applyGatewayConfig(nextConfig, profile.gateway);
|
|
234
|
+
|
|
235
|
+
const pluginTrustMode = normalizePluginTrustMode(profile?.oomiChannel?.pluginTrustMode);
|
|
236
|
+
nextConfig =
|
|
237
|
+
pluginTrustMode === 'plugins.allow'
|
|
238
|
+
? ensurePluginAllowList(nextConfig)
|
|
239
|
+
: clearPluginAllowList(nextConfig);
|
|
240
|
+
|
|
241
241
|
if (normalizeBoolean(profile?.oomiChannel?.enabled, false)) {
|
|
242
242
|
nextConfig = applyOomiChannelConfig(nextConfig, profile.oomiChannel);
|
|
243
243
|
} else {
|
|
244
244
|
nextConfig = removeOomiChannelConfig(nextConfig);
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
writeJson(resolvedConfigPath, nextConfig);
|
|
248
|
-
|
|
249
|
-
const identityCreated =
|
|
250
|
-
ensureIdentity && trimString(profile?.device?.id)
|
|
251
|
-
? ensureDeviceIdentity(resolvedIdentityPath, profile.device.id)
|
|
252
|
-
: false;
|
|
253
|
-
|
|
254
|
-
return {
|
|
255
|
-
ok: true,
|
|
256
|
-
profileId: sanitizeProfileId(profile.profileId),
|
|
257
|
-
preset: trimString(profile.preset) || DEFAULT_PROFILE_PRESET,
|
|
258
|
-
configPath: resolvedConfigPath,
|
|
259
|
-
identityPath: resolvedIdentityPath,
|
|
260
|
-
openclawHome: homeRoot,
|
|
261
|
-
pluginTrustMode,
|
|
262
|
-
oomiChannelEnabled: normalizeBoolean(profile?.oomiChannel?.enabled, false),
|
|
263
|
-
identityCreated,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
246
|
+
|
|
247
|
+
writeJson(resolvedConfigPath, nextConfig);
|
|
248
|
+
|
|
249
|
+
const identityCreated =
|
|
250
|
+
ensureIdentity && trimString(profile?.device?.id)
|
|
251
|
+
? ensureDeviceIdentity(resolvedIdentityPath, profile.device.id)
|
|
252
|
+
: false;
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
profileId: sanitizeProfileId(profile.profileId),
|
|
257
|
+
preset: trimString(profile.preset) || DEFAULT_PROFILE_PRESET,
|
|
258
|
+
configPath: resolvedConfigPath,
|
|
259
|
+
identityPath: resolvedIdentityPath,
|
|
260
|
+
openclawHome: homeRoot,
|
|
261
|
+
pluginTrustMode,
|
|
262
|
+
oomiChannelEnabled: normalizeBoolean(profile?.oomiChannel?.enabled, false),
|
|
263
|
+
identityCreated,
|
|
264
|
+
};
|
|
265
|
+
}
|