oomi-ai 0.2.2 → 0.2.3

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 CHANGED
@@ -49,12 +49,15 @@ oomi openclaw pair --app-url https://your-oomi-app.vercel.app --device-id my-ope
49
49
  `--app-url` must be reachable from the OpenClaw host. If OpenClaw runs on a different machine/network, do not use `localhost` unless tunneled.
50
50
 
51
51
  This prints:
52
- - `Connect code: <device-id>`
53
- - `Connect URL: https://.../?connect=managed://<device-id>&sessionKey=...`
52
+ - `Auth invite URL: https://.../connect/<single-use-token>`
54
53
  - A copy-ready block for the user:
55
54
  - `Oomi Connect Ready`
56
- - `Code: ...`
57
- - `Link: ...`
55
+ - `Auth Link: ...`
56
+
57
+ If you need a fresh auth link later (without re-pairing), run:
58
+ ```
59
+ oomi openclaw invite --app-url https://your-oomi-app.vercel.app
60
+ ```
58
61
 
59
62
  Agent-intent mapping (recommended):
60
63
  - If user says `Connect yourself to Oomi. Use app URL https://www.oomi.ai.`
@@ -68,7 +71,7 @@ Agent-intent mapping (recommended):
68
71
 
69
72
  Important distinction:
70
73
  - `pairCode` is one-time and used internally by the pair/bootstrap flow.
71
- - `connect code` is the stable device id used by browser connect (`managed://<device-id>`).
74
+ - Invite auth links are the required user flow.
72
75
 
73
76
  Sync personas from the repo into the backend registry:
74
77
  ```
@@ -31,7 +31,12 @@ If the user asks to connect OpenClaw to Oomi voice/web:
31
31
  - Example: `oomi openclaw pair --app-url <URL> --no-start`
32
32
  8. Return this exact result format to the user:
33
33
  - `Oomi Connect Ready`
34
- - `Code: ...`
35
- - `Link: ...`
34
+ - `Auth Link: ...`
35
+ - No extra narrative text before or after those lines.
36
+
37
+ Primary UX requirement:
38
+ - Never ask the user to enter raw pairing identifiers.
39
+ - The user should open the auth link, complete sign-in, and land directly in connected chat.
40
+ - Return `/connect/<invite-token>` auth links only.
36
41
 
37
42
  Do not ask users to paste gateway IP/token/password when managed connect is available.
package/bin/oomi-ai.js CHANGED
@@ -142,6 +142,9 @@ Commands:
142
142
  openclaw pair
143
143
  Pair this OpenClaw host with Oomi and start bridge (single command).
144
144
 
145
+ openclaw invite
146
+ Create a single-use auth invite link for the paired OpenClaw device.
147
+
145
148
  openclaw plugin
146
149
  Print OpenClaw extension install/config guidance for Oomi channel plugin.
147
150
 
@@ -158,7 +161,7 @@ Common flags:
158
161
  --broker-http URL Managed broker HTTPS URL (for pair claim)
159
162
  --broker-ws URL Managed broker device WS URL (wss://.../cable)
160
163
  --pair-code CODE One-time pairing code from Oomi
161
- --app-url URL Oomi app URL used for pairing APIs (default: http://127.0.0.1:3000)
164
+ --app-url URL Oomi app URL used for pairing APIs (default: http://127.0.0.1:3456)
162
165
  --label TEXT Pairing label shown in broker logs
163
166
  --session-key KEY Session key used in generated connect URL
164
167
  --detach Start bridge in background and exit
@@ -595,6 +598,25 @@ async function requestManagedPairCode({ appUrl, label }) {
595
598
  return payload;
596
599
  }
597
600
 
601
+ async function requestConnectInviteLink({ backendHttp, appUrl, sessionKey, deviceToken }) {
602
+ const response = await fetch(`${backendHttp.replace(/\/$/, '')}/v1/invite_links/start`, {
603
+ method: 'POST',
604
+ headers: {
605
+ 'Content-Type': 'application/json',
606
+ Authorization: `Bearer ${deviceToken}`,
607
+ },
608
+ body: JSON.stringify({ appUrl, sessionKey }),
609
+ });
610
+ const payload = await response.json().catch(() => ({}));
611
+ if (!response.ok || !payload?.inviteUrl) {
612
+ const message =
613
+ (payload && typeof payload.error === 'string' && payload.error) ||
614
+ `Invite link start failed (${response.status})`;
615
+ throw new Error(message);
616
+ }
617
+ return payload;
618
+ }
619
+
598
620
  async function fetchManagedGatewayConfig({ appUrl }) {
599
621
  const baseUrl = appUrl.replace(/\/$/, '');
600
622
  const response = await fetch(`${baseUrl}/api/gateway/managed/config`, {
@@ -924,7 +946,7 @@ async function startOpenclawBridge(flags) {
924
946
 
925
947
  async function pairAndStartOpenclawBridge(flags) {
926
948
  const bridgeState = readBridgeState();
927
- const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:3000').trim();
949
+ const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:3456').trim();
928
950
  const deviceId = resolveDeviceId(flags, bridgeState);
929
951
  const label = String(flags.label || `${deviceId}-bridge`).trim();
930
952
  const sessionKey = String(
@@ -961,19 +983,24 @@ async function pairAndStartOpenclawBridge(flags) {
961
983
  brokerWs,
962
984
  deviceId,
963
985
  deviceToken,
986
+ sessionKey,
964
987
  claimedAt: new Date().toISOString(),
965
988
  expiresAt: claimed.expiresAt || null,
966
989
  });
967
990
 
968
- const connectCode = deviceId;
969
- const gatewayValue = `managed://${deviceId}`;
970
- const connectUrl = `${appUrl.replace(/\/$/, '')}/?connect=${encodeURIComponent(gatewayValue)}&sessionKey=${encodeURIComponent(sessionKey)}`;
991
+ const invite = await requestConnectInviteLink({
992
+ backendHttp: managedConfig.brokerHttpUrl,
993
+ appUrl,
994
+ sessionKey,
995
+ deviceToken,
996
+ });
997
+ const inviteUrl = String(invite.inviteUrl || '').trim();
998
+ const inviteExpiresAt = String(invite.expiresAt || '').trim();
971
999
 
972
1000
  const pairSummary = {
973
1001
  deviceId,
974
- connectCode,
975
- gatewayValue,
976
- connectUrl,
1002
+ inviteUrl,
1003
+ inviteExpiresAt,
977
1004
  brokerHttpUrl: managedConfig.brokerHttpUrl,
978
1005
  brokerDeviceWsUrl: brokerWs,
979
1006
  bridgeMode: shouldStart ? (detach ? 'detached' : 'attached') : 'skipped',
@@ -984,15 +1011,15 @@ async function pairAndStartOpenclawBridge(flags) {
984
1011
  console.log(JSON.stringify(pairSummary, null, 2));
985
1012
  } else {
986
1013
  console.log(`Paired device: ${deviceId}`);
987
- console.log(`Connect code: ${connectCode}`);
988
- console.log(`Gateway value: ${gatewayValue}`);
989
- console.log(`Connect URL: ${connectUrl}`);
1014
+ console.log(`Auth invite URL: ${inviteUrl}`);
1015
+ if (inviteExpiresAt) {
1016
+ console.log(`Invite expires at: ${inviteExpiresAt}`);
1017
+ }
990
1018
  console.log('');
991
- console.log('Share this with the user:');
1019
+ console.log('Share this exact response with the user (no extra text):');
992
1020
  console.log('----------------------------------------');
993
1021
  console.log('Oomi Connect Ready');
994
- console.log(`Code: ${connectCode}`);
995
- console.log(`Link: ${connectUrl}`);
1022
+ console.log(`Auth Link: ${inviteUrl}`);
996
1023
  console.log('----------------------------------------');
997
1024
  }
998
1025
 
@@ -1033,6 +1060,61 @@ async function pairAndStartOpenclawBridge(flags) {
1033
1060
  });
1034
1061
  }
1035
1062
 
1063
+ async function createOpenclawInviteLink(flags) {
1064
+ const bridgeState = readBridgeState();
1065
+ const backendHttp = String(
1066
+ flags['backend-url'] ||
1067
+ flags['broker-http'] ||
1068
+ process.env.OOMI_BACKEND_URL ||
1069
+ process.env.OOMI_CHAT_BROKER_HTTP_URL ||
1070
+ bridgeState.brokerHttp ||
1071
+ ''
1072
+ ).trim();
1073
+ const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:3456').trim();
1074
+ const sessionKey = String(
1075
+ flags['session-key'] ||
1076
+ process.env.OOMI_SESSION_KEY ||
1077
+ bridgeState.sessionKey ||
1078
+ 'agent:main:webchat:channel:oomi'
1079
+ ).trim();
1080
+ const deviceToken = String(flags['device-token'] || bridgeState.deviceToken || '').trim();
1081
+ const jsonOutput = isTruthyFlag(flags.json);
1082
+
1083
+ if (!backendHttp) {
1084
+ throw new Error('Missing backend URL. Set --backend-url (or --broker-http) or pair first.');
1085
+ }
1086
+ if (!deviceToken) {
1087
+ throw new Error('Missing device token in bridge state. Run: oomi openclaw pair --app-url https://www.oomi.ai --no-start');
1088
+ }
1089
+
1090
+ const invite = await requestConnectInviteLink({
1091
+ backendHttp,
1092
+ appUrl,
1093
+ sessionKey,
1094
+ deviceToken,
1095
+ });
1096
+
1097
+ const summary = {
1098
+ appUrl,
1099
+ backendHttp,
1100
+ inviteUrl: invite.inviteUrl,
1101
+ expiresAt: invite.expiresAt || null,
1102
+ sessionKey,
1103
+ };
1104
+
1105
+ if (jsonOutput) {
1106
+ console.log(JSON.stringify(summary, null, 2));
1107
+ return;
1108
+ }
1109
+
1110
+ console.log('Oomi Auth Invite Ready');
1111
+ console.log('----------------------');
1112
+ console.log(`Auth Link: ${summary.inviteUrl}`);
1113
+ if (summary.expiresAt) {
1114
+ console.log(`Expires: ${summary.expiresAt}`);
1115
+ }
1116
+ }
1117
+
1036
1118
  function printOpenclawPluginSetup(flags) {
1037
1119
  const bridgeState = readBridgeState();
1038
1120
  const backendUrl = String(
@@ -1141,6 +1223,11 @@ async function main() {
1141
1223
  return;
1142
1224
  }
1143
1225
 
1226
+ if (command === 'openclaw' && subcommand === 'invite') {
1227
+ await createOpenclawInviteLink(args.flags);
1228
+ return;
1229
+ }
1230
+
1144
1231
  if (command === 'openclaw' && subcommand === 'plugin') {
1145
1232
  printOpenclawPluginSetup(args.flags);
1146
1233
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oomi-ai",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Oomi CLI for OpenClaw setup",
5
5
  "bin": {
6
6
  "oomi": "bin/oomi-ai.js"
@@ -31,7 +31,12 @@ If the user asks to connect OpenClaw to Oomi voice/web:
31
31
  - Example: `oomi openclaw pair --app-url <URL> --no-start`
32
32
  8. Return this exact result format to the user:
33
33
  - `Oomi Connect Ready`
34
- - `Code: ...`
35
- - `Link: ...`
34
+ - `Auth Link: ...`
35
+ - No extra narrative text before or after those lines.
36
+
37
+ Primary UX requirement:
38
+ - Never ask the user to enter raw pairing identifiers.
39
+ - The user should open the auth link, complete sign-in, and land directly in connected chat.
40
+ - Return `/connect/<invite-token>` auth links only.
36
41
 
37
42
  Do not ask users to paste gateway IP/token/password when managed connect is available.