@leg3ndy/otto-bridge 0.1.3 → 0.2.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 +34 -6
- package/dist/config.js +22 -3
- package/dist/executors/native_macos.js +255 -0
- package/dist/main.js +3 -3
- package/dist/runtime.js +4 -0
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Companion local do Otto para:
|
|
|
5
5
|
- reivindicar um codigo de pareamento gerado pela web
|
|
6
6
|
- armazenar o `device_token` do dispositivo
|
|
7
7
|
- manter um WebSocket persistente com o backend
|
|
8
|
-
- executar jobs locais com `mock` ou `clawd-cursor`
|
|
8
|
+
- executar jobs locais com executor proprio do Otto no macOS, `mock` ou `clawd-cursor`
|
|
9
9
|
|
|
10
10
|
## Guia de uso
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ Enquanto o pacote nao estiver publicado, voce pode gerar um tarball local:
|
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
npm pack
|
|
34
|
-
npm install -g ./leg3ndy-otto-bridge-0.
|
|
34
|
+
npm install -g ./leg3ndy-otto-bridge-0.2.0.tgz
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Publicacao
|
|
@@ -66,7 +66,7 @@ otto-bridge --help
|
|
|
66
66
|
### Parear o dispositivo
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
otto-bridge pair --api http://localhost:8000 --code ABC123
|
|
69
|
+
otto-bridge pair --api http://localhost:8000 --code ABC123
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Opcoes suportadas:
|
|
@@ -74,18 +74,32 @@ Opcoes suportadas:
|
|
|
74
74
|
- `--name`: nome amigavel do dispositivo
|
|
75
75
|
- `--timeout-seconds`: limite de espera pela aprovacao web
|
|
76
76
|
- `--poll-interval-ms`: intervalo de polling do claim
|
|
77
|
-
- `--executor`: `mock` ou `clawd-cursor`
|
|
77
|
+
- `--executor`: `native-macos`, `mock` ou `clawd-cursor`
|
|
78
78
|
- `--clawd-url`: base URL da API local do `clawd-cursor`
|
|
79
79
|
- `--clawd-poll-interval-ms`: polling do status/logs do `clawd-cursor`
|
|
80
80
|
|
|
81
|
+
No macOS, o caminho recomendado agora e o executor nativo do Otto Bridge. Se nenhum `--executor` for informado, o `pair` usa `native-macos` por padrao no Mac.
|
|
82
|
+
|
|
81
83
|
### Rodar o bridge
|
|
82
84
|
|
|
83
85
|
```bash
|
|
84
|
-
otto-bridge run
|
|
86
|
+
otto-bridge run
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
Se o executor estiver salvo no `config.json`, o `run` usa essa configuracao por padrao.
|
|
88
90
|
|
|
91
|
+
Para forcar o executor nativo no macOS sem reparar:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
otto-bridge run --executor native-macos
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
O adapter `clawd-cursor` continua disponivel como override opcional:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
otto-bridge run --executor clawd-cursor --clawd-url http://127.0.0.1:3847
|
|
101
|
+
```
|
|
102
|
+
|
|
89
103
|
### Ver estado local
|
|
90
104
|
|
|
91
105
|
```bash
|
|
@@ -136,7 +150,7 @@ otto-bridge unpair
|
|
|
136
150
|
|
|
137
151
|
## Payload esperado para jobs desktop
|
|
138
152
|
|
|
139
|
-
|
|
153
|
+
Os executores locais do Otto Bridge procuram a tarefa em uma destas chaves, nessa ordem:
|
|
140
154
|
|
|
141
155
|
- `task`
|
|
142
156
|
- `prompt`
|
|
@@ -144,6 +158,20 @@ O adapter do `clawd-cursor` procura a tarefa em uma destas chaves, nessa ordem:
|
|
|
144
158
|
- `instructions`
|
|
145
159
|
- `message`
|
|
146
160
|
|
|
161
|
+
O executor nativo do macOS tambem aceita payload estruturado em `actions[]`, por exemplo:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"job_type": "desktop_actions",
|
|
166
|
+
"payload": {
|
|
167
|
+
"actions": [
|
|
168
|
+
{ "type": "open_app", "app": "Safari" },
|
|
169
|
+
{ "type": "open_url", "url": "https://www.youtube.com", "app": "Safari" }
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
147
175
|
Exemplo:
|
|
148
176
|
|
|
149
177
|
```json
|
package/dist/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir, hostname, platform, arch } from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { BRIDGE_CONFIG_VERSION, BRIDGE_VERSION, DEFAULT_CLAWD_CURSOR_BASE_URL, DEFAULT_CLAWD_CURSOR_POLL_INTERVAL_MS, DEFAULT_API_BASE_URL,
|
|
5
|
+
import { BRIDGE_CONFIG_VERSION, BRIDGE_VERSION, DEFAULT_CLAWD_CURSOR_BASE_URL, DEFAULT_CLAWD_CURSOR_POLL_INTERVAL_MS, DEFAULT_API_BASE_URL, } from "./types.js";
|
|
6
6
|
function sanitizeApiBaseUrl(value) {
|
|
7
7
|
const raw = String(value || DEFAULT_API_BASE_URL).trim();
|
|
8
8
|
if (!raw) {
|
|
@@ -10,8 +10,14 @@ function sanitizeApiBaseUrl(value) {
|
|
|
10
10
|
}
|
|
11
11
|
return raw.replace(/\/+$/, "");
|
|
12
12
|
}
|
|
13
|
+
function resolveDefaultExecutorType() {
|
|
14
|
+
return platform() === "darwin" ? "native-macos" : "mock";
|
|
15
|
+
}
|
|
13
16
|
function sanitizeExecutorType(value) {
|
|
14
|
-
|
|
17
|
+
if (value === "clawd-cursor" || value === "native-macos" || value === "mock") {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
return resolveDefaultExecutorType();
|
|
15
21
|
}
|
|
16
22
|
function sanitizeClawdCursorBaseUrl(value) {
|
|
17
23
|
const raw = String(value || DEFAULT_CLAWD_CURSOR_BASE_URL).trim();
|
|
@@ -27,6 +33,16 @@ function sanitizePollIntervalMs(value, fallback = DEFAULT_CLAWD_CURSOR_POLL_INTE
|
|
|
27
33
|
}
|
|
28
34
|
return Math.max(250, Math.floor(parsed));
|
|
29
35
|
}
|
|
36
|
+
function migrateLegacyExecutor(current) {
|
|
37
|
+
if (platform() === "darwin"
|
|
38
|
+
&& current?.type === "clawd-cursor"
|
|
39
|
+
&& sanitizeClawdCursorBaseUrl(current.baseUrl) === DEFAULT_CLAWD_CURSOR_BASE_URL) {
|
|
40
|
+
// Old macOS pairings defaulted to clawd-cursor while the bridge was still bootstrapping.
|
|
41
|
+
// Newer builds should run Otto's native executor by default without forcing users to re-pair.
|
|
42
|
+
return { type: "native-macos" };
|
|
43
|
+
}
|
|
44
|
+
return current || null;
|
|
45
|
+
}
|
|
30
46
|
export function getBridgeHomeDir() {
|
|
31
47
|
const custom = String(process.env.OTTO_BRIDGE_HOME || "").trim();
|
|
32
48
|
return custom || path.join(homedir(), ".otto-bridge");
|
|
@@ -51,7 +67,7 @@ export async function loadBridgeConfig() {
|
|
|
51
67
|
...parsed,
|
|
52
68
|
apiBaseUrl: sanitizeApiBaseUrl(parsed.apiBaseUrl),
|
|
53
69
|
wsUrl: buildWebSocketUrl(parsed.apiBaseUrl),
|
|
54
|
-
executor: resolveExecutorConfig(undefined, parsed.executor),
|
|
70
|
+
executor: resolveExecutorConfig(undefined, migrateLegacyExecutor(parsed.executor)),
|
|
55
71
|
};
|
|
56
72
|
}
|
|
57
73
|
catch {
|
|
@@ -83,6 +99,9 @@ export function resolveExecutorConfig(overrides, current) {
|
|
|
83
99
|
?? process.env.OTTO_CLAWD_POLL_INTERVAL_MS),
|
|
84
100
|
};
|
|
85
101
|
}
|
|
102
|
+
if (type === "native-macos") {
|
|
103
|
+
return { type: "native-macos" };
|
|
104
|
+
}
|
|
86
105
|
return { type: "mock" };
|
|
87
106
|
}
|
|
88
107
|
export function buildWebSocketUrl(apiBaseUrl) {
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { JobCancelledError } from "./shared.js";
|
|
4
|
+
const KNOWN_APPS = [
|
|
5
|
+
{ canonical: "Safari", patterns: [/\bsafari\b/i] },
|
|
6
|
+
{ canonical: "Google Chrome", patterns: [/\bgoogle chrome\b/i, /\bchrome\b/i] },
|
|
7
|
+
{ canonical: "Firefox", patterns: [/\bfirefox\b/i] },
|
|
8
|
+
{ canonical: "Finder", patterns: [/\bfinder\b/i] },
|
|
9
|
+
{ canonical: "Notes", patterns: [/\bnotes\b/i, /\bnotas\b/i] },
|
|
10
|
+
{ canonical: "Mail", patterns: [/\bmail\b/i] },
|
|
11
|
+
{ canonical: "Messages", patterns: [/\bmessages\b/i, /\bmensagens\b/i] },
|
|
12
|
+
{ canonical: "Calendar", patterns: [/\bcalendar\b/i, /\bcalend[áa]rio\b/i] },
|
|
13
|
+
{ canonical: "Terminal", patterns: [/\bterminal\b/i] },
|
|
14
|
+
{ canonical: "System Settings", patterns: [/\bsystem settings\b/i, /\bajustes do sistema\b/i, /\bconfigura[cç][õo]es do sistema\b/i] },
|
|
15
|
+
];
|
|
16
|
+
const KNOWN_SITES = [
|
|
17
|
+
{ url: "https://www.youtube.com", patterns: [/\byoutube\b/i, /\byou tube\b/i] },
|
|
18
|
+
{ url: "https://mail.google.com", patterns: [/\bgmail\b/i] },
|
|
19
|
+
{ url: "https://www.google.com", patterns: [/\bgoogle\b/i] },
|
|
20
|
+
{ url: "https://github.com", patterns: [/\bgithub\b/i] },
|
|
21
|
+
{ url: "https://chat.openai.com", patterns: [/\bchatgpt\b/i] },
|
|
22
|
+
{ url: "https://web.whatsapp.com", patterns: [/\bwhatsapp\b/i] },
|
|
23
|
+
{ url: "https://x.com", patterns: [/\bx\.com\b/i, /\btwitter\b/i, /\bxis\b/i] },
|
|
24
|
+
];
|
|
25
|
+
function asRecord(value) {
|
|
26
|
+
return value && typeof value === "object" ? value : {};
|
|
27
|
+
}
|
|
28
|
+
function asString(value) {
|
|
29
|
+
if (typeof value !== "string") {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
return trimmed || null;
|
|
34
|
+
}
|
|
35
|
+
function normalizeText(value) {
|
|
36
|
+
return value
|
|
37
|
+
.normalize("NFD")
|
|
38
|
+
.replace(/\p{Diacritic}/gu, "")
|
|
39
|
+
.toLowerCase();
|
|
40
|
+
}
|
|
41
|
+
function escapeAppleScript(value) {
|
|
42
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
43
|
+
}
|
|
44
|
+
function extractTaskText(job) {
|
|
45
|
+
const payload = asRecord(job.payload);
|
|
46
|
+
const candidates = [
|
|
47
|
+
payload.task,
|
|
48
|
+
payload.prompt,
|
|
49
|
+
payload.instruction,
|
|
50
|
+
payload.instructions,
|
|
51
|
+
payload.message,
|
|
52
|
+
];
|
|
53
|
+
for (const candidate of candidates) {
|
|
54
|
+
const text = asString(candidate);
|
|
55
|
+
if (text) {
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return `Execute Otto job ${job.job_type}`;
|
|
60
|
+
}
|
|
61
|
+
function normalizeUrl(raw) {
|
|
62
|
+
const trimmed = raw.trim();
|
|
63
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
64
|
+
return trimmed;
|
|
65
|
+
}
|
|
66
|
+
return `https://${trimmed.replace(/^\/+/, "")}`;
|
|
67
|
+
}
|
|
68
|
+
function detectKnownApp(task) {
|
|
69
|
+
for (const app of KNOWN_APPS) {
|
|
70
|
+
if (app.patterns.some((pattern) => pattern.test(task))) {
|
|
71
|
+
return app.canonical;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function detectUrl(task) {
|
|
77
|
+
const explicitMatch = task.match(/https?:\/\/[^\s]+/i);
|
|
78
|
+
if (explicitMatch?.[0]) {
|
|
79
|
+
return normalizeUrl(explicitMatch[0]);
|
|
80
|
+
}
|
|
81
|
+
const normalized = normalizeText(task);
|
|
82
|
+
for (const site of KNOWN_SITES) {
|
|
83
|
+
if (site.patterns.some((pattern) => pattern.test(normalized))) {
|
|
84
|
+
return site.url;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
function parseStructuredActions(job) {
|
|
90
|
+
const payload = asRecord(job.payload);
|
|
91
|
+
const rawActions = Array.isArray(payload.actions) ? payload.actions : [];
|
|
92
|
+
const actions = [];
|
|
93
|
+
for (const rawAction of rawActions) {
|
|
94
|
+
const action = asRecord(rawAction);
|
|
95
|
+
const type = asString(action.type);
|
|
96
|
+
if (!type) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (type === "open_app" || type === "focus_app") {
|
|
100
|
+
const app = asString(action.app) || asString(action.application) || asString(action.name);
|
|
101
|
+
if (app) {
|
|
102
|
+
actions.push({ type: "open_app", app });
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (type === "open_url") {
|
|
107
|
+
const url = asString(action.url) || asString(action.href);
|
|
108
|
+
const app = asString(action.app) || asString(action.application);
|
|
109
|
+
if (url) {
|
|
110
|
+
actions.push({ type: "open_url", url: normalizeUrl(url), app: app || undefined });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return actions;
|
|
115
|
+
}
|
|
116
|
+
function deriveActionsFromText(job) {
|
|
117
|
+
const task = extractTaskText(job);
|
|
118
|
+
const detectedApp = detectKnownApp(task);
|
|
119
|
+
const detectedUrl = detectUrl(task);
|
|
120
|
+
if (detectedUrl) {
|
|
121
|
+
return [{
|
|
122
|
+
type: "open_url",
|
|
123
|
+
url: detectedUrl,
|
|
124
|
+
app: detectedApp || undefined,
|
|
125
|
+
}];
|
|
126
|
+
}
|
|
127
|
+
if (detectedApp) {
|
|
128
|
+
return [{
|
|
129
|
+
type: "open_app",
|
|
130
|
+
app: detectedApp,
|
|
131
|
+
}];
|
|
132
|
+
}
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
function extractActions(job) {
|
|
136
|
+
const structured = parseStructuredActions(job);
|
|
137
|
+
if (structured.length > 0) {
|
|
138
|
+
return structured;
|
|
139
|
+
}
|
|
140
|
+
return deriveActionsFromText(job);
|
|
141
|
+
}
|
|
142
|
+
export class NativeMacOSJobExecutor {
|
|
143
|
+
cancelledJobs = new Set();
|
|
144
|
+
activeChild = null;
|
|
145
|
+
async run(job, reporter) {
|
|
146
|
+
if (process.platform !== "darwin") {
|
|
147
|
+
throw new Error("The native-macos executor only runs on macOS");
|
|
148
|
+
}
|
|
149
|
+
const actions = extractActions(job);
|
|
150
|
+
if (actions.length === 0) {
|
|
151
|
+
throw new Error("Otto Bridge native-macos could not derive a supported local action from this request");
|
|
152
|
+
}
|
|
153
|
+
await reporter.accepted();
|
|
154
|
+
try {
|
|
155
|
+
for (let index = 0; index < actions.length; index += 1) {
|
|
156
|
+
this.assertNotCancelled(job.job_id);
|
|
157
|
+
const action = actions[index];
|
|
158
|
+
const progressPercent = Math.max(10, Math.round(((index + 1) / actions.length) * 100));
|
|
159
|
+
if (action.type === "open_app") {
|
|
160
|
+
await reporter.progress(progressPercent, `Abrindo ${action.app} no macOS`);
|
|
161
|
+
await this.openApp(action.app);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
await reporter.progress(progressPercent, `Abrindo ${action.url}${action.app ? ` em ${action.app}` : ""}`);
|
|
165
|
+
await this.openUrl(action.url, action.app);
|
|
166
|
+
}
|
|
167
|
+
const summary = actions.length === 1
|
|
168
|
+
? this.describeAction(actions[0])
|
|
169
|
+
: `${actions.length} ações executadas no macOS`;
|
|
170
|
+
await reporter.completed({
|
|
171
|
+
executor: "native-macos",
|
|
172
|
+
summary,
|
|
173
|
+
actions,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
this.cancelledJobs.delete(job.job_id);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async cancel(jobId) {
|
|
181
|
+
this.cancelledJobs.add(jobId);
|
|
182
|
+
if (this.activeChild) {
|
|
183
|
+
this.activeChild.kill("SIGTERM");
|
|
184
|
+
this.activeChild = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
assertNotCancelled(jobId) {
|
|
188
|
+
if (this.cancelledJobs.has(jobId)) {
|
|
189
|
+
throw new JobCancelledError(jobId);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async openApp(app) {
|
|
193
|
+
await this.runCommand("open", ["-a", app]);
|
|
194
|
+
await this.runCommand("osascript", ["-e", `tell application "${escapeAppleScript(app)}" to activate`]);
|
|
195
|
+
}
|
|
196
|
+
async openUrl(url, app) {
|
|
197
|
+
if (app) {
|
|
198
|
+
await this.runCommand("open", ["-a", app, url]);
|
|
199
|
+
await this.runCommand("osascript", ["-e", `tell application "${escapeAppleScript(app)}" to activate`]);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
await this.runCommand("open", [url]);
|
|
203
|
+
}
|
|
204
|
+
describeAction(action) {
|
|
205
|
+
if (action.type === "open_app") {
|
|
206
|
+
return `${action.app} foi aberto no macOS`;
|
|
207
|
+
}
|
|
208
|
+
return `${action.url} foi aberto${action.app ? ` em ${action.app}` : ""}`;
|
|
209
|
+
}
|
|
210
|
+
async runCommand(command, args) {
|
|
211
|
+
const child = spawn(command, args, {
|
|
212
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
213
|
+
});
|
|
214
|
+
this.activeChild = child;
|
|
215
|
+
try {
|
|
216
|
+
const { stdout, stderr } = await new Promise((resolve, reject) => {
|
|
217
|
+
let stdout = "";
|
|
218
|
+
let stderr = "";
|
|
219
|
+
child.stdout.on("data", (chunk) => {
|
|
220
|
+
stdout += String(chunk);
|
|
221
|
+
});
|
|
222
|
+
child.stderr.on("data", (chunk) => {
|
|
223
|
+
stderr += String(chunk);
|
|
224
|
+
});
|
|
225
|
+
child.on("error", (error) => {
|
|
226
|
+
reject(error);
|
|
227
|
+
});
|
|
228
|
+
child.on("close", (code) => {
|
|
229
|
+
if (code === 0) {
|
|
230
|
+
resolve({ stdout, stderr });
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
reject(new Error(`${command} ${args.join(" ")} failed: ${stderr.trim() || stdout.trim() || `exit code ${code ?? "unknown"}`}`));
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
const stderrText = stderr.trim();
|
|
237
|
+
if (stderrText) {
|
|
238
|
+
console.warn(`[otto-bridge] ${command} stderr=${stderrText}`);
|
|
239
|
+
}
|
|
240
|
+
const stdoutText = stdout.trim();
|
|
241
|
+
if (stdoutText) {
|
|
242
|
+
console.log(`[otto-bridge] ${command} stdout=${stdoutText}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
247
|
+
throw new Error(detail);
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
if (this.activeChild === child) {
|
|
251
|
+
this.activeChild = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -53,15 +53,15 @@ function resolveExecutorOverrides(args, current) {
|
|
|
53
53
|
}
|
|
54
54
|
function printUsage() {
|
|
55
55
|
console.log(`Usage:
|
|
56
|
-
otto-bridge pair --api http://localhost:8000 --code ABC123 [--name "Meu PC"] [--executor mock|clawd-cursor]
|
|
57
|
-
otto-bridge run [--executor mock|clawd-cursor] [--clawd-url http://127.0.0.1:3847]
|
|
56
|
+
otto-bridge pair --api http://localhost:8000 --code ABC123 [--name "Meu PC"] [--executor native-macos|mock|clawd-cursor]
|
|
57
|
+
otto-bridge run [--executor native-macos|mock|clawd-cursor] [--clawd-url http://127.0.0.1:3847]
|
|
58
58
|
otto-bridge status
|
|
59
59
|
otto-bridge version
|
|
60
60
|
otto-bridge update [--tag latest|next] [--dry-run]
|
|
61
61
|
otto-bridge unpair
|
|
62
62
|
|
|
63
63
|
Examples:
|
|
64
|
-
otto-bridge pair --api https://api.leg3ndy.com.br --code ABC123
|
|
64
|
+
otto-bridge pair --api https://api.leg3ndy.com.br --code ABC123
|
|
65
65
|
otto-bridge run
|
|
66
66
|
otto-bridge version
|
|
67
67
|
otto-bridge update
|
package/dist/runtime.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_RECONNECT_BASE_DELAY_MS, DEFAULT_RECONNECT_MAX_DELAY_MS, } from "./types.js";
|
|
2
2
|
import { ClawdCursorJobExecutor } from "./executors/clawd_cursor.js";
|
|
3
3
|
import { MockJobExecutor } from "./executors/mock.js";
|
|
4
|
+
import { NativeMacOSJobExecutor } from "./executors/native_macos.js";
|
|
4
5
|
import { JobCancelledError } from "./executors/shared.js";
|
|
5
6
|
function delay(ms) {
|
|
6
7
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -278,6 +279,9 @@ export class BridgeRuntime {
|
|
|
278
279
|
if (config.executor.type === "clawd-cursor") {
|
|
279
280
|
return new ClawdCursorJobExecutor(config.executor);
|
|
280
281
|
}
|
|
282
|
+
if (config.executor.type === "native-macos") {
|
|
283
|
+
return new NativeMacOSJobExecutor();
|
|
284
|
+
}
|
|
281
285
|
return new MockJobExecutor();
|
|
282
286
|
}
|
|
283
287
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const BRIDGE_CONFIG_VERSION = 1;
|
|
2
|
-
export const BRIDGE_VERSION = "0.
|
|
2
|
+
export const BRIDGE_VERSION = "0.2.0";
|
|
3
3
|
export const BRIDGE_PACKAGE_NAME = "@leg3ndy/otto-bridge";
|
|
4
4
|
export const DEFAULT_API_BASE_URL = "http://localhost:8000";
|
|
5
5
|
export const DEFAULT_POLL_INTERVAL_MS = 3000;
|