openviber 0.4.3 → 0.5.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 +24 -1
- package/dist/cli/index.cjs +2784 -170
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2797 -183
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +415 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +416 -145
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -7347,103 +7347,33 @@ async function runTask(goal, options, messages) {
|
|
|
7347
7347
|
}
|
|
7348
7348
|
|
|
7349
7349
|
// src/daemon/terminal.ts
|
|
7350
|
-
import { spawn, execSync } from "child_process";
|
|
7350
|
+
import { spawn, spawnSync, execSync } from "child_process";
|
|
7351
7351
|
import { EventEmitter } from "events";
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
{ encoding: "utf8", stdio: "pipe" }
|
|
7357
|
-
).trim();
|
|
7358
|
-
if (!out) return [];
|
|
7359
|
-
return out.split("\n").map((line) => {
|
|
7360
|
-
const [name, windows, attached] = line.split("|");
|
|
7361
|
-
return {
|
|
7362
|
-
name,
|
|
7363
|
-
windows: parseInt(windows, 10) || 0,
|
|
7364
|
-
attached: attached === "1"
|
|
7365
|
-
};
|
|
7366
|
-
});
|
|
7367
|
-
} catch {
|
|
7368
|
-
return [];
|
|
7369
|
-
}
|
|
7370
|
-
}
|
|
7371
|
-
function listPanes() {
|
|
7372
|
-
try {
|
|
7373
|
-
const out = execSync(
|
|
7374
|
-
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7375
|
-
{ encoding: "utf8", stdio: "pipe" }
|
|
7376
|
-
).trim();
|
|
7377
|
-
if (!out) return [];
|
|
7378
|
-
return out.split("\n").map((line) => {
|
|
7379
|
-
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7380
|
-
return {
|
|
7381
|
-
session,
|
|
7382
|
-
window: window2,
|
|
7383
|
-
windowName,
|
|
7384
|
-
pane,
|
|
7385
|
-
command,
|
|
7386
|
-
target: `${session}:${window2}.${pane}`
|
|
7387
|
-
};
|
|
7388
|
-
});
|
|
7389
|
-
} catch {
|
|
7390
|
-
return [];
|
|
7391
|
-
}
|
|
7392
|
-
}
|
|
7393
|
-
function sendKeys(target, keys, pressEnter = false) {
|
|
7394
|
-
try {
|
|
7395
|
-
const args = ["send-keys", "-t", target, keys];
|
|
7396
|
-
if (pressEnter) args.push("Enter");
|
|
7397
|
-
execSync(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7398
|
-
encoding: "utf8",
|
|
7399
|
-
stdio: "pipe"
|
|
7400
|
-
});
|
|
7401
|
-
return true;
|
|
7402
|
-
} catch {
|
|
7403
|
-
return false;
|
|
7404
|
-
}
|
|
7352
|
+
import { randomUUID } from "crypto";
|
|
7353
|
+
var SAFE_NAME_RE = /[^a-zA-Z0-9_.:-]/g;
|
|
7354
|
+
function sanitizeName(input) {
|
|
7355
|
+
return input.replace(SAFE_NAME_RE, "-");
|
|
7405
7356
|
}
|
|
7406
|
-
function
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
];
|
|
7411
|
-
for (const cmd of cmds) {
|
|
7412
|
-
try {
|
|
7413
|
-
return execSync(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7414
|
-
} catch {
|
|
7415
|
-
}
|
|
7416
|
-
}
|
|
7417
|
-
return "";
|
|
7418
|
-
}
|
|
7419
|
-
function resizePane(target, cols, rows) {
|
|
7420
|
-
try {
|
|
7421
|
-
execSync(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7422
|
-
encoding: "utf8",
|
|
7423
|
-
stdio: "pipe"
|
|
7424
|
-
});
|
|
7425
|
-
return true;
|
|
7426
|
-
} catch {
|
|
7427
|
-
return false;
|
|
7357
|
+
function resolveAppTarget(target, appHint) {
|
|
7358
|
+
if (target.includes("::")) {
|
|
7359
|
+
const [appId, ...rest] = target.split("::");
|
|
7360
|
+
return { appId, rawTarget: rest.join("::") };
|
|
7428
7361
|
}
|
|
7362
|
+
return { appId: appHint || "tmux", rawTarget: target };
|
|
7429
7363
|
}
|
|
7430
|
-
var
|
|
7431
|
-
target;
|
|
7432
|
-
catProcess = null;
|
|
7433
|
-
pipePath;
|
|
7434
|
-
isAttached = false;
|
|
7364
|
+
var TmuxTerminalStream = class extends EventEmitter {
|
|
7435
7365
|
constructor(target) {
|
|
7436
7366
|
super();
|
|
7437
7367
|
this.target = target;
|
|
7438
7368
|
this.pipePath = `/tmp/viber-term-${target.replace(/[^a-zA-Z0-9]/g, "-")}-${Date.now()}`;
|
|
7439
7369
|
}
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7370
|
+
catProcess = null;
|
|
7371
|
+
pipePath;
|
|
7372
|
+
isAttached = false;
|
|
7443
7373
|
async attach() {
|
|
7444
7374
|
if (this.isAttached) return true;
|
|
7445
7375
|
try {
|
|
7446
|
-
const history =
|
|
7376
|
+
const history = captureTmuxPane(this.target, 200);
|
|
7447
7377
|
if (history) {
|
|
7448
7378
|
this.emit("data", history);
|
|
7449
7379
|
}
|
|
@@ -7473,9 +7403,6 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7473
7403
|
return false;
|
|
7474
7404
|
}
|
|
7475
7405
|
}
|
|
7476
|
-
/**
|
|
7477
|
-
* Stop streaming
|
|
7478
|
-
*/
|
|
7479
7406
|
detach() {
|
|
7480
7407
|
if (!this.isAttached) return;
|
|
7481
7408
|
try {
|
|
@@ -7484,12 +7411,6 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7484
7411
|
}
|
|
7485
7412
|
this.cleanup();
|
|
7486
7413
|
}
|
|
7487
|
-
/**
|
|
7488
|
-
* Send input to the pane
|
|
7489
|
-
*/
|
|
7490
|
-
sendInput(keys) {
|
|
7491
|
-
return sendKeys(this.target, keys, false);
|
|
7492
|
-
}
|
|
7493
7414
|
cleanup() {
|
|
7494
7415
|
this.isAttached = false;
|
|
7495
7416
|
if (this.catProcess) {
|
|
@@ -7506,20 +7427,61 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7506
7427
|
return this.isAttached;
|
|
7507
7428
|
}
|
|
7508
7429
|
};
|
|
7509
|
-
var
|
|
7430
|
+
var TmuxTerminalApp = class {
|
|
7431
|
+
id = "tmux";
|
|
7432
|
+
label = "tmux";
|
|
7510
7433
|
streams = /* @__PURE__ */ new Map();
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7434
|
+
isAvailable() {
|
|
7435
|
+
try {
|
|
7436
|
+
execSync("tmux -V", { stdio: "pipe" });
|
|
7437
|
+
return true;
|
|
7438
|
+
} catch {
|
|
7439
|
+
return false;
|
|
7440
|
+
}
|
|
7441
|
+
}
|
|
7442
|
+
listSessions() {
|
|
7443
|
+
try {
|
|
7444
|
+
const out = execSync(
|
|
7445
|
+
"tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_attached}' 2>/dev/null",
|
|
7446
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7447
|
+
).trim();
|
|
7448
|
+
if (!out) return [];
|
|
7449
|
+
return out.split("\n").map((line) => {
|
|
7450
|
+
const [name, windows, attached] = line.split("|");
|
|
7451
|
+
return {
|
|
7452
|
+
appId: this.id,
|
|
7453
|
+
name,
|
|
7454
|
+
windows: parseInt(windows, 10) || 0,
|
|
7455
|
+
attached: attached === "1"
|
|
7456
|
+
};
|
|
7457
|
+
});
|
|
7458
|
+
} catch {
|
|
7459
|
+
return [];
|
|
7460
|
+
}
|
|
7461
|
+
}
|
|
7462
|
+
listPanes() {
|
|
7463
|
+
try {
|
|
7464
|
+
const out = execSync(
|
|
7465
|
+
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7466
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7467
|
+
).trim();
|
|
7468
|
+
if (!out) return [];
|
|
7469
|
+
return out.split("\n").map((line) => {
|
|
7470
|
+
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7471
|
+
return {
|
|
7472
|
+
appId: this.id,
|
|
7473
|
+
session,
|
|
7474
|
+
window: window2,
|
|
7475
|
+
windowName,
|
|
7476
|
+
pane,
|
|
7477
|
+
command,
|
|
7478
|
+
target: `${session}:${window2}.${pane}`
|
|
7479
|
+
};
|
|
7480
|
+
});
|
|
7481
|
+
} catch {
|
|
7482
|
+
return [];
|
|
7483
|
+
}
|
|
7519
7484
|
}
|
|
7520
|
-
/**
|
|
7521
|
-
* Attach to a pane and return the stream
|
|
7522
|
-
*/
|
|
7523
7485
|
async attach(target, onData, onClose) {
|
|
7524
7486
|
let stream = this.streams.get(target);
|
|
7525
7487
|
if (stream && stream.attached) {
|
|
@@ -7527,7 +7489,7 @@ var TerminalManager = class {
|
|
|
7527
7489
|
stream.on("close", onClose);
|
|
7528
7490
|
return true;
|
|
7529
7491
|
}
|
|
7530
|
-
stream = new
|
|
7492
|
+
stream = new TmuxTerminalStream(target);
|
|
7531
7493
|
stream.on("data", onData);
|
|
7532
7494
|
stream.on("close", () => {
|
|
7533
7495
|
this.streams.delete(target);
|
|
@@ -7539,31 +7501,62 @@ var TerminalManager = class {
|
|
|
7539
7501
|
}
|
|
7540
7502
|
return ok;
|
|
7541
7503
|
}
|
|
7542
|
-
/**
|
|
7543
|
-
* Detach from a pane
|
|
7544
|
-
*/
|
|
7545
7504
|
detach(target) {
|
|
7546
7505
|
const stream = this.streams.get(target);
|
|
7547
|
-
if (stream)
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
}
|
|
7506
|
+
if (!stream) return;
|
|
7507
|
+
stream.detach();
|
|
7508
|
+
this.streams.delete(target);
|
|
7551
7509
|
}
|
|
7552
|
-
/**
|
|
7553
|
-
* Send input to a pane
|
|
7554
|
-
*/
|
|
7555
7510
|
sendInput(target, keys) {
|
|
7556
|
-
return
|
|
7511
|
+
return sendTmuxKeys(target, keys);
|
|
7557
7512
|
}
|
|
7558
|
-
/**
|
|
7559
|
-
* Resize pane to match web terminal
|
|
7560
|
-
*/
|
|
7561
7513
|
resize(target, cols, rows) {
|
|
7562
|
-
|
|
7514
|
+
try {
|
|
7515
|
+
execSync(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7516
|
+
encoding: "utf8",
|
|
7517
|
+
stdio: "pipe"
|
|
7518
|
+
});
|
|
7519
|
+
return true;
|
|
7520
|
+
} catch {
|
|
7521
|
+
return false;
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7525
|
+
const safeSession = sanitizeName(sessionName || "coding");
|
|
7526
|
+
const safeWindow = sanitizeName(windowName || "main");
|
|
7527
|
+
try {
|
|
7528
|
+
execSync(`tmux has-session -t '${safeSession}' 2>/dev/null`, { stdio: "pipe" });
|
|
7529
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7530
|
+
} catch {
|
|
7531
|
+
}
|
|
7532
|
+
const args = ["new-session", "-d", "-s", safeSession, "-n", safeWindow];
|
|
7533
|
+
if (cwd) {
|
|
7534
|
+
args.push("-c", cwd);
|
|
7535
|
+
}
|
|
7536
|
+
const result = spawnSync("tmux", args, {
|
|
7537
|
+
encoding: "utf8",
|
|
7538
|
+
stdio: "pipe"
|
|
7539
|
+
});
|
|
7540
|
+
if (result.error) {
|
|
7541
|
+
return {
|
|
7542
|
+
ok: false,
|
|
7543
|
+
appId: this.id,
|
|
7544
|
+
sessionName: safeSession,
|
|
7545
|
+
created: false,
|
|
7546
|
+
error: `Failed to start tmux: ${result.error.message}`
|
|
7547
|
+
};
|
|
7548
|
+
}
|
|
7549
|
+
if (result.status !== 0) {
|
|
7550
|
+
return {
|
|
7551
|
+
ok: false,
|
|
7552
|
+
appId: this.id,
|
|
7553
|
+
sessionName: safeSession,
|
|
7554
|
+
created: false,
|
|
7555
|
+
error: (result.stderr || result.stdout || "Failed to create tmux session").trim()
|
|
7556
|
+
};
|
|
7557
|
+
}
|
|
7558
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7563
7559
|
}
|
|
7564
|
-
/**
|
|
7565
|
-
* Detach all streams
|
|
7566
|
-
*/
|
|
7567
7560
|
detachAll() {
|
|
7568
7561
|
for (const stream of this.streams.values()) {
|
|
7569
7562
|
stream.detach();
|
|
@@ -7571,6 +7564,203 @@ var TerminalManager = class {
|
|
|
7571
7564
|
this.streams.clear();
|
|
7572
7565
|
}
|
|
7573
7566
|
};
|
|
7567
|
+
var ShellTerminalApp = class {
|
|
7568
|
+
id = "shell";
|
|
7569
|
+
label = "shell";
|
|
7570
|
+
sessions = /* @__PURE__ */ new Map();
|
|
7571
|
+
isAvailable() {
|
|
7572
|
+
return true;
|
|
7573
|
+
}
|
|
7574
|
+
listSessions() {
|
|
7575
|
+
return Array.from(this.sessions.values()).map((state) => ({
|
|
7576
|
+
appId: this.id,
|
|
7577
|
+
name: state.sessionName,
|
|
7578
|
+
windows: 1,
|
|
7579
|
+
attached: state.listeners.size > 0
|
|
7580
|
+
}));
|
|
7581
|
+
}
|
|
7582
|
+
listPanes() {
|
|
7583
|
+
return Array.from(this.sessions.entries()).map(([id, state]) => ({
|
|
7584
|
+
appId: this.id,
|
|
7585
|
+
session: state.sessionName,
|
|
7586
|
+
window: "0",
|
|
7587
|
+
windowName: state.windowName,
|
|
7588
|
+
pane: state.pane,
|
|
7589
|
+
command: process.env.SHELL || "sh",
|
|
7590
|
+
target: id
|
|
7591
|
+
}));
|
|
7592
|
+
}
|
|
7593
|
+
async attach(target, onData, onClose) {
|
|
7594
|
+
const state = this.sessions.get(target);
|
|
7595
|
+
if (!state) return false;
|
|
7596
|
+
state.listeners.add(onData);
|
|
7597
|
+
state.closeListeners.add(onClose);
|
|
7598
|
+
if (state.history.length > 0) {
|
|
7599
|
+
onData(state.history.join(""));
|
|
7600
|
+
}
|
|
7601
|
+
return true;
|
|
7602
|
+
}
|
|
7603
|
+
detach(target) {
|
|
7604
|
+
const state = this.sessions.get(target);
|
|
7605
|
+
if (!state) return;
|
|
7606
|
+
state.listeners.clear();
|
|
7607
|
+
state.closeListeners.clear();
|
|
7608
|
+
}
|
|
7609
|
+
sendInput(target, keys) {
|
|
7610
|
+
const state = this.sessions.get(target);
|
|
7611
|
+
if (!state || !state.proc.stdin?.writable) return false;
|
|
7612
|
+
state.proc.stdin.write(keys);
|
|
7613
|
+
return true;
|
|
7614
|
+
}
|
|
7615
|
+
resize(_target, _cols, _rows) {
|
|
7616
|
+
return true;
|
|
7617
|
+
}
|
|
7618
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7619
|
+
const safeSession = sanitizeName(sessionName || `shell-${Date.now()}`);
|
|
7620
|
+
const shell = process.env.SHELL || "sh";
|
|
7621
|
+
const target = `${safeSession}:${randomUUID().slice(0, 8)}`;
|
|
7622
|
+
if (this.sessions.has(target)) {
|
|
7623
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7624
|
+
}
|
|
7625
|
+
const proc = spawn(shell, [], {
|
|
7626
|
+
cwd,
|
|
7627
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
7628
|
+
env: process.env
|
|
7629
|
+
});
|
|
7630
|
+
if (!proc.pid) {
|
|
7631
|
+
return {
|
|
7632
|
+
ok: false,
|
|
7633
|
+
appId: this.id,
|
|
7634
|
+
sessionName: safeSession,
|
|
7635
|
+
created: false,
|
|
7636
|
+
error: "Failed to start shell process"
|
|
7637
|
+
};
|
|
7638
|
+
}
|
|
7639
|
+
const state = {
|
|
7640
|
+
proc,
|
|
7641
|
+
sessionName: safeSession,
|
|
7642
|
+
windowName,
|
|
7643
|
+
pane: "0",
|
|
7644
|
+
history: [],
|
|
7645
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
7646
|
+
closeListeners: /* @__PURE__ */ new Set()
|
|
7647
|
+
};
|
|
7648
|
+
const pushChunk = (chunk) => {
|
|
7649
|
+
const text = chunk.toString();
|
|
7650
|
+
state.history.push(text);
|
|
7651
|
+
if (state.history.length > 200) {
|
|
7652
|
+
state.history.shift();
|
|
7653
|
+
}
|
|
7654
|
+
for (const listener of state.listeners) {
|
|
7655
|
+
listener(text);
|
|
7656
|
+
}
|
|
7657
|
+
};
|
|
7658
|
+
proc.stdout?.on("data", pushChunk);
|
|
7659
|
+
proc.stderr?.on("data", pushChunk);
|
|
7660
|
+
proc.on("close", () => {
|
|
7661
|
+
for (const onClose of state.closeListeners) {
|
|
7662
|
+
onClose();
|
|
7663
|
+
}
|
|
7664
|
+
this.sessions.delete(target);
|
|
7665
|
+
});
|
|
7666
|
+
this.sessions.set(target, state);
|
|
7667
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7668
|
+
}
|
|
7669
|
+
detachAll() {
|
|
7670
|
+
for (const [id, state] of this.sessions.entries()) {
|
|
7671
|
+
state.proc.kill();
|
|
7672
|
+
this.sessions.delete(id);
|
|
7673
|
+
}
|
|
7674
|
+
}
|
|
7675
|
+
};
|
|
7676
|
+
function sendTmuxKeys(target, keys, pressEnter = false) {
|
|
7677
|
+
try {
|
|
7678
|
+
const args = ["send-keys", "-t", target, keys];
|
|
7679
|
+
if (pressEnter) args.push("Enter");
|
|
7680
|
+
execSync(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7681
|
+
encoding: "utf8",
|
|
7682
|
+
stdio: "pipe"
|
|
7683
|
+
});
|
|
7684
|
+
return true;
|
|
7685
|
+
} catch {
|
|
7686
|
+
return false;
|
|
7687
|
+
}
|
|
7688
|
+
}
|
|
7689
|
+
function captureTmuxPane(target, lines = 500) {
|
|
7690
|
+
const cmds = [
|
|
7691
|
+
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7692
|
+
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
7693
|
+
];
|
|
7694
|
+
for (const cmd of cmds) {
|
|
7695
|
+
try {
|
|
7696
|
+
return execSync(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7697
|
+
} catch {
|
|
7698
|
+
}
|
|
7699
|
+
}
|
|
7700
|
+
return "";
|
|
7701
|
+
}
|
|
7702
|
+
var TerminalManager = class {
|
|
7703
|
+
apps = /* @__PURE__ */ new Map();
|
|
7704
|
+
constructor(adapters) {
|
|
7705
|
+
const defaultAdapters = adapters ?? [new TmuxTerminalApp(), new ShellTerminalApp()];
|
|
7706
|
+
for (const adapter of defaultAdapters) {
|
|
7707
|
+
this.apps.set(adapter.id, adapter);
|
|
7708
|
+
}
|
|
7709
|
+
}
|
|
7710
|
+
list() {
|
|
7711
|
+
const metadata = Array.from(this.apps.values()).map((app) => ({
|
|
7712
|
+
id: app.id,
|
|
7713
|
+
label: app.label,
|
|
7714
|
+
available: app.isAvailable()
|
|
7715
|
+
}));
|
|
7716
|
+
const sessions = [];
|
|
7717
|
+
const panes = [];
|
|
7718
|
+
for (const app of this.apps.values()) {
|
|
7719
|
+
if (!app.isAvailable()) continue;
|
|
7720
|
+
sessions.push(...app.listSessions());
|
|
7721
|
+
panes.push(...app.listPanes());
|
|
7722
|
+
}
|
|
7723
|
+
return { apps: metadata, sessions, panes };
|
|
7724
|
+
}
|
|
7725
|
+
async attach(target, onData, onClose, appHint) {
|
|
7726
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7727
|
+
const app = this.apps.get(appId);
|
|
7728
|
+
if (!app || !app.isAvailable()) return false;
|
|
7729
|
+
return app.attach(rawTarget, onData, onClose);
|
|
7730
|
+
}
|
|
7731
|
+
detach(target, appHint) {
|
|
7732
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7733
|
+
this.apps.get(appId)?.detach(rawTarget);
|
|
7734
|
+
}
|
|
7735
|
+
sendInput(target, keys, appHint) {
|
|
7736
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7737
|
+
const app = this.apps.get(appId);
|
|
7738
|
+
return !!app && app.isAvailable() ? app.sendInput(rawTarget, keys) : false;
|
|
7739
|
+
}
|
|
7740
|
+
resize(target, cols, rows, appHint) {
|
|
7741
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7742
|
+
const app = this.apps.get(appId);
|
|
7743
|
+
return !!app && app.isAvailable() ? app.resize(rawTarget, cols, rows) : false;
|
|
7744
|
+
}
|
|
7745
|
+
createSession(sessionName, windowName = "main", cwd, appId = "tmux") {
|
|
7746
|
+
const app = this.apps.get(appId);
|
|
7747
|
+
if (!app || !app.isAvailable()) {
|
|
7748
|
+
return {
|
|
7749
|
+
ok: false,
|
|
7750
|
+
appId,
|
|
7751
|
+
sessionName,
|
|
7752
|
+
created: false,
|
|
7753
|
+
error: `Terminal app '${appId}' is not available`
|
|
7754
|
+
};
|
|
7755
|
+
}
|
|
7756
|
+
return app.createSession(sessionName, windowName, cwd);
|
|
7757
|
+
}
|
|
7758
|
+
detachAll() {
|
|
7759
|
+
for (const app of this.apps.values()) {
|
|
7760
|
+
app.detachAll();
|
|
7761
|
+
}
|
|
7762
|
+
}
|
|
7763
|
+
};
|
|
7574
7764
|
|
|
7575
7765
|
// src/daemon/controller.ts
|
|
7576
7766
|
var ViberController = class extends EventEmitter2 {
|
|
@@ -7721,16 +7911,16 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7721
7911
|
this.handleTerminalList();
|
|
7722
7912
|
break;
|
|
7723
7913
|
case "terminal:attach":
|
|
7724
|
-
await this.handleTerminalAttach(message.target);
|
|
7914
|
+
await this.handleTerminalAttach(message.target, message.appId);
|
|
7725
7915
|
break;
|
|
7726
7916
|
case "terminal:detach":
|
|
7727
|
-
this.handleTerminalDetach(message.target);
|
|
7917
|
+
this.handleTerminalDetach(message.target, message.appId);
|
|
7728
7918
|
break;
|
|
7729
7919
|
case "terminal:input":
|
|
7730
|
-
this.handleTerminalInput(message.target, message.keys);
|
|
7920
|
+
this.handleTerminalInput(message.target, message.keys, message.appId);
|
|
7731
7921
|
break;
|
|
7732
7922
|
case "terminal:resize":
|
|
7733
|
-
this.handleTerminalResize(message.target, message.cols, message.rows);
|
|
7923
|
+
this.handleTerminalResize(message.target, message.cols, message.rows, message.appId);
|
|
7734
7924
|
break;
|
|
7735
7925
|
}
|
|
7736
7926
|
} catch (error) {
|
|
@@ -7760,7 +7950,87 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7760
7950
|
},
|
|
7761
7951
|
messages
|
|
7762
7952
|
);
|
|
7763
|
-
|
|
7953
|
+
let finalText = "";
|
|
7954
|
+
let pendingDelta = "";
|
|
7955
|
+
let lastProgressAt = 0;
|
|
7956
|
+
const flushProgress = (force = false) => {
|
|
7957
|
+
if (!pendingDelta) return;
|
|
7958
|
+
const now = Date.now();
|
|
7959
|
+
if (!force && now - lastProgressAt < 250) return;
|
|
7960
|
+
this.send({
|
|
7961
|
+
type: "task:progress",
|
|
7962
|
+
taskId,
|
|
7963
|
+
event: {
|
|
7964
|
+
kind: "text-delta",
|
|
7965
|
+
delta: pendingDelta,
|
|
7966
|
+
totalLength: finalText.length,
|
|
7967
|
+
at: new Date(now).toISOString()
|
|
7968
|
+
}
|
|
7969
|
+
});
|
|
7970
|
+
pendingDelta = "";
|
|
7971
|
+
lastProgressAt = now;
|
|
7972
|
+
};
|
|
7973
|
+
this.send({
|
|
7974
|
+
type: "task:progress",
|
|
7975
|
+
taskId,
|
|
7976
|
+
event: {
|
|
7977
|
+
kind: "status",
|
|
7978
|
+
phase: "executing",
|
|
7979
|
+
message: "Agent execution started",
|
|
7980
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7981
|
+
}
|
|
7982
|
+
});
|
|
7983
|
+
for await (const part of streamResult.fullStream) {
|
|
7984
|
+
switch (part.type) {
|
|
7985
|
+
case "text-delta":
|
|
7986
|
+
if (part.text) {
|
|
7987
|
+
finalText += part.text;
|
|
7988
|
+
pendingDelta += part.text;
|
|
7989
|
+
flushProgress(false);
|
|
7990
|
+
}
|
|
7991
|
+
break;
|
|
7992
|
+
case "tool-call":
|
|
7993
|
+
this.send({
|
|
7994
|
+
type: "task:progress",
|
|
7995
|
+
taskId,
|
|
7996
|
+
event: {
|
|
7997
|
+
kind: "tool-call",
|
|
7998
|
+
toolName: part.toolName,
|
|
7999
|
+
toolCallId: part.toolCallId,
|
|
8000
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8001
|
+
}
|
|
8002
|
+
});
|
|
8003
|
+
break;
|
|
8004
|
+
case "tool-result":
|
|
8005
|
+
this.send({
|
|
8006
|
+
type: "task:progress",
|
|
8007
|
+
taskId,
|
|
8008
|
+
event: {
|
|
8009
|
+
kind: "tool-result",
|
|
8010
|
+
toolCallId: part.toolCallId,
|
|
8011
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8012
|
+
}
|
|
8013
|
+
});
|
|
8014
|
+
break;
|
|
8015
|
+
case "error":
|
|
8016
|
+
throw new Error(part.error?.message || "Task stream error");
|
|
8017
|
+
case "finish":
|
|
8018
|
+
flushProgress(true);
|
|
8019
|
+
this.send({
|
|
8020
|
+
type: "task:progress",
|
|
8021
|
+
taskId,
|
|
8022
|
+
event: {
|
|
8023
|
+
kind: "status",
|
|
8024
|
+
phase: "verifying",
|
|
8025
|
+
message: "Agent execution finished, preparing final output",
|
|
8026
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8027
|
+
}
|
|
8028
|
+
});
|
|
8029
|
+
break;
|
|
8030
|
+
default:
|
|
8031
|
+
break;
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
7764
8034
|
this.send({
|
|
7765
8035
|
type: "task:completed",
|
|
7766
8036
|
taskId,
|
|
@@ -7797,33 +8067,34 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7797
8067
|
}
|
|
7798
8068
|
// ==================== Terminal Streaming ====================
|
|
7799
8069
|
handleTerminalList() {
|
|
7800
|
-
const { sessions, panes } = this.terminalManager.list();
|
|
7801
|
-
this.send({ type: "terminal:list", sessions, panes });
|
|
8070
|
+
const { apps, sessions, panes } = this.terminalManager.list();
|
|
8071
|
+
this.send({ type: "terminal:list", apps, sessions, panes });
|
|
7802
8072
|
}
|
|
7803
|
-
async handleTerminalAttach(target) {
|
|
8073
|
+
async handleTerminalAttach(target, appId) {
|
|
7804
8074
|
console.log(`[Viber] Attaching to terminal: ${target}`);
|
|
7805
8075
|
const ok = await this.terminalManager.attach(
|
|
7806
8076
|
target,
|
|
7807
8077
|
(data) => {
|
|
7808
|
-
this.send({ type: "terminal:output", target, data });
|
|
8078
|
+
this.send({ type: "terminal:output", target, appId, data });
|
|
7809
8079
|
},
|
|
7810
8080
|
() => {
|
|
7811
|
-
this.send({ type: "terminal:detached", target });
|
|
7812
|
-
}
|
|
8081
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
8082
|
+
},
|
|
8083
|
+
appId
|
|
7813
8084
|
);
|
|
7814
|
-
this.send({ type: "terminal:attached", target, ok });
|
|
8085
|
+
this.send({ type: "terminal:attached", target, appId, ok });
|
|
7815
8086
|
}
|
|
7816
|
-
handleTerminalDetach(target) {
|
|
8087
|
+
handleTerminalDetach(target, appId) {
|
|
7817
8088
|
console.log(`[Viber] Detaching from terminal: ${target}`);
|
|
7818
|
-
this.terminalManager.detach(target);
|
|
7819
|
-
this.send({ type: "terminal:detached", target });
|
|
8089
|
+
this.terminalManager.detach(target, appId);
|
|
8090
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
7820
8091
|
}
|
|
7821
|
-
handleTerminalInput(target, keys) {
|
|
7822
|
-
this.terminalManager.sendInput(target, keys);
|
|
8092
|
+
handleTerminalInput(target, keys, appId) {
|
|
8093
|
+
this.terminalManager.sendInput(target, keys, appId);
|
|
7823
8094
|
}
|
|
7824
|
-
handleTerminalResize(target, cols, rows) {
|
|
7825
|
-
const ok = this.terminalManager.resize(target, cols, rows);
|
|
7826
|
-
this.send({ type: "terminal:resized", target, ok });
|
|
8095
|
+
handleTerminalResize(target, cols, rows, appId) {
|
|
8096
|
+
const ok = this.terminalManager.resize(target, cols, rows, appId);
|
|
8097
|
+
this.send({ type: "terminal:resized", target, appId, ok });
|
|
7827
8098
|
}
|
|
7828
8099
|
// ==================== Communication ====================
|
|
7829
8100
|
send(message) {
|