@brantrusnak/openclaw-omadeus 1.0.3 → 1.0.4
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 +13 -62
- package/dist/src/api/auth.api.js +29 -26
- package/dist/src/onboarding.js +29 -35
- package/package.json +1 -1
- package/src/api/auth.api.ts +27 -7
- package/src/onboarding.ts +56 -63
package/README.md
CHANGED
|
@@ -1,61 +1,44 @@
|
|
|
1
1
|
# OpenClaw Omadeus Plugin
|
|
2
2
|
|
|
3
|
-
[
|
|
3
|
+
[](https://badge.socket.dev/npm/package/@brantrusnak/openclaw-omadeus)
|
|
4
|
+
[](https://github.com/brantrusnak/openclaw-omadeus-plugin/actions/workflows/npm-publish.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/@brantrusnak/openclaw-omadeus)
|
|
6
|
+
[](https://www.npmjs.com/package/@brantrusnak/openclaw-omadeus)
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
for Omadeus messages and reply through the selected Omadeus channel.
|
|
8
|
+
[Omadeus](https://omadeus.com) plugin for [OpenClaw](https://www.npmjs.com/package/openclaw).
|
|
7
9
|
|
|
8
10
|
## Requirements
|
|
9
11
|
|
|
10
12
|
- Node.js 22 or newer
|
|
11
13
|
- OpenClaw 2026.4.10 or newer
|
|
12
|
-
- An Omadeus account
|
|
13
|
-
OpenClaw to use
|
|
14
|
+
- An Omadeus account
|
|
14
15
|
|
|
15
16
|
## Install
|
|
16
17
|
|
|
17
|
-
Install OpenClaw first:
|
|
18
|
-
|
|
19
18
|
```bash
|
|
20
19
|
npm install -g openclaw
|
|
20
|
+
openclaw plugins install @brantrusnak/openclaw-omadeus
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
openclaw onboard
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Then install this plugin with the OpenClaw plugin command:
|
|
23
|
+
Verify the plugin was installed:
|
|
30
24
|
|
|
31
25
|
```bash
|
|
32
|
-
openclaw plugins
|
|
26
|
+
openclaw plugins list
|
|
33
27
|
```
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
Then run setup:
|
|
36
30
|
|
|
37
31
|
```bash
|
|
38
|
-
openclaw
|
|
39
|
-
openclaw plugins inspect omadeus
|
|
32
|
+
openclaw onboard
|
|
40
33
|
```
|
|
41
34
|
|
|
42
35
|
## Configure
|
|
43
36
|
|
|
44
|
-
After installing the plugin, run OpenClaw configuration and choose Omadeus when
|
|
45
|
-
prompted:
|
|
46
|
-
|
|
47
37
|
```bash
|
|
48
38
|
openclaw configure
|
|
49
39
|
```
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- Omadeus email and password
|
|
54
|
-
- Organization ID
|
|
55
|
-
- The Omadeus member/account to listen as
|
|
56
|
-
- The Omadeus channel to use for messages
|
|
57
|
-
|
|
58
|
-
The plugin also supports these environment variables:
|
|
41
|
+
You can also set credentials via environment variables:
|
|
59
42
|
|
|
60
43
|
```bash
|
|
61
44
|
export OMADEUS_EMAIL="you@example.com"
|
|
@@ -63,48 +46,16 @@ export OMADEUS_PASSWORD="your-password"
|
|
|
63
46
|
export OMADEUS_ORGANIZATION_ID="123"
|
|
64
47
|
```
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- CAS: `https://dev1-cas.rouztech.com`
|
|
69
|
-
- Maestro: `https://dev3-maestro.rouztech.com`
|
|
70
|
-
|
|
71
|
-
If your Omadeus deployment uses different endpoints, configure them through the
|
|
72
|
-
OpenClaw setup flow or in your OpenClaw config under `channels.omadeus`.
|
|
73
|
-
|
|
74
|
-
## Start OpenClaw
|
|
75
|
-
|
|
76
|
-
Once OpenClaw and the plugin are configured, start or restart the gateway:
|
|
49
|
+
## Start
|
|
77
50
|
|
|
78
51
|
```bash
|
|
79
52
|
openclaw gateway
|
|
80
53
|
```
|
|
81
54
|
|
|
82
|
-
Check channel health with:
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
openclaw channels status --deep
|
|
86
|
-
openclaw plugins doctor
|
|
87
|
-
```
|
|
88
|
-
|
|
89
55
|
## Local Development
|
|
90
56
|
|
|
91
|
-
Build the runtime files before linking a local checkout into OpenClaw:
|
|
92
|
-
|
|
93
57
|
```bash
|
|
94
58
|
npm install
|
|
95
59
|
npm run build
|
|
96
60
|
openclaw plugins install . --link
|
|
97
61
|
```
|
|
98
|
-
|
|
99
|
-
Before publishing, inspect the npm package contents:
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
npm run prepack
|
|
103
|
-
npm pack --dry-run
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Publish to npm:
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
npm publish
|
|
110
|
-
```
|
package/dist/src/api/auth.api.js
CHANGED
|
@@ -2,20 +2,29 @@ import { getCasSession, setCasSession } from "../store.js";
|
|
|
2
2
|
//#region src/api/auth.api.ts
|
|
3
3
|
const CAS_APPLICATION_ID = 1;
|
|
4
4
|
const CAS_SCOPES = "title,email,avatar,firstName,lastName,birth,phone,countryCode";
|
|
5
|
+
function formatFetchError(label, url, method, err) {
|
|
6
|
+
const base = err instanceof Error ? err.message : String(err);
|
|
7
|
+
const cause = err instanceof Error && err.cause instanceof Error ? err.cause.message : void 0;
|
|
8
|
+
const detail = cause && cause !== base ? `${base} (${cause})` : base;
|
|
9
|
+
return /* @__PURE__ */ new Error(`${label} (${method} ${url}) failed: ${detail}`);
|
|
10
|
+
}
|
|
11
|
+
async function omadeusFetch(label, url, init) {
|
|
12
|
+
const method = init.method ?? "GET";
|
|
13
|
+
try {
|
|
14
|
+
return await fetch(url, init);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
throw formatFetchError(label, url, method, err);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
5
19
|
async function createCasToken(params) {
|
|
6
20
|
const { casUrl, email, password } = params;
|
|
7
|
-
const
|
|
8
|
-
const jsonBody = JSON.stringify({
|
|
9
|
-
email,
|
|
10
|
-
password
|
|
11
|
-
});
|
|
12
|
-
const res = await fetch(url, {
|
|
21
|
+
const res = await omadeusFetch("CAS token request", `${casUrl}/apiv1/tokens`, {
|
|
13
22
|
method: "CREATE",
|
|
14
|
-
headers: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
email,
|
|
26
|
+
password
|
|
27
|
+
})
|
|
19
28
|
});
|
|
20
29
|
if (!res.ok) {
|
|
21
30
|
const text = await res.text().catch(() => "");
|
|
@@ -42,16 +51,13 @@ async function createAuthorizationCode(params) {
|
|
|
42
51
|
redirectUri: redirectUri ?? ""
|
|
43
52
|
});
|
|
44
53
|
if (redirectUri) qs.set("redirectUri", redirectUri);
|
|
45
|
-
const
|
|
46
|
-
const body = "";
|
|
47
|
-
const headers = {
|
|
48
|
-
Authorization: `Bearer ${token}`,
|
|
49
|
-
...casSession?.refreshCookie ? { Cookie: casSession.refreshCookie } : {}
|
|
50
|
-
};
|
|
51
|
-
const res = await fetch(url, {
|
|
54
|
+
const res = await omadeusFetch("CAS authorization code request", `${casUrl}/apiv1/authorizationcodes?${qs}`, {
|
|
52
55
|
method: "CREATE",
|
|
53
|
-
body,
|
|
54
|
-
headers
|
|
56
|
+
body: "",
|
|
57
|
+
headers: {
|
|
58
|
+
Authorization: `Bearer ${token}`,
|
|
59
|
+
...casSession?.refreshCookie ? { Cookie: casSession.refreshCookie } : {}
|
|
60
|
+
}
|
|
55
61
|
});
|
|
56
62
|
if (!res.ok) {
|
|
57
63
|
const text = await res.text().catch(() => "");
|
|
@@ -64,8 +70,7 @@ async function createAuthorizationCode(params) {
|
|
|
64
70
|
}
|
|
65
71
|
async function obtainSessionToken(params) {
|
|
66
72
|
const { maestroUrl, authorizationCode, organizationId } = params;
|
|
67
|
-
const
|
|
68
|
-
const res = await fetch(url, {
|
|
73
|
+
const res = await omadeusFetch("Omadeus session token request", `${maestroUrl}/dolphin/apiv1/oauth2/tokens`, {
|
|
69
74
|
method: "OBTAIN",
|
|
70
75
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
71
76
|
body: JSON.stringify({
|
|
@@ -83,8 +88,7 @@ async function obtainSessionToken(params) {
|
|
|
83
88
|
}
|
|
84
89
|
async function listOrganizations(params) {
|
|
85
90
|
const { maestroUrl, email } = params;
|
|
86
|
-
const
|
|
87
|
-
const res = await fetch(url, {
|
|
91
|
+
const res = await omadeusFetch("Omadeus list organizations", `${maestroUrl}/dolphin/apiv1/organizations`, {
|
|
88
92
|
method: "LIST",
|
|
89
93
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
90
94
|
body: JSON.stringify({ email })
|
|
@@ -97,8 +101,7 @@ async function listOrganizations(params) {
|
|
|
97
101
|
}
|
|
98
102
|
async function listOrganizationMembers(params) {
|
|
99
103
|
const { maestroUrl, sessionToken, organizationId } = params;
|
|
100
|
-
const
|
|
101
|
-
const res = await fetch(url, {
|
|
104
|
+
const res = await omadeusFetch("Omadeus list organization members", `${maestroUrl}/dolphin/apiv1/organizations/${organizationId}/members`, {
|
|
102
105
|
method: "LIST",
|
|
103
106
|
headers: {
|
|
104
107
|
Authorization: `Bearer ${sessionToken}`,
|
package/dist/src/onboarding.js
CHANGED
|
@@ -8,7 +8,17 @@ import { authenticate } from "./auth.js";
|
|
|
8
8
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
|
|
9
9
|
//#region src/onboarding.ts
|
|
10
10
|
const channel = "omadeus";
|
|
11
|
-
|
|
11
|
+
function formatAuthError(err) {
|
|
12
|
+
if (!(err instanceof Error)) return String(err);
|
|
13
|
+
const parts = [err.message];
|
|
14
|
+
const { cause } = err;
|
|
15
|
+
if (cause instanceof Error) {
|
|
16
|
+
parts.push(cause.message);
|
|
17
|
+
const code = cause.code;
|
|
18
|
+
if (typeof code === "string" && code) parts.push(`(${code})`);
|
|
19
|
+
} else if (typeof cause === "string" && cause.trim()) parts.push(cause);
|
|
20
|
+
return parts.join(" — ");
|
|
21
|
+
}
|
|
12
22
|
async function noteOmadeusAuthHelp(prompter) {
|
|
13
23
|
await prompter.note([
|
|
14
24
|
"Omadeus authenticates via CAS + Maestro (email + password + organization).",
|
|
@@ -66,7 +76,14 @@ async function promptChannelSelection(params) {
|
|
|
66
76
|
skip: 0,
|
|
67
77
|
take: 100
|
|
68
78
|
});
|
|
69
|
-
if (channels.length === 0)
|
|
79
|
+
if (channels.length === 0) {
|
|
80
|
+
await prompter.note("No channels found for this account. Channel listening will stay disabled.", "Omadeus channels");
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
if (!await prompter.confirm({
|
|
84
|
+
message: "Listen for messages in Omadeus channels?",
|
|
85
|
+
initialValue: (existingChannelViewIds?.length ?? 0) > 0
|
|
86
|
+
})) return [];
|
|
70
87
|
const selected = await promptMultiSelect({
|
|
71
88
|
prompter,
|
|
72
89
|
message: "Which channels should OpenClaw listen to?",
|
|
@@ -75,11 +92,9 @@ async function promptChannelSelection(params) {
|
|
|
75
92
|
label: item.title || `Channel ${item.id}`,
|
|
76
93
|
hint: [item.privateRoomId ? `private:${item.privateRoomId}` : void 0, item.publicRoomId ? `public:${item.publicRoomId}` : void 0].filter(Boolean).join(" | ")
|
|
77
94
|
})),
|
|
78
|
-
initialValues: existingChannelViewIds && existingChannelViewIds.length > 0 ? existingChannelViewIds.map(String) :
|
|
95
|
+
initialValues: existingChannelViewIds && existingChannelViewIds.length > 0 ? existingChannelViewIds.map(String) : void 0
|
|
79
96
|
});
|
|
80
|
-
|
|
81
|
-
if (chosen.length === 0) throw new Error("At least one channel must be selected.");
|
|
82
|
-
return chosen;
|
|
97
|
+
return channels.filter((item) => selected.includes(String(item.id)));
|
|
83
98
|
}
|
|
84
99
|
function memberHint(member) {
|
|
85
100
|
const parts = [
|
|
@@ -90,32 +105,11 @@ function memberHint(member) {
|
|
|
90
105
|
return parts.length > 0 ? parts.join(" | ") : void 0;
|
|
91
106
|
}
|
|
92
107
|
async function promptMultiSelect(params) {
|
|
93
|
-
|
|
94
|
-
const runMulti = multi.multiSelect ?? multi.multiselect;
|
|
95
|
-
if (runMulti) return runMulti({
|
|
108
|
+
return params.prompter.multiselect({
|
|
96
109
|
message: params.message,
|
|
97
110
|
options: params.options,
|
|
98
|
-
initialValues: params.initialValues
|
|
99
|
-
initialValue: params.initialValues
|
|
111
|
+
initialValues: params.initialValues
|
|
100
112
|
});
|
|
101
|
-
const selected = new Set(params.initialValues ?? []);
|
|
102
|
-
while (true) {
|
|
103
|
-
const next = await params.prompter.select({
|
|
104
|
-
message: `${params.message} (${selected.size} selected)`,
|
|
105
|
-
options: [{
|
|
106
|
-
value: DONE,
|
|
107
|
-
label: selected.size > 0 ? "Done" : "Done (select none)"
|
|
108
|
-
}, ...params.options.map((option) => ({
|
|
109
|
-
...option,
|
|
110
|
-
label: selected.has(option.value) ? `[selected] ${option.label}` : option.label
|
|
111
|
-
}))],
|
|
112
|
-
initialValue: DONE
|
|
113
|
-
});
|
|
114
|
-
const value = String(next);
|
|
115
|
-
if (value === DONE) return [...selected];
|
|
116
|
-
if (selected.has(value)) selected.delete(value);
|
|
117
|
-
else selected.add(value);
|
|
118
|
-
}
|
|
119
113
|
}
|
|
120
114
|
async function loadSelectableMembers(params) {
|
|
121
115
|
const excluded = new Set(params.excludeReferenceIds ?? []);
|
|
@@ -244,8 +238,7 @@ const omadeusSetupWizard = {
|
|
|
244
238
|
await prompter.note(`Authenticated as ${payload.email}`, "Omadeus authentication");
|
|
245
239
|
break;
|
|
246
240
|
} catch (err) {
|
|
247
|
-
|
|
248
|
-
await prompter.note(`Authentication failed: ${msg}`, "Omadeus authentication");
|
|
241
|
+
await prompter.note(`Authentication failed: ${formatAuthError(err)}`, "Omadeus authentication");
|
|
249
242
|
if (!await prompter.confirm({
|
|
250
243
|
message: "Re-enter email/password and try again?",
|
|
251
244
|
initialValue: true
|
|
@@ -280,12 +273,12 @@ const omadeusSetupWizard = {
|
|
|
280
273
|
memberReferenceId: selfReferenceId,
|
|
281
274
|
existingChannelViewIds: existingInbound?.channels?.allowedChannelViewIds
|
|
282
275
|
});
|
|
283
|
-
const channelSenderIds = await promptSenderAllowlist({
|
|
276
|
+
const channelSenderIds = selectedChannels.length > 0 ? await promptSenderAllowlist({
|
|
284
277
|
prompter,
|
|
285
278
|
message: "Which users can trigger OpenClaw from allowed channels?",
|
|
286
279
|
members,
|
|
287
280
|
existingReferenceIds: existingInbound?.channels?.allowedSenderReferenceIds
|
|
288
|
-
});
|
|
281
|
+
}) : void 0;
|
|
289
282
|
const entityKinds = await promptEntityKindSelection({
|
|
290
283
|
prompter,
|
|
291
284
|
existingKinds: existingInbound?.entities?.allowedKinds
|
|
@@ -301,10 +294,11 @@ const omadeusSetupWizard = {
|
|
|
301
294
|
const channelTitles = selectedChannels.map((selectedChannel) => selectedChannel.title || `Channel ${selectedChannel.id}`).join(", ");
|
|
302
295
|
const senderSummary = (ids) => ids && ids.length > 0 ? ids.join(", ") : "all users";
|
|
303
296
|
const entityKindSummary = entityKinds.length > 0 ? entityKinds.join(", ") : "none (entity rooms disabled)";
|
|
297
|
+
const channelSummary = selectedChannels.length > 0 ? `- Channels "${channelTitles}": rooms ${channelRoomIds.join(", ") || "(no room ids)"} from ${senderSummary(channelSenderIds)}; @mention not required in those rooms.` : "- Channels: disabled (none selected).";
|
|
304
298
|
await prompter.note([
|
|
305
299
|
`Inbound policy (Jaguar chat):`,
|
|
306
300
|
`- Direct messages: enabled for ${senderSummary(directSenderIds)} (no @mention required).`,
|
|
307
|
-
|
|
301
|
+
channelSummary,
|
|
308
302
|
`- Entity rooms (${entityKindSummary}): ${senderSummary(entitySenderIds)}; @mention required.`
|
|
309
303
|
].join("\n"), "Omadeus inbound policy");
|
|
310
304
|
next = {
|
|
@@ -327,7 +321,7 @@ const omadeusSetupWizard = {
|
|
|
327
321
|
requireMention: "never"
|
|
328
322
|
},
|
|
329
323
|
channels: {
|
|
330
|
-
enabled:
|
|
324
|
+
enabled: selectedChannels.length > 0,
|
|
331
325
|
allowedRoomIds: channelRoomIds,
|
|
332
326
|
allowedChannelViewIds: channelViewIds,
|
|
333
327
|
...channelSenderIds ? { allowedSenderReferenceIds: channelSenderIds } : {},
|
package/package.json
CHANGED
package/src/api/auth.api.ts
CHANGED
|
@@ -9,6 +9,27 @@ import type {
|
|
|
9
9
|
const CAS_APPLICATION_ID = 1;
|
|
10
10
|
const CAS_SCOPES = "title,email,avatar,firstName,lastName,birth,phone,countryCode";
|
|
11
11
|
|
|
12
|
+
function formatFetchError(label: string, url: string, method: string, err: unknown): Error {
|
|
13
|
+
const base = err instanceof Error ? err.message : String(err);
|
|
14
|
+
const cause =
|
|
15
|
+
err instanceof Error && err.cause instanceof Error ? err.cause.message : undefined;
|
|
16
|
+
const detail = cause && cause !== base ? `${base} (${cause})` : base;
|
|
17
|
+
return new Error(`${label} (${method} ${url}) failed: ${detail}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function omadeusFetch(
|
|
21
|
+
label: string,
|
|
22
|
+
url: string,
|
|
23
|
+
init: RequestInit,
|
|
24
|
+
): Promise<Response> {
|
|
25
|
+
const method = init.method ?? "GET";
|
|
26
|
+
try {
|
|
27
|
+
return await fetch(url, init);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
throw formatFetchError(label, url, method, err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
12
33
|
export async function createCasToken(params: {
|
|
13
34
|
casUrl: string;
|
|
14
35
|
email: string;
|
|
@@ -17,11 +38,10 @@ export async function createCasToken(params: {
|
|
|
17
38
|
const { casUrl, email, password } = params;
|
|
18
39
|
const url = `${casUrl}/apiv1/tokens`;
|
|
19
40
|
const jsonBody = JSON.stringify({ email, password });
|
|
20
|
-
const res = await
|
|
41
|
+
const res = await omadeusFetch("CAS token request", url, {
|
|
21
42
|
method: "CREATE",
|
|
22
43
|
headers: {
|
|
23
44
|
"Content-Type": "application/json;charset=UTF-8",
|
|
24
|
-
"Content-Length": String(jsonBody.length),
|
|
25
45
|
},
|
|
26
46
|
body: jsonBody,
|
|
27
47
|
});
|
|
@@ -44,7 +64,7 @@ export async function getMe(params: {
|
|
|
44
64
|
}): Promise<{ email: string }> {
|
|
45
65
|
const { casUrl, casToken, refreshCookie } = params;
|
|
46
66
|
const url = `${casUrl}/apiv1/members/me`;
|
|
47
|
-
const res = await
|
|
67
|
+
const res = await omadeusFetch("CAS get member", url, {
|
|
48
68
|
method: "GET",
|
|
49
69
|
headers: {
|
|
50
70
|
Authorization: `Bearer ${casToken}`,
|
|
@@ -80,7 +100,7 @@ export async function createAuthorizationCode(params: {
|
|
|
80
100
|
Authorization: `Bearer ${token}`,
|
|
81
101
|
...(casSession?.refreshCookie ? { Cookie: casSession.refreshCookie } : {}),
|
|
82
102
|
};
|
|
83
|
-
const res = await
|
|
103
|
+
const res = await omadeusFetch("CAS authorization code request", url, {
|
|
84
104
|
method: "CREATE",
|
|
85
105
|
body,
|
|
86
106
|
headers,
|
|
@@ -104,7 +124,7 @@ export async function obtainSessionToken(params: {
|
|
|
104
124
|
}): Promise<string> {
|
|
105
125
|
const { maestroUrl, authorizationCode, organizationId } = params;
|
|
106
126
|
const url = `${maestroUrl}/dolphin/apiv1/oauth2/tokens`;
|
|
107
|
-
const res = await
|
|
127
|
+
const res = await omadeusFetch("Omadeus session token request", url, {
|
|
108
128
|
method: "OBTAIN",
|
|
109
129
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
110
130
|
body: JSON.stringify({ authorizationCode, organizationId }),
|
|
@@ -126,7 +146,7 @@ export async function listOrganizations(params: {
|
|
|
126
146
|
}): Promise<OmadeusOrganization[]> {
|
|
127
147
|
const { maestroUrl, email } = params;
|
|
128
148
|
const url = `${maestroUrl}/dolphin/apiv1/organizations`;
|
|
129
|
-
const res = await
|
|
149
|
+
const res = await omadeusFetch("Omadeus list organizations", url, {
|
|
130
150
|
method: "LIST",
|
|
131
151
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
|
132
152
|
body: JSON.stringify({ email }),
|
|
@@ -145,7 +165,7 @@ export async function listOrganizationMembers(params: {
|
|
|
145
165
|
}): Promise<OmadeusOrganizationMember[]> {
|
|
146
166
|
const { maestroUrl, sessionToken, organizationId } = params;
|
|
147
167
|
const url = `${maestroUrl}/dolphin/apiv1/organizations/${organizationId}/members`;
|
|
148
|
-
const res = await
|
|
168
|
+
const res = await omadeusFetch("Omadeus list organization members", url, {
|
|
149
169
|
method: "LIST",
|
|
150
170
|
headers: {
|
|
151
171
|
Authorization: `Bearer ${sessionToken}`,
|
package/src/onboarding.ts
CHANGED
|
@@ -18,7 +18,6 @@ import type {
|
|
|
18
18
|
import { OMADEUS_INBOUND_ENTITY_KINDS } from "./types.js";
|
|
19
19
|
|
|
20
20
|
const channel = "omadeus" as const;
|
|
21
|
-
const DONE = "__done__";
|
|
22
21
|
|
|
23
22
|
type SelectOption = {
|
|
24
23
|
value: string;
|
|
@@ -26,17 +25,21 @@ type SelectOption = {
|
|
|
26
25
|
hint?: string;
|
|
27
26
|
};
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
28
|
+
function formatAuthError(err: unknown): string {
|
|
29
|
+
if (!(err instanceof Error)) return String(err);
|
|
30
|
+
const parts = [err.message];
|
|
31
|
+
const { cause } = err;
|
|
32
|
+
if (cause instanceof Error) {
|
|
33
|
+
parts.push(cause.message);
|
|
34
|
+
const code = (cause as Error & { code?: unknown }).code;
|
|
35
|
+
if (typeof code === "string" && code) {
|
|
36
|
+
parts.push(`(${code})`);
|
|
37
|
+
}
|
|
38
|
+
} else if (typeof cause === "string" && cause.trim()) {
|
|
39
|
+
parts.push(cause);
|
|
40
|
+
}
|
|
41
|
+
return parts.join(" — ");
|
|
42
|
+
}
|
|
40
43
|
|
|
41
44
|
async function noteOmadeusAuthHelp(prompter: WizardPrompter): Promise<void> {
|
|
42
45
|
await prompter.note(
|
|
@@ -118,8 +121,21 @@ async function promptChannelSelection(params: {
|
|
|
118
121
|
take: 100,
|
|
119
122
|
});
|
|
120
123
|
if (channels.length === 0) {
|
|
121
|
-
|
|
124
|
+
await prompter.note(
|
|
125
|
+
"No channels found for this account. Channel listening will stay disabled.",
|
|
126
|
+
"Omadeus channels",
|
|
127
|
+
);
|
|
128
|
+
return [];
|
|
122
129
|
}
|
|
130
|
+
|
|
131
|
+
const listenToChannels = await prompter.confirm({
|
|
132
|
+
message: "Listen for messages in Omadeus channels?",
|
|
133
|
+
initialValue: (existingChannelViewIds?.length ?? 0) > 0,
|
|
134
|
+
});
|
|
135
|
+
if (!listenToChannels) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
|
|
123
139
|
const selected = await promptMultiSelect({
|
|
124
140
|
prompter,
|
|
125
141
|
message: "Which channels should OpenClaw listen to?",
|
|
@@ -133,13 +149,9 @@ async function promptChannelSelection(params: {
|
|
|
133
149
|
initialValues:
|
|
134
150
|
existingChannelViewIds && existingChannelViewIds.length > 0
|
|
135
151
|
? existingChannelViewIds.map(String)
|
|
136
|
-
:
|
|
152
|
+
: undefined,
|
|
137
153
|
});
|
|
138
|
-
|
|
139
|
-
if (chosen.length === 0) {
|
|
140
|
-
throw new Error("At least one channel must be selected.");
|
|
141
|
-
}
|
|
142
|
-
return chosen;
|
|
154
|
+
return channels.filter((item) => selected.includes(String(item.id)));
|
|
143
155
|
}
|
|
144
156
|
|
|
145
157
|
function memberHint(member: OmadeusOrganizationMember): string | undefined {
|
|
@@ -154,40 +166,11 @@ async function promptMultiSelect(params: {
|
|
|
154
166
|
options: SelectOption[];
|
|
155
167
|
initialValues?: string[];
|
|
156
168
|
}): Promise<string[]> {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
options: params.options,
|
|
163
|
-
initialValues: params.initialValues,
|
|
164
|
-
initialValue: params.initialValues,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const selected = new Set(params.initialValues ?? []);
|
|
169
|
-
while (true) {
|
|
170
|
-
const next = await params.prompter.select({
|
|
171
|
-
message: `${params.message} (${selected.size} selected)`,
|
|
172
|
-
options: [
|
|
173
|
-
{ value: DONE, label: selected.size > 0 ? "Done" : "Done (select none)" },
|
|
174
|
-
...params.options.map((option) => ({
|
|
175
|
-
...option,
|
|
176
|
-
label: selected.has(option.value) ? `[selected] ${option.label}` : option.label,
|
|
177
|
-
})),
|
|
178
|
-
],
|
|
179
|
-
initialValue: DONE,
|
|
180
|
-
});
|
|
181
|
-
const value = String(next);
|
|
182
|
-
if (value === DONE) {
|
|
183
|
-
return [...selected];
|
|
184
|
-
}
|
|
185
|
-
if (selected.has(value)) {
|
|
186
|
-
selected.delete(value);
|
|
187
|
-
} else {
|
|
188
|
-
selected.add(value);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
169
|
+
return params.prompter.multiselect({
|
|
170
|
+
message: params.message,
|
|
171
|
+
options: params.options,
|
|
172
|
+
initialValues: params.initialValues,
|
|
173
|
+
});
|
|
191
174
|
}
|
|
192
175
|
|
|
193
176
|
async function loadSelectableMembers(params: {
|
|
@@ -370,8 +353,10 @@ export const omadeusSetupWizard: ChannelSetupWizard = {
|
|
|
370
353
|
await prompter.note(`Authenticated as ${payload.email}`, "Omadeus authentication");
|
|
371
354
|
break;
|
|
372
355
|
} catch (err) {
|
|
373
|
-
|
|
374
|
-
|
|
356
|
+
await prompter.note(
|
|
357
|
+
`Authentication failed: ${formatAuthError(err)}`,
|
|
358
|
+
"Omadeus authentication",
|
|
359
|
+
);
|
|
375
360
|
const retry = await prompter.confirm({
|
|
376
361
|
message: "Re-enter email/password and try again?",
|
|
377
362
|
initialValue: true,
|
|
@@ -418,12 +403,15 @@ export const omadeusSetupWizard: ChannelSetupWizard = {
|
|
|
418
403
|
existingChannelViewIds: existingInbound?.channels?.allowedChannelViewIds,
|
|
419
404
|
});
|
|
420
405
|
|
|
421
|
-
const channelSenderIds =
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
406
|
+
const channelSenderIds =
|
|
407
|
+
selectedChannels.length > 0
|
|
408
|
+
? await promptSenderAllowlist({
|
|
409
|
+
prompter,
|
|
410
|
+
message: "Which users can trigger OpenClaw from allowed channels?",
|
|
411
|
+
members,
|
|
412
|
+
existingReferenceIds: existingInbound?.channels?.allowedSenderReferenceIds,
|
|
413
|
+
})
|
|
414
|
+
: undefined;
|
|
427
415
|
|
|
428
416
|
const entityKinds = await promptEntityKindSelection({
|
|
429
417
|
prompter,
|
|
@@ -456,11 +444,16 @@ export const omadeusSetupWizard: ChannelSetupWizard = {
|
|
|
456
444
|
const entityKindSummary =
|
|
457
445
|
entityKinds.length > 0 ? entityKinds.join(", ") : "none (entity rooms disabled)";
|
|
458
446
|
|
|
447
|
+
const channelSummary =
|
|
448
|
+
selectedChannels.length > 0
|
|
449
|
+
? `- Channels "${channelTitles}": rooms ${channelRoomIds.join(", ") || "(no room ids)"} from ${senderSummary(channelSenderIds)}; @mention not required in those rooms.`
|
|
450
|
+
: "- Channels: disabled (none selected).";
|
|
451
|
+
|
|
459
452
|
await prompter.note(
|
|
460
453
|
[
|
|
461
454
|
`Inbound policy (Jaguar chat):`,
|
|
462
455
|
`- Direct messages: enabled for ${senderSummary(directSenderIds)} (no @mention required).`,
|
|
463
|
-
|
|
456
|
+
channelSummary,
|
|
464
457
|
`- Entity rooms (${entityKindSummary}): ${senderSummary(entitySenderIds)}; @mention required.`,
|
|
465
458
|
].join("\n"),
|
|
466
459
|
"Omadeus inbound policy",
|
|
@@ -486,7 +479,7 @@ export const omadeusSetupWizard: ChannelSetupWizard = {
|
|
|
486
479
|
requireMention: "never",
|
|
487
480
|
},
|
|
488
481
|
channels: {
|
|
489
|
-
enabled:
|
|
482
|
+
enabled: selectedChannels.length > 0,
|
|
490
483
|
allowedRoomIds: channelRoomIds,
|
|
491
484
|
allowedChannelViewIds: channelViewIds,
|
|
492
485
|
...(channelSenderIds ? { allowedSenderReferenceIds: channelSenderIds } : {}),
|