@leg3ndy/otto-bridge 0.6.2 → 0.6.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 +4 -4
- package/dist/main.js +176 -5
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,10 +33,10 @@ Enquanto o pacote nao estiver publicado, voce pode gerar um tarball local:
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
npm pack
|
|
36
|
-
npm install -g ./leg3ndy-otto-bridge-0.6.
|
|
36
|
+
npm install -g ./leg3ndy-otto-bridge-0.6.4.tgz
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
No `0.6.
|
|
39
|
+
No `0.6.4`, `playwright` deixa de ser opcional no `otto-bridge`. O primeiro `npm install -g @leg3ndy/otto-bridge` pode demorar mais porque instala o browser persistente usado pelo WhatsApp Web e pelos fluxos web em background do bridge.
|
|
40
40
|
|
|
41
41
|
## Publicacao
|
|
42
42
|
|
|
@@ -106,7 +106,7 @@ otto-bridge run --executor clawd-cursor --clawd-url http://127.0.0.1:3847
|
|
|
106
106
|
|
|
107
107
|
### WhatsApp Web em background
|
|
108
108
|
|
|
109
|
-
Fluxo recomendado no `0.6.
|
|
109
|
+
Fluxo recomendado no `0.6.4`:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
112
|
otto-bridge extensions --install whatsappweb
|
|
@@ -116,7 +116,7 @@ otto-bridge extensions --status whatsappweb
|
|
|
116
116
|
|
|
117
117
|
O setup agora abre o login do WhatsApp Web em um browser persistente do proprio bridge. Depois do QR code, o Otto usa a sessao local em background, sem depender de aba visivel no Safari.
|
|
118
118
|
|
|
119
|
-
Contrato do `0.6.
|
|
119
|
+
Contrato do `0.6.4`:
|
|
120
120
|
|
|
121
121
|
- `otto-bridge extensions --setup whatsappweb`: autentica a sessao uma vez
|
|
122
122
|
- `otto-bridge run`: mantem o browser persistente do WhatsApp vivo em background enquanto o runtime estiver ativo
|
package/dist/main.js
CHANGED
|
@@ -8,6 +8,7 @@ import { BridgeRuntime } from "./runtime.js";
|
|
|
8
8
|
import { detectWhatsAppBackgroundStatus, runWhatsAppBackgroundSetup, } from "./whatsapp_background.js";
|
|
9
9
|
import { BRIDGE_PACKAGE_NAME, BRIDGE_VERSION, DEFAULT_PAIR_TIMEOUT_SECONDS, DEFAULT_POLL_INTERVAL_MS, } from "./types.js";
|
|
10
10
|
const RUNTIME_STATUS_FRESHNESS_MS = 90_000;
|
|
11
|
+
const UPDATE_RETRY_DELAYS_MS = [0, 8_000, 20_000];
|
|
11
12
|
function parseArgs(argv) {
|
|
12
13
|
const [maybeCommand, ...rest] = argv;
|
|
13
14
|
if (maybeCommand === "--help" || maybeCommand === "-h") {
|
|
@@ -54,6 +55,42 @@ function hasFreshRuntimeAttachment(state) {
|
|
|
54
55
|
const lastHeartbeatAt = Date.parse(state.lastRuntimeHeartbeatAt);
|
|
55
56
|
return Number.isFinite(lastHeartbeatAt) && Date.now() - lastHeartbeatAt <= RUNTIME_STATUS_FRESHNESS_MS;
|
|
56
57
|
}
|
|
58
|
+
function parseSemverTuple(value) {
|
|
59
|
+
const text = String(value || "").trim().replace(/^[vV]/, "");
|
|
60
|
+
if (!text) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const parts = text.split(".");
|
|
64
|
+
const parsed = [];
|
|
65
|
+
for (const part of parts) {
|
|
66
|
+
const match = part.match(/^(\d+)/);
|
|
67
|
+
if (!match) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
parsed.push(Number(match[1]));
|
|
71
|
+
}
|
|
72
|
+
return parsed.length > 0 ? parsed : null;
|
|
73
|
+
}
|
|
74
|
+
function compareSemver(left, right) {
|
|
75
|
+
const a = parseSemverTuple(left);
|
|
76
|
+
const b = parseSemverTuple(right);
|
|
77
|
+
if (!a && !b)
|
|
78
|
+
return 0;
|
|
79
|
+
if (!a)
|
|
80
|
+
return -1;
|
|
81
|
+
if (!b)
|
|
82
|
+
return 1;
|
|
83
|
+
const maxLength = Math.max(a.length, b.length);
|
|
84
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
85
|
+
const leftPart = a[index] ?? 0;
|
|
86
|
+
const rightPart = b[index] ?? 0;
|
|
87
|
+
if (leftPart < rightPart)
|
|
88
|
+
return -1;
|
|
89
|
+
if (leftPart > rightPart)
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
57
94
|
function resolveExecutorOverrides(args, current) {
|
|
58
95
|
return resolveExecutorConfig({
|
|
59
96
|
type: option(args, "executor") || process.env.OTTO_BRIDGE_EXECUTOR,
|
|
@@ -108,6 +145,85 @@ function runChildCommand(command, args) {
|
|
|
108
145
|
});
|
|
109
146
|
});
|
|
110
147
|
}
|
|
148
|
+
function runChildCommandCapture(command, args) {
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
const child = spawn(command, args, {
|
|
151
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
152
|
+
env: process.env,
|
|
153
|
+
});
|
|
154
|
+
let stdout = "";
|
|
155
|
+
let stderr = "";
|
|
156
|
+
child.stdout?.setEncoding("utf8");
|
|
157
|
+
child.stdout?.on("data", (chunk) => {
|
|
158
|
+
stdout += String(chunk || "");
|
|
159
|
+
});
|
|
160
|
+
child.stderr?.setEncoding("utf8");
|
|
161
|
+
child.stderr?.on("data", (chunk) => {
|
|
162
|
+
stderr += String(chunk || "");
|
|
163
|
+
});
|
|
164
|
+
child.on("error", (error) => {
|
|
165
|
+
reject(error);
|
|
166
|
+
});
|
|
167
|
+
child.on("exit", (code) => {
|
|
168
|
+
resolve({
|
|
169
|
+
stdout,
|
|
170
|
+
stderr,
|
|
171
|
+
code: code ?? 1,
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
async function resolvePublishedPackageVersion(tag) {
|
|
177
|
+
const command = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
178
|
+
const result = await runChildCommandCapture(command, [
|
|
179
|
+
"view",
|
|
180
|
+
`${BRIDGE_PACKAGE_NAME}@${tag}`,
|
|
181
|
+
"version",
|
|
182
|
+
"--json",
|
|
183
|
+
]).catch(() => null);
|
|
184
|
+
if (!result || result.code !== 0) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const stdout = String(result.stdout || "").trim();
|
|
188
|
+
if (!stdout) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const parsed = JSON.parse(stdout);
|
|
193
|
+
if (typeof parsed === "string" && parsed.trim()) {
|
|
194
|
+
return parsed.trim();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
if (stdout && stdout !== "null") {
|
|
199
|
+
return stdout.replace(/^"|"$/g, "").trim() || null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
async function resolveActiveCliVersion() {
|
|
205
|
+
const binary = process.platform === "win32" ? "otto-bridge.cmd" : "otto-bridge";
|
|
206
|
+
const result = await runChildCommandCapture(binary, ["version"]).catch(() => null);
|
|
207
|
+
if (!result || result.code !== 0) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const output = String(result.stdout || "").trim();
|
|
211
|
+
const match = output.match(/@leg3ndy\/otto-bridge\s+([0-9]+(?:\.[0-9]+){1,3})/i);
|
|
212
|
+
return match?.[1]?.trim() || null;
|
|
213
|
+
}
|
|
214
|
+
function isRetryableNpmUpdateFailure(detail) {
|
|
215
|
+
const normalized = String(detail || "").toLowerCase();
|
|
216
|
+
return [
|
|
217
|
+
"code etarget",
|
|
218
|
+
"no matching version found",
|
|
219
|
+
"notarget",
|
|
220
|
+
"code enoversions",
|
|
221
|
+
"package version that doesn't exist",
|
|
222
|
+
].some((pattern) => normalized.includes(pattern));
|
|
223
|
+
}
|
|
224
|
+
async function delay(ms) {
|
|
225
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
226
|
+
}
|
|
111
227
|
async function openManagedExtensionSetup(slug) {
|
|
112
228
|
const definition = getManagedBridgeExtensionDefinition(slug);
|
|
113
229
|
if (process.platform !== "darwin") {
|
|
@@ -385,20 +501,75 @@ async function runUnpairCommand() {
|
|
|
385
501
|
}
|
|
386
502
|
async function runUpdateCommand(args) {
|
|
387
503
|
const tag = option(args, "tag") || "latest";
|
|
388
|
-
const
|
|
504
|
+
const publishedVersion = await resolvePublishedPackageVersion(tag);
|
|
505
|
+
if (publishedVersion && compareSemver(publishedVersion, BRIDGE_VERSION) <= 0) {
|
|
506
|
+
console.log(`[otto-bridge] current=${BRIDGE_VERSION}`);
|
|
507
|
+
console.log(`[otto-bridge] latest published=${publishedVersion}`);
|
|
508
|
+
console.log("[otto-bridge] nenhuma atualizacao mais nova publicada no npm no momento");
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const packageSpec = `${BRIDGE_PACKAGE_NAME}@${publishedVersion || tag}`;
|
|
389
512
|
const command = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
390
|
-
const commandArgs = ["install", "-g", packageSpec];
|
|
513
|
+
const commandArgs = ["install", "-g", packageSpec, "--prefer-online"];
|
|
391
514
|
const commandString = `${command} ${commandArgs.join(" ")}`;
|
|
392
515
|
if (args.options.has("dry-run") || args.options.has("check")) {
|
|
393
516
|
console.log(`[otto-bridge] current=${BRIDGE_VERSION}`);
|
|
517
|
+
if (publishedVersion) {
|
|
518
|
+
console.log(`[otto-bridge] target=${publishedVersion}`);
|
|
519
|
+
}
|
|
394
520
|
console.log(`[otto-bridge] update command: ${commandString}`);
|
|
395
521
|
return;
|
|
396
522
|
}
|
|
397
523
|
console.log(`[otto-bridge] current=${BRIDGE_VERSION}`);
|
|
524
|
+
if (publishedVersion) {
|
|
525
|
+
console.log(`[otto-bridge] target=${publishedVersion}`);
|
|
526
|
+
}
|
|
398
527
|
console.log(`[otto-bridge] updating with: ${commandString}`);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
528
|
+
let lastFailureDetail = "";
|
|
529
|
+
for (let attemptIndex = 0; attemptIndex < UPDATE_RETRY_DELAYS_MS.length; attemptIndex += 1) {
|
|
530
|
+
const waitMs = UPDATE_RETRY_DELAYS_MS[attemptIndex];
|
|
531
|
+
if (waitMs > 0) {
|
|
532
|
+
console.log(`[otto-bridge] aguardando ${Math.round(waitMs / 1000)}s para tentar novamente...`);
|
|
533
|
+
await delay(waitMs);
|
|
534
|
+
}
|
|
535
|
+
const result = await runChildCommandCapture(command, commandArgs).catch((error) => ({
|
|
536
|
+
stdout: "",
|
|
537
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
538
|
+
code: 1,
|
|
539
|
+
}));
|
|
540
|
+
if (result.stdout.trim()) {
|
|
541
|
+
process.stdout.write(result.stdout);
|
|
542
|
+
}
|
|
543
|
+
if (result.stderr.trim()) {
|
|
544
|
+
process.stderr.write(result.stderr);
|
|
545
|
+
}
|
|
546
|
+
if (result.code === 0) {
|
|
547
|
+
const activeVersion = await resolveActiveCliVersion();
|
|
548
|
+
if (!publishedVersion) {
|
|
549
|
+
console.log("[otto-bridge] update completed");
|
|
550
|
+
console.log("[otto-bridge] run `otto-bridge version` to confirm the installed version");
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (activeVersion && compareSemver(activeVersion, publishedVersion) >= 0) {
|
|
554
|
+
console.log(`[otto-bridge] update completed active=${activeVersion}`);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
const observedVersion = activeVersion || BRIDGE_VERSION;
|
|
558
|
+
throw new Error(`[otto-bridge] O npm concluiu o install, mas o comando \`otto-bridge\` ainda responde ${observedVersion}. `
|
|
559
|
+
+ `A atualizacao para ${publishedVersion} nao ficou ativa neste PATH ainda.\n`
|
|
560
|
+
+ `[otto-bridge] Tente abrir um novo terminal e rodar \`otto-bridge version\`.\n`
|
|
561
|
+
+ `[otto-bridge] Se continuar igual, rode manualmente: npm install -g ${BRIDGE_PACKAGE_NAME}@${publishedVersion} --prefer-online`);
|
|
562
|
+
}
|
|
563
|
+
lastFailureDetail = `${command} exited with code ${result.code}\n${result.stderr || result.stdout}`.trim();
|
|
564
|
+
const retryable = isRetryableNpmUpdateFailure(lastFailureDetail);
|
|
565
|
+
const hasNextAttempt = attemptIndex < UPDATE_RETRY_DELAYS_MS.length - 1;
|
|
566
|
+
if (!retryable || !hasNextAttempt) {
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
console.log("[otto-bridge] A release ainda pode estar propagando no npm. Vou tentar novamente com cache online.");
|
|
570
|
+
}
|
|
571
|
+
const hintSpec = `${BRIDGE_PACKAGE_NAME}@${publishedVersion || tag}`;
|
|
572
|
+
throw new Error(`${lastFailureDetail}\n[otto-bridge] Se a release acabou de ser publicada, isso costuma ser propagacao do npm.\n[otto-bridge] Fallback manual: npm install -g ${hintSpec} --prefer-online`);
|
|
402
573
|
}
|
|
403
574
|
async function main() {
|
|
404
575
|
const args = parseArgs(process.argv.slice(2));
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const BRIDGE_CONFIG_VERSION = 1;
|
|
2
|
-
export const BRIDGE_VERSION = "0.6.
|
|
2
|
+
export const BRIDGE_VERSION = "0.6.4";
|
|
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;
|