@meowlynxsea/koi 0.1.2 → 0.1.3

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/main.js CHANGED
@@ -252591,7 +252591,7 @@ var require_braces = __commonJS((exports, module4) => {
252591
252591
  module4.exports = braces;
252592
252592
  });
252593
252593
 
252594
- // node_modules/picomatch/lib/constants.js
252594
+ // node_modules/micromatch/node_modules/picomatch/lib/constants.js
252595
252595
  var require_constants5 = __commonJS((exports, module4) => {
252596
252596
  var path7 = __require("path");
252597
252597
  var WIN_SLASH = "\\\\/";
@@ -252735,7 +252735,7 @@ var require_constants5 = __commonJS((exports, module4) => {
252735
252735
  };
252736
252736
  });
252737
252737
 
252738
- // node_modules/picomatch/lib/utils.js
252738
+ // node_modules/micromatch/node_modules/picomatch/lib/utils.js
252739
252739
  var require_utils2 = __commonJS((exports) => {
252740
252740
  var path7 = __require("path");
252741
252741
  var win322 = process.platform === "win32";
@@ -252795,7 +252795,7 @@ var require_utils2 = __commonJS((exports) => {
252795
252795
  };
252796
252796
  });
252797
252797
 
252798
- // node_modules/picomatch/lib/scan.js
252798
+ // node_modules/micromatch/node_modules/picomatch/lib/scan.js
252799
252799
  var require_scan = __commonJS((exports, module4) => {
252800
252800
  var utils3 = require_utils2();
252801
252801
  var {
@@ -253110,7 +253110,7 @@ var require_scan = __commonJS((exports, module4) => {
253110
253110
  module4.exports = scan2;
253111
253111
  });
253112
253112
 
253113
- // node_modules/picomatch/lib/parse.js
253113
+ // node_modules/micromatch/node_modules/picomatch/lib/parse.js
253114
253114
  var require_parse3 = __commonJS((exports, module4) => {
253115
253115
  var constants11 = require_constants5();
253116
253116
  var utils3 = require_utils2();
@@ -254117,7 +254117,7 @@ var require_parse3 = __commonJS((exports, module4) => {
254117
254117
  module4.exports = parse10;
254118
254118
  });
254119
254119
 
254120
- // node_modules/picomatch/lib/picomatch.js
254120
+ // node_modules/micromatch/node_modules/picomatch/lib/picomatch.js
254121
254121
  var require_picomatch = __commonJS((exports, module4) => {
254122
254122
  var path7 = __require("path");
254123
254123
  var scan2 = require_scan();
@@ -305499,7 +305499,7 @@ var require_cross_spawn = __commonJS((exports, module4) => {
305499
305499
  var cp = __require("child_process");
305500
305500
  var parse15 = require_parse4();
305501
305501
  var enoent = require_enoent();
305502
- function spawn14(command, args, options4) {
305502
+ function spawn13(command, args, options4) {
305503
305503
  const parsed = parse15(command, args, options4);
305504
305504
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
305505
305505
  enoent.hookChildProcess(spawned, parsed);
@@ -305511,8 +305511,8 @@ var require_cross_spawn = __commonJS((exports, module4) => {
305511
305511
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
305512
305512
  return result;
305513
305513
  }
305514
- module4.exports = spawn14;
305515
- module4.exports.spawn = spawn14;
305514
+ module4.exports = spawn13;
305515
+ module4.exports.spawn = spawn13;
305516
305516
  module4.exports.sync = spawnSync11;
305517
305517
  module4.exports._parse = parse15;
305518
305518
  module4.exports._enoent = enoent;
@@ -306359,7 +306359,8 @@ var init_mode = __esm(() => {
306359
306359
  "exitPlanMode",
306360
306360
  "agent",
306361
306361
  "CreateMonitor",
306362
- "CancelMonitor"
306362
+ "CancelMonitor",
306363
+ "SendToMonitor"
306363
306364
  ];
306364
306365
  READONLY_TOOLS = [
306365
306366
  "read",
@@ -474848,9 +474849,6 @@ function createLsToolDefinition2(_cwd) {
474848
474849
  };
474849
474850
  }
474850
474851
 
474851
- // src/tools/bash.ts
474852
- import { spawn as spawn13 } from "child_process";
474853
-
474854
474852
  // src/agent/tool-orchestration.ts
474855
474853
  class WriteToolMutex {
474856
474854
  queue = Promise.resolve();
@@ -474875,92 +474873,474 @@ async function withWriteLock(fn) {
474875
474873
  }
474876
474874
  }
474877
474875
 
474876
+ // src/tools/pty.ts
474877
+ import { EventEmitter as EventEmitter13 } from "events";
474878
+ var DEFAULT_COLS = 120;
474879
+ var DEFAULT_ROWS = 30;
474880
+
474881
+ class BunPty extends EventEmitter13 {
474882
+ pid;
474883
+ proc;
474884
+ textDecoder = new TextDecoder;
474885
+ constructor(options4) {
474886
+ super();
474887
+ const shell = process.platform === "win32" ? "powershell.exe" : "bash";
474888
+ const args = process.platform === "win32" ? [] : ["--login"];
474889
+ const command = options4.command ?? shell;
474890
+ const commandArgs = options4.args ?? args;
474891
+ const self2 = this;
474892
+ this.proc = Bun.spawn([command, ...commandArgs], {
474893
+ cwd: options4.cwd ?? process.cwd(),
474894
+ env: {
474895
+ ...process.env,
474896
+ ...options4.env,
474897
+ CLAUDECODE: "1",
474898
+ TERM: "xterm-256color"
474899
+ },
474900
+ terminal: {
474901
+ name: options4.name ?? "xterm-256color",
474902
+ cols: options4.cols ?? DEFAULT_COLS,
474903
+ rows: options4.rows ?? DEFAULT_ROWS,
474904
+ data(_terminal, data) {
474905
+ self2.emit("data", self2.textDecoder.decode(data));
474906
+ }
474907
+ },
474908
+ onExit(_subprocess, exitCode, signalCode) {
474909
+ self2.emit("exit", { exitCode: exitCode ?? 0, signal: signalCode ?? "" });
474910
+ }
474911
+ });
474912
+ this.pid = this.proc.pid;
474913
+ }
474914
+ onData(handler) {
474915
+ this.on("data", handler);
474916
+ }
474917
+ onExit(handler) {
474918
+ this.on("exit", handler);
474919
+ }
474920
+ write(data) {
474921
+ this.proc.terminal?.write(data);
474922
+ }
474923
+ resize(cols, rows) {
474924
+ try {
474925
+ this.proc.terminal?.resize(cols, rows);
474926
+ } catch {}
474927
+ }
474928
+ kill(signal) {
474929
+ try {
474930
+ this.proc.kill(signal);
474931
+ } catch {}
474932
+ }
474933
+ }
474934
+ function spawnPty(options4) {
474935
+ return new BunPty(options4);
474936
+ }
474937
+
474938
+ class PtySession extends EventEmitter13 {
474939
+ id;
474940
+ command;
474941
+ startTime;
474942
+ pty;
474943
+ outputBuffer = [];
474944
+ lastOutput = "";
474945
+ _exitCode;
474946
+ _isRunning = true;
474947
+ _dataHandler;
474948
+ _exitHandler;
474949
+ constructor(id2, pty, command) {
474950
+ super();
474951
+ this.id = id2;
474952
+ this.pty = pty;
474953
+ this.command = command;
474954
+ this.startTime = Date.now();
474955
+ this._dataHandler = (data) => {
474956
+ this.lastOutput = data;
474957
+ this.outputBuffer.push(data);
474958
+ this.emit("data", data);
474959
+ };
474960
+ this._exitHandler = ({ exitCode, signal }) => {
474961
+ this._isRunning = false;
474962
+ this._exitCode = exitCode;
474963
+ this.emit("exit", { exitCode, signal });
474964
+ };
474965
+ pty.onData(this._dataHandler);
474966
+ pty.onExit(this._exitHandler);
474967
+ }
474968
+ write(data) {
474969
+ if (this._isRunning) {
474970
+ this.pty.write(data);
474971
+ }
474972
+ }
474973
+ sendLine(line) {
474974
+ this.write(line + `
474975
+ `);
474976
+ }
474977
+ sendInterrupt() {
474978
+ this.write("\x03");
474979
+ }
474980
+ resize(cols, rows) {
474981
+ try {
474982
+ this.pty.resize(cols, rows);
474983
+ } catch (e) {}
474984
+ }
474985
+ get isRunning() {
474986
+ return this._isRunning;
474987
+ }
474988
+ get exitCode() {
474989
+ return this._exitCode;
474990
+ }
474991
+ get currentOutput() {
474992
+ return this.lastOutput;
474993
+ }
474994
+ getAllOutput() {
474995
+ return this.outputBuffer.join("");
474996
+ }
474997
+ getOutputLines() {
474998
+ const all = this.getAllOutput();
474999
+ return all.split(`
475000
+ `).filter((line) => line.length > 0);
475001
+ }
475002
+ cleanup() {
475003
+ try {
475004
+ const ptyAsEmitter = this.pty;
475005
+ if (typeof ptyAsEmitter.removeListener === "function") {
475006
+ ptyAsEmitter.removeListener("data", this._dataHandler);
475007
+ ptyAsEmitter.removeListener("exit", this._exitHandler);
475008
+ }
475009
+ } catch {}
475010
+ this.removeAllListeners();
475011
+ this._isRunning = false;
475012
+ }
475013
+ detach() {
475014
+ this.cleanup();
475015
+ }
475016
+ kill(signal = "SIGTERM") {
475017
+ try {
475018
+ this.pty.kill(signal);
475019
+ } catch {}
475020
+ this._isRunning = false;
475021
+ }
475022
+ }
475023
+ function generatePtyId() {
475024
+ return `pty-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
475025
+ }
475026
+
475027
+ // src/agent/monitor-registry.ts
475028
+ import { EventEmitter as EventEmitter14 } from "events";
475029
+ var INTERACTIVE_PATTERNS = [
475030
+ /password\s*[:\uFF1A]/i,
475031
+ /passphrase\s*[:\uFF1A]/i,
475032
+ /enter\s*(your)?\s*password/i,
475033
+ /\[sudo\]\s*password/i,
475034
+ /press\s*(any)?\s*key\s*to/i,
475035
+ /press\s*enter\s*to/i,
475036
+ /continue\s*\?\s*\[y\/n\]/i,
475037
+ /yes\/no\s*\[\w\]\s*:/i,
475038
+ /confirm\s*\?\s*\[y\/n\]/i
475039
+ ];
475040
+ function detectInteractivePrompt(output) {
475041
+ for (const pattern4 of INTERACTIVE_PATTERNS) {
475042
+ if (pattern4.test(output)) {
475043
+ return true;
475044
+ }
475045
+ }
475046
+ return false;
475047
+ }
475048
+ function createMonitorNotification(monitorId, type3, payload) {
475049
+ const escaped = payload.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
475050
+ return `<monitor-notification>
475051
+ <monitor-id>${monitorId}</monitor-id>
475052
+ <type>${type3}</type>
475053
+ <payload>${escaped}</payload>
475054
+ </monitor-notification>`;
475055
+ }
475056
+ function generateMonitorId() {
475057
+ return `monitor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
475058
+ }
475059
+
475060
+ class MonitorRegistryImpl extends EventEmitter14 {
475061
+ monitors = new Map;
475062
+ sessions = new Map;
475063
+ launch(sessionId, command, description = "") {
475064
+ const id2 = generateMonitorId();
475065
+ const entry = {
475066
+ id: id2,
475067
+ sessionId,
475068
+ description: description || `Monitor: ${command.slice(0, 40)}${command.length > 40 ? "\u2026" : ""}`,
475069
+ command,
475070
+ status: "running",
475071
+ startTime: Date.now(),
475072
+ outputLines: []
475073
+ };
475074
+ this.monitors.set(id2, entry);
475075
+ const pty = spawnPty({
475076
+ command: "bash",
475077
+ args: ["-c", command]
475078
+ });
475079
+ const session = new PtySession(id2, pty, command);
475080
+ session.on("data", (data) => {
475081
+ this.handlePtyData(id2, { type: "data", data });
475082
+ });
475083
+ session.on("exit", ({ exitCode }) => {
475084
+ this.handlePtyExit(id2, exitCode ?? 0);
475085
+ });
475086
+ this.sessions.set(id2, session);
475087
+ this.emit("change", this.getAll());
475088
+ return id2;
475089
+ }
475090
+ adopt(oldSession, sessionId, command, description) {
475091
+ const id2 = oldSession.id;
475092
+ const pty = oldSession.pty;
475093
+ const newSession = new PtySession(id2, pty, command);
475094
+ const entry = {
475095
+ id: id2,
475096
+ sessionId,
475097
+ description: description || `Monitor: ${command.slice(0, 40)}${command.length > 40 ? "\u2026" : ""}`,
475098
+ command,
475099
+ status: "running",
475100
+ startTime: oldSession.startTime,
475101
+ outputLines: []
475102
+ };
475103
+ this.monitors.set(id2, entry);
475104
+ this.sessions.set(id2, newSession);
475105
+ newSession.on("data", (data) => {
475106
+ this.handlePtyData(id2, { type: "data", data });
475107
+ });
475108
+ newSession.on("exit", ({ exitCode }) => {
475109
+ this.handlePtyExit(id2, exitCode ?? 0);
475110
+ });
475111
+ this.emit("change", this.getAll());
475112
+ return id2;
475113
+ }
475114
+ handlePtyData(id2, data) {
475115
+ const monitor = this.monitors.get(id2);
475116
+ if (!monitor)
475117
+ return;
475118
+ if (data.type === "data" && data.data) {
475119
+ monitor.outputLines.push(data.data);
475120
+ monitor.lastOutput = data.data;
475121
+ if (detectInteractivePrompt(data.data)) {
475122
+ monitor.hasPendingInput = true;
475123
+ const notification = createMonitorNotification(id2, "interactive", data.data);
475124
+ this.notifyParent(notification);
475125
+ } else {
475126
+ const notification = createMonitorNotification(id2, "output", data.data);
475127
+ this.notifyParent(notification);
475128
+ }
475129
+ }
475130
+ this.emit("change", this.getAll());
475131
+ }
475132
+ handlePtyExit(id2, exitCode) {
475133
+ this.sessions.delete(id2);
475134
+ const monitor = this.monitors.get(id2);
475135
+ if (!monitor)
475136
+ return;
475137
+ monitor.status = exitCode === 0 ? "completed" : "error";
475138
+ monitor.exitCode = exitCode;
475139
+ monitor.endTime = Date.now();
475140
+ const notification = createMonitorNotification(id2, "completed", `Exited with code ${exitCode}`);
475141
+ this.notifyParent(notification);
475142
+ this.emit("change", this.getAll());
475143
+ }
475144
+ write(id2, input) {
475145
+ const session = this.sessions.get(id2);
475146
+ if (!session)
475147
+ return false;
475148
+ const monitor = this.monitors.get(id2);
475149
+ if (monitor) {
475150
+ monitor.hasPendingInput = false;
475151
+ }
475152
+ session.write(input);
475153
+ return true;
475154
+ }
475155
+ sendLine(id2, line) {
475156
+ return this.write(id2, line + `
475157
+ `);
475158
+ }
475159
+ interrupt(id2) {
475160
+ const session = this.sessions.get(id2);
475161
+ if (!session)
475162
+ return false;
475163
+ session.sendInterrupt();
475164
+ return true;
475165
+ }
475166
+ kill(id2) {
475167
+ const session = this.sessions.get(id2);
475168
+ if (!session)
475169
+ return false;
475170
+ session.kill("SIGTERM");
475171
+ this.sessions.delete(id2);
475172
+ const monitor = this.monitors.get(id2);
475173
+ if (monitor) {
475174
+ monitor.status = "killed";
475175
+ monitor.endTime = Date.now();
475176
+ this.emit("change", this.getAll());
475177
+ }
475178
+ return true;
475179
+ }
475180
+ get(id2) {
475181
+ return this.monitors.get(id2);
475182
+ }
475183
+ getSession(id2) {
475184
+ return this.sessions.get(id2);
475185
+ }
475186
+ getAll() {
475187
+ return Array.from(this.monitors.values());
475188
+ }
475189
+ getBySession(sessionId) {
475190
+ return this.getAll().filter((m2) => m2.sessionId === sessionId);
475191
+ }
475192
+ getRunning() {
475193
+ return this.getAll().filter((m2) => m2.status === "running");
475194
+ }
475195
+ getRunningBySession(sessionId) {
475196
+ return this.getBySession(sessionId).filter((m2) => m2.status === "running");
475197
+ }
475198
+ subscribe(listener) {
475199
+ this.on("change", listener);
475200
+ return () => this.off("change", listener);
475201
+ }
475202
+ remove(id2) {
475203
+ const session = this.sessions.get(id2);
475204
+ if (session) {
475205
+ session.detach();
475206
+ this.sessions.delete(id2);
475207
+ }
475208
+ const existed = this.monitors.has(id2);
475209
+ this.monitors.delete(id2);
475210
+ if (existed)
475211
+ this.emit("change", this.getAll());
475212
+ return existed;
475213
+ }
475214
+ clear() {
475215
+ for (const session of this.sessions.values()) {
475216
+ session.kill("SIGTERM");
475217
+ }
475218
+ this.sessions.clear();
475219
+ this.monitors.clear();
475220
+ this.emit("change", this.getAll());
475221
+ }
475222
+ notifyParent(notification) {
475223
+ const parent = activeSessionRef.current;
475224
+ if (!parent) {
475225
+ console.warn("[MonitorRegistry] No active session to notify");
475226
+ return;
475227
+ }
475228
+ if (parent.isStreaming) {
475229
+ parent.steer(notification).catch(() => {});
475230
+ } else {
475231
+ parent.prompt(notification).catch(() => {});
475232
+ }
475233
+ }
475234
+ }
475235
+ var monitorRegistry = new MonitorRegistryImpl;
475236
+
474878
475237
  // src/tools/bash.ts
474879
475238
  var bashSchema2 = exports_typebox.Object({
474880
475239
  command: exports_typebox.String({ description: "Bash command to execute" }),
474881
475240
  timeout: exports_typebox.Optional(exports_typebox.Number({ description: "Timeout in seconds (default: 60). For long-running tasks that exceed this limit, use CreateMonitor instead.", default: 60 }))
474882
475241
  });
474883
475242
  var MAX_OUTPUT_CHARS = 200000;
474884
- function execBash(command, timeoutSec) {
474885
- return new Promise((resolve4, reject) => {
474886
- const shell = process.platform === "win32" ? "cmd" : "bash";
474887
- const shellFlag = process.platform === "win32" ? "/c" : "-c";
474888
- const child = spawn13(shell, [shellFlag, command], {
474889
- cwd: process.cwd(),
474890
- env: { ...process.env, CLAUDECODE: "1", GIT_EDITOR: "true" },
474891
- stdio: ["ignore", "pipe", "pipe"]
474892
- });
474893
- let stdout = "";
474894
- let stderr = "";
474895
- let timedOut = false;
474896
- let timeoutHandle;
474897
- const effectiveTimeout = timeoutSec ?? 60;
474898
- if (effectiveTimeout > 0) {
474899
- timeoutHandle = setTimeout(() => {
474900
- timedOut = true;
474901
- child.kill("SIGTERM");
474902
- setTimeout(() => {
474903
- if (!child.killed)
474904
- child.kill("SIGKILL");
474905
- }, 5000);
474906
- }, effectiveTimeout * 1000);
475243
+ async function execBashWithPty(command, timeoutSec = 60, onData, signal, onTimeout) {
475244
+ const sessionId = activeSessionRef.current?.sessionId ?? "unknown";
475245
+ const ptyId = generatePtyId();
475246
+ let output = "";
475247
+ let timeoutHandle;
475248
+ let timedOut = false;
475249
+ let ptySession;
475250
+ let resolvePromise;
475251
+ const ptyProcess = spawnPty({
475252
+ command: "bash",
475253
+ args: ["-c", command]
475254
+ });
475255
+ ptyProcess.onData((data) => {
475256
+ output += data;
475257
+ onData?.(data);
475258
+ });
475259
+ ptySession = new PtySession(ptyId, ptyProcess, command);
475260
+ if (timeoutSec > 0) {
475261
+ timeoutHandle = setTimeout(() => {
475262
+ timedOut = true;
475263
+ const monitorId = monitorRegistry.adopt(ptySession, sessionId, command, `Bash timeout transfer: ${command.slice(0, 50)}${command.length > 50 ? "\u2026" : ""}`);
475264
+ ptySession.cleanup();
475265
+ onTimeout?.(monitorId);
475266
+ signal?.removeEventListener("abort", onAbort);
475267
+ resolvePromise?.({
475268
+ exitCode: undefined,
475269
+ output,
475270
+ timedOut: true,
475271
+ transferredMonitorId: monitorId,
475272
+ session: undefined
475273
+ });
475274
+ }, timeoutSec * 1000);
475275
+ }
475276
+ const onAbort = () => {
475277
+ if (!timedOut) {
475278
+ ptySession?.kill("SIGTERM");
474907
475279
  }
474908
- child.stdout?.on("data", (chunk) => {
474909
- stdout += chunk.toString("utf-8");
474910
- if (stdout.length + stderr.length > MAX_OUTPUT_CHARS * 2) {
474911
- child.kill("SIGKILL");
474912
- }
474913
- });
474914
- child.stderr?.on("data", (chunk) => {
474915
- stderr += chunk.toString("utf-8");
474916
- if (stdout.length + stderr.length > MAX_OUTPUT_CHARS * 2) {
474917
- child.kill("SIGKILL");
474918
- }
474919
- });
474920
- child.on("error", (err) => {
474921
- if (timeoutHandle)
474922
- clearTimeout(timeoutHandle);
474923
- reject(err);
474924
- });
474925
- child.on("close", (code2) => {
475280
+ };
475281
+ signal?.addEventListener("abort", onAbort);
475282
+ return new Promise((resolve4) => {
475283
+ resolvePromise = resolve4;
475284
+ ptyProcess.onExit(({ exitCode }) => {
474926
475285
  if (timeoutHandle)
474927
475286
  clearTimeout(timeoutHandle);
474928
- resolve4({ stdout, stderr, exitCode: code2 ?? 0, timedOut });
475287
+ signal?.removeEventListener("abort", onAbort);
475288
+ resolve4({
475289
+ exitCode: exitCode ?? 0,
475290
+ output,
475291
+ timedOut: false,
475292
+ transferredMonitorId: undefined,
475293
+ session: undefined
475294
+ });
474929
475295
  });
474930
475296
  });
474931
475297
  }
474932
475298
  async function executeBash(params) {
474933
- const { stdout, stderr, exitCode, timedOut } = await execBash(params.command, params.timeout);
474934
- let output = stdout;
474935
- if (stderr) {
474936
- output += (output ? `
474937
-
474938
- ` : "") + `[stderr]
474939
- ${stderr}`;
474940
- }
474941
- if (timedOut) {
474942
- output += `
474943
-
474944
- [Command timed out and was terminated]`;
475299
+ let monitorId;
475300
+ const { exitCode, output, timedOut, transferredMonitorId } = await execBashWithPty(params.command, params.timeout, undefined, undefined, (id2) => {
475301
+ monitorId = id2;
475302
+ });
475303
+ if (timedOut && !monitorId) {
475304
+ monitorId = transferredMonitorId;
474945
475305
  }
474946
- if (output.length > MAX_OUTPUT_CHARS) {
474947
- output = output.slice(0, MAX_OUTPUT_CHARS) + `
475306
+ let displayOutput = output;
475307
+ if (displayOutput.length > MAX_OUTPUT_CHARS) {
475308
+ displayOutput = displayOutput.slice(0, MAX_OUTPUT_CHARS) + `
474948
475309
 
474949
475310
  [Output truncated: ${output.length} chars total, limit: ${MAX_OUTPUT_CHARS}]`;
474950
475311
  }
474951
475312
  const warning = isDangerousBashCommand(params.command) ? `
474952
475313
 
474953
475314
  [Warning: This command may be destructive. Proceed with caution.]` : "";
475315
+ if (timedOut && monitorId) {
475316
+ return {
475317
+ content: [
475318
+ {
475319
+ type: "text",
475320
+ text: `Command timed out after ${params.timeout}s.
475321
+
475322
+ ` + `The process has been transferred to a background monitor.
475323
+
475324
+ ` + `Monitor ID: ${monitorId}
475325
+ ` + `Use SendToMonitor to provide input (e.g., passwords) or InterruptMonitor to stop it.
475326
+
475327
+ ` + `Latest output:
475328
+ ${displayOutput.slice(-2000)}${warning}`
475329
+ }
475330
+ ],
475331
+ details: { exitCode: undefined, timedOut: true, monitorId }
475332
+ };
475333
+ }
474954
475334
  return {
474955
- content: [{ type: "text", text: output + warning }],
474956
- details: { exitCode, timedOut }
475335
+ content: [{ type: "text", text: displayOutput + warning }],
475336
+ details: { exitCode, timedOut: false }
474957
475337
  };
474958
475338
  }
474959
475339
  function createBashToolDefinition2(_cwd) {
474960
475340
  return {
474961
475341
  name: "bash",
474962
475342
  label: "Bash",
474963
- description: `Execute a bash command in the environment.
475343
+ description: `Execute a bash command in the environment with full PTY isolation.
474964
475344
 
474965
475345
  ` + "IMPORTANT: Avoid using this tool to run `find`, `grep`, `cat`, `head`, `tail`, `sed`, `awk`, or `echo` commands. " + `Instead, use the appropriate dedicated tool.
474966
475346
 
@@ -474968,8 +475348,11 @@ function createBashToolDefinition2(_cwd) {
474968
475348
  ` + `- NEVER update the git config
474969
475349
  ` + `- NEVER run destructive git commands (push --force, reset --hard, checkout .) unless explicitly requested
474970
475350
  ` + `- NEVER use git commands with the -i flag (interactive)
474971
- ` + "- NEVER skip hooks (--no-verify, --no-gpg-sign) unless explicitly asked",
474972
- promptSnippet: "Bash: execute shell commands (last resort \u2014 prefer dedicated tools)",
475351
+ ` + `- NEVER skip hooks (--no-verify, --no-gpg-sign) unless explicitly asked
475352
+
475353
+ ` + `Timeout Handling:
475354
+ ` + "If the command times out, it will be transferred to a background monitor instead of being killed. " + "Use SendToMonitor to interact with the process (e.g., enter sudo passwords).",
475355
+ promptSnippet: "Bash: execute shell commands with PTY isolation (last resort \u2014 prefer dedicated tools)",
474973
475356
  parameters: bashSchema2,
474974
475357
  executionMode: "parallel",
474975
475358
  async execute(_toolCallId, params, _signal, _onUpdate) {
@@ -477210,7 +477593,7 @@ class AxiosTransformStream extends stream4.Transform {
477210
477593
  var AxiosTransformStream_default = AxiosTransformStream;
477211
477594
 
477212
477595
  // node_modules/axios/lib/adapters/http.js
477213
- import { EventEmitter as EventEmitter13 } from "events";
477596
+ import { EventEmitter as EventEmitter15 } from "events";
477214
477597
 
477215
477598
  // node_modules/axios/lib/helpers/formDataToStream.js
477216
477599
  import util38 from "util";
@@ -477947,7 +478330,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config3) {
477947
478330
  });
477948
478331
  };
477949
478332
  }
477950
- const abortEmitter = new EventEmitter13;
478333
+ const abortEmitter = new EventEmitter15;
477951
478334
  function abort(reason) {
477952
478335
  try {
477953
478336
  abortEmitter.emit("abort", !reason || reason.type ? new CanceledError_default(null, config3, req) : reason);
@@ -481373,180 +481756,6 @@ function createTaskUpdateToolDefinition(_cwd, taskManager) {
481373
481756
  };
481374
481757
  }
481375
481758
 
481376
- // src/agent/monitor-registry.ts
481377
- import { spawn as spawn16 } from "child_process";
481378
- import { EventEmitter as EventEmitter14 } from "events";
481379
- function createMonitorNotification(monitorId, type3, payload) {
481380
- return `<monitor-notification>
481381
- <monitor-id>${monitorId}</monitor-id>
481382
- <type>${type3}</type>
481383
- <payload>${escapeXml2(payload)}</payload>
481384
- </monitor-notification>`;
481385
- }
481386
- function escapeXml2(str3) {
481387
- return str3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
481388
- }
481389
- function generateMonitorId() {
481390
- return `monitor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
481391
- }
481392
-
481393
- class MonitorRegistryImpl extends EventEmitter14 {
481394
- monitors = new Map;
481395
- processes = new Map;
481396
- launch(sessionId, command, description = "") {
481397
- const id2 = generateMonitorId();
481398
- const entry = {
481399
- id: id2,
481400
- sessionId,
481401
- description: description || `Monitor: ${command.slice(0, 40)}${command.length > 40 ? "\u2026" : ""}`,
481402
- command,
481403
- status: "running",
481404
- startTime: Date.now(),
481405
- outputLines: []
481406
- };
481407
- this.monitors.set(id2, entry);
481408
- this.emit("change", this.getAll());
481409
- const child = spawn16("bash", ["-c", command], {
481410
- stdio: ["ignore", "pipe", "pipe"],
481411
- detached: false
481412
- });
481413
- this.processes.set(id2, child);
481414
- let stderrBuffer = "";
481415
- child.stdout?.on("data", (chunk) => {
481416
- const lines = chunk.toString().split(`
481417
- `);
481418
- for (const line of lines) {
481419
- if (!line && lines.length === 1)
481420
- continue;
481421
- const trimmed = line.trimEnd();
481422
- if (!trimmed)
481423
- continue;
481424
- const monitor = this.monitors.get(id2);
481425
- if (monitor) {
481426
- monitor.outputLines.push(trimmed);
481427
- monitor.lastOutput = trimmed;
481428
- }
481429
- const notification = createMonitorNotification(id2, "output", trimmed);
481430
- this.notifyParent(notification);
481431
- this.emit("change", this.getAll());
481432
- }
481433
- });
481434
- child.stderr?.on("data", (chunk) => {
481435
- stderrBuffer += chunk.toString();
481436
- });
481437
- child.on("close", (code2) => {
481438
- this.processes.delete(id2);
481439
- const monitor = this.monitors.get(id2);
481440
- if (!monitor)
481441
- return;
481442
- if (stderrBuffer.trim()) {
481443
- monitor.error = stderrBuffer.trim();
481444
- const notification = createMonitorNotification(id2, "error", stderrBuffer.trim());
481445
- this.notifyParent(notification);
481446
- }
481447
- if (monitor.status === "running") {
481448
- monitor.status = code2 === 0 ? "completed" : "error";
481449
- monitor.exitCode = code2 ?? undefined;
481450
- monitor.endTime = Date.now();
481451
- const notification = createMonitorNotification(id2, "completed", `Exited with code ${code2 ?? "unknown"}`);
481452
- this.notifyParent(notification);
481453
- }
481454
- this.emit("change", this.getAll());
481455
- });
481456
- child.on("error", (err) => {
481457
- this.processes.delete(id2);
481458
- const monitor = this.monitors.get(id2);
481459
- if (monitor) {
481460
- monitor.status = "error";
481461
- monitor.error = err.message;
481462
- monitor.endTime = Date.now();
481463
- const notification = createMonitorNotification(id2, "error", err.message);
481464
- this.notifyParent(notification);
481465
- }
481466
- this.emit("change", this.getAll());
481467
- });
481468
- return id2;
481469
- }
481470
- kill(id2) {
481471
- const child = this.processes.get(id2);
481472
- if (!child)
481473
- return false;
481474
- try {
481475
- process.kill(child.pid, "SIGTERM");
481476
- setTimeout(() => {
481477
- const monitor2 = this.monitors.get(id2);
481478
- if (monitor2 && monitor2.status === "running") {
481479
- try {
481480
- process.kill(child.pid, 0);
481481
- } catch {
481482
- return;
481483
- }
481484
- try {
481485
- process.kill(child.pid, "SIGKILL");
481486
- } catch {}
481487
- }
481488
- }, 500);
481489
- } catch {}
481490
- const monitor = this.monitors.get(id2);
481491
- if (monitor) {
481492
- monitor.status = "killed";
481493
- monitor.endTime = Date.now();
481494
- this.emit("change", this.getAll());
481495
- }
481496
- return true;
481497
- }
481498
- get(id2) {
481499
- return this.monitors.get(id2);
481500
- }
481501
- getAll() {
481502
- return Array.from(this.monitors.values());
481503
- }
481504
- getBySession(sessionId) {
481505
- return this.getAll().filter((m2) => m2.sessionId === sessionId);
481506
- }
481507
- getRunning() {
481508
- return this.getAll().filter((m2) => m2.status === "running");
481509
- }
481510
- getRunningBySession(sessionId) {
481511
- return this.getBySession(sessionId).filter((m2) => m2.status === "running");
481512
- }
481513
- subscribe(listener) {
481514
- this.on("change", listener);
481515
- return () => this.off("change", listener);
481516
- }
481517
- remove(id2) {
481518
- const existed = this.monitors.has(id2);
481519
- this.monitors.delete(id2);
481520
- if (existed)
481521
- this.emit("change", this.getAll());
481522
- return existed;
481523
- }
481524
- clear() {
481525
- for (const [id2, child] of this.processes) {
481526
- try {
481527
- process.kill(child.pid, "SIGTERM");
481528
- } catch {}
481529
- this.monitors.delete(id2);
481530
- }
481531
- this.processes.clear();
481532
- this.monitors.clear();
481533
- this.emit("change", this.getAll());
481534
- }
481535
- notifyParent(notification) {
481536
- const parent = activeSessionRef.current;
481537
- if (!parent) {
481538
- console.warn("[MonitorRegistry] No active session to notify");
481539
- return;
481540
- }
481541
- if (parent.isStreaming) {
481542
- parent.steer(notification).catch(() => {});
481543
- } else {
481544
- parent.prompt(notification).catch(() => {});
481545
- }
481546
- }
481547
- }
481548
- var monitorRegistry = new MonitorRegistryImpl;
481549
-
481550
481759
  // src/tools/monitor.ts
481551
481760
  var createMonitorSchema = exports_typebox.Object({
481552
481761
  command: exports_typebox.String({
@@ -481649,6 +481858,111 @@ function createCancelMonitorToolDefinition() {
481649
481858
  };
481650
481859
  }
481651
481860
 
481861
+ // src/tools/send-to-monitor.ts
481862
+ var sendToMonitorSchema = exports_typebox.Object({
481863
+ monitorId: exports_typebox.String({
481864
+ description: "The ID of the monitor to send input to."
481865
+ }),
481866
+ input: exports_typebox.String({
481867
+ description: "The input string to send to the monitor's PTY. " + "For passwords, type the password and it will be sent to the PTY. " + "For newlines, include \\n in the string or use sendLine: true."
481868
+ }),
481869
+ sendLine: exports_typebox.Optional(exports_typebox.Boolean({
481870
+ description: "If true, append a newline after the input (equivalent to pressing Enter). " + "Default: false (raw input without newline).",
481871
+ default: false
481872
+ })),
481873
+ interrupt: exports_typebox.Optional(exports_typebox.Boolean({
481874
+ description: "If true, send Ctrl+C to interrupt the running process instead of sending text input. " + "When set to true, the 'input' parameter is ignored.",
481875
+ default: false
481876
+ }))
481877
+ });
481878
+ function createSendToMonitorToolDefinition() {
481879
+ return {
481880
+ name: "SendToMonitor",
481881
+ label: "SendToMonitor",
481882
+ description: `Send input to a running monitor's PTY process.
481883
+
481884
+ ` + `Use this tool when:
481885
+ ` + `- A monitor prompts for a password (e.g., sudo)
481886
+ ` + `- A monitor asks for confirmation (y/n)
481887
+ ` + `- You need to interact with an interactive command running in a monitor
481888
+
481889
+ ` + `The input is sent directly to the PTY, completely bypassing any terminal UI,
481890
+ ` + "ensuring no sensitive information is leaked to the outer environment.",
481891
+ promptSnippet: "SendToMonitor: send input to a background monitor process",
481892
+ parameters: sendToMonitorSchema,
481893
+ executionMode: "parallel",
481894
+ async execute(_toolCallId, params) {
481895
+ const monitor = monitorRegistry.get(params.monitorId);
481896
+ if (!monitor) {
481897
+ return {
481898
+ content: [
481899
+ {
481900
+ type: "text",
481901
+ text: `Monitor not found: ${params.monitorId}`
481902
+ }
481903
+ ],
481904
+ details: { success: false, monitorId: params.monitorId },
481905
+ isError: true
481906
+ };
481907
+ }
481908
+ if (monitor.status !== "running") {
481909
+ return {
481910
+ content: [
481911
+ {
481912
+ type: "text",
481913
+ text: `Monitor ${params.monitorId} is not running (status: ${monitor.status}).`
481914
+ }
481915
+ ],
481916
+ details: { success: false, monitorId: params.monitorId },
481917
+ isError: true
481918
+ };
481919
+ }
481920
+ const session = monitorRegistry.getSession(params.monitorId);
481921
+ if (!session) {
481922
+ return {
481923
+ content: [
481924
+ {
481925
+ type: "text",
481926
+ text: `Monitor ${params.monitorId} session not found (may have already exited).`
481927
+ }
481928
+ ],
481929
+ details: { success: false, monitorId: params.monitorId },
481930
+ isError: true
481931
+ };
481932
+ }
481933
+ let success2 = false;
481934
+ if (params.interrupt) {
481935
+ success2 = monitorRegistry.interrupt(params.monitorId);
481936
+ return {
481937
+ content: [
481938
+ {
481939
+ type: "text",
481940
+ text: success2 ? `Interrupt (Ctrl+C) sent to monitor ${params.monitorId}.` : `Monitor ${params.monitorId} could not be interrupted.`
481941
+ }
481942
+ ],
481943
+ details: { success: success2, monitorId: params.monitorId }
481944
+ };
481945
+ }
481946
+ if (params.sendLine) {
481947
+ monitorRegistry.sendLine(params.monitorId, params.input);
481948
+ } else {
481949
+ monitorRegistry.write(params.monitorId, params.input);
481950
+ }
481951
+ success2 = true;
481952
+ const displayInput = params.input.length > 0 && params.input === params.input.trim() ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : params.input;
481953
+ return {
481954
+ content: [
481955
+ {
481956
+ type: "text",
481957
+ text: `Input sent to monitor ${params.monitorId}: ${params.sendLine ? displayInput + "\\n" : displayInput}`
481958
+ }
481959
+ ],
481960
+ details: { success: success2, monitorId: params.monitorId }
481961
+ };
481962
+ }
481963
+ };
481964
+ }
481965
+
481652
481966
  // src/skills/loader.ts
481653
481967
  import path23 from "path";
481654
481968
  import os14 from "os";
@@ -483686,6 +484000,7 @@ function createCodingToolDefinitions(_cwd, taskManager) {
483686
484000
  createTaskUpdateToolDefinition(_cwd, taskManager),
483687
484001
  createMonitorToolDefinition(),
483688
484002
  createCancelMonitorToolDefinition(),
484003
+ createSendToMonitorToolDefinition(),
483689
484004
  createSkillToolDefinition()
483690
484005
  ];
483691
484006
  }
@@ -485858,6 +486173,22 @@ function InfoBar({ width = 80, exitMode = false, yoloMode: yoloMode2 = false, on
485858
486173
 
485859
486174
  // src/tui/components/side-bar.tsx
485860
486175
  init_mcp();
486176
+
486177
+ // src/config/version.ts
486178
+ import { readFileSync as readFileSync25 } from "fs";
486179
+ import { resolve as resolve27 } from "path";
486180
+ function getVersion() {
486181
+ try {
486182
+ const packageJsonPath = resolve27(process.cwd(), "package.json");
486183
+ const packageJson = JSON.parse(readFileSync25(packageJsonPath, "utf-8"));
486184
+ return `v${packageJson.version}`;
486185
+ } catch {
486186
+ return "v0.0.0";
486187
+ }
486188
+ }
486189
+ var VERSION6 = getVersion();
486190
+
486191
+ // src/tui/components/side-bar.tsx
485861
486192
  var KOI_LOGO = [
485862
486193
  "\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588",
485863
486194
  "\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588 \u2588\u2588 ",
@@ -485865,7 +486196,6 @@ var KOI_LOGO = [
485865
486196
  "\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 ",
485866
486197
  "\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588"
485867
486198
  ];
485868
- var VERSION6 = "v0.1.0";
485869
486199
  var GRADIENT_STOPS = [
485870
486200
  "#778899",
485871
486201
  "#708090",