@leg3ndy/otto-bridge 1.0.5 → 1.0.7
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 +8 -8
- package/dist/cli_terminal.js +164 -18
- package/dist/runtime.js +16 -2
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.mjs +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Para o estado atual da arquitetura, capacidades entregues, limitacoes e roadmap
|
|
|
15
15
|
|
|
16
16
|
Para o corte de arquitetura do `0.9.0`, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_0_9_0_RELEASE.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_0_9_0_RELEASE.md).
|
|
17
17
|
|
|
18
|
-
Para a release atual `1.0.
|
|
18
|
+
Para a release atual `1.0.7`, com hotfix do input-box TTY do console, veja [`leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_0_7_PATCH.md`](../leg3ndy-ai-backend/docs/otto-bridge/releases/OTTO_BRIDGE_1_0_7_PATCH.md).
|
|
19
19
|
|
|
20
20
|
## Distribuicao
|
|
21
21
|
|
|
@@ -38,14 +38,14 @@ Enquanto o pacote nao estiver publicado, voce pode gerar um tarball local:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
npm pack
|
|
41
|
-
npm install -g ./leg3ndy-otto-bridge-1.0.
|
|
41
|
+
npm install -g ./leg3ndy-otto-bridge-1.0.7.tgz
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Na linha `1.0.
|
|
44
|
+
Na linha `1.0.7`, `playwright` segue como dependencia obrigatoria 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.
|
|
45
45
|
|
|
46
|
-
No macOS, a linha `1.0.
|
|
46
|
+
No macOS, a linha `1.0.7` usa o provider `macos-helper`, um helper `WKWebView` sem Dock para o WhatsApp Web. O helper sobe com user-agent de Chrome moderno para evitar o bloqueio do WhatsApp ao detectar Safari/WebKit. O runtime antigo com Chromium/Playwright fica disponivel apenas como override explicito via `OTTO_BRIDGE_WHATSAPP_RUNTIME_PROVIDER=embedded-playwright`.
|
|
47
47
|
|
|
48
|
-
No nivel arquitetural, o `0.9.0` marcou a mudanca de papel do bridge: ele publica tools e resultados estruturados para o Otto, em vez de injetar resposta pronta como caminho principal do chat. O `1.0.0` oficializou isso como runtime agentico; o `1.0.
|
|
48
|
+
No nivel arquitetural, o `0.9.0` marcou a mudanca de papel do bridge: ele publica tools e resultados estruturados para o Otto, em vez de injetar resposta pronta como caminho principal do chat. O `1.0.0` oficializou isso como runtime agentico; o `1.0.7` preserva esse fluxo e corrige o freeze do input-box TTY introduzido no refinamento visual do console.
|
|
49
49
|
|
|
50
50
|
## Publicacao
|
|
51
51
|
|
|
@@ -157,7 +157,7 @@ Esse comando abre um shell local interativo para instalar extensoes, rodar coman
|
|
|
157
157
|
|
|
158
158
|
### WhatsApp Web em background
|
|
159
159
|
|
|
160
|
-
Fluxo recomendado na linha `1.0.
|
|
160
|
+
Fluxo recomendado na linha `1.0.7`:
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
163
|
otto-bridge extensions --install whatsappweb
|
|
@@ -167,13 +167,13 @@ otto-bridge extensions --status whatsappweb
|
|
|
167
167
|
|
|
168
168
|
O setup agora abre o login do WhatsApp Web no helper/background browser do proprio bridge. Depois do QR code, o Otto usa a sessao local em background, sem depender de aba visivel no Safari.
|
|
169
169
|
|
|
170
|
-
Contrato da linha `1.0.
|
|
170
|
+
Contrato da linha `1.0.7`:
|
|
171
171
|
|
|
172
172
|
- `otto-bridge extensions --setup whatsappweb`: autentica a sessao uma vez
|
|
173
173
|
- `otto-bridge`: mantem o browser persistente do WhatsApp vivo em background enquanto o runtime do hub estiver ativo, sem depender de uma aba aberta no Safari
|
|
174
174
|
- ao fechar o `otto-bridge`: o browser em background e desligado, mas a sessao local fica lembrada para o proximo boot
|
|
175
175
|
|
|
176
|
-
## Handoff rapido da linha 1.0.
|
|
176
|
+
## Handoff rapido da linha 1.0.7
|
|
177
177
|
|
|
178
178
|
Ja fechado no codigo:
|
|
179
179
|
|
package/dist/cli_terminal.js
CHANGED
|
@@ -59,6 +59,7 @@ class CliRuntimeSession {
|
|
|
59
59
|
status = "offline";
|
|
60
60
|
detail = "Aguardando pairing.";
|
|
61
61
|
lastError = null;
|
|
62
|
+
releaseNotice = null;
|
|
62
63
|
constructor(config) {
|
|
63
64
|
this.config = config;
|
|
64
65
|
}
|
|
@@ -92,8 +93,24 @@ class CliRuntimeSession {
|
|
|
92
93
|
}
|
|
93
94
|
return;
|
|
94
95
|
case "update_required":
|
|
96
|
+
this.releaseNotice = {
|
|
97
|
+
kind: "required",
|
|
98
|
+
message: event.message,
|
|
99
|
+
currentVersion: normalizeText(event.currentVersion),
|
|
100
|
+
latestVersion: normalizeText(event.latestVersion),
|
|
101
|
+
minSupportedVersion: normalizeText(event.minSupportedVersion),
|
|
102
|
+
updateCommand: normalizeText(event.updateCommand) || "otto-bridge update",
|
|
103
|
+
};
|
|
104
|
+
return;
|
|
95
105
|
case "update_available":
|
|
96
|
-
this.
|
|
106
|
+
this.releaseNotice = {
|
|
107
|
+
kind: "available",
|
|
108
|
+
message: event.message,
|
|
109
|
+
currentVersion: normalizeText(event.currentVersion),
|
|
110
|
+
latestVersion: normalizeText(event.latestVersion),
|
|
111
|
+
minSupportedVersion: normalizeText(event.minSupportedVersion),
|
|
112
|
+
updateCommand: normalizeText(event.updateCommand) || "otto-bridge update",
|
|
113
|
+
};
|
|
97
114
|
return;
|
|
98
115
|
default:
|
|
99
116
|
return;
|
|
@@ -180,6 +197,9 @@ class CliRuntimeSession {
|
|
|
180
197
|
getLastError() {
|
|
181
198
|
return this.lastError;
|
|
182
199
|
}
|
|
200
|
+
getReleaseNotice() {
|
|
201
|
+
return this.releaseNotice;
|
|
202
|
+
}
|
|
183
203
|
}
|
|
184
204
|
function style(text, color, enabled = true) {
|
|
185
205
|
if (!enabled) {
|
|
@@ -400,6 +420,7 @@ function extractConfirmationPrompt(job) {
|
|
|
400
420
|
|| payload.confirmation_message) || "O Otto está aguardando sua confirmação para continuar.";
|
|
401
421
|
}
|
|
402
422
|
function renderStatusOverview(config, runtimeSession) {
|
|
423
|
+
const releaseNotice = runtimeSession?.getReleaseNotice();
|
|
403
424
|
return [
|
|
404
425
|
`${style("Device", ANSI.brandBlue, supportsAnsi())}: ${config.deviceName}`,
|
|
405
426
|
`${style("Device ID", ANSI.brandBlue, supportsAnsi())}: ${config.deviceId}`,
|
|
@@ -410,6 +431,21 @@ function renderStatusOverview(config, runtimeSession) {
|
|
|
410
431
|
...(runtimeSession?.getStatusDetail()
|
|
411
432
|
? [`${style("Runtime note", ANSI.brandBlue, supportsAnsi())}: ${runtimeSession.getStatusDetail()}`]
|
|
412
433
|
: []),
|
|
434
|
+
...(releaseNotice
|
|
435
|
+
? [
|
|
436
|
+
`${style("Bridge update", ANSI.brandBlue, supportsAnsi())}: ${releaseNotice.kind === "required" ? "required" : "available"}`,
|
|
437
|
+
...(releaseNotice.currentVersion
|
|
438
|
+
? [`${style("Current version", ANSI.brandBlue, supportsAnsi())}: ${releaseNotice.currentVersion}`]
|
|
439
|
+
: []),
|
|
440
|
+
...(releaseNotice.latestVersion
|
|
441
|
+
? [`${style("Latest version", ANSI.brandBlue, supportsAnsi())}: ${releaseNotice.latestVersion}`]
|
|
442
|
+
: []),
|
|
443
|
+
...(releaseNotice.minSupportedVersion
|
|
444
|
+
? [`${style("Min supported", ANSI.brandBlue, supportsAnsi())}: ${releaseNotice.minSupportedVersion}`]
|
|
445
|
+
: []),
|
|
446
|
+
`${style("Update command", ANSI.brandBlue, supportsAnsi())}: ${releaseNotice.updateCommand || "otto-bridge update"}`,
|
|
447
|
+
]
|
|
448
|
+
: []),
|
|
413
449
|
`${style("Config", ANSI.brandBlue, supportsAnsi())}: ${getBridgeConfigPath()}`,
|
|
414
450
|
];
|
|
415
451
|
}
|
|
@@ -442,6 +478,9 @@ function styleCardLine(line, tone, enabled) {
|
|
|
442
478
|
if (tone === "title") {
|
|
443
479
|
return `${ANSI.bold}${ANSI.brandBlue}${line}${ANSI.reset}`;
|
|
444
480
|
}
|
|
481
|
+
if (tone === "warning") {
|
|
482
|
+
return `${ANSI.bold}${ANSI.amber}${line}${ANSI.reset}`;
|
|
483
|
+
}
|
|
445
484
|
if (tone === "muted") {
|
|
446
485
|
return `${ANSI.slateItalic}${line}${ANSI.reset}`;
|
|
447
486
|
}
|
|
@@ -477,17 +516,50 @@ function buildWelcomeCard(runtimeSession, modelMode) {
|
|
|
477
516
|
{ text: renderRuntimeHeadline(runtimeSession), tone: "muted" },
|
|
478
517
|
];
|
|
479
518
|
}
|
|
519
|
+
function buildBridgeReleaseCard(notice) {
|
|
520
|
+
const isRequired = notice.kind === "required";
|
|
521
|
+
return [
|
|
522
|
+
{
|
|
523
|
+
text: isRequired ? "Atualização obrigatória do bridge" : "Atualização disponível do bridge",
|
|
524
|
+
tone: "warning",
|
|
525
|
+
},
|
|
526
|
+
{ text: "", tone: "muted" },
|
|
527
|
+
{
|
|
528
|
+
text: isRequired
|
|
529
|
+
? `Atual: ${notice.currentVersion || "desconhecida"} | mínima: ${notice.minSupportedVersion || "desconhecida"}`
|
|
530
|
+
: `Atual: ${notice.currentVersion || "desconhecida"} | nova: ${notice.latestVersion || "desconhecida"}`,
|
|
531
|
+
tone: "muted",
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
text: isRequired
|
|
535
|
+
? "Este bridge precisa ser atualizado para continuar suportado."
|
|
536
|
+
: "Há uma nova versão do Otto Bridge pronta para instalar.",
|
|
537
|
+
tone: "muted",
|
|
538
|
+
},
|
|
539
|
+
{ text: `Rode: ${notice.updateCommand || "otto-bridge update"}`, tone: "primary" },
|
|
540
|
+
];
|
|
541
|
+
}
|
|
480
542
|
function printHubScreen(runtimeSession, modelMode) {
|
|
481
543
|
clearScreen();
|
|
482
544
|
console.log(renderBanner());
|
|
483
545
|
console.log("");
|
|
484
546
|
console.log(renderInfoCard(buildWelcomeCard(runtimeSession, modelMode)));
|
|
547
|
+
const releaseNotice = runtimeSession?.getReleaseNotice();
|
|
548
|
+
if (releaseNotice) {
|
|
549
|
+
console.log("");
|
|
550
|
+
console.log(renderInfoCard(buildBridgeReleaseCard(releaseNotice)));
|
|
551
|
+
}
|
|
485
552
|
}
|
|
486
553
|
function printConsoleScreen(runtimeSession, modelMode) {
|
|
487
554
|
clearScreen();
|
|
488
555
|
console.log(renderBanner());
|
|
489
556
|
console.log("");
|
|
490
557
|
console.log(renderInfoCard(buildWelcomeCard(runtimeSession, modelMode)));
|
|
558
|
+
const releaseNotice = runtimeSession.getReleaseNotice();
|
|
559
|
+
if (releaseNotice) {
|
|
560
|
+
console.log("");
|
|
561
|
+
console.log(renderInfoCard(buildBridgeReleaseCard(releaseNotice)));
|
|
562
|
+
}
|
|
491
563
|
console.log("");
|
|
492
564
|
}
|
|
493
565
|
function renderPromptFrameLine(width, edgeLeft, edgeRight) {
|
|
@@ -507,26 +579,90 @@ function renderConsolePromptContentLine(text, width, tone) {
|
|
|
507
579
|
return `${border} ${body} ${border}`;
|
|
508
580
|
}
|
|
509
581
|
async function askConsoleInput(rl) {
|
|
510
|
-
if (!supportsAnsi()) {
|
|
511
|
-
printMuted(CONSOLE_PLACEHOLDER);
|
|
582
|
+
if (!supportsAnsi() || typeof input.setRawMode !== "function" || !input.isTTY) {
|
|
512
583
|
printSoft(`Comandos: ${CONSOLE_COMMAND_HINT}`);
|
|
584
|
+
console.log("");
|
|
513
585
|
return normalizeText(await question(rl, "> "));
|
|
514
586
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
587
|
+
rl.pause();
|
|
588
|
+
input.setRawMode(true);
|
|
589
|
+
input.resume();
|
|
590
|
+
return await new Promise((resolve, reject) => {
|
|
591
|
+
const enabled = supportsAnsi();
|
|
592
|
+
const availableWidth = Number(output.columns || 96);
|
|
593
|
+
const innerWidth = Math.max(42, Math.min(availableWidth - 8, 116));
|
|
594
|
+
const sectionTopOffsetFromInputLine = 3;
|
|
595
|
+
let renderedOnce = false;
|
|
596
|
+
let value = "";
|
|
597
|
+
const cleanup = () => {
|
|
598
|
+
input.removeListener("data", onData);
|
|
599
|
+
input.setRawMode(false);
|
|
600
|
+
input.pause();
|
|
601
|
+
rl.resume();
|
|
602
|
+
};
|
|
603
|
+
const renderInputContent = () => {
|
|
604
|
+
const promptPlain = "> ";
|
|
605
|
+
const promptStyled = style(">", `${ANSI.bold}${ANSI.white}`, enabled);
|
|
606
|
+
const maxValueLength = Math.max(0, innerWidth - promptPlain.length);
|
|
607
|
+
if (!value) {
|
|
608
|
+
const placeholder = truncate(CONSOLE_PLACEHOLDER, maxValueLength);
|
|
609
|
+
const padded = `${style(placeholder, ANSI.slate, enabled)}${" ".repeat(Math.max(0, maxValueLength - placeholder.length))}`;
|
|
610
|
+
return `${promptStyled} ${padded}`;
|
|
611
|
+
}
|
|
612
|
+
const visibleValue = value.length > maxValueLength
|
|
613
|
+
? value.slice(value.length - maxValueLength)
|
|
614
|
+
: value;
|
|
615
|
+
return `${promptStyled} ${visibleValue}${" ".repeat(Math.max(0, maxValueLength - visibleValue.length))}`;
|
|
616
|
+
};
|
|
617
|
+
const render = () => {
|
|
618
|
+
if (renderedOnce) {
|
|
619
|
+
cursorTo(output, 0);
|
|
620
|
+
moveCursor(output, 0, -sectionTopOffsetFromInputLine);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
renderedOnce = true;
|
|
624
|
+
}
|
|
625
|
+
const commands = style(`Comandos: ${CONSOLE_COMMAND_HINT}`, ANSI.slateItalic, enabled);
|
|
626
|
+
const top = renderPromptFrameLine(innerWidth + 2, "┌", "┐");
|
|
627
|
+
const border = style("│", ANSI.brandBlue, enabled);
|
|
628
|
+
const middle = `${border} ${renderInputContent()} ${border}`;
|
|
629
|
+
const bottom = renderPromptFrameLine(innerWidth + 2, "└", "┘");
|
|
630
|
+
output.write("\u001b[J");
|
|
631
|
+
output.write(`${commands}\n\n${top}\n${middle}\n${bottom}\n`);
|
|
632
|
+
cursorTo(output, 0);
|
|
633
|
+
moveCursor(output, 0, -2);
|
|
634
|
+
const visibleValueLength = Math.min(value.length, Math.max(0, innerWidth - 2));
|
|
635
|
+
cursorTo(output, 4 + visibleValueLength);
|
|
636
|
+
};
|
|
637
|
+
const onData = (chunk) => {
|
|
638
|
+
const text = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
639
|
+
for (const char of Array.from(text)) {
|
|
640
|
+
if (char === "\u0003") {
|
|
641
|
+
cleanup();
|
|
642
|
+
reject(createCliExitError());
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (char === "\r" || char === "\n") {
|
|
646
|
+
cleanup();
|
|
647
|
+
output.write("\n");
|
|
648
|
+
resolve(normalizeText(value));
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (char === "\u007f" || char === "\b") {
|
|
652
|
+
value = value.slice(0, -1);
|
|
653
|
+
render();
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (char === "\u001b") {
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
value += char;
|
|
660
|
+
render();
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
render();
|
|
664
|
+
input.on("data", onData);
|
|
665
|
+
});
|
|
530
666
|
}
|
|
531
667
|
function printAssistantMessage(message) {
|
|
532
668
|
const text = normalizeText(message);
|
|
@@ -647,6 +783,16 @@ export function renderStructuredOutcome(job, options) {
|
|
|
647
783
|
}
|
|
648
784
|
return lines.join("\n").trim();
|
|
649
785
|
}
|
|
786
|
+
export function renderBridgeReleaseNoticeCard(notice) {
|
|
787
|
+
return renderInfoCard(buildBridgeReleaseCard({
|
|
788
|
+
kind: notice.kind,
|
|
789
|
+
message: normalizeText(notice.message),
|
|
790
|
+
currentVersion: normalizeText(notice.currentVersion),
|
|
791
|
+
latestVersion: normalizeText(notice.latestVersion),
|
|
792
|
+
minSupportedVersion: normalizeText(notice.minSupportedVersion),
|
|
793
|
+
updateCommand: normalizeText(notice.updateCommand) || "otto-bridge update",
|
|
794
|
+
}));
|
|
795
|
+
}
|
|
650
796
|
function printStructuredOutcome(job) {
|
|
651
797
|
const rendered = renderStructuredOutcome(job);
|
|
652
798
|
if (!rendered) {
|
package/dist/runtime.js
CHANGED
|
@@ -389,13 +389,27 @@ export class BridgeRuntime {
|
|
|
389
389
|
if (updateRequired) {
|
|
390
390
|
const message = `[otto-bridge] update required current=${this.config.bridgeVersion} min_supported=${minSupportedVersion || "unknown"} latest=${latestVersion || "unknown"} command="${updateCommand}"`;
|
|
391
391
|
this.logWarn(message);
|
|
392
|
-
this.emit({
|
|
392
|
+
this.emit({
|
|
393
|
+
type: "update_required",
|
|
394
|
+
message,
|
|
395
|
+
currentVersion: this.config.bridgeVersion,
|
|
396
|
+
latestVersion,
|
|
397
|
+
minSupportedVersion,
|
|
398
|
+
updateCommand,
|
|
399
|
+
});
|
|
393
400
|
return;
|
|
394
401
|
}
|
|
395
402
|
if (updateAvailable) {
|
|
396
403
|
const message = `[otto-bridge] update available current=${this.config.bridgeVersion} latest=${latestVersion || "unknown"} command="${updateCommand}"`;
|
|
397
404
|
this.logInfo(message);
|
|
398
|
-
this.emit({
|
|
405
|
+
this.emit({
|
|
406
|
+
type: "update_available",
|
|
407
|
+
message,
|
|
408
|
+
currentVersion: this.config.bridgeVersion,
|
|
409
|
+
latestVersion,
|
|
410
|
+
minSupportedVersion,
|
|
411
|
+
updateCommand,
|
|
412
|
+
});
|
|
399
413
|
}
|
|
400
414
|
}
|
|
401
415
|
clearPendingConfirmations(jobId) {
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const BRIDGE_CONFIG_VERSION = 1;
|
|
2
|
-
export const BRIDGE_VERSION = "1.0.
|
|
2
|
+
export const BRIDGE_VERSION = "1.0.7";
|
|
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;
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -24,7 +24,7 @@ if (!existsSync(mainPath)) {
|
|
|
24
24
|
process.exit(0);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
console.log("\n[otto-bridge] Welcome to OTTOAI 1.0.
|
|
27
|
+
console.log("\n[otto-bridge] Welcome to OTTOAI 1.0.7");
|
|
28
28
|
console.log("[otto-bridge] Vamos iniciar o setup interativo do bridge.\n");
|
|
29
29
|
|
|
30
30
|
const result = spawnSync(process.execPath, [mainPath, "setup", "--postinstall"], {
|