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/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
- function listSessions() {
7403
- try {
7404
- const out = (0, import_child_process2.execSync)(
7405
- "tmux list-sessions -F '#{session_name}|#{session_windows}|#{session_attached}' 2>/dev/null",
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 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;
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 TerminalStream = class extends import_events.EventEmitter {
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
- * Start streaming the pane output
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 = capturePane(this.target, 200);
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 TerminalManager = class {
7480
+ var TmuxTerminalApp = class {
7481
+ id = "tmux";
7482
+ label = "tmux";
7560
7483
  streams = /* @__PURE__ */ new Map();
7561
- /**
7562
- * List all available terminals
7563
- */
7564
- list() {
7565
- return {
7566
- sessions: listSessions(),
7567
- panes: listPanes()
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 TerminalStream(target);
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
- stream.detach();
7599
- this.streams.delete(target);
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 sendKeys(target, keys, false);
7561
+ return sendTmuxKeys(target, keys);
7607
7562
  }
7608
- /**
7609
- * Resize pane to match web terminal
7610
- */
7611
7563
  resize(target, cols, rows) {
7612
- return resizePane(target, cols, rows);
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
- const finalText = await streamResult.text;
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) {