openviber 0.4.3 → 0.5.1
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 +2802 -171
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2815 -184
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +443 -155
- 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 +444 -156
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -4514,21 +4514,38 @@ import * as path8 from "path";
|
|
|
4514
4514
|
import * as yaml2 from "yaml";
|
|
4515
4515
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4516
4516
|
function getDefaultSkillsPath() {
|
|
4517
|
-
const
|
|
4517
|
+
const userSkillsPath = path8.join(getViberRoot(), "skills");
|
|
4518
4518
|
try {
|
|
4519
|
-
fsSync.accessSync(
|
|
4520
|
-
console.log(`[SkillRegistry] Using skills path (
|
|
4521
|
-
return
|
|
4519
|
+
fsSync.accessSync(userSkillsPath);
|
|
4520
|
+
console.log(`[SkillRegistry] Using skills path (user): ${userSkillsPath}`);
|
|
4521
|
+
return userSkillsPath;
|
|
4522
4522
|
} catch {
|
|
4523
|
-
const
|
|
4523
|
+
const bundledPath = path8.resolve(__dirname2, ".");
|
|
4524
4524
|
try {
|
|
4525
|
-
fsSync.accessSync(
|
|
4526
|
-
|
|
4527
|
-
|
|
4525
|
+
fsSync.accessSync(bundledPath);
|
|
4526
|
+
const hasSkillDirs = fsSync.readdirSync(bundledPath).some((f) => {
|
|
4527
|
+
const skillMd = path8.join(bundledPath, f, "SKILL.md");
|
|
4528
|
+
try {
|
|
4529
|
+
fsSync.accessSync(skillMd);
|
|
4530
|
+
return true;
|
|
4531
|
+
} catch {
|
|
4532
|
+
return false;
|
|
4533
|
+
}
|
|
4534
|
+
});
|
|
4535
|
+
if (hasSkillDirs) {
|
|
4536
|
+
console.log(`[SkillRegistry] Using skills path (bundled): ${bundledPath}`);
|
|
4537
|
+
return bundledPath;
|
|
4538
|
+
}
|
|
4528
4539
|
} catch {
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4540
|
+
}
|
|
4541
|
+
const devPath = path8.resolve(process.cwd(), "src/skills");
|
|
4542
|
+
try {
|
|
4543
|
+
fsSync.accessSync(devPath);
|
|
4544
|
+
console.log(`[SkillRegistry] Using skills path (dev): ${devPath}`);
|
|
4545
|
+
return devPath;
|
|
4546
|
+
} catch {
|
|
4547
|
+
console.log(`[SkillRegistry] Using skills path (default): ${userSkillsPath}`);
|
|
4548
|
+
return userSkillsPath;
|
|
4532
4549
|
}
|
|
4533
4550
|
}
|
|
4534
4551
|
}
|
|
@@ -7347,103 +7364,33 @@ async function runTask(goal, options, messages) {
|
|
|
7347
7364
|
}
|
|
7348
7365
|
|
|
7349
7366
|
// src/daemon/terminal.ts
|
|
7350
|
-
import { spawn, execSync } from "child_process";
|
|
7367
|
+
import { spawn, spawnSync, execSync } from "child_process";
|
|
7351
7368
|
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
|
-
}
|
|
7369
|
+
import { randomUUID } from "crypto";
|
|
7370
|
+
var SAFE_NAME_RE = /[^a-zA-Z0-9_.:-]/g;
|
|
7371
|
+
function sanitizeName(input) {
|
|
7372
|
+
return input.replace(SAFE_NAME_RE, "-");
|
|
7392
7373
|
}
|
|
7393
|
-
function
|
|
7394
|
-
|
|
7395
|
-
const
|
|
7396
|
-
|
|
7397
|
-
execSync(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7398
|
-
encoding: "utf8",
|
|
7399
|
-
stdio: "pipe"
|
|
7400
|
-
});
|
|
7401
|
-
return true;
|
|
7402
|
-
} catch {
|
|
7403
|
-
return false;
|
|
7404
|
-
}
|
|
7405
|
-
}
|
|
7406
|
-
function capturePane(target, lines = 500) {
|
|
7407
|
-
const cmds = [
|
|
7408
|
-
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7409
|
-
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
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;
|
|
7374
|
+
function resolveAppTarget(target, appHint) {
|
|
7375
|
+
if (target.includes("::")) {
|
|
7376
|
+
const [appId, ...rest] = target.split("::");
|
|
7377
|
+
return { appId, rawTarget: rest.join("::") };
|
|
7428
7378
|
}
|
|
7379
|
+
return { appId: appHint || "tmux", rawTarget: target };
|
|
7429
7380
|
}
|
|
7430
|
-
var
|
|
7431
|
-
target;
|
|
7432
|
-
catProcess = null;
|
|
7433
|
-
pipePath;
|
|
7434
|
-
isAttached = false;
|
|
7381
|
+
var TmuxTerminalStream = class extends EventEmitter {
|
|
7435
7382
|
constructor(target) {
|
|
7436
7383
|
super();
|
|
7437
7384
|
this.target = target;
|
|
7438
7385
|
this.pipePath = `/tmp/viber-term-${target.replace(/[^a-zA-Z0-9]/g, "-")}-${Date.now()}`;
|
|
7439
7386
|
}
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7387
|
+
catProcess = null;
|
|
7388
|
+
pipePath;
|
|
7389
|
+
isAttached = false;
|
|
7443
7390
|
async attach() {
|
|
7444
7391
|
if (this.isAttached) return true;
|
|
7445
7392
|
try {
|
|
7446
|
-
const history =
|
|
7393
|
+
const history = captureTmuxPane(this.target, 200);
|
|
7447
7394
|
if (history) {
|
|
7448
7395
|
this.emit("data", history);
|
|
7449
7396
|
}
|
|
@@ -7473,9 +7420,6 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7473
7420
|
return false;
|
|
7474
7421
|
}
|
|
7475
7422
|
}
|
|
7476
|
-
/**
|
|
7477
|
-
* Stop streaming
|
|
7478
|
-
*/
|
|
7479
7423
|
detach() {
|
|
7480
7424
|
if (!this.isAttached) return;
|
|
7481
7425
|
try {
|
|
@@ -7484,12 +7428,6 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7484
7428
|
}
|
|
7485
7429
|
this.cleanup();
|
|
7486
7430
|
}
|
|
7487
|
-
/**
|
|
7488
|
-
* Send input to the pane
|
|
7489
|
-
*/
|
|
7490
|
-
sendInput(keys) {
|
|
7491
|
-
return sendKeys(this.target, keys, false);
|
|
7492
|
-
}
|
|
7493
7431
|
cleanup() {
|
|
7494
7432
|
this.isAttached = false;
|
|
7495
7433
|
if (this.catProcess) {
|
|
@@ -7506,20 +7444,61 @@ var TerminalStream = class extends EventEmitter {
|
|
|
7506
7444
|
return this.isAttached;
|
|
7507
7445
|
}
|
|
7508
7446
|
};
|
|
7509
|
-
var
|
|
7447
|
+
var TmuxTerminalApp = class {
|
|
7448
|
+
id = "tmux";
|
|
7449
|
+
label = "tmux";
|
|
7510
7450
|
streams = /* @__PURE__ */ new Map();
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7451
|
+
isAvailable() {
|
|
7452
|
+
try {
|
|
7453
|
+
execSync("tmux -V", { stdio: "pipe" });
|
|
7454
|
+
return true;
|
|
7455
|
+
} catch {
|
|
7456
|
+
return false;
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7459
|
+
listSessions() {
|
|
7460
|
+
try {
|
|
7461
|
+
const out = execSync(
|
|
7462
|
+
"tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_attached}' 2>/dev/null",
|
|
7463
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7464
|
+
).trim();
|
|
7465
|
+
if (!out) return [];
|
|
7466
|
+
return out.split("\n").map((line) => {
|
|
7467
|
+
const [name, windows, attached] = line.split("|");
|
|
7468
|
+
return {
|
|
7469
|
+
appId: this.id,
|
|
7470
|
+
name,
|
|
7471
|
+
windows: parseInt(windows, 10) || 0,
|
|
7472
|
+
attached: attached === "1"
|
|
7473
|
+
};
|
|
7474
|
+
});
|
|
7475
|
+
} catch {
|
|
7476
|
+
return [];
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
listPanes() {
|
|
7480
|
+
try {
|
|
7481
|
+
const out = execSync(
|
|
7482
|
+
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7483
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7484
|
+
).trim();
|
|
7485
|
+
if (!out) return [];
|
|
7486
|
+
return out.split("\n").map((line) => {
|
|
7487
|
+
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7488
|
+
return {
|
|
7489
|
+
appId: this.id,
|
|
7490
|
+
session,
|
|
7491
|
+
window: window2,
|
|
7492
|
+
windowName,
|
|
7493
|
+
pane,
|
|
7494
|
+
command,
|
|
7495
|
+
target: `${session}:${window2}.${pane}`
|
|
7496
|
+
};
|
|
7497
|
+
});
|
|
7498
|
+
} catch {
|
|
7499
|
+
return [];
|
|
7500
|
+
}
|
|
7519
7501
|
}
|
|
7520
|
-
/**
|
|
7521
|
-
* Attach to a pane and return the stream
|
|
7522
|
-
*/
|
|
7523
7502
|
async attach(target, onData, onClose) {
|
|
7524
7503
|
let stream = this.streams.get(target);
|
|
7525
7504
|
if (stream && stream.attached) {
|
|
@@ -7527,7 +7506,7 @@ var TerminalManager = class {
|
|
|
7527
7506
|
stream.on("close", onClose);
|
|
7528
7507
|
return true;
|
|
7529
7508
|
}
|
|
7530
|
-
stream = new
|
|
7509
|
+
stream = new TmuxTerminalStream(target);
|
|
7531
7510
|
stream.on("data", onData);
|
|
7532
7511
|
stream.on("close", () => {
|
|
7533
7512
|
this.streams.delete(target);
|
|
@@ -7539,31 +7518,62 @@ var TerminalManager = class {
|
|
|
7539
7518
|
}
|
|
7540
7519
|
return ok;
|
|
7541
7520
|
}
|
|
7542
|
-
/**
|
|
7543
|
-
* Detach from a pane
|
|
7544
|
-
*/
|
|
7545
7521
|
detach(target) {
|
|
7546
7522
|
const stream = this.streams.get(target);
|
|
7547
|
-
if (stream)
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
}
|
|
7523
|
+
if (!stream) return;
|
|
7524
|
+
stream.detach();
|
|
7525
|
+
this.streams.delete(target);
|
|
7551
7526
|
}
|
|
7552
|
-
/**
|
|
7553
|
-
* Send input to a pane
|
|
7554
|
-
*/
|
|
7555
7527
|
sendInput(target, keys) {
|
|
7556
|
-
return
|
|
7528
|
+
return sendTmuxKeys(target, keys);
|
|
7557
7529
|
}
|
|
7558
|
-
/**
|
|
7559
|
-
* Resize pane to match web terminal
|
|
7560
|
-
*/
|
|
7561
7530
|
resize(target, cols, rows) {
|
|
7562
|
-
|
|
7531
|
+
try {
|
|
7532
|
+
execSync(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7533
|
+
encoding: "utf8",
|
|
7534
|
+
stdio: "pipe"
|
|
7535
|
+
});
|
|
7536
|
+
return true;
|
|
7537
|
+
} catch {
|
|
7538
|
+
return false;
|
|
7539
|
+
}
|
|
7540
|
+
}
|
|
7541
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7542
|
+
const safeSession = sanitizeName(sessionName || "coding");
|
|
7543
|
+
const safeWindow = sanitizeName(windowName || "main");
|
|
7544
|
+
try {
|
|
7545
|
+
execSync(`tmux has-session -t '${safeSession}' 2>/dev/null`, { stdio: "pipe" });
|
|
7546
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7547
|
+
} catch {
|
|
7548
|
+
}
|
|
7549
|
+
const args = ["new-session", "-d", "-s", safeSession, "-n", safeWindow];
|
|
7550
|
+
if (cwd) {
|
|
7551
|
+
args.push("-c", cwd);
|
|
7552
|
+
}
|
|
7553
|
+
const result = spawnSync("tmux", args, {
|
|
7554
|
+
encoding: "utf8",
|
|
7555
|
+
stdio: "pipe"
|
|
7556
|
+
});
|
|
7557
|
+
if (result.error) {
|
|
7558
|
+
return {
|
|
7559
|
+
ok: false,
|
|
7560
|
+
appId: this.id,
|
|
7561
|
+
sessionName: safeSession,
|
|
7562
|
+
created: false,
|
|
7563
|
+
error: `Failed to start tmux: ${result.error.message}`
|
|
7564
|
+
};
|
|
7565
|
+
}
|
|
7566
|
+
if (result.status !== 0) {
|
|
7567
|
+
return {
|
|
7568
|
+
ok: false,
|
|
7569
|
+
appId: this.id,
|
|
7570
|
+
sessionName: safeSession,
|
|
7571
|
+
created: false,
|
|
7572
|
+
error: (result.stderr || result.stdout || "Failed to create tmux session").trim()
|
|
7573
|
+
};
|
|
7574
|
+
}
|
|
7575
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7563
7576
|
}
|
|
7564
|
-
/**
|
|
7565
|
-
* Detach all streams
|
|
7566
|
-
*/
|
|
7567
7577
|
detachAll() {
|
|
7568
7578
|
for (const stream of this.streams.values()) {
|
|
7569
7579
|
stream.detach();
|
|
@@ -7571,6 +7581,203 @@ var TerminalManager = class {
|
|
|
7571
7581
|
this.streams.clear();
|
|
7572
7582
|
}
|
|
7573
7583
|
};
|
|
7584
|
+
var ShellTerminalApp = class {
|
|
7585
|
+
id = "shell";
|
|
7586
|
+
label = "shell";
|
|
7587
|
+
sessions = /* @__PURE__ */ new Map();
|
|
7588
|
+
isAvailable() {
|
|
7589
|
+
return true;
|
|
7590
|
+
}
|
|
7591
|
+
listSessions() {
|
|
7592
|
+
return Array.from(this.sessions.values()).map((state) => ({
|
|
7593
|
+
appId: this.id,
|
|
7594
|
+
name: state.sessionName,
|
|
7595
|
+
windows: 1,
|
|
7596
|
+
attached: state.listeners.size > 0
|
|
7597
|
+
}));
|
|
7598
|
+
}
|
|
7599
|
+
listPanes() {
|
|
7600
|
+
return Array.from(this.sessions.entries()).map(([id, state]) => ({
|
|
7601
|
+
appId: this.id,
|
|
7602
|
+
session: state.sessionName,
|
|
7603
|
+
window: "0",
|
|
7604
|
+
windowName: state.windowName,
|
|
7605
|
+
pane: state.pane,
|
|
7606
|
+
command: process.env.SHELL || "sh",
|
|
7607
|
+
target: id
|
|
7608
|
+
}));
|
|
7609
|
+
}
|
|
7610
|
+
async attach(target, onData, onClose) {
|
|
7611
|
+
const state = this.sessions.get(target);
|
|
7612
|
+
if (!state) return false;
|
|
7613
|
+
state.listeners.add(onData);
|
|
7614
|
+
state.closeListeners.add(onClose);
|
|
7615
|
+
if (state.history.length > 0) {
|
|
7616
|
+
onData(state.history.join(""));
|
|
7617
|
+
}
|
|
7618
|
+
return true;
|
|
7619
|
+
}
|
|
7620
|
+
detach(target) {
|
|
7621
|
+
const state = this.sessions.get(target);
|
|
7622
|
+
if (!state) return;
|
|
7623
|
+
state.listeners.clear();
|
|
7624
|
+
state.closeListeners.clear();
|
|
7625
|
+
}
|
|
7626
|
+
sendInput(target, keys) {
|
|
7627
|
+
const state = this.sessions.get(target);
|
|
7628
|
+
if (!state || !state.proc.stdin?.writable) return false;
|
|
7629
|
+
state.proc.stdin.write(keys);
|
|
7630
|
+
return true;
|
|
7631
|
+
}
|
|
7632
|
+
resize(_target, _cols, _rows) {
|
|
7633
|
+
return true;
|
|
7634
|
+
}
|
|
7635
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7636
|
+
const safeSession = sanitizeName(sessionName || `shell-${Date.now()}`);
|
|
7637
|
+
const shell = process.env.SHELL || "sh";
|
|
7638
|
+
const target = `${safeSession}:${randomUUID().slice(0, 8)}`;
|
|
7639
|
+
if (this.sessions.has(target)) {
|
|
7640
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7641
|
+
}
|
|
7642
|
+
const proc = spawn(shell, [], {
|
|
7643
|
+
cwd,
|
|
7644
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
7645
|
+
env: process.env
|
|
7646
|
+
});
|
|
7647
|
+
if (!proc.pid) {
|
|
7648
|
+
return {
|
|
7649
|
+
ok: false,
|
|
7650
|
+
appId: this.id,
|
|
7651
|
+
sessionName: safeSession,
|
|
7652
|
+
created: false,
|
|
7653
|
+
error: "Failed to start shell process"
|
|
7654
|
+
};
|
|
7655
|
+
}
|
|
7656
|
+
const state = {
|
|
7657
|
+
proc,
|
|
7658
|
+
sessionName: safeSession,
|
|
7659
|
+
windowName,
|
|
7660
|
+
pane: "0",
|
|
7661
|
+
history: [],
|
|
7662
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
7663
|
+
closeListeners: /* @__PURE__ */ new Set()
|
|
7664
|
+
};
|
|
7665
|
+
const pushChunk = (chunk) => {
|
|
7666
|
+
const text = chunk.toString();
|
|
7667
|
+
state.history.push(text);
|
|
7668
|
+
if (state.history.length > 200) {
|
|
7669
|
+
state.history.shift();
|
|
7670
|
+
}
|
|
7671
|
+
for (const listener of state.listeners) {
|
|
7672
|
+
listener(text);
|
|
7673
|
+
}
|
|
7674
|
+
};
|
|
7675
|
+
proc.stdout?.on("data", pushChunk);
|
|
7676
|
+
proc.stderr?.on("data", pushChunk);
|
|
7677
|
+
proc.on("close", () => {
|
|
7678
|
+
for (const onClose of state.closeListeners) {
|
|
7679
|
+
onClose();
|
|
7680
|
+
}
|
|
7681
|
+
this.sessions.delete(target);
|
|
7682
|
+
});
|
|
7683
|
+
this.sessions.set(target, state);
|
|
7684
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7685
|
+
}
|
|
7686
|
+
detachAll() {
|
|
7687
|
+
for (const [id, state] of this.sessions.entries()) {
|
|
7688
|
+
state.proc.kill();
|
|
7689
|
+
this.sessions.delete(id);
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7692
|
+
};
|
|
7693
|
+
function sendTmuxKeys(target, keys, pressEnter = false) {
|
|
7694
|
+
try {
|
|
7695
|
+
const args = ["send-keys", "-t", target, keys];
|
|
7696
|
+
if (pressEnter) args.push("Enter");
|
|
7697
|
+
execSync(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7698
|
+
encoding: "utf8",
|
|
7699
|
+
stdio: "pipe"
|
|
7700
|
+
});
|
|
7701
|
+
return true;
|
|
7702
|
+
} catch {
|
|
7703
|
+
return false;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
function captureTmuxPane(target, lines = 500) {
|
|
7707
|
+
const cmds = [
|
|
7708
|
+
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7709
|
+
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
7710
|
+
];
|
|
7711
|
+
for (const cmd of cmds) {
|
|
7712
|
+
try {
|
|
7713
|
+
return execSync(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7714
|
+
} catch {
|
|
7715
|
+
}
|
|
7716
|
+
}
|
|
7717
|
+
return "";
|
|
7718
|
+
}
|
|
7719
|
+
var TerminalManager = class {
|
|
7720
|
+
apps = /* @__PURE__ */ new Map();
|
|
7721
|
+
constructor(adapters) {
|
|
7722
|
+
const defaultAdapters = adapters ?? [new TmuxTerminalApp(), new ShellTerminalApp()];
|
|
7723
|
+
for (const adapter of defaultAdapters) {
|
|
7724
|
+
this.apps.set(adapter.id, adapter);
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
list() {
|
|
7728
|
+
const metadata = Array.from(this.apps.values()).map((app) => ({
|
|
7729
|
+
id: app.id,
|
|
7730
|
+
label: app.label,
|
|
7731
|
+
available: app.isAvailable()
|
|
7732
|
+
}));
|
|
7733
|
+
const sessions = [];
|
|
7734
|
+
const panes = [];
|
|
7735
|
+
for (const app of this.apps.values()) {
|
|
7736
|
+
if (!app.isAvailable()) continue;
|
|
7737
|
+
sessions.push(...app.listSessions());
|
|
7738
|
+
panes.push(...app.listPanes());
|
|
7739
|
+
}
|
|
7740
|
+
return { apps: metadata, sessions, panes };
|
|
7741
|
+
}
|
|
7742
|
+
async attach(target, onData, onClose, appHint) {
|
|
7743
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7744
|
+
const app = this.apps.get(appId);
|
|
7745
|
+
if (!app || !app.isAvailable()) return false;
|
|
7746
|
+
return app.attach(rawTarget, onData, onClose);
|
|
7747
|
+
}
|
|
7748
|
+
detach(target, appHint) {
|
|
7749
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7750
|
+
this.apps.get(appId)?.detach(rawTarget);
|
|
7751
|
+
}
|
|
7752
|
+
sendInput(target, keys, appHint) {
|
|
7753
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7754
|
+
const app = this.apps.get(appId);
|
|
7755
|
+
return !!app && app.isAvailable() ? app.sendInput(rawTarget, keys) : false;
|
|
7756
|
+
}
|
|
7757
|
+
resize(target, cols, rows, appHint) {
|
|
7758
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7759
|
+
const app = this.apps.get(appId);
|
|
7760
|
+
return !!app && app.isAvailable() ? app.resize(rawTarget, cols, rows) : false;
|
|
7761
|
+
}
|
|
7762
|
+
createSession(sessionName, windowName = "main", cwd, appId = "tmux") {
|
|
7763
|
+
const app = this.apps.get(appId);
|
|
7764
|
+
if (!app || !app.isAvailable()) {
|
|
7765
|
+
return {
|
|
7766
|
+
ok: false,
|
|
7767
|
+
appId,
|
|
7768
|
+
sessionName,
|
|
7769
|
+
created: false,
|
|
7770
|
+
error: `Terminal app '${appId}' is not available`
|
|
7771
|
+
};
|
|
7772
|
+
}
|
|
7773
|
+
return app.createSession(sessionName, windowName, cwd);
|
|
7774
|
+
}
|
|
7775
|
+
detachAll() {
|
|
7776
|
+
for (const app of this.apps.values()) {
|
|
7777
|
+
app.detachAll();
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7780
|
+
};
|
|
7574
7781
|
|
|
7575
7782
|
// src/daemon/controller.ts
|
|
7576
7783
|
var ViberController = class extends EventEmitter2 {
|
|
@@ -7721,16 +7928,16 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7721
7928
|
this.handleTerminalList();
|
|
7722
7929
|
break;
|
|
7723
7930
|
case "terminal:attach":
|
|
7724
|
-
await this.handleTerminalAttach(message.target);
|
|
7931
|
+
await this.handleTerminalAttach(message.target, message.appId);
|
|
7725
7932
|
break;
|
|
7726
7933
|
case "terminal:detach":
|
|
7727
|
-
this.handleTerminalDetach(message.target);
|
|
7934
|
+
this.handleTerminalDetach(message.target, message.appId);
|
|
7728
7935
|
break;
|
|
7729
7936
|
case "terminal:input":
|
|
7730
|
-
this.handleTerminalInput(message.target, message.keys);
|
|
7937
|
+
this.handleTerminalInput(message.target, message.keys, message.appId);
|
|
7731
7938
|
break;
|
|
7732
7939
|
case "terminal:resize":
|
|
7733
|
-
this.handleTerminalResize(message.target, message.cols, message.rows);
|
|
7940
|
+
this.handleTerminalResize(message.target, message.cols, message.rows, message.appId);
|
|
7734
7941
|
break;
|
|
7735
7942
|
}
|
|
7736
7943
|
} catch (error) {
|
|
@@ -7760,7 +7967,87 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7760
7967
|
},
|
|
7761
7968
|
messages
|
|
7762
7969
|
);
|
|
7763
|
-
|
|
7970
|
+
let finalText = "";
|
|
7971
|
+
let pendingDelta = "";
|
|
7972
|
+
let lastProgressAt = 0;
|
|
7973
|
+
const flushProgress = (force = false) => {
|
|
7974
|
+
if (!pendingDelta) return;
|
|
7975
|
+
const now = Date.now();
|
|
7976
|
+
if (!force && now - lastProgressAt < 250) return;
|
|
7977
|
+
this.send({
|
|
7978
|
+
type: "task:progress",
|
|
7979
|
+
taskId,
|
|
7980
|
+
event: {
|
|
7981
|
+
kind: "text-delta",
|
|
7982
|
+
delta: pendingDelta,
|
|
7983
|
+
totalLength: finalText.length,
|
|
7984
|
+
at: new Date(now).toISOString()
|
|
7985
|
+
}
|
|
7986
|
+
});
|
|
7987
|
+
pendingDelta = "";
|
|
7988
|
+
lastProgressAt = now;
|
|
7989
|
+
};
|
|
7990
|
+
this.send({
|
|
7991
|
+
type: "task:progress",
|
|
7992
|
+
taskId,
|
|
7993
|
+
event: {
|
|
7994
|
+
kind: "status",
|
|
7995
|
+
phase: "executing",
|
|
7996
|
+
message: "Agent execution started",
|
|
7997
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7998
|
+
}
|
|
7999
|
+
});
|
|
8000
|
+
for await (const part of streamResult.fullStream) {
|
|
8001
|
+
switch (part.type) {
|
|
8002
|
+
case "text-delta":
|
|
8003
|
+
if (part.text) {
|
|
8004
|
+
finalText += part.text;
|
|
8005
|
+
pendingDelta += part.text;
|
|
8006
|
+
flushProgress(false);
|
|
8007
|
+
}
|
|
8008
|
+
break;
|
|
8009
|
+
case "tool-call":
|
|
8010
|
+
this.send({
|
|
8011
|
+
type: "task:progress",
|
|
8012
|
+
taskId,
|
|
8013
|
+
event: {
|
|
8014
|
+
kind: "tool-call",
|
|
8015
|
+
toolName: part.toolName,
|
|
8016
|
+
toolCallId: part.toolCallId,
|
|
8017
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8018
|
+
}
|
|
8019
|
+
});
|
|
8020
|
+
break;
|
|
8021
|
+
case "tool-result":
|
|
8022
|
+
this.send({
|
|
8023
|
+
type: "task:progress",
|
|
8024
|
+
taskId,
|
|
8025
|
+
event: {
|
|
8026
|
+
kind: "tool-result",
|
|
8027
|
+
toolCallId: part.toolCallId,
|
|
8028
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8029
|
+
}
|
|
8030
|
+
});
|
|
8031
|
+
break;
|
|
8032
|
+
case "error":
|
|
8033
|
+
throw new Error(part.error?.message || "Task stream error");
|
|
8034
|
+
case "finish":
|
|
8035
|
+
flushProgress(true);
|
|
8036
|
+
this.send({
|
|
8037
|
+
type: "task:progress",
|
|
8038
|
+
taskId,
|
|
8039
|
+
event: {
|
|
8040
|
+
kind: "status",
|
|
8041
|
+
phase: "verifying",
|
|
8042
|
+
message: "Agent execution finished, preparing final output",
|
|
8043
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8044
|
+
}
|
|
8045
|
+
});
|
|
8046
|
+
break;
|
|
8047
|
+
default:
|
|
8048
|
+
break;
|
|
8049
|
+
}
|
|
8050
|
+
}
|
|
7764
8051
|
this.send({
|
|
7765
8052
|
type: "task:completed",
|
|
7766
8053
|
taskId,
|
|
@@ -7797,33 +8084,34 @@ var ViberController = class extends EventEmitter2 {
|
|
|
7797
8084
|
}
|
|
7798
8085
|
// ==================== Terminal Streaming ====================
|
|
7799
8086
|
handleTerminalList() {
|
|
7800
|
-
const { sessions, panes } = this.terminalManager.list();
|
|
7801
|
-
this.send({ type: "terminal:list", sessions, panes });
|
|
8087
|
+
const { apps, sessions, panes } = this.terminalManager.list();
|
|
8088
|
+
this.send({ type: "terminal:list", apps, sessions, panes });
|
|
7802
8089
|
}
|
|
7803
|
-
async handleTerminalAttach(target) {
|
|
8090
|
+
async handleTerminalAttach(target, appId) {
|
|
7804
8091
|
console.log(`[Viber] Attaching to terminal: ${target}`);
|
|
7805
8092
|
const ok = await this.terminalManager.attach(
|
|
7806
8093
|
target,
|
|
7807
8094
|
(data) => {
|
|
7808
|
-
this.send({ type: "terminal:output", target, data });
|
|
8095
|
+
this.send({ type: "terminal:output", target, appId, data });
|
|
7809
8096
|
},
|
|
7810
8097
|
() => {
|
|
7811
|
-
this.send({ type: "terminal:detached", target });
|
|
7812
|
-
}
|
|
8098
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
8099
|
+
},
|
|
8100
|
+
appId
|
|
7813
8101
|
);
|
|
7814
|
-
this.send({ type: "terminal:attached", target, ok });
|
|
8102
|
+
this.send({ type: "terminal:attached", target, appId, ok });
|
|
7815
8103
|
}
|
|
7816
|
-
handleTerminalDetach(target) {
|
|
8104
|
+
handleTerminalDetach(target, appId) {
|
|
7817
8105
|
console.log(`[Viber] Detaching from terminal: ${target}`);
|
|
7818
|
-
this.terminalManager.detach(target);
|
|
7819
|
-
this.send({ type: "terminal:detached", target });
|
|
8106
|
+
this.terminalManager.detach(target, appId);
|
|
8107
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
7820
8108
|
}
|
|
7821
|
-
handleTerminalInput(target, keys) {
|
|
7822
|
-
this.terminalManager.sendInput(target, keys);
|
|
8109
|
+
handleTerminalInput(target, keys, appId) {
|
|
8110
|
+
this.terminalManager.sendInput(target, keys, appId);
|
|
7823
8111
|
}
|
|
7824
|
-
handleTerminalResize(target, cols, rows) {
|
|
7825
|
-
const ok = this.terminalManager.resize(target, cols, rows);
|
|
7826
|
-
this.send({ type: "terminal:resized", target, ok });
|
|
8112
|
+
handleTerminalResize(target, cols, rows, appId) {
|
|
8113
|
+
const ok = this.terminalManager.resize(target, cols, rows, appId);
|
|
8114
|
+
this.send({ type: "terminal:resized", target, appId, ok });
|
|
7827
8115
|
}
|
|
7828
8116
|
// ==================== Communication ====================
|
|
7829
8117
|
send(message) {
|