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.cjs
CHANGED
|
@@ -7399,101 +7399,31 @@ async function runTask(goal, options, messages) {
|
|
|
7399
7399
|
// src/daemon/terminal.ts
|
|
7400
7400
|
var import_child_process2 = require("child_process");
|
|
7401
7401
|
var import_events = require("events");
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
{ encoding: "utf8", stdio: "pipe" }
|
|
7407
|
-
).trim();
|
|
7408
|
-
if (!out) return [];
|
|
7409
|
-
return out.split("\n").map((line) => {
|
|
7410
|
-
const [name, windows, attached] = line.split("|");
|
|
7411
|
-
return {
|
|
7412
|
-
name,
|
|
7413
|
-
windows: parseInt(windows, 10) || 0,
|
|
7414
|
-
attached: attached === "1"
|
|
7415
|
-
};
|
|
7416
|
-
});
|
|
7417
|
-
} catch {
|
|
7418
|
-
return [];
|
|
7419
|
-
}
|
|
7420
|
-
}
|
|
7421
|
-
function listPanes() {
|
|
7422
|
-
try {
|
|
7423
|
-
const out = (0, import_child_process2.execSync)(
|
|
7424
|
-
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7425
|
-
{ encoding: "utf8", stdio: "pipe" }
|
|
7426
|
-
).trim();
|
|
7427
|
-
if (!out) return [];
|
|
7428
|
-
return out.split("\n").map((line) => {
|
|
7429
|
-
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7430
|
-
return {
|
|
7431
|
-
session,
|
|
7432
|
-
window: window2,
|
|
7433
|
-
windowName,
|
|
7434
|
-
pane,
|
|
7435
|
-
command,
|
|
7436
|
-
target: `${session}:${window2}.${pane}`
|
|
7437
|
-
};
|
|
7438
|
-
});
|
|
7439
|
-
} catch {
|
|
7440
|
-
return [];
|
|
7441
|
-
}
|
|
7442
|
-
}
|
|
7443
|
-
function sendKeys(target, keys, pressEnter = false) {
|
|
7444
|
-
try {
|
|
7445
|
-
const args = ["send-keys", "-t", target, keys];
|
|
7446
|
-
if (pressEnter) args.push("Enter");
|
|
7447
|
-
(0, import_child_process2.execSync)(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7448
|
-
encoding: "utf8",
|
|
7449
|
-
stdio: "pipe"
|
|
7450
|
-
});
|
|
7451
|
-
return true;
|
|
7452
|
-
} catch {
|
|
7453
|
-
return false;
|
|
7454
|
-
}
|
|
7402
|
+
var import_crypto = require("crypto");
|
|
7403
|
+
var SAFE_NAME_RE = /[^a-zA-Z0-9_.:-]/g;
|
|
7404
|
+
function sanitizeName(input) {
|
|
7405
|
+
return input.replace(SAFE_NAME_RE, "-");
|
|
7455
7406
|
}
|
|
7456
|
-
function
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
];
|
|
7461
|
-
for (const cmd of cmds) {
|
|
7462
|
-
try {
|
|
7463
|
-
return (0, import_child_process2.execSync)(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7464
|
-
} catch {
|
|
7465
|
-
}
|
|
7466
|
-
}
|
|
7467
|
-
return "";
|
|
7468
|
-
}
|
|
7469
|
-
function resizePane(target, cols, rows) {
|
|
7470
|
-
try {
|
|
7471
|
-
(0, import_child_process2.execSync)(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7472
|
-
encoding: "utf8",
|
|
7473
|
-
stdio: "pipe"
|
|
7474
|
-
});
|
|
7475
|
-
return true;
|
|
7476
|
-
} catch {
|
|
7477
|
-
return false;
|
|
7407
|
+
function resolveAppTarget(target, appHint) {
|
|
7408
|
+
if (target.includes("::")) {
|
|
7409
|
+
const [appId, ...rest] = target.split("::");
|
|
7410
|
+
return { appId, rawTarget: rest.join("::") };
|
|
7478
7411
|
}
|
|
7412
|
+
return { appId: appHint || "tmux", rawTarget: target };
|
|
7479
7413
|
}
|
|
7480
|
-
var
|
|
7481
|
-
target;
|
|
7482
|
-
catProcess = null;
|
|
7483
|
-
pipePath;
|
|
7484
|
-
isAttached = false;
|
|
7414
|
+
var TmuxTerminalStream = class extends import_events.EventEmitter {
|
|
7485
7415
|
constructor(target) {
|
|
7486
7416
|
super();
|
|
7487
7417
|
this.target = target;
|
|
7488
7418
|
this.pipePath = `/tmp/viber-term-${target.replace(/[^a-zA-Z0-9]/g, "-")}-${Date.now()}`;
|
|
7489
7419
|
}
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7420
|
+
catProcess = null;
|
|
7421
|
+
pipePath;
|
|
7422
|
+
isAttached = false;
|
|
7493
7423
|
async attach() {
|
|
7494
7424
|
if (this.isAttached) return true;
|
|
7495
7425
|
try {
|
|
7496
|
-
const history =
|
|
7426
|
+
const history = captureTmuxPane(this.target, 200);
|
|
7497
7427
|
if (history) {
|
|
7498
7428
|
this.emit("data", history);
|
|
7499
7429
|
}
|
|
@@ -7523,9 +7453,6 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7523
7453
|
return false;
|
|
7524
7454
|
}
|
|
7525
7455
|
}
|
|
7526
|
-
/**
|
|
7527
|
-
* Stop streaming
|
|
7528
|
-
*/
|
|
7529
7456
|
detach() {
|
|
7530
7457
|
if (!this.isAttached) return;
|
|
7531
7458
|
try {
|
|
@@ -7534,12 +7461,6 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7534
7461
|
}
|
|
7535
7462
|
this.cleanup();
|
|
7536
7463
|
}
|
|
7537
|
-
/**
|
|
7538
|
-
* Send input to the pane
|
|
7539
|
-
*/
|
|
7540
|
-
sendInput(keys) {
|
|
7541
|
-
return sendKeys(this.target, keys, false);
|
|
7542
|
-
}
|
|
7543
7464
|
cleanup() {
|
|
7544
7465
|
this.isAttached = false;
|
|
7545
7466
|
if (this.catProcess) {
|
|
@@ -7556,20 +7477,61 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7556
7477
|
return this.isAttached;
|
|
7557
7478
|
}
|
|
7558
7479
|
};
|
|
7559
|
-
var
|
|
7480
|
+
var TmuxTerminalApp = class {
|
|
7481
|
+
id = "tmux";
|
|
7482
|
+
label = "tmux";
|
|
7560
7483
|
streams = /* @__PURE__ */ new Map();
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7484
|
+
isAvailable() {
|
|
7485
|
+
try {
|
|
7486
|
+
(0, import_child_process2.execSync)("tmux -V", { stdio: "pipe" });
|
|
7487
|
+
return true;
|
|
7488
|
+
} catch {
|
|
7489
|
+
return false;
|
|
7490
|
+
}
|
|
7491
|
+
}
|
|
7492
|
+
listSessions() {
|
|
7493
|
+
try {
|
|
7494
|
+
const out = (0, import_child_process2.execSync)(
|
|
7495
|
+
"tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_attached}' 2>/dev/null",
|
|
7496
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7497
|
+
).trim();
|
|
7498
|
+
if (!out) return [];
|
|
7499
|
+
return out.split("\n").map((line) => {
|
|
7500
|
+
const [name, windows, attached] = line.split("|");
|
|
7501
|
+
return {
|
|
7502
|
+
appId: this.id,
|
|
7503
|
+
name,
|
|
7504
|
+
windows: parseInt(windows, 10) || 0,
|
|
7505
|
+
attached: attached === "1"
|
|
7506
|
+
};
|
|
7507
|
+
});
|
|
7508
|
+
} catch {
|
|
7509
|
+
return [];
|
|
7510
|
+
}
|
|
7511
|
+
}
|
|
7512
|
+
listPanes() {
|
|
7513
|
+
try {
|
|
7514
|
+
const out = (0, import_child_process2.execSync)(
|
|
7515
|
+
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7516
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7517
|
+
).trim();
|
|
7518
|
+
if (!out) return [];
|
|
7519
|
+
return out.split("\n").map((line) => {
|
|
7520
|
+
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7521
|
+
return {
|
|
7522
|
+
appId: this.id,
|
|
7523
|
+
session,
|
|
7524
|
+
window: window2,
|
|
7525
|
+
windowName,
|
|
7526
|
+
pane,
|
|
7527
|
+
command,
|
|
7528
|
+
target: `${session}:${window2}.${pane}`
|
|
7529
|
+
};
|
|
7530
|
+
});
|
|
7531
|
+
} catch {
|
|
7532
|
+
return [];
|
|
7533
|
+
}
|
|
7569
7534
|
}
|
|
7570
|
-
/**
|
|
7571
|
-
* Attach to a pane and return the stream
|
|
7572
|
-
*/
|
|
7573
7535
|
async attach(target, onData, onClose) {
|
|
7574
7536
|
let stream = this.streams.get(target);
|
|
7575
7537
|
if (stream && stream.attached) {
|
|
@@ -7577,7 +7539,7 @@ var TerminalManager = class {
|
|
|
7577
7539
|
stream.on("close", onClose);
|
|
7578
7540
|
return true;
|
|
7579
7541
|
}
|
|
7580
|
-
stream = new
|
|
7542
|
+
stream = new TmuxTerminalStream(target);
|
|
7581
7543
|
stream.on("data", onData);
|
|
7582
7544
|
stream.on("close", () => {
|
|
7583
7545
|
this.streams.delete(target);
|
|
@@ -7589,31 +7551,62 @@ var TerminalManager = class {
|
|
|
7589
7551
|
}
|
|
7590
7552
|
return ok;
|
|
7591
7553
|
}
|
|
7592
|
-
/**
|
|
7593
|
-
* Detach from a pane
|
|
7594
|
-
*/
|
|
7595
7554
|
detach(target) {
|
|
7596
7555
|
const stream = this.streams.get(target);
|
|
7597
|
-
if (stream)
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
}
|
|
7556
|
+
if (!stream) return;
|
|
7557
|
+
stream.detach();
|
|
7558
|
+
this.streams.delete(target);
|
|
7601
7559
|
}
|
|
7602
|
-
/**
|
|
7603
|
-
* Send input to a pane
|
|
7604
|
-
*/
|
|
7605
7560
|
sendInput(target, keys) {
|
|
7606
|
-
return
|
|
7561
|
+
return sendTmuxKeys(target, keys);
|
|
7607
7562
|
}
|
|
7608
|
-
/**
|
|
7609
|
-
* Resize pane to match web terminal
|
|
7610
|
-
*/
|
|
7611
7563
|
resize(target, cols, rows) {
|
|
7612
|
-
|
|
7564
|
+
try {
|
|
7565
|
+
(0, import_child_process2.execSync)(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7566
|
+
encoding: "utf8",
|
|
7567
|
+
stdio: "pipe"
|
|
7568
|
+
});
|
|
7569
|
+
return true;
|
|
7570
|
+
} catch {
|
|
7571
|
+
return false;
|
|
7572
|
+
}
|
|
7573
|
+
}
|
|
7574
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7575
|
+
const safeSession = sanitizeName(sessionName || "coding");
|
|
7576
|
+
const safeWindow = sanitizeName(windowName || "main");
|
|
7577
|
+
try {
|
|
7578
|
+
(0, import_child_process2.execSync)(`tmux has-session -t '${safeSession}' 2>/dev/null`, { stdio: "pipe" });
|
|
7579
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7580
|
+
} catch {
|
|
7581
|
+
}
|
|
7582
|
+
const args = ["new-session", "-d", "-s", safeSession, "-n", safeWindow];
|
|
7583
|
+
if (cwd) {
|
|
7584
|
+
args.push("-c", cwd);
|
|
7585
|
+
}
|
|
7586
|
+
const result = (0, import_child_process2.spawnSync)("tmux", args, {
|
|
7587
|
+
encoding: "utf8",
|
|
7588
|
+
stdio: "pipe"
|
|
7589
|
+
});
|
|
7590
|
+
if (result.error) {
|
|
7591
|
+
return {
|
|
7592
|
+
ok: false,
|
|
7593
|
+
appId: this.id,
|
|
7594
|
+
sessionName: safeSession,
|
|
7595
|
+
created: false,
|
|
7596
|
+
error: `Failed to start tmux: ${result.error.message}`
|
|
7597
|
+
};
|
|
7598
|
+
}
|
|
7599
|
+
if (result.status !== 0) {
|
|
7600
|
+
return {
|
|
7601
|
+
ok: false,
|
|
7602
|
+
appId: this.id,
|
|
7603
|
+
sessionName: safeSession,
|
|
7604
|
+
created: false,
|
|
7605
|
+
error: (result.stderr || result.stdout || "Failed to create tmux session").trim()
|
|
7606
|
+
};
|
|
7607
|
+
}
|
|
7608
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7613
7609
|
}
|
|
7614
|
-
/**
|
|
7615
|
-
* Detach all streams
|
|
7616
|
-
*/
|
|
7617
7610
|
detachAll() {
|
|
7618
7611
|
for (const stream of this.streams.values()) {
|
|
7619
7612
|
stream.detach();
|
|
@@ -7621,6 +7614,203 @@ var TerminalManager = class {
|
|
|
7621
7614
|
this.streams.clear();
|
|
7622
7615
|
}
|
|
7623
7616
|
};
|
|
7617
|
+
var ShellTerminalApp = class {
|
|
7618
|
+
id = "shell";
|
|
7619
|
+
label = "shell";
|
|
7620
|
+
sessions = /* @__PURE__ */ new Map();
|
|
7621
|
+
isAvailable() {
|
|
7622
|
+
return true;
|
|
7623
|
+
}
|
|
7624
|
+
listSessions() {
|
|
7625
|
+
return Array.from(this.sessions.values()).map((state) => ({
|
|
7626
|
+
appId: this.id,
|
|
7627
|
+
name: state.sessionName,
|
|
7628
|
+
windows: 1,
|
|
7629
|
+
attached: state.listeners.size > 0
|
|
7630
|
+
}));
|
|
7631
|
+
}
|
|
7632
|
+
listPanes() {
|
|
7633
|
+
return Array.from(this.sessions.entries()).map(([id, state]) => ({
|
|
7634
|
+
appId: this.id,
|
|
7635
|
+
session: state.sessionName,
|
|
7636
|
+
window: "0",
|
|
7637
|
+
windowName: state.windowName,
|
|
7638
|
+
pane: state.pane,
|
|
7639
|
+
command: process.env.SHELL || "sh",
|
|
7640
|
+
target: id
|
|
7641
|
+
}));
|
|
7642
|
+
}
|
|
7643
|
+
async attach(target, onData, onClose) {
|
|
7644
|
+
const state = this.sessions.get(target);
|
|
7645
|
+
if (!state) return false;
|
|
7646
|
+
state.listeners.add(onData);
|
|
7647
|
+
state.closeListeners.add(onClose);
|
|
7648
|
+
if (state.history.length > 0) {
|
|
7649
|
+
onData(state.history.join(""));
|
|
7650
|
+
}
|
|
7651
|
+
return true;
|
|
7652
|
+
}
|
|
7653
|
+
detach(target) {
|
|
7654
|
+
const state = this.sessions.get(target);
|
|
7655
|
+
if (!state) return;
|
|
7656
|
+
state.listeners.clear();
|
|
7657
|
+
state.closeListeners.clear();
|
|
7658
|
+
}
|
|
7659
|
+
sendInput(target, keys) {
|
|
7660
|
+
const state = this.sessions.get(target);
|
|
7661
|
+
if (!state || !state.proc.stdin?.writable) return false;
|
|
7662
|
+
state.proc.stdin.write(keys);
|
|
7663
|
+
return true;
|
|
7664
|
+
}
|
|
7665
|
+
resize(_target, _cols, _rows) {
|
|
7666
|
+
return true;
|
|
7667
|
+
}
|
|
7668
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7669
|
+
const safeSession = sanitizeName(sessionName || `shell-${Date.now()}`);
|
|
7670
|
+
const shell = process.env.SHELL || "sh";
|
|
7671
|
+
const target = `${safeSession}:${(0, import_crypto.randomUUID)().slice(0, 8)}`;
|
|
7672
|
+
if (this.sessions.has(target)) {
|
|
7673
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7674
|
+
}
|
|
7675
|
+
const proc = (0, import_child_process2.spawn)(shell, [], {
|
|
7676
|
+
cwd,
|
|
7677
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
7678
|
+
env: process.env
|
|
7679
|
+
});
|
|
7680
|
+
if (!proc.pid) {
|
|
7681
|
+
return {
|
|
7682
|
+
ok: false,
|
|
7683
|
+
appId: this.id,
|
|
7684
|
+
sessionName: safeSession,
|
|
7685
|
+
created: false,
|
|
7686
|
+
error: "Failed to start shell process"
|
|
7687
|
+
};
|
|
7688
|
+
}
|
|
7689
|
+
const state = {
|
|
7690
|
+
proc,
|
|
7691
|
+
sessionName: safeSession,
|
|
7692
|
+
windowName,
|
|
7693
|
+
pane: "0",
|
|
7694
|
+
history: [],
|
|
7695
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
7696
|
+
closeListeners: /* @__PURE__ */ new Set()
|
|
7697
|
+
};
|
|
7698
|
+
const pushChunk = (chunk) => {
|
|
7699
|
+
const text = chunk.toString();
|
|
7700
|
+
state.history.push(text);
|
|
7701
|
+
if (state.history.length > 200) {
|
|
7702
|
+
state.history.shift();
|
|
7703
|
+
}
|
|
7704
|
+
for (const listener of state.listeners) {
|
|
7705
|
+
listener(text);
|
|
7706
|
+
}
|
|
7707
|
+
};
|
|
7708
|
+
proc.stdout?.on("data", pushChunk);
|
|
7709
|
+
proc.stderr?.on("data", pushChunk);
|
|
7710
|
+
proc.on("close", () => {
|
|
7711
|
+
for (const onClose of state.closeListeners) {
|
|
7712
|
+
onClose();
|
|
7713
|
+
}
|
|
7714
|
+
this.sessions.delete(target);
|
|
7715
|
+
});
|
|
7716
|
+
this.sessions.set(target, state);
|
|
7717
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7718
|
+
}
|
|
7719
|
+
detachAll() {
|
|
7720
|
+
for (const [id, state] of this.sessions.entries()) {
|
|
7721
|
+
state.proc.kill();
|
|
7722
|
+
this.sessions.delete(id);
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
};
|
|
7726
|
+
function sendTmuxKeys(target, keys, pressEnter = false) {
|
|
7727
|
+
try {
|
|
7728
|
+
const args = ["send-keys", "-t", target, keys];
|
|
7729
|
+
if (pressEnter) args.push("Enter");
|
|
7730
|
+
(0, import_child_process2.execSync)(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7731
|
+
encoding: "utf8",
|
|
7732
|
+
stdio: "pipe"
|
|
7733
|
+
});
|
|
7734
|
+
return true;
|
|
7735
|
+
} catch {
|
|
7736
|
+
return false;
|
|
7737
|
+
}
|
|
7738
|
+
}
|
|
7739
|
+
function captureTmuxPane(target, lines = 500) {
|
|
7740
|
+
const cmds = [
|
|
7741
|
+
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7742
|
+
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
7743
|
+
];
|
|
7744
|
+
for (const cmd of cmds) {
|
|
7745
|
+
try {
|
|
7746
|
+
return (0, import_child_process2.execSync)(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7747
|
+
} catch {
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7750
|
+
return "";
|
|
7751
|
+
}
|
|
7752
|
+
var TerminalManager = class {
|
|
7753
|
+
apps = /* @__PURE__ */ new Map();
|
|
7754
|
+
constructor(adapters) {
|
|
7755
|
+
const defaultAdapters = adapters ?? [new TmuxTerminalApp(), new ShellTerminalApp()];
|
|
7756
|
+
for (const adapter of defaultAdapters) {
|
|
7757
|
+
this.apps.set(adapter.id, adapter);
|
|
7758
|
+
}
|
|
7759
|
+
}
|
|
7760
|
+
list() {
|
|
7761
|
+
const metadata = Array.from(this.apps.values()).map((app) => ({
|
|
7762
|
+
id: app.id,
|
|
7763
|
+
label: app.label,
|
|
7764
|
+
available: app.isAvailable()
|
|
7765
|
+
}));
|
|
7766
|
+
const sessions = [];
|
|
7767
|
+
const panes = [];
|
|
7768
|
+
for (const app of this.apps.values()) {
|
|
7769
|
+
if (!app.isAvailable()) continue;
|
|
7770
|
+
sessions.push(...app.listSessions());
|
|
7771
|
+
panes.push(...app.listPanes());
|
|
7772
|
+
}
|
|
7773
|
+
return { apps: metadata, sessions, panes };
|
|
7774
|
+
}
|
|
7775
|
+
async attach(target, onData, onClose, appHint) {
|
|
7776
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7777
|
+
const app = this.apps.get(appId);
|
|
7778
|
+
if (!app || !app.isAvailable()) return false;
|
|
7779
|
+
return app.attach(rawTarget, onData, onClose);
|
|
7780
|
+
}
|
|
7781
|
+
detach(target, appHint) {
|
|
7782
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7783
|
+
this.apps.get(appId)?.detach(rawTarget);
|
|
7784
|
+
}
|
|
7785
|
+
sendInput(target, keys, appHint) {
|
|
7786
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7787
|
+
const app = this.apps.get(appId);
|
|
7788
|
+
return !!app && app.isAvailable() ? app.sendInput(rawTarget, keys) : false;
|
|
7789
|
+
}
|
|
7790
|
+
resize(target, cols, rows, appHint) {
|
|
7791
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7792
|
+
const app = this.apps.get(appId);
|
|
7793
|
+
return !!app && app.isAvailable() ? app.resize(rawTarget, cols, rows) : false;
|
|
7794
|
+
}
|
|
7795
|
+
createSession(sessionName, windowName = "main", cwd, appId = "tmux") {
|
|
7796
|
+
const app = this.apps.get(appId);
|
|
7797
|
+
if (!app || !app.isAvailable()) {
|
|
7798
|
+
return {
|
|
7799
|
+
ok: false,
|
|
7800
|
+
appId,
|
|
7801
|
+
sessionName,
|
|
7802
|
+
created: false,
|
|
7803
|
+
error: `Terminal app '${appId}' is not available`
|
|
7804
|
+
};
|
|
7805
|
+
}
|
|
7806
|
+
return app.createSession(sessionName, windowName, cwd);
|
|
7807
|
+
}
|
|
7808
|
+
detachAll() {
|
|
7809
|
+
for (const app of this.apps.values()) {
|
|
7810
|
+
app.detachAll();
|
|
7811
|
+
}
|
|
7812
|
+
}
|
|
7813
|
+
};
|
|
7624
7814
|
|
|
7625
7815
|
// src/daemon/controller.ts
|
|
7626
7816
|
var ViberController = class extends import_events2.EventEmitter {
|
|
@@ -7771,16 +7961,16 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7771
7961
|
this.handleTerminalList();
|
|
7772
7962
|
break;
|
|
7773
7963
|
case "terminal:attach":
|
|
7774
|
-
await this.handleTerminalAttach(message.target);
|
|
7964
|
+
await this.handleTerminalAttach(message.target, message.appId);
|
|
7775
7965
|
break;
|
|
7776
7966
|
case "terminal:detach":
|
|
7777
|
-
this.handleTerminalDetach(message.target);
|
|
7967
|
+
this.handleTerminalDetach(message.target, message.appId);
|
|
7778
7968
|
break;
|
|
7779
7969
|
case "terminal:input":
|
|
7780
|
-
this.handleTerminalInput(message.target, message.keys);
|
|
7970
|
+
this.handleTerminalInput(message.target, message.keys, message.appId);
|
|
7781
7971
|
break;
|
|
7782
7972
|
case "terminal:resize":
|
|
7783
|
-
this.handleTerminalResize(message.target, message.cols, message.rows);
|
|
7973
|
+
this.handleTerminalResize(message.target, message.cols, message.rows, message.appId);
|
|
7784
7974
|
break;
|
|
7785
7975
|
}
|
|
7786
7976
|
} catch (error) {
|
|
@@ -7810,7 +8000,87 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7810
8000
|
},
|
|
7811
8001
|
messages
|
|
7812
8002
|
);
|
|
7813
|
-
|
|
8003
|
+
let finalText = "";
|
|
8004
|
+
let pendingDelta = "";
|
|
8005
|
+
let lastProgressAt = 0;
|
|
8006
|
+
const flushProgress = (force = false) => {
|
|
8007
|
+
if (!pendingDelta) return;
|
|
8008
|
+
const now = Date.now();
|
|
8009
|
+
if (!force && now - lastProgressAt < 250) return;
|
|
8010
|
+
this.send({
|
|
8011
|
+
type: "task:progress",
|
|
8012
|
+
taskId,
|
|
8013
|
+
event: {
|
|
8014
|
+
kind: "text-delta",
|
|
8015
|
+
delta: pendingDelta,
|
|
8016
|
+
totalLength: finalText.length,
|
|
8017
|
+
at: new Date(now).toISOString()
|
|
8018
|
+
}
|
|
8019
|
+
});
|
|
8020
|
+
pendingDelta = "";
|
|
8021
|
+
lastProgressAt = now;
|
|
8022
|
+
};
|
|
8023
|
+
this.send({
|
|
8024
|
+
type: "task:progress",
|
|
8025
|
+
taskId,
|
|
8026
|
+
event: {
|
|
8027
|
+
kind: "status",
|
|
8028
|
+
phase: "executing",
|
|
8029
|
+
message: "Agent execution started",
|
|
8030
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8031
|
+
}
|
|
8032
|
+
});
|
|
8033
|
+
for await (const part of streamResult.fullStream) {
|
|
8034
|
+
switch (part.type) {
|
|
8035
|
+
case "text-delta":
|
|
8036
|
+
if (part.text) {
|
|
8037
|
+
finalText += part.text;
|
|
8038
|
+
pendingDelta += part.text;
|
|
8039
|
+
flushProgress(false);
|
|
8040
|
+
}
|
|
8041
|
+
break;
|
|
8042
|
+
case "tool-call":
|
|
8043
|
+
this.send({
|
|
8044
|
+
type: "task:progress",
|
|
8045
|
+
taskId,
|
|
8046
|
+
event: {
|
|
8047
|
+
kind: "tool-call",
|
|
8048
|
+
toolName: part.toolName,
|
|
8049
|
+
toolCallId: part.toolCallId,
|
|
8050
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8051
|
+
}
|
|
8052
|
+
});
|
|
8053
|
+
break;
|
|
8054
|
+
case "tool-result":
|
|
8055
|
+
this.send({
|
|
8056
|
+
type: "task:progress",
|
|
8057
|
+
taskId,
|
|
8058
|
+
event: {
|
|
8059
|
+
kind: "tool-result",
|
|
8060
|
+
toolCallId: part.toolCallId,
|
|
8061
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8062
|
+
}
|
|
8063
|
+
});
|
|
8064
|
+
break;
|
|
8065
|
+
case "error":
|
|
8066
|
+
throw new Error(part.error?.message || "Task stream error");
|
|
8067
|
+
case "finish":
|
|
8068
|
+
flushProgress(true);
|
|
8069
|
+
this.send({
|
|
8070
|
+
type: "task:progress",
|
|
8071
|
+
taskId,
|
|
8072
|
+
event: {
|
|
8073
|
+
kind: "status",
|
|
8074
|
+
phase: "verifying",
|
|
8075
|
+
message: "Agent execution finished, preparing final output",
|
|
8076
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8077
|
+
}
|
|
8078
|
+
});
|
|
8079
|
+
break;
|
|
8080
|
+
default:
|
|
8081
|
+
break;
|
|
8082
|
+
}
|
|
8083
|
+
}
|
|
7814
8084
|
this.send({
|
|
7815
8085
|
type: "task:completed",
|
|
7816
8086
|
taskId,
|
|
@@ -7847,33 +8117,34 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7847
8117
|
}
|
|
7848
8118
|
// ==================== Terminal Streaming ====================
|
|
7849
8119
|
handleTerminalList() {
|
|
7850
|
-
const { sessions, panes } = this.terminalManager.list();
|
|
7851
|
-
this.send({ type: "terminal:list", sessions, panes });
|
|
8120
|
+
const { apps, sessions, panes } = this.terminalManager.list();
|
|
8121
|
+
this.send({ type: "terminal:list", apps, sessions, panes });
|
|
7852
8122
|
}
|
|
7853
|
-
async handleTerminalAttach(target) {
|
|
8123
|
+
async handleTerminalAttach(target, appId) {
|
|
7854
8124
|
console.log(`[Viber] Attaching to terminal: ${target}`);
|
|
7855
8125
|
const ok = await this.terminalManager.attach(
|
|
7856
8126
|
target,
|
|
7857
8127
|
(data) => {
|
|
7858
|
-
this.send({ type: "terminal:output", target, data });
|
|
8128
|
+
this.send({ type: "terminal:output", target, appId, data });
|
|
7859
8129
|
},
|
|
7860
8130
|
() => {
|
|
7861
|
-
this.send({ type: "terminal:detached", target });
|
|
7862
|
-
}
|
|
8131
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
8132
|
+
},
|
|
8133
|
+
appId
|
|
7863
8134
|
);
|
|
7864
|
-
this.send({ type: "terminal:attached", target, ok });
|
|
8135
|
+
this.send({ type: "terminal:attached", target, appId, ok });
|
|
7865
8136
|
}
|
|
7866
|
-
handleTerminalDetach(target) {
|
|
8137
|
+
handleTerminalDetach(target, appId) {
|
|
7867
8138
|
console.log(`[Viber] Detaching from terminal: ${target}`);
|
|
7868
|
-
this.terminalManager.detach(target);
|
|
7869
|
-
this.send({ type: "terminal:detached", target });
|
|
8139
|
+
this.terminalManager.detach(target, appId);
|
|
8140
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
7870
8141
|
}
|
|
7871
|
-
handleTerminalInput(target, keys) {
|
|
7872
|
-
this.terminalManager.sendInput(target, keys);
|
|
8142
|
+
handleTerminalInput(target, keys, appId) {
|
|
8143
|
+
this.terminalManager.sendInput(target, keys, appId);
|
|
7873
8144
|
}
|
|
7874
|
-
handleTerminalResize(target, cols, rows) {
|
|
7875
|
-
const ok = this.terminalManager.resize(target, cols, rows);
|
|
7876
|
-
this.send({ type: "terminal:resized", target, ok });
|
|
8145
|
+
handleTerminalResize(target, cols, rows, appId) {
|
|
8146
|
+
const ok = this.terminalManager.resize(target, cols, rows, appId);
|
|
8147
|
+
this.send({ type: "terminal:resized", target, appId, ok });
|
|
7877
8148
|
}
|
|
7878
8149
|
// ==================== Communication ====================
|
|
7879
8150
|
send(message) {
|