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.cjs
CHANGED
|
@@ -4516,21 +4516,38 @@ __export(registry_exports, {
|
|
|
4516
4516
|
defaultRegistry: () => defaultRegistry
|
|
4517
4517
|
});
|
|
4518
4518
|
function getDefaultSkillsPath() {
|
|
4519
|
-
const
|
|
4519
|
+
const userSkillsPath = path8.join(getViberRoot(), "skills");
|
|
4520
4520
|
try {
|
|
4521
|
-
fsSync.accessSync(
|
|
4522
|
-
console.log(`[SkillRegistry] Using skills path (
|
|
4523
|
-
return
|
|
4521
|
+
fsSync.accessSync(userSkillsPath);
|
|
4522
|
+
console.log(`[SkillRegistry] Using skills path (user): ${userSkillsPath}`);
|
|
4523
|
+
return userSkillsPath;
|
|
4524
4524
|
} catch {
|
|
4525
|
-
const
|
|
4525
|
+
const bundledPath = path8.resolve(__dirname2, ".");
|
|
4526
4526
|
try {
|
|
4527
|
-
fsSync.accessSync(
|
|
4528
|
-
|
|
4529
|
-
|
|
4527
|
+
fsSync.accessSync(bundledPath);
|
|
4528
|
+
const hasSkillDirs = fsSync.readdirSync(bundledPath).some((f) => {
|
|
4529
|
+
const skillMd = path8.join(bundledPath, f, "SKILL.md");
|
|
4530
|
+
try {
|
|
4531
|
+
fsSync.accessSync(skillMd);
|
|
4532
|
+
return true;
|
|
4533
|
+
} catch {
|
|
4534
|
+
return false;
|
|
4535
|
+
}
|
|
4536
|
+
});
|
|
4537
|
+
if (hasSkillDirs) {
|
|
4538
|
+
console.log(`[SkillRegistry] Using skills path (bundled): ${bundledPath}`);
|
|
4539
|
+
return bundledPath;
|
|
4540
|
+
}
|
|
4530
4541
|
} catch {
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4542
|
+
}
|
|
4543
|
+
const devPath = path8.resolve(process.cwd(), "src/skills");
|
|
4544
|
+
try {
|
|
4545
|
+
fsSync.accessSync(devPath);
|
|
4546
|
+
console.log(`[SkillRegistry] Using skills path (dev): ${devPath}`);
|
|
4547
|
+
return devPath;
|
|
4548
|
+
} catch {
|
|
4549
|
+
console.log(`[SkillRegistry] Using skills path (default): ${userSkillsPath}`);
|
|
4550
|
+
return userSkillsPath;
|
|
4534
4551
|
}
|
|
4535
4552
|
}
|
|
4536
4553
|
}
|
|
@@ -7399,101 +7416,31 @@ async function runTask(goal, options, messages) {
|
|
|
7399
7416
|
// src/daemon/terminal.ts
|
|
7400
7417
|
var import_child_process2 = require("child_process");
|
|
7401
7418
|
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
|
-
}
|
|
7419
|
+
var import_crypto = require("crypto");
|
|
7420
|
+
var SAFE_NAME_RE = /[^a-zA-Z0-9_.:-]/g;
|
|
7421
|
+
function sanitizeName(input) {
|
|
7422
|
+
return input.replace(SAFE_NAME_RE, "-");
|
|
7442
7423
|
}
|
|
7443
|
-
function
|
|
7444
|
-
|
|
7445
|
-
const
|
|
7446
|
-
|
|
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
|
-
}
|
|
7455
|
-
}
|
|
7456
|
-
function capturePane(target, lines = 500) {
|
|
7457
|
-
const cmds = [
|
|
7458
|
-
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7459
|
-
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
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;
|
|
7424
|
+
function resolveAppTarget(target, appHint) {
|
|
7425
|
+
if (target.includes("::")) {
|
|
7426
|
+
const [appId, ...rest] = target.split("::");
|
|
7427
|
+
return { appId, rawTarget: rest.join("::") };
|
|
7478
7428
|
}
|
|
7429
|
+
return { appId: appHint || "tmux", rawTarget: target };
|
|
7479
7430
|
}
|
|
7480
|
-
var
|
|
7481
|
-
target;
|
|
7482
|
-
catProcess = null;
|
|
7483
|
-
pipePath;
|
|
7484
|
-
isAttached = false;
|
|
7431
|
+
var TmuxTerminalStream = class extends import_events.EventEmitter {
|
|
7485
7432
|
constructor(target) {
|
|
7486
7433
|
super();
|
|
7487
7434
|
this.target = target;
|
|
7488
7435
|
this.pipePath = `/tmp/viber-term-${target.replace(/[^a-zA-Z0-9]/g, "-")}-${Date.now()}`;
|
|
7489
7436
|
}
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7437
|
+
catProcess = null;
|
|
7438
|
+
pipePath;
|
|
7439
|
+
isAttached = false;
|
|
7493
7440
|
async attach() {
|
|
7494
7441
|
if (this.isAttached) return true;
|
|
7495
7442
|
try {
|
|
7496
|
-
const history =
|
|
7443
|
+
const history = captureTmuxPane(this.target, 200);
|
|
7497
7444
|
if (history) {
|
|
7498
7445
|
this.emit("data", history);
|
|
7499
7446
|
}
|
|
@@ -7523,9 +7470,6 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7523
7470
|
return false;
|
|
7524
7471
|
}
|
|
7525
7472
|
}
|
|
7526
|
-
/**
|
|
7527
|
-
* Stop streaming
|
|
7528
|
-
*/
|
|
7529
7473
|
detach() {
|
|
7530
7474
|
if (!this.isAttached) return;
|
|
7531
7475
|
try {
|
|
@@ -7534,12 +7478,6 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7534
7478
|
}
|
|
7535
7479
|
this.cleanup();
|
|
7536
7480
|
}
|
|
7537
|
-
/**
|
|
7538
|
-
* Send input to the pane
|
|
7539
|
-
*/
|
|
7540
|
-
sendInput(keys) {
|
|
7541
|
-
return sendKeys(this.target, keys, false);
|
|
7542
|
-
}
|
|
7543
7481
|
cleanup() {
|
|
7544
7482
|
this.isAttached = false;
|
|
7545
7483
|
if (this.catProcess) {
|
|
@@ -7556,20 +7494,61 @@ var TerminalStream = class extends import_events.EventEmitter {
|
|
|
7556
7494
|
return this.isAttached;
|
|
7557
7495
|
}
|
|
7558
7496
|
};
|
|
7559
|
-
var
|
|
7497
|
+
var TmuxTerminalApp = class {
|
|
7498
|
+
id = "tmux";
|
|
7499
|
+
label = "tmux";
|
|
7560
7500
|
streams = /* @__PURE__ */ new Map();
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7501
|
+
isAvailable() {
|
|
7502
|
+
try {
|
|
7503
|
+
(0, import_child_process2.execSync)("tmux -V", { stdio: "pipe" });
|
|
7504
|
+
return true;
|
|
7505
|
+
} catch {
|
|
7506
|
+
return false;
|
|
7507
|
+
}
|
|
7508
|
+
}
|
|
7509
|
+
listSessions() {
|
|
7510
|
+
try {
|
|
7511
|
+
const out = (0, import_child_process2.execSync)(
|
|
7512
|
+
"tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_attached}' 2>/dev/null",
|
|
7513
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7514
|
+
).trim();
|
|
7515
|
+
if (!out) return [];
|
|
7516
|
+
return out.split("\n").map((line) => {
|
|
7517
|
+
const [name, windows, attached] = line.split("|");
|
|
7518
|
+
return {
|
|
7519
|
+
appId: this.id,
|
|
7520
|
+
name,
|
|
7521
|
+
windows: parseInt(windows, 10) || 0,
|
|
7522
|
+
attached: attached === "1"
|
|
7523
|
+
};
|
|
7524
|
+
});
|
|
7525
|
+
} catch {
|
|
7526
|
+
return [];
|
|
7527
|
+
}
|
|
7528
|
+
}
|
|
7529
|
+
listPanes() {
|
|
7530
|
+
try {
|
|
7531
|
+
const out = (0, import_child_process2.execSync)(
|
|
7532
|
+
"tmux list-panes -a -F '#{session_name}|#{window_index}|#{window_name}|#{pane_index}|#{pane_current_command}' 2>/dev/null",
|
|
7533
|
+
{ encoding: "utf8", stdio: "pipe" }
|
|
7534
|
+
).trim();
|
|
7535
|
+
if (!out) return [];
|
|
7536
|
+
return out.split("\n").map((line) => {
|
|
7537
|
+
const [session, window2, windowName, pane, command] = line.split("|");
|
|
7538
|
+
return {
|
|
7539
|
+
appId: this.id,
|
|
7540
|
+
session,
|
|
7541
|
+
window: window2,
|
|
7542
|
+
windowName,
|
|
7543
|
+
pane,
|
|
7544
|
+
command,
|
|
7545
|
+
target: `${session}:${window2}.${pane}`
|
|
7546
|
+
};
|
|
7547
|
+
});
|
|
7548
|
+
} catch {
|
|
7549
|
+
return [];
|
|
7550
|
+
}
|
|
7569
7551
|
}
|
|
7570
|
-
/**
|
|
7571
|
-
* Attach to a pane and return the stream
|
|
7572
|
-
*/
|
|
7573
7552
|
async attach(target, onData, onClose) {
|
|
7574
7553
|
let stream = this.streams.get(target);
|
|
7575
7554
|
if (stream && stream.attached) {
|
|
@@ -7577,7 +7556,7 @@ var TerminalManager = class {
|
|
|
7577
7556
|
stream.on("close", onClose);
|
|
7578
7557
|
return true;
|
|
7579
7558
|
}
|
|
7580
|
-
stream = new
|
|
7559
|
+
stream = new TmuxTerminalStream(target);
|
|
7581
7560
|
stream.on("data", onData);
|
|
7582
7561
|
stream.on("close", () => {
|
|
7583
7562
|
this.streams.delete(target);
|
|
@@ -7589,31 +7568,62 @@ var TerminalManager = class {
|
|
|
7589
7568
|
}
|
|
7590
7569
|
return ok;
|
|
7591
7570
|
}
|
|
7592
|
-
/**
|
|
7593
|
-
* Detach from a pane
|
|
7594
|
-
*/
|
|
7595
7571
|
detach(target) {
|
|
7596
7572
|
const stream = this.streams.get(target);
|
|
7597
|
-
if (stream)
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
}
|
|
7573
|
+
if (!stream) return;
|
|
7574
|
+
stream.detach();
|
|
7575
|
+
this.streams.delete(target);
|
|
7601
7576
|
}
|
|
7602
|
-
/**
|
|
7603
|
-
* Send input to a pane
|
|
7604
|
-
*/
|
|
7605
7577
|
sendInput(target, keys) {
|
|
7606
|
-
return
|
|
7578
|
+
return sendTmuxKeys(target, keys);
|
|
7607
7579
|
}
|
|
7608
|
-
/**
|
|
7609
|
-
* Resize pane to match web terminal
|
|
7610
|
-
*/
|
|
7611
7580
|
resize(target, cols, rows) {
|
|
7612
|
-
|
|
7581
|
+
try {
|
|
7582
|
+
(0, import_child_process2.execSync)(`tmux resize-pane -t '${target}' -x ${cols} -y ${rows}`, {
|
|
7583
|
+
encoding: "utf8",
|
|
7584
|
+
stdio: "pipe"
|
|
7585
|
+
});
|
|
7586
|
+
return true;
|
|
7587
|
+
} catch {
|
|
7588
|
+
return false;
|
|
7589
|
+
}
|
|
7590
|
+
}
|
|
7591
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7592
|
+
const safeSession = sanitizeName(sessionName || "coding");
|
|
7593
|
+
const safeWindow = sanitizeName(windowName || "main");
|
|
7594
|
+
try {
|
|
7595
|
+
(0, import_child_process2.execSync)(`tmux has-session -t '${safeSession}' 2>/dev/null`, { stdio: "pipe" });
|
|
7596
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7597
|
+
} catch {
|
|
7598
|
+
}
|
|
7599
|
+
const args = ["new-session", "-d", "-s", safeSession, "-n", safeWindow];
|
|
7600
|
+
if (cwd) {
|
|
7601
|
+
args.push("-c", cwd);
|
|
7602
|
+
}
|
|
7603
|
+
const result = (0, import_child_process2.spawnSync)("tmux", args, {
|
|
7604
|
+
encoding: "utf8",
|
|
7605
|
+
stdio: "pipe"
|
|
7606
|
+
});
|
|
7607
|
+
if (result.error) {
|
|
7608
|
+
return {
|
|
7609
|
+
ok: false,
|
|
7610
|
+
appId: this.id,
|
|
7611
|
+
sessionName: safeSession,
|
|
7612
|
+
created: false,
|
|
7613
|
+
error: `Failed to start tmux: ${result.error.message}`
|
|
7614
|
+
};
|
|
7615
|
+
}
|
|
7616
|
+
if (result.status !== 0) {
|
|
7617
|
+
return {
|
|
7618
|
+
ok: false,
|
|
7619
|
+
appId: this.id,
|
|
7620
|
+
sessionName: safeSession,
|
|
7621
|
+
created: false,
|
|
7622
|
+
error: (result.stderr || result.stdout || "Failed to create tmux session").trim()
|
|
7623
|
+
};
|
|
7624
|
+
}
|
|
7625
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7613
7626
|
}
|
|
7614
|
-
/**
|
|
7615
|
-
* Detach all streams
|
|
7616
|
-
*/
|
|
7617
7627
|
detachAll() {
|
|
7618
7628
|
for (const stream of this.streams.values()) {
|
|
7619
7629
|
stream.detach();
|
|
@@ -7621,6 +7631,203 @@ var TerminalManager = class {
|
|
|
7621
7631
|
this.streams.clear();
|
|
7622
7632
|
}
|
|
7623
7633
|
};
|
|
7634
|
+
var ShellTerminalApp = class {
|
|
7635
|
+
id = "shell";
|
|
7636
|
+
label = "shell";
|
|
7637
|
+
sessions = /* @__PURE__ */ new Map();
|
|
7638
|
+
isAvailable() {
|
|
7639
|
+
return true;
|
|
7640
|
+
}
|
|
7641
|
+
listSessions() {
|
|
7642
|
+
return Array.from(this.sessions.values()).map((state) => ({
|
|
7643
|
+
appId: this.id,
|
|
7644
|
+
name: state.sessionName,
|
|
7645
|
+
windows: 1,
|
|
7646
|
+
attached: state.listeners.size > 0
|
|
7647
|
+
}));
|
|
7648
|
+
}
|
|
7649
|
+
listPanes() {
|
|
7650
|
+
return Array.from(this.sessions.entries()).map(([id, state]) => ({
|
|
7651
|
+
appId: this.id,
|
|
7652
|
+
session: state.sessionName,
|
|
7653
|
+
window: "0",
|
|
7654
|
+
windowName: state.windowName,
|
|
7655
|
+
pane: state.pane,
|
|
7656
|
+
command: process.env.SHELL || "sh",
|
|
7657
|
+
target: id
|
|
7658
|
+
}));
|
|
7659
|
+
}
|
|
7660
|
+
async attach(target, onData, onClose) {
|
|
7661
|
+
const state = this.sessions.get(target);
|
|
7662
|
+
if (!state) return false;
|
|
7663
|
+
state.listeners.add(onData);
|
|
7664
|
+
state.closeListeners.add(onClose);
|
|
7665
|
+
if (state.history.length > 0) {
|
|
7666
|
+
onData(state.history.join(""));
|
|
7667
|
+
}
|
|
7668
|
+
return true;
|
|
7669
|
+
}
|
|
7670
|
+
detach(target) {
|
|
7671
|
+
const state = this.sessions.get(target);
|
|
7672
|
+
if (!state) return;
|
|
7673
|
+
state.listeners.clear();
|
|
7674
|
+
state.closeListeners.clear();
|
|
7675
|
+
}
|
|
7676
|
+
sendInput(target, keys) {
|
|
7677
|
+
const state = this.sessions.get(target);
|
|
7678
|
+
if (!state || !state.proc.stdin?.writable) return false;
|
|
7679
|
+
state.proc.stdin.write(keys);
|
|
7680
|
+
return true;
|
|
7681
|
+
}
|
|
7682
|
+
resize(_target, _cols, _rows) {
|
|
7683
|
+
return true;
|
|
7684
|
+
}
|
|
7685
|
+
createSession(sessionName, windowName = "main", cwd) {
|
|
7686
|
+
const safeSession = sanitizeName(sessionName || `shell-${Date.now()}`);
|
|
7687
|
+
const shell = process.env.SHELL || "sh";
|
|
7688
|
+
const target = `${safeSession}:${(0, import_crypto.randomUUID)().slice(0, 8)}`;
|
|
7689
|
+
if (this.sessions.has(target)) {
|
|
7690
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: false };
|
|
7691
|
+
}
|
|
7692
|
+
const proc = (0, import_child_process2.spawn)(shell, [], {
|
|
7693
|
+
cwd,
|
|
7694
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
7695
|
+
env: process.env
|
|
7696
|
+
});
|
|
7697
|
+
if (!proc.pid) {
|
|
7698
|
+
return {
|
|
7699
|
+
ok: false,
|
|
7700
|
+
appId: this.id,
|
|
7701
|
+
sessionName: safeSession,
|
|
7702
|
+
created: false,
|
|
7703
|
+
error: "Failed to start shell process"
|
|
7704
|
+
};
|
|
7705
|
+
}
|
|
7706
|
+
const state = {
|
|
7707
|
+
proc,
|
|
7708
|
+
sessionName: safeSession,
|
|
7709
|
+
windowName,
|
|
7710
|
+
pane: "0",
|
|
7711
|
+
history: [],
|
|
7712
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
7713
|
+
closeListeners: /* @__PURE__ */ new Set()
|
|
7714
|
+
};
|
|
7715
|
+
const pushChunk = (chunk) => {
|
|
7716
|
+
const text = chunk.toString();
|
|
7717
|
+
state.history.push(text);
|
|
7718
|
+
if (state.history.length > 200) {
|
|
7719
|
+
state.history.shift();
|
|
7720
|
+
}
|
|
7721
|
+
for (const listener of state.listeners) {
|
|
7722
|
+
listener(text);
|
|
7723
|
+
}
|
|
7724
|
+
};
|
|
7725
|
+
proc.stdout?.on("data", pushChunk);
|
|
7726
|
+
proc.stderr?.on("data", pushChunk);
|
|
7727
|
+
proc.on("close", () => {
|
|
7728
|
+
for (const onClose of state.closeListeners) {
|
|
7729
|
+
onClose();
|
|
7730
|
+
}
|
|
7731
|
+
this.sessions.delete(target);
|
|
7732
|
+
});
|
|
7733
|
+
this.sessions.set(target, state);
|
|
7734
|
+
return { ok: true, appId: this.id, sessionName: safeSession, created: true };
|
|
7735
|
+
}
|
|
7736
|
+
detachAll() {
|
|
7737
|
+
for (const [id, state] of this.sessions.entries()) {
|
|
7738
|
+
state.proc.kill();
|
|
7739
|
+
this.sessions.delete(id);
|
|
7740
|
+
}
|
|
7741
|
+
}
|
|
7742
|
+
};
|
|
7743
|
+
function sendTmuxKeys(target, keys, pressEnter = false) {
|
|
7744
|
+
try {
|
|
7745
|
+
const args = ["send-keys", "-t", target, keys];
|
|
7746
|
+
if (pressEnter) args.push("Enter");
|
|
7747
|
+
(0, import_child_process2.execSync)(`tmux ${args.map((a) => `'${a}'`).join(" ")}`, {
|
|
7748
|
+
encoding: "utf8",
|
|
7749
|
+
stdio: "pipe"
|
|
7750
|
+
});
|
|
7751
|
+
return true;
|
|
7752
|
+
} catch {
|
|
7753
|
+
return false;
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
function captureTmuxPane(target, lines = 500) {
|
|
7757
|
+
const cmds = [
|
|
7758
|
+
`tmux capture-pane -t '${target}' -pae -S -${lines}`,
|
|
7759
|
+
`tmux capture-pane -t '${target}' -pe -S -${lines}`
|
|
7760
|
+
];
|
|
7761
|
+
for (const cmd of cmds) {
|
|
7762
|
+
try {
|
|
7763
|
+
return (0, import_child_process2.execSync)(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
7764
|
+
} catch {
|
|
7765
|
+
}
|
|
7766
|
+
}
|
|
7767
|
+
return "";
|
|
7768
|
+
}
|
|
7769
|
+
var TerminalManager = class {
|
|
7770
|
+
apps = /* @__PURE__ */ new Map();
|
|
7771
|
+
constructor(adapters) {
|
|
7772
|
+
const defaultAdapters = adapters ?? [new TmuxTerminalApp(), new ShellTerminalApp()];
|
|
7773
|
+
for (const adapter of defaultAdapters) {
|
|
7774
|
+
this.apps.set(adapter.id, adapter);
|
|
7775
|
+
}
|
|
7776
|
+
}
|
|
7777
|
+
list() {
|
|
7778
|
+
const metadata = Array.from(this.apps.values()).map((app) => ({
|
|
7779
|
+
id: app.id,
|
|
7780
|
+
label: app.label,
|
|
7781
|
+
available: app.isAvailable()
|
|
7782
|
+
}));
|
|
7783
|
+
const sessions = [];
|
|
7784
|
+
const panes = [];
|
|
7785
|
+
for (const app of this.apps.values()) {
|
|
7786
|
+
if (!app.isAvailable()) continue;
|
|
7787
|
+
sessions.push(...app.listSessions());
|
|
7788
|
+
panes.push(...app.listPanes());
|
|
7789
|
+
}
|
|
7790
|
+
return { apps: metadata, sessions, panes };
|
|
7791
|
+
}
|
|
7792
|
+
async attach(target, onData, onClose, appHint) {
|
|
7793
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7794
|
+
const app = this.apps.get(appId);
|
|
7795
|
+
if (!app || !app.isAvailable()) return false;
|
|
7796
|
+
return app.attach(rawTarget, onData, onClose);
|
|
7797
|
+
}
|
|
7798
|
+
detach(target, appHint) {
|
|
7799
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7800
|
+
this.apps.get(appId)?.detach(rawTarget);
|
|
7801
|
+
}
|
|
7802
|
+
sendInput(target, keys, appHint) {
|
|
7803
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7804
|
+
const app = this.apps.get(appId);
|
|
7805
|
+
return !!app && app.isAvailable() ? app.sendInput(rawTarget, keys) : false;
|
|
7806
|
+
}
|
|
7807
|
+
resize(target, cols, rows, appHint) {
|
|
7808
|
+
const { appId, rawTarget } = resolveAppTarget(target, appHint);
|
|
7809
|
+
const app = this.apps.get(appId);
|
|
7810
|
+
return !!app && app.isAvailable() ? app.resize(rawTarget, cols, rows) : false;
|
|
7811
|
+
}
|
|
7812
|
+
createSession(sessionName, windowName = "main", cwd, appId = "tmux") {
|
|
7813
|
+
const app = this.apps.get(appId);
|
|
7814
|
+
if (!app || !app.isAvailable()) {
|
|
7815
|
+
return {
|
|
7816
|
+
ok: false,
|
|
7817
|
+
appId,
|
|
7818
|
+
sessionName,
|
|
7819
|
+
created: false,
|
|
7820
|
+
error: `Terminal app '${appId}' is not available`
|
|
7821
|
+
};
|
|
7822
|
+
}
|
|
7823
|
+
return app.createSession(sessionName, windowName, cwd);
|
|
7824
|
+
}
|
|
7825
|
+
detachAll() {
|
|
7826
|
+
for (const app of this.apps.values()) {
|
|
7827
|
+
app.detachAll();
|
|
7828
|
+
}
|
|
7829
|
+
}
|
|
7830
|
+
};
|
|
7624
7831
|
|
|
7625
7832
|
// src/daemon/controller.ts
|
|
7626
7833
|
var ViberController = class extends import_events2.EventEmitter {
|
|
@@ -7771,16 +7978,16 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7771
7978
|
this.handleTerminalList();
|
|
7772
7979
|
break;
|
|
7773
7980
|
case "terminal:attach":
|
|
7774
|
-
await this.handleTerminalAttach(message.target);
|
|
7981
|
+
await this.handleTerminalAttach(message.target, message.appId);
|
|
7775
7982
|
break;
|
|
7776
7983
|
case "terminal:detach":
|
|
7777
|
-
this.handleTerminalDetach(message.target);
|
|
7984
|
+
this.handleTerminalDetach(message.target, message.appId);
|
|
7778
7985
|
break;
|
|
7779
7986
|
case "terminal:input":
|
|
7780
|
-
this.handleTerminalInput(message.target, message.keys);
|
|
7987
|
+
this.handleTerminalInput(message.target, message.keys, message.appId);
|
|
7781
7988
|
break;
|
|
7782
7989
|
case "terminal:resize":
|
|
7783
|
-
this.handleTerminalResize(message.target, message.cols, message.rows);
|
|
7990
|
+
this.handleTerminalResize(message.target, message.cols, message.rows, message.appId);
|
|
7784
7991
|
break;
|
|
7785
7992
|
}
|
|
7786
7993
|
} catch (error) {
|
|
@@ -7810,7 +8017,87 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7810
8017
|
},
|
|
7811
8018
|
messages
|
|
7812
8019
|
);
|
|
7813
|
-
|
|
8020
|
+
let finalText = "";
|
|
8021
|
+
let pendingDelta = "";
|
|
8022
|
+
let lastProgressAt = 0;
|
|
8023
|
+
const flushProgress = (force = false) => {
|
|
8024
|
+
if (!pendingDelta) return;
|
|
8025
|
+
const now = Date.now();
|
|
8026
|
+
if (!force && now - lastProgressAt < 250) return;
|
|
8027
|
+
this.send({
|
|
8028
|
+
type: "task:progress",
|
|
8029
|
+
taskId,
|
|
8030
|
+
event: {
|
|
8031
|
+
kind: "text-delta",
|
|
8032
|
+
delta: pendingDelta,
|
|
8033
|
+
totalLength: finalText.length,
|
|
8034
|
+
at: new Date(now).toISOString()
|
|
8035
|
+
}
|
|
8036
|
+
});
|
|
8037
|
+
pendingDelta = "";
|
|
8038
|
+
lastProgressAt = now;
|
|
8039
|
+
};
|
|
8040
|
+
this.send({
|
|
8041
|
+
type: "task:progress",
|
|
8042
|
+
taskId,
|
|
8043
|
+
event: {
|
|
8044
|
+
kind: "status",
|
|
8045
|
+
phase: "executing",
|
|
8046
|
+
message: "Agent execution started",
|
|
8047
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8048
|
+
}
|
|
8049
|
+
});
|
|
8050
|
+
for await (const part of streamResult.fullStream) {
|
|
8051
|
+
switch (part.type) {
|
|
8052
|
+
case "text-delta":
|
|
8053
|
+
if (part.text) {
|
|
8054
|
+
finalText += part.text;
|
|
8055
|
+
pendingDelta += part.text;
|
|
8056
|
+
flushProgress(false);
|
|
8057
|
+
}
|
|
8058
|
+
break;
|
|
8059
|
+
case "tool-call":
|
|
8060
|
+
this.send({
|
|
8061
|
+
type: "task:progress",
|
|
8062
|
+
taskId,
|
|
8063
|
+
event: {
|
|
8064
|
+
kind: "tool-call",
|
|
8065
|
+
toolName: part.toolName,
|
|
8066
|
+
toolCallId: part.toolCallId,
|
|
8067
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8068
|
+
}
|
|
8069
|
+
});
|
|
8070
|
+
break;
|
|
8071
|
+
case "tool-result":
|
|
8072
|
+
this.send({
|
|
8073
|
+
type: "task:progress",
|
|
8074
|
+
taskId,
|
|
8075
|
+
event: {
|
|
8076
|
+
kind: "tool-result",
|
|
8077
|
+
toolCallId: part.toolCallId,
|
|
8078
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8079
|
+
}
|
|
8080
|
+
});
|
|
8081
|
+
break;
|
|
8082
|
+
case "error":
|
|
8083
|
+
throw new Error(part.error?.message || "Task stream error");
|
|
8084
|
+
case "finish":
|
|
8085
|
+
flushProgress(true);
|
|
8086
|
+
this.send({
|
|
8087
|
+
type: "task:progress",
|
|
8088
|
+
taskId,
|
|
8089
|
+
event: {
|
|
8090
|
+
kind: "status",
|
|
8091
|
+
phase: "verifying",
|
|
8092
|
+
message: "Agent execution finished, preparing final output",
|
|
8093
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
8094
|
+
}
|
|
8095
|
+
});
|
|
8096
|
+
break;
|
|
8097
|
+
default:
|
|
8098
|
+
break;
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
7814
8101
|
this.send({
|
|
7815
8102
|
type: "task:completed",
|
|
7816
8103
|
taskId,
|
|
@@ -7847,33 +8134,34 @@ var ViberController = class extends import_events2.EventEmitter {
|
|
|
7847
8134
|
}
|
|
7848
8135
|
// ==================== Terminal Streaming ====================
|
|
7849
8136
|
handleTerminalList() {
|
|
7850
|
-
const { sessions, panes } = this.terminalManager.list();
|
|
7851
|
-
this.send({ type: "terminal:list", sessions, panes });
|
|
8137
|
+
const { apps, sessions, panes } = this.terminalManager.list();
|
|
8138
|
+
this.send({ type: "terminal:list", apps, sessions, panes });
|
|
7852
8139
|
}
|
|
7853
|
-
async handleTerminalAttach(target) {
|
|
8140
|
+
async handleTerminalAttach(target, appId) {
|
|
7854
8141
|
console.log(`[Viber] Attaching to terminal: ${target}`);
|
|
7855
8142
|
const ok = await this.terminalManager.attach(
|
|
7856
8143
|
target,
|
|
7857
8144
|
(data) => {
|
|
7858
|
-
this.send({ type: "terminal:output", target, data });
|
|
8145
|
+
this.send({ type: "terminal:output", target, appId, data });
|
|
7859
8146
|
},
|
|
7860
8147
|
() => {
|
|
7861
|
-
this.send({ type: "terminal:detached", target });
|
|
7862
|
-
}
|
|
8148
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
8149
|
+
},
|
|
8150
|
+
appId
|
|
7863
8151
|
);
|
|
7864
|
-
this.send({ type: "terminal:attached", target, ok });
|
|
8152
|
+
this.send({ type: "terminal:attached", target, appId, ok });
|
|
7865
8153
|
}
|
|
7866
|
-
handleTerminalDetach(target) {
|
|
8154
|
+
handleTerminalDetach(target, appId) {
|
|
7867
8155
|
console.log(`[Viber] Detaching from terminal: ${target}`);
|
|
7868
|
-
this.terminalManager.detach(target);
|
|
7869
|
-
this.send({ type: "terminal:detached", target });
|
|
8156
|
+
this.terminalManager.detach(target, appId);
|
|
8157
|
+
this.send({ type: "terminal:detached", target, appId });
|
|
7870
8158
|
}
|
|
7871
|
-
handleTerminalInput(target, keys) {
|
|
7872
|
-
this.terminalManager.sendInput(target, keys);
|
|
8159
|
+
handleTerminalInput(target, keys, appId) {
|
|
8160
|
+
this.terminalManager.sendInput(target, keys, appId);
|
|
7873
8161
|
}
|
|
7874
|
-
handleTerminalResize(target, cols, rows) {
|
|
7875
|
-
const ok = this.terminalManager.resize(target, cols, rows);
|
|
7876
|
-
this.send({ type: "terminal:resized", target, ok });
|
|
8162
|
+
handleTerminalResize(target, cols, rows, appId) {
|
|
8163
|
+
const ok = this.terminalManager.resize(target, cols, rows, appId);
|
|
8164
|
+
this.send({ type: "terminal:resized", target, appId, ok });
|
|
7877
8165
|
}
|
|
7878
8166
|
// ==================== Communication ====================
|
|
7879
8167
|
send(message) {
|