agent-yes 1.43.0 → 1.44.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/cli.js +952 -180
- package/dist/index.js +304 -123
- package/package.json +6 -3
- package/ts/agentRegistry.ts +82 -0
- package/ts/cli.ts +8 -0
- package/ts/index.ts +372 -63
- package/ts/mcp-server.ts +447 -0
- package/ts/pidStore.ts +13 -5
package/dist/cli.js
CHANGED
|
@@ -20719,6 +20719,7 @@ class PidStore {
|
|
|
20719
20719
|
cli TEXT NOT NULL,
|
|
20720
20720
|
args TEXT NOT NULL,
|
|
20721
20721
|
prompt TEXT,
|
|
20722
|
+
cwd TEXT NOT NULL,
|
|
20722
20723
|
logFile TEXT NOT NULL,
|
|
20723
20724
|
fifoFile TEXT NOT NULL,
|
|
20724
20725
|
status TEXT NOT NULL DEFAULT 'active',
|
|
@@ -20740,7 +20741,8 @@ class PidStore {
|
|
|
20740
20741
|
pid,
|
|
20741
20742
|
cli,
|
|
20742
20743
|
args,
|
|
20743
|
-
prompt
|
|
20744
|
+
prompt,
|
|
20745
|
+
cwd
|
|
20744
20746
|
}) {
|
|
20745
20747
|
const now = Date.now();
|
|
20746
20748
|
const argsJson = JSON.stringify(args);
|
|
@@ -20748,16 +20750,16 @@ class PidStore {
|
|
|
20748
20750
|
const fifoFile = this.getFifoPath(pid);
|
|
20749
20751
|
try {
|
|
20750
20752
|
this.db.run(`
|
|
20751
|
-
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
20752
|
-
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
20753
|
-
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
20753
|
+
INSERT INTO pid_records (pid, cli, args, prompt, cwd, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
20754
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
20755
|
+
`, [pid, cli, argsJson, prompt, cwd, logFile, fifoFile, now, now]);
|
|
20754
20756
|
} catch (error) {
|
|
20755
20757
|
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
20756
20758
|
this.db.run(`
|
|
20757
20759
|
UPDATE pid_records
|
|
20758
|
-
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
20760
|
+
SET cli = ?, args = ?, prompt = ?, cwd = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
20759
20761
|
WHERE pid = ?
|
|
20760
|
-
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
20762
|
+
`, [cli, argsJson, prompt, cwd, logFile, fifoFile, now, now, pid]);
|
|
20761
20763
|
} else {
|
|
20762
20764
|
throw error;
|
|
20763
20765
|
}
|
|
@@ -20782,6 +20784,9 @@ class PidStore {
|
|
|
20782
20784
|
}
|
|
20783
20785
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20784
20786
|
}
|
|
20787
|
+
getAllRecords() {
|
|
20788
|
+
return this.db.query("SELECT * FROM pid_records");
|
|
20789
|
+
}
|
|
20785
20790
|
getLogDir() {
|
|
20786
20791
|
return path10.resolve(this.storeDir, "logs");
|
|
20787
20792
|
}
|
|
@@ -21237,83 +21242,7 @@ class AgentContext {
|
|
|
21237
21242
|
}
|
|
21238
21243
|
var init_context = () => {};
|
|
21239
21244
|
|
|
21240
|
-
// ts/core/responders.ts
|
|
21241
|
-
async function createAutoResponseHandler(line, lineIndex, options) {
|
|
21242
|
-
const { ctx, conf, cli, workingDir, exitAgent } = options;
|
|
21243
|
-
logger.debug(`stdout|${line}`);
|
|
21244
|
-
if (conf.ready?.some((rx) => line.match(rx))) {
|
|
21245
|
-
logger.debug(`ready |${line}`);
|
|
21246
|
-
if (cli === "gemini" && lineIndex <= 80)
|
|
21247
|
-
return;
|
|
21248
|
-
ctx.stdinReady.ready();
|
|
21249
|
-
ctx.stdinFirstReady.ready();
|
|
21250
|
-
}
|
|
21251
|
-
if (conf.enter?.some((rx) => line.match(rx))) {
|
|
21252
|
-
logger.debug(`sendEnter matched|${line}`);
|
|
21253
|
-
return await sendEnter(ctx.messageContext, 400);
|
|
21254
|
-
}
|
|
21255
|
-
const typingResponded = await src_default(Object.entries(conf.typingRespond ?? {})).filter(([_sendString, onThePatterns]) => onThePatterns.some((rx) => line.match(rx))).map(async ([sendString]) => await sendMessage3(ctx.messageContext, sendString, { waitForReady: false })).toCount();
|
|
21256
|
-
if (typingResponded)
|
|
21257
|
-
return;
|
|
21258
|
-
if (conf.fatal?.some((rx) => line.match(rx))) {
|
|
21259
|
-
logger.debug(`fatal |${line}`);
|
|
21260
|
-
ctx.isFatal = true;
|
|
21261
|
-
await exitAgent();
|
|
21262
|
-
}
|
|
21263
|
-
if (conf.restartWithoutContinueArg?.some((rx) => line.match(rx))) {
|
|
21264
|
-
logger.debug(`restart-without-continue|${line}`);
|
|
21265
|
-
ctx.shouldRestartWithoutContinue = true;
|
|
21266
|
-
ctx.isFatal = true;
|
|
21267
|
-
await exitAgent();
|
|
21268
|
-
}
|
|
21269
|
-
if (cli === "codex") {
|
|
21270
|
-
const sessionId = extractSessionId(line);
|
|
21271
|
-
if (sessionId) {
|
|
21272
|
-
logger.debug(`session|captured session ID: ${sessionId}`);
|
|
21273
|
-
await storeSessionForCwd(workingDir, sessionId);
|
|
21274
|
-
}
|
|
21275
|
-
}
|
|
21276
|
-
}
|
|
21277
|
-
var init_responders = __esm(() => {
|
|
21278
|
-
init_dist4();
|
|
21279
|
-
init_logger();
|
|
21280
|
-
init_messaging();
|
|
21281
|
-
init_codexSessionManager();
|
|
21282
|
-
});
|
|
21283
|
-
|
|
21284
21245
|
// ts/core/streamHelpers.ts
|
|
21285
|
-
function handleConsoleControlCodes(text, shell, terminalRender, cli, verbose) {
|
|
21286
|
-
terminalRender.write(text);
|
|
21287
|
-
if (text.includes("\x1B[c") || text.includes("\x1B[0c")) {
|
|
21288
|
-
shell.write("\x1B[?1;2c");
|
|
21289
|
-
if (verbose) {
|
|
21290
|
-
logger.debug("device|respond DA: VT100 with Advanced Video Option");
|
|
21291
|
-
}
|
|
21292
|
-
return;
|
|
21293
|
-
}
|
|
21294
|
-
if (process.stdin.isTTY)
|
|
21295
|
-
return;
|
|
21296
|
-
if (!text.includes("\x1B[6n"))
|
|
21297
|
-
return;
|
|
21298
|
-
const { col, row } = terminalRender.getCursorPosition();
|
|
21299
|
-
shell.write(`\x1B[${row};${col}R`);
|
|
21300
|
-
logger.debug(`cursor|respond position: row=${String(row)}, col=${String(col)}`);
|
|
21301
|
-
}
|
|
21302
|
-
function createTerminateSignalHandler(stdinReady, onAbort) {
|
|
21303
|
-
let aborted2 = false;
|
|
21304
|
-
return (chunk) => {
|
|
21305
|
-
if (!aborted2 && chunk === "\x1A") {
|
|
21306
|
-
return "";
|
|
21307
|
-
}
|
|
21308
|
-
if (!aborted2 && !stdinReady.isReady && chunk === "\x03") {
|
|
21309
|
-
logger.error("User aborted: SIGINT");
|
|
21310
|
-
onAbort(130);
|
|
21311
|
-
aborted2 = true;
|
|
21312
|
-
return chunk;
|
|
21313
|
-
}
|
|
21314
|
-
return chunk;
|
|
21315
|
-
};
|
|
21316
|
-
}
|
|
21317
21246
|
function createTerminatorStream(exitPromise) {
|
|
21318
21247
|
return new TransformStream({
|
|
21319
21248
|
start: function terminator(ctrl) {
|
|
@@ -21323,8 +21252,48 @@ function createTerminatorStream(exitPromise) {
|
|
|
21323
21252
|
flush: (ctrl) => ctrl.terminate()
|
|
21324
21253
|
});
|
|
21325
21254
|
}
|
|
21326
|
-
|
|
21327
|
-
|
|
21255
|
+
|
|
21256
|
+
// ts/agentRegistry.ts
|
|
21257
|
+
class AgentRegistry {
|
|
21258
|
+
agents = new Map;
|
|
21259
|
+
register(pid, instance) {
|
|
21260
|
+
this.agents.set(pid, instance);
|
|
21261
|
+
}
|
|
21262
|
+
unregister(pid) {
|
|
21263
|
+
this.agents.delete(pid);
|
|
21264
|
+
}
|
|
21265
|
+
get(pid) {
|
|
21266
|
+
return this.agents.get(pid);
|
|
21267
|
+
}
|
|
21268
|
+
list() {
|
|
21269
|
+
return Array.from(this.agents.values());
|
|
21270
|
+
}
|
|
21271
|
+
appendStdout(pid, data) {
|
|
21272
|
+
const instance = this.agents.get(pid);
|
|
21273
|
+
if (!instance) {
|
|
21274
|
+
return;
|
|
21275
|
+
}
|
|
21276
|
+
const lines2 = data.split(`
|
|
21277
|
+
`);
|
|
21278
|
+
instance.stdoutBuffer.push(...lines2);
|
|
21279
|
+
if (instance.stdoutBuffer.length > MAX_BUFFER_SIZE) {
|
|
21280
|
+
instance.stdoutBuffer = instance.stdoutBuffer.slice(-MAX_BUFFER_SIZE);
|
|
21281
|
+
}
|
|
21282
|
+
}
|
|
21283
|
+
getStdout(pid, tail) {
|
|
21284
|
+
const instance = this.agents.get(pid);
|
|
21285
|
+
if (!instance) {
|
|
21286
|
+
return [];
|
|
21287
|
+
}
|
|
21288
|
+
if (tail !== undefined) {
|
|
21289
|
+
return instance.stdoutBuffer.slice(-tail);
|
|
21290
|
+
}
|
|
21291
|
+
return instance.stdoutBuffer;
|
|
21292
|
+
}
|
|
21293
|
+
}
|
|
21294
|
+
var MAX_BUFFER_SIZE = 1000, globalAgentRegistry;
|
|
21295
|
+
var init_agentRegistry = __esm(() => {
|
|
21296
|
+
globalAgentRegistry = new AgentRegistry;
|
|
21328
21297
|
});
|
|
21329
21298
|
|
|
21330
21299
|
// ts/defineConfig.ts
|
|
@@ -21367,6 +21336,7 @@ function getDefaultConfig() {
|
|
|
21367
21336
|
clis: {
|
|
21368
21337
|
claude: {
|
|
21369
21338
|
promptArg: "last-arg",
|
|
21339
|
+
systemPrompt: "--append-system-prompt",
|
|
21370
21340
|
install: {
|
|
21371
21341
|
powershell: "irm https://claude.ai/install.ps1 | iex",
|
|
21372
21342
|
bash: "curl -fsSL https://claude.ai/install.sh | bash",
|
|
@@ -21379,6 +21349,7 @@ function getDefaultConfig() {
|
|
|
21379
21349
|
/^>[ \u00A0]/,
|
|
21380
21350
|
/──────────+/
|
|
21381
21351
|
],
|
|
21352
|
+
working: [/esc to interrupt/, /to run in background/],
|
|
21382
21353
|
typingRespond: {
|
|
21383
21354
|
"1\n": [/│ Do you want to use this API key\?/]
|
|
21384
21355
|
},
|
|
@@ -21534,16 +21505,385 @@ var require_get_caller_file = __commonJS((exports, module) => {
|
|
|
21534
21505
|
};
|
|
21535
21506
|
});
|
|
21536
21507
|
|
|
21508
|
+
// ts/mcp-server.ts
|
|
21509
|
+
var exports_mcp_server = {};
|
|
21510
|
+
__export(exports_mcp_server, {
|
|
21511
|
+
startMcpServer: () => startMcpServer
|
|
21512
|
+
});
|
|
21513
|
+
import { Server } from "@modelcontextprotocol/sdk/server";
|
|
21514
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
|
|
21515
|
+
import {
|
|
21516
|
+
CallToolRequestSchema,
|
|
21517
|
+
ListToolsRequestSchema
|
|
21518
|
+
} from "@modelcontextprotocol/sdk/types";
|
|
21519
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
21520
|
+
function getTerminalDimensions() {
|
|
21521
|
+
if (!process.stdout.isTTY)
|
|
21522
|
+
return { cols: 80, rows: 24 };
|
|
21523
|
+
return {
|
|
21524
|
+
cols: Math.max(20, process.stdout.columns),
|
|
21525
|
+
rows: process.stdout.rows
|
|
21526
|
+
};
|
|
21527
|
+
}
|
|
21528
|
+
async function startMcpServer() {
|
|
21529
|
+
try {
|
|
21530
|
+
const config2 = await init_agent_yes_config().then(() => exports_agent_yes_config);
|
|
21531
|
+
CLIS_CONFIG2 = config2.default.clis;
|
|
21532
|
+
} catch (error) {
|
|
21533
|
+
console.error("[MCP] Failed to load agent-yes.config.ts:", error);
|
|
21534
|
+
process.exit(1);
|
|
21535
|
+
}
|
|
21536
|
+
const server = new Server({ name: "agent-yes-mcp-server", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
21537
|
+
const tools = [
|
|
21538
|
+
{
|
|
21539
|
+
name: "spawn-agent",
|
|
21540
|
+
description: "Spawn a new AI agent with specified CLI and prompt",
|
|
21541
|
+
inputSchema: {
|
|
21542
|
+
type: "object",
|
|
21543
|
+
properties: {
|
|
21544
|
+
cwd: {
|
|
21545
|
+
type: "string",
|
|
21546
|
+
description: "Working directory for the agent"
|
|
21547
|
+
},
|
|
21548
|
+
cli: {
|
|
21549
|
+
type: "string",
|
|
21550
|
+
enum: Object.keys(CLIS_CONFIG2),
|
|
21551
|
+
description: "AI CLI to spawn (e.g., 'claude', 'codex', 'gemini')"
|
|
21552
|
+
},
|
|
21553
|
+
prompt: {
|
|
21554
|
+
type: "string",
|
|
21555
|
+
description: "Initial prompt to send to the agent (optional)"
|
|
21556
|
+
}
|
|
21557
|
+
},
|
|
21558
|
+
required: ["cwd", "cli"]
|
|
21559
|
+
}
|
|
21560
|
+
},
|
|
21561
|
+
{
|
|
21562
|
+
name: "kill-agent",
|
|
21563
|
+
description: "Terminate a running agent by PID",
|
|
21564
|
+
inputSchema: {
|
|
21565
|
+
type: "object",
|
|
21566
|
+
properties: {
|
|
21567
|
+
pid: {
|
|
21568
|
+
type: "number",
|
|
21569
|
+
description: "Process ID of the agent to kill"
|
|
21570
|
+
}
|
|
21571
|
+
},
|
|
21572
|
+
required: ["pid"]
|
|
21573
|
+
}
|
|
21574
|
+
},
|
|
21575
|
+
{
|
|
21576
|
+
name: "read-stdout",
|
|
21577
|
+
description: "Read stdout output from an agent (live or historical)",
|
|
21578
|
+
inputSchema: {
|
|
21579
|
+
type: "object",
|
|
21580
|
+
properties: {
|
|
21581
|
+
pid: {
|
|
21582
|
+
type: "number",
|
|
21583
|
+
description: "Process ID of the agent"
|
|
21584
|
+
},
|
|
21585
|
+
tail: {
|
|
21586
|
+
type: "number",
|
|
21587
|
+
description: "Number of lines to return from the end (default: 100)"
|
|
21588
|
+
}
|
|
21589
|
+
},
|
|
21590
|
+
required: ["pid"]
|
|
21591
|
+
}
|
|
21592
|
+
},
|
|
21593
|
+
{
|
|
21594
|
+
name: "write-stdin",
|
|
21595
|
+
description: "Send a message to an agent's stdin",
|
|
21596
|
+
inputSchema: {
|
|
21597
|
+
type: "object",
|
|
21598
|
+
properties: {
|
|
21599
|
+
pid: {
|
|
21600
|
+
type: "number",
|
|
21601
|
+
description: "Process ID of the agent"
|
|
21602
|
+
},
|
|
21603
|
+
message: {
|
|
21604
|
+
type: "string",
|
|
21605
|
+
description: "Message to send to the agent"
|
|
21606
|
+
}
|
|
21607
|
+
},
|
|
21608
|
+
required: ["pid", "message"]
|
|
21609
|
+
}
|
|
21610
|
+
},
|
|
21611
|
+
{
|
|
21612
|
+
name: "list-agents",
|
|
21613
|
+
description: "List all agents in a working directory (live and historical)",
|
|
21614
|
+
inputSchema: {
|
|
21615
|
+
type: "object",
|
|
21616
|
+
properties: {
|
|
21617
|
+
cwd: {
|
|
21618
|
+
type: "string",
|
|
21619
|
+
description: "Working directory to list agents from (defaults to current directory)"
|
|
21620
|
+
}
|
|
21621
|
+
}
|
|
21622
|
+
}
|
|
21623
|
+
}
|
|
21624
|
+
];
|
|
21625
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
21626
|
+
tools
|
|
21627
|
+
}));
|
|
21628
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
21629
|
+
const { name, arguments: args } = request.params;
|
|
21630
|
+
try {
|
|
21631
|
+
switch (name) {
|
|
21632
|
+
case "spawn-agent":
|
|
21633
|
+
return await handleSpawnAgent(args);
|
|
21634
|
+
case "kill-agent":
|
|
21635
|
+
return await handleKillAgent(args);
|
|
21636
|
+
case "read-stdout":
|
|
21637
|
+
return await handleReadStdout(args);
|
|
21638
|
+
case "write-stdin":
|
|
21639
|
+
return await handleWriteStdin(args);
|
|
21640
|
+
case "list-agents":
|
|
21641
|
+
return await handleListAgents(args);
|
|
21642
|
+
default:
|
|
21643
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
21644
|
+
}
|
|
21645
|
+
} catch (error) {
|
|
21646
|
+
console.error(`[MCP] Error handling tool ${name}:`, error);
|
|
21647
|
+
return {
|
|
21648
|
+
content: [
|
|
21649
|
+
{
|
|
21650
|
+
type: "text",
|
|
21651
|
+
text: JSON.stringify({ error: error.message || String(error) })
|
|
21652
|
+
}
|
|
21653
|
+
]
|
|
21654
|
+
};
|
|
21655
|
+
}
|
|
21656
|
+
});
|
|
21657
|
+
const transport = new StdioServerTransport;
|
|
21658
|
+
await server.connect(transport);
|
|
21659
|
+
console.error("[agent-yes-mcp] Server started on stdio");
|
|
21660
|
+
}
|
|
21661
|
+
async function handleSpawnAgent(args) {
|
|
21662
|
+
const { cwd, cli, prompt } = args;
|
|
21663
|
+
if (!CLIS_CONFIG2[cli]) {
|
|
21664
|
+
throw new Error(`Unknown CLI: ${cli}. Available: ${Object.keys(CLIS_CONFIG2).join(", ")}`);
|
|
21665
|
+
}
|
|
21666
|
+
const cliConf = CLIS_CONFIG2[cli];
|
|
21667
|
+
const ptyOptions = {
|
|
21668
|
+
name: "xterm-color",
|
|
21669
|
+
...getTerminalDimensions(),
|
|
21670
|
+
cwd,
|
|
21671
|
+
env: { ...process.env, AGENT_YES_MCP: "true" }
|
|
21672
|
+
};
|
|
21673
|
+
const shell = spawnAgent({
|
|
21674
|
+
cli,
|
|
21675
|
+
cliConf,
|
|
21676
|
+
cliArgs: [],
|
|
21677
|
+
verbose: false,
|
|
21678
|
+
install: false,
|
|
21679
|
+
ptyOptions
|
|
21680
|
+
});
|
|
21681
|
+
const pidStore = new PidStore(cwd);
|
|
21682
|
+
await pidStore.init();
|
|
21683
|
+
try {
|
|
21684
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args: [], prompt, cwd });
|
|
21685
|
+
} catch (error) {
|
|
21686
|
+
console.error(`[MCP] Failed to register process ${shell.pid}:`, error);
|
|
21687
|
+
}
|
|
21688
|
+
const logPaths = await initializeLogPaths(pidStore, shell.pid);
|
|
21689
|
+
setupDebugLogging(logPaths.debuggingLogsPath);
|
|
21690
|
+
const ctx = new AgentContext({
|
|
21691
|
+
shell,
|
|
21692
|
+
pidStore,
|
|
21693
|
+
logPaths,
|
|
21694
|
+
cli,
|
|
21695
|
+
cliConf,
|
|
21696
|
+
verbose: false,
|
|
21697
|
+
robust: false
|
|
21698
|
+
});
|
|
21699
|
+
const pendingExitCode = Promise.withResolvers();
|
|
21700
|
+
const outputStream = src_default(createTerminatorStream(pendingExitCode.promise)).writable;
|
|
21701
|
+
const outputWriter = outputStream.getWriter();
|
|
21702
|
+
shell.onData(async (data) => {
|
|
21703
|
+
await outputWriter.write(data);
|
|
21704
|
+
globalAgentRegistry.appendStdout(shell.pid, data);
|
|
21705
|
+
});
|
|
21706
|
+
shell.onExit(async ({ exitCode }) => {
|
|
21707
|
+
globalAgentRegistry.unregister(shell.pid);
|
|
21708
|
+
try {
|
|
21709
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
21710
|
+
exitReason: exitCode === 0 ? "normal" : "crash",
|
|
21711
|
+
exitCode: exitCode ?? undefined
|
|
21712
|
+
});
|
|
21713
|
+
} catch (error) {
|
|
21714
|
+
console.error(`[MCP] Failed to update status for PID ${shell.pid}:`, error);
|
|
21715
|
+
}
|
|
21716
|
+
pendingExitCode.resolve(exitCode);
|
|
21717
|
+
});
|
|
21718
|
+
try {
|
|
21719
|
+
globalAgentRegistry.register(shell.pid, {
|
|
21720
|
+
pid: shell.pid,
|
|
21721
|
+
context: ctx,
|
|
21722
|
+
cwd,
|
|
21723
|
+
cli,
|
|
21724
|
+
prompt,
|
|
21725
|
+
startTime: Date.now(),
|
|
21726
|
+
stdoutBuffer: []
|
|
21727
|
+
});
|
|
21728
|
+
} catch (error) {
|
|
21729
|
+
console.error(`[MCP] Failed to register agent ${shell.pid} in registry:`, error);
|
|
21730
|
+
}
|
|
21731
|
+
if (prompt) {
|
|
21732
|
+
shell.write(prompt + `
|
|
21733
|
+
`);
|
|
21734
|
+
}
|
|
21735
|
+
return {
|
|
21736
|
+
content: [
|
|
21737
|
+
{
|
|
21738
|
+
type: "text",
|
|
21739
|
+
text: JSON.stringify({ pid: shell.pid, status: "spawned", cli, cwd })
|
|
21740
|
+
}
|
|
21741
|
+
]
|
|
21742
|
+
};
|
|
21743
|
+
}
|
|
21744
|
+
async function handleKillAgent(args) {
|
|
21745
|
+
const { pid } = args;
|
|
21746
|
+
const instance = globalAgentRegistry.get(pid);
|
|
21747
|
+
if (!instance) {
|
|
21748
|
+
return {
|
|
21749
|
+
content: [
|
|
21750
|
+
{
|
|
21751
|
+
type: "text",
|
|
21752
|
+
text: JSON.stringify({ status: "not_running", pid })
|
|
21753
|
+
}
|
|
21754
|
+
]
|
|
21755
|
+
};
|
|
21756
|
+
}
|
|
21757
|
+
instance.context.shell.kill("SIGTERM");
|
|
21758
|
+
globalAgentRegistry.unregister(pid);
|
|
21759
|
+
return {
|
|
21760
|
+
content: [{ type: "text", text: JSON.stringify({ status: "killed", pid }) }]
|
|
21761
|
+
};
|
|
21762
|
+
}
|
|
21763
|
+
async function handleReadStdout(args) {
|
|
21764
|
+
const { pid, tail = 100 } = args;
|
|
21765
|
+
const instance = globalAgentRegistry.get(pid);
|
|
21766
|
+
if (instance) {
|
|
21767
|
+
const lines2 = instance.stdoutBuffer.slice(-tail);
|
|
21768
|
+
return {
|
|
21769
|
+
content: [{ type: "text", text: lines2.join(`
|
|
21770
|
+
`) }]
|
|
21771
|
+
};
|
|
21772
|
+
}
|
|
21773
|
+
try {
|
|
21774
|
+
const possibleDirs = [process.cwd(), args.cwd || process.cwd()];
|
|
21775
|
+
for (const dir of possibleDirs) {
|
|
21776
|
+
const pidStore = new PidStore(dir);
|
|
21777
|
+
await pidStore.init();
|
|
21778
|
+
const record = pidStore.getAllRecords().find((r) => r.pid === pid);
|
|
21779
|
+
if (record && record.logFile) {
|
|
21780
|
+
const content = await readFile4(record.logFile, "utf8");
|
|
21781
|
+
const lines2 = content.split(`
|
|
21782
|
+
`);
|
|
21783
|
+
const tailedLines = lines2.slice(-tail);
|
|
21784
|
+
return {
|
|
21785
|
+
content: [{ type: "text", text: tailedLines.join(`
|
|
21786
|
+
`) }]
|
|
21787
|
+
};
|
|
21788
|
+
}
|
|
21789
|
+
}
|
|
21790
|
+
return {
|
|
21791
|
+
content: [{ type: "text", text: "" }]
|
|
21792
|
+
};
|
|
21793
|
+
} catch (error) {
|
|
21794
|
+
return {
|
|
21795
|
+
content: [
|
|
21796
|
+
{
|
|
21797
|
+
type: "text",
|
|
21798
|
+
text: JSON.stringify({ error: `Failed to read stdout: ${error.message}` })
|
|
21799
|
+
}
|
|
21800
|
+
]
|
|
21801
|
+
};
|
|
21802
|
+
}
|
|
21803
|
+
}
|
|
21804
|
+
async function handleWriteStdin(args) {
|
|
21805
|
+
const { pid, message } = args;
|
|
21806
|
+
const instance = globalAgentRegistry.get(pid);
|
|
21807
|
+
if (!instance) {
|
|
21808
|
+
return {
|
|
21809
|
+
content: [
|
|
21810
|
+
{
|
|
21811
|
+
type: "text",
|
|
21812
|
+
text: JSON.stringify({ error: `Agent with PID ${pid} not found (not running)` })
|
|
21813
|
+
}
|
|
21814
|
+
]
|
|
21815
|
+
};
|
|
21816
|
+
}
|
|
21817
|
+
try {
|
|
21818
|
+
await sendMessage3(instance.context.messageContext, message);
|
|
21819
|
+
return {
|
|
21820
|
+
content: [{ type: "text", text: JSON.stringify({ status: "sent", pid, message }) }]
|
|
21821
|
+
};
|
|
21822
|
+
} catch (error) {
|
|
21823
|
+
return {
|
|
21824
|
+
content: [
|
|
21825
|
+
{
|
|
21826
|
+
type: "text",
|
|
21827
|
+
text: JSON.stringify({ error: `Failed to send message: ${error.message}` })
|
|
21828
|
+
}
|
|
21829
|
+
]
|
|
21830
|
+
};
|
|
21831
|
+
}
|
|
21832
|
+
}
|
|
21833
|
+
async function handleListAgents(args) {
|
|
21834
|
+
const cwd = args.cwd || process.cwd();
|
|
21835
|
+
const liveAgents = globalAgentRegistry.list().filter((a2) => a2.cwd === cwd).map((a2) => ({
|
|
21836
|
+
pid: a2.pid,
|
|
21837
|
+
cli: a2.cli,
|
|
21838
|
+
cwd: a2.cwd,
|
|
21839
|
+
status: "running",
|
|
21840
|
+
startTime: a2.startTime,
|
|
21841
|
+
prompt: a2.prompt
|
|
21842
|
+
}));
|
|
21843
|
+
const pidStore = new PidStore(cwd);
|
|
21844
|
+
await pidStore.init();
|
|
21845
|
+
const dbAgents = pidStore.getAllRecords().filter((r) => r.cwd === cwd).map((r) => ({
|
|
21846
|
+
pid: r.pid,
|
|
21847
|
+
cli: r.cli,
|
|
21848
|
+
cwd: r.cwd,
|
|
21849
|
+
status: r.status,
|
|
21850
|
+
exitCode: r.exitCode,
|
|
21851
|
+
startTime: r.startedAt,
|
|
21852
|
+
prompt: r.prompt
|
|
21853
|
+
}));
|
|
21854
|
+
const allAgents = [...liveAgents];
|
|
21855
|
+
const livePids = new Set(liveAgents.map((a2) => a2.pid));
|
|
21856
|
+
for (const dbAgent of dbAgents) {
|
|
21857
|
+
if (!livePids.has(dbAgent.pid)) {
|
|
21858
|
+
allAgents.push(dbAgent);
|
|
21859
|
+
}
|
|
21860
|
+
}
|
|
21861
|
+
return {
|
|
21862
|
+
content: [{ type: "text", text: JSON.stringify({ agents: allAgents, cwd }) }]
|
|
21863
|
+
};
|
|
21864
|
+
}
|
|
21865
|
+
var CLIS_CONFIG2;
|
|
21866
|
+
var init_mcp_server = __esm(async () => {
|
|
21867
|
+
init_agentRegistry();
|
|
21868
|
+
init_pidStore();
|
|
21869
|
+
init_messaging();
|
|
21870
|
+
init_logging();
|
|
21871
|
+
init_context();
|
|
21872
|
+
init_dist4();
|
|
21873
|
+
await init_spawner();
|
|
21874
|
+
});
|
|
21875
|
+
|
|
21537
21876
|
// ts/index.ts
|
|
21538
21877
|
var exports_ts = {};
|
|
21539
21878
|
__export(exports_ts, {
|
|
21540
21879
|
removeControlCharacters: () => removeControlCharacters,
|
|
21541
21880
|
default: () => agentYes2,
|
|
21542
21881
|
config: () => config2,
|
|
21543
|
-
CLIS_CONFIG: () =>
|
|
21882
|
+
CLIS_CONFIG: () => CLIS_CONFIG3,
|
|
21883
|
+
AgentContext: () => AgentContext
|
|
21544
21884
|
});
|
|
21545
|
-
import {
|
|
21546
|
-
import { mkdir as mkdir9, readFile as
|
|
21885
|
+
import { fromWritable as fromWritable2 } from "from-node-stream";
|
|
21886
|
+
import { mkdir as mkdir9, readFile as readFile5, writeFile as writeFile8 } from "fs/promises";
|
|
21547
21887
|
import path15 from "path";
|
|
21548
21888
|
async function agentYes2({
|
|
21549
21889
|
cli,
|
|
@@ -21564,7 +21904,7 @@ async function agentYes2({
|
|
|
21564
21904
|
}) {
|
|
21565
21905
|
if (!cli)
|
|
21566
21906
|
throw new Error(`cli is required`);
|
|
21567
|
-
const conf =
|
|
21907
|
+
const conf = CLIS_CONFIG3[cli] || phpdie_default(`Unsupported cli tool: ${cli}, current process.argv: ${process.argv.join(" ")}`);
|
|
21568
21908
|
const workingDir = cwd ?? process.cwd();
|
|
21569
21909
|
if (queue) {
|
|
21570
21910
|
if (queue && shouldUseLock(workingDir)) {
|
|
@@ -21603,14 +21943,18 @@ async function agentYes2({
|
|
|
21603
21943
|
stdinFirstReady.ready();
|
|
21604
21944
|
});
|
|
21605
21945
|
const nextStdout = new ReadyManager;
|
|
21946
|
+
if (verbose)
|
|
21947
|
+
logger.debug(`[stdin] isTTY: ${process.stdin.isTTY}, setRawMode available: ${!!process.stdin.setRawMode}`);
|
|
21606
21948
|
process.stdin.setRawMode?.(true);
|
|
21949
|
+
if (verbose)
|
|
21950
|
+
logger.debug(`[stdin] Raw mode set, isRaw: ${process.stdin.isRaw}`);
|
|
21607
21951
|
const shellOutputStream = new TransformStream;
|
|
21608
21952
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
21609
21953
|
logger.debug(`Using ${ptyPackage} for pseudo terminal management.`);
|
|
21610
21954
|
const isSubAgent = !!process.env.CLAUDE_PPID;
|
|
21611
21955
|
if (isSubAgent)
|
|
21612
21956
|
logger.info(`[${cli}-yes] Running as sub-agent (CLAUDE_PPID=${process.env.CLAUDE_PPID})`);
|
|
21613
|
-
const cliConf =
|
|
21957
|
+
const cliConf = CLIS_CONFIG3[cli] || {};
|
|
21614
21958
|
cliArgs = cliConf.defaultArgs ? [...cliConf.defaultArgs, ...cliArgs] : cliArgs;
|
|
21615
21959
|
try {
|
|
21616
21960
|
const workingDir2 = cwd ?? process.cwd();
|
|
@@ -21630,7 +21974,7 @@ async function agentYes2({
|
|
|
21630
21974
|
const searchLimit = gitRoot || path15.parse(currentDir).root;
|
|
21631
21975
|
while (true) {
|
|
21632
21976
|
const skillPath = path15.resolve(currentDir, "SKILL.md");
|
|
21633
|
-
const md = await
|
|
21977
|
+
const md = await readFile5(skillPath, "utf8").catch(() => null);
|
|
21634
21978
|
if (md) {
|
|
21635
21979
|
const headerMatch = md.match(/^[\s\S]*?(?=\n##\s)/);
|
|
21636
21980
|
const headerRaw = (headerMatch ? headerMatch[0] : md).trim();
|
|
@@ -21708,7 +22052,7 @@ ${prompt}` : prefix;
|
|
|
21708
22052
|
const ptyEnv = { ...env2 ?? process.env };
|
|
21709
22053
|
const ptyOptions = {
|
|
21710
22054
|
name: "xterm-color",
|
|
21711
|
-
...
|
|
22055
|
+
...getTerminalDimensions2(),
|
|
21712
22056
|
cwd: cwd ?? process.cwd(),
|
|
21713
22057
|
env: ptyEnv
|
|
21714
22058
|
};
|
|
@@ -21720,7 +22064,11 @@ ${prompt}` : prefix;
|
|
|
21720
22064
|
install,
|
|
21721
22065
|
ptyOptions
|
|
21722
22066
|
});
|
|
21723
|
-
|
|
22067
|
+
try {
|
|
22068
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args: cliArgs, prompt, cwd: workingDir });
|
|
22069
|
+
} catch (error) {
|
|
22070
|
+
logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
|
|
22071
|
+
}
|
|
21724
22072
|
const logPaths = await initializeLogPaths(pidStore, shell.pid);
|
|
21725
22073
|
setupDebugLogging(logPaths.debuggingLogsPath);
|
|
21726
22074
|
const ctx = new AgentContext({
|
|
@@ -21732,6 +22080,19 @@ ${prompt}` : prefix;
|
|
|
21732
22080
|
verbose,
|
|
21733
22081
|
robust
|
|
21734
22082
|
});
|
|
22083
|
+
try {
|
|
22084
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22085
|
+
pid: shell.pid,
|
|
22086
|
+
context: ctx,
|
|
22087
|
+
cwd: workingDir,
|
|
22088
|
+
cli,
|
|
22089
|
+
prompt,
|
|
22090
|
+
startTime: Date.now(),
|
|
22091
|
+
stdoutBuffer: []
|
|
22092
|
+
});
|
|
22093
|
+
} catch (error) {
|
|
22094
|
+
logger.warn(`[agentRegistry] Failed to register agent ${shell.pid}:`, error);
|
|
22095
|
+
}
|
|
21735
22096
|
sleep3(1e4).then(() => {
|
|
21736
22097
|
if (!ctx.stdinReady.isReady)
|
|
21737
22098
|
ctx.stdinReady.ready();
|
|
@@ -21741,16 +22102,22 @@ ${prompt}` : prefix;
|
|
|
21741
22102
|
const pendingExitCode = Promise.withResolvers();
|
|
21742
22103
|
async function onData(data) {
|
|
21743
22104
|
await outputWriter.write(data);
|
|
22105
|
+
globalAgentRegistry.appendStdout(shell.pid, data);
|
|
21744
22106
|
}
|
|
21745
22107
|
shell.onData(onData);
|
|
21746
22108
|
shell.onExit(async function onExit2({ exitCode: exitCode2 }) {
|
|
22109
|
+
globalAgentRegistry.unregister(shell.pid);
|
|
21747
22110
|
ctx.stdinReady.unready();
|
|
21748
22111
|
const agentCrashed = exitCode2 !== 0;
|
|
21749
22112
|
if (ctx.shouldRestartWithoutContinue) {
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
|
|
21753
|
-
|
|
22113
|
+
try {
|
|
22114
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22115
|
+
exitReason: "restarted",
|
|
22116
|
+
exitCode: exitCode2 ?? undefined
|
|
22117
|
+
});
|
|
22118
|
+
} catch (error) {
|
|
22119
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22120
|
+
}
|
|
21754
22121
|
ctx.shouldRestartWithoutContinue = false;
|
|
21755
22122
|
ctx.isFatal = false;
|
|
21756
22123
|
const cliCommand = cliConf?.binary || cli;
|
|
@@ -21761,32 +22128,58 @@ ${prompt}` : prefix;
|
|
|
21761
22128
|
logger.info(`Restarting ${cli} ${JSON.stringify([bin, ...args])}`);
|
|
21762
22129
|
const restartPtyOptions = {
|
|
21763
22130
|
name: "xterm-color",
|
|
21764
|
-
...
|
|
22131
|
+
...getTerminalDimensions2(),
|
|
21765
22132
|
cwd: cwd ?? process.cwd(),
|
|
21766
22133
|
env: ptyEnv
|
|
21767
22134
|
};
|
|
21768
22135
|
shell = pty_default.spawn(bin, args, restartPtyOptions);
|
|
21769
|
-
|
|
22136
|
+
try {
|
|
22137
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args, prompt, cwd: workingDir });
|
|
22138
|
+
} catch (error) {
|
|
22139
|
+
logger.warn(`[pidStore] Failed to register restarted process ${shell.pid}:`, error);
|
|
22140
|
+
}
|
|
22141
|
+
ctx.shell = shell;
|
|
22142
|
+
try {
|
|
22143
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22144
|
+
pid: shell.pid,
|
|
22145
|
+
context: ctx,
|
|
22146
|
+
cwd: workingDir,
|
|
22147
|
+
cli,
|
|
22148
|
+
prompt,
|
|
22149
|
+
startTime: Date.now(),
|
|
22150
|
+
stdoutBuffer: []
|
|
22151
|
+
});
|
|
22152
|
+
} catch (error) {
|
|
22153
|
+
logger.warn(`[agentRegistry] Failed to register restarted agent ${shell.pid}:`, error);
|
|
22154
|
+
}
|
|
21770
22155
|
shell.onData(onData);
|
|
21771
22156
|
shell.onExit(onExit2);
|
|
21772
22157
|
return;
|
|
21773
22158
|
}
|
|
21774
22159
|
if (agentCrashed && robust && conf?.restoreArgs) {
|
|
21775
22160
|
if (!conf.restoreArgs) {
|
|
21776
|
-
logger.warn(`robust is only supported for ${Object.entries(
|
|
22161
|
+
logger.warn(`robust is only supported for ${Object.entries(CLIS_CONFIG3).filter(([_, v]) => v.restoreArgs).map(([k]) => k).join(", ")} currently, not ${cli}`);
|
|
21777
22162
|
return;
|
|
21778
22163
|
}
|
|
21779
22164
|
if (ctx.isFatal) {
|
|
22165
|
+
try {
|
|
22166
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22167
|
+
exitReason: "fatal",
|
|
22168
|
+
exitCode: exitCode2 ?? undefined
|
|
22169
|
+
});
|
|
22170
|
+
} catch (error) {
|
|
22171
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22172
|
+
}
|
|
22173
|
+
return pendingExitCode.resolve(exitCode2);
|
|
22174
|
+
}
|
|
22175
|
+
try {
|
|
21780
22176
|
await pidStore.updateStatus(shell.pid, "exited", {
|
|
21781
|
-
exitReason: "
|
|
22177
|
+
exitReason: "restarted",
|
|
21782
22178
|
exitCode: exitCode2 ?? undefined
|
|
21783
22179
|
});
|
|
21784
|
-
|
|
22180
|
+
} catch (error) {
|
|
22181
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
21785
22182
|
}
|
|
21786
|
-
await pidStore.updateStatus(shell.pid, "exited", {
|
|
21787
|
-
exitReason: "restarted",
|
|
21788
|
-
exitCode: exitCode2 ?? undefined
|
|
21789
|
-
});
|
|
21790
22183
|
logger.info(`${cli} crashed, restarting...`);
|
|
21791
22184
|
let restoreArgs = conf.restoreArgs;
|
|
21792
22185
|
if (cli === "codex") {
|
|
@@ -21800,45 +22193,155 @@ ${prompt}` : prefix;
|
|
|
21800
22193
|
}
|
|
21801
22194
|
const restorePtyOptions = {
|
|
21802
22195
|
name: "xterm-color",
|
|
21803
|
-
...
|
|
22196
|
+
...getTerminalDimensions2(),
|
|
21804
22197
|
cwd: cwd ?? process.cwd(),
|
|
21805
22198
|
env: ptyEnv
|
|
21806
22199
|
};
|
|
21807
22200
|
shell = pty_default.spawn(cli, restoreArgs, restorePtyOptions);
|
|
21808
|
-
|
|
22201
|
+
try {
|
|
22202
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args: restoreArgs, prompt, cwd: workingDir });
|
|
22203
|
+
} catch (error) {
|
|
22204
|
+
logger.warn(`[pidStore] Failed to register restored process ${shell.pid}:`, error);
|
|
22205
|
+
}
|
|
22206
|
+
ctx.shell = shell;
|
|
22207
|
+
try {
|
|
22208
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22209
|
+
pid: shell.pid,
|
|
22210
|
+
context: ctx,
|
|
22211
|
+
cwd: workingDir,
|
|
22212
|
+
cli,
|
|
22213
|
+
prompt,
|
|
22214
|
+
startTime: Date.now(),
|
|
22215
|
+
stdoutBuffer: []
|
|
22216
|
+
});
|
|
22217
|
+
} catch (error) {
|
|
22218
|
+
logger.warn(`[agentRegistry] Failed to register restored agent ${shell.pid}:`, error);
|
|
22219
|
+
}
|
|
21809
22220
|
shell.onData(onData);
|
|
21810
22221
|
shell.onExit(onExit2);
|
|
21811
22222
|
return;
|
|
21812
22223
|
}
|
|
21813
22224
|
const exitReason = agentCrashed ? "crash" : "normal";
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
22225
|
+
try {
|
|
22226
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22227
|
+
exitReason,
|
|
22228
|
+
exitCode: exitCode2 ?? undefined
|
|
22229
|
+
});
|
|
22230
|
+
} catch (error) {
|
|
22231
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22232
|
+
}
|
|
21818
22233
|
return pendingExitCode.resolve(exitCode2);
|
|
21819
22234
|
});
|
|
21820
22235
|
process.stdout.on("resize", () => {
|
|
21821
|
-
const { cols, rows } =
|
|
22236
|
+
const { cols, rows } = getTerminalDimensions2();
|
|
21822
22237
|
shell.resize(cols, rows);
|
|
21823
22238
|
});
|
|
21824
22239
|
const terminalRender = new TerminalTextRender;
|
|
21825
|
-
const isStillWorkingQ = () =>
|
|
22240
|
+
const isStillWorkingQ = () => {
|
|
22241
|
+
const rendered = terminalRender.tail(24).replace(/\s+/g, " ");
|
|
22242
|
+
return conf.working?.some((rgx) => rgx.test(rendered));
|
|
22243
|
+
};
|
|
22244
|
+
let lastHeartbeatRendered = "";
|
|
22245
|
+
const heartbeatInterval = setInterval(async () => {
|
|
22246
|
+
try {
|
|
22247
|
+
const rendered = removeControlCharacters(terminalRender.tail(12));
|
|
22248
|
+
if (rendered === lastHeartbeatRendered)
|
|
22249
|
+
return;
|
|
22250
|
+
lastHeartbeatRendered = rendered;
|
|
22251
|
+
const lines2 = rendered.split(`
|
|
22252
|
+
`).filter((line) => line.trim());
|
|
22253
|
+
for (const line of lines2) {
|
|
22254
|
+
if (conf.ready?.some((rx) => rx.test(line))) {
|
|
22255
|
+
logger.debug(`heartbeat|ready |${line}`);
|
|
22256
|
+
ctx.stdinReady.ready();
|
|
22257
|
+
ctx.stdinFirstReady.ready();
|
|
22258
|
+
}
|
|
22259
|
+
if (conf.enter?.some((rx) => rx.test(line))) {
|
|
22260
|
+
logger.debug(`heartbeat|sendEnter matched|${line}`);
|
|
22261
|
+
await sendEnter(ctx.messageContext, 400);
|
|
22262
|
+
continue;
|
|
22263
|
+
}
|
|
22264
|
+
const typeingRespondMatched = Object.entries(conf.typingRespond ?? {}).filter(([_sendString, onThePatterns]) => onThePatterns.some((rx) => rx.test(line)));
|
|
22265
|
+
if (typeingRespondMatched.length) {
|
|
22266
|
+
await src_default(typeingRespondMatched).map(async ([sendString]) => await sendMessage3(ctx.messageContext, sendString, { waitForReady: false })).toCount();
|
|
22267
|
+
continue;
|
|
22268
|
+
}
|
|
22269
|
+
if (conf.fatal?.some((rx) => rx.test(line))) {
|
|
22270
|
+
logger.debug(`heartbeat|fatal |${line}`);
|
|
22271
|
+
ctx.isFatal = true;
|
|
22272
|
+
await exitAgent();
|
|
22273
|
+
break;
|
|
22274
|
+
}
|
|
22275
|
+
if (conf.restartWithoutContinueArg?.some((rx) => rx.test(line))) {
|
|
22276
|
+
logger.debug(`heartbeat|restart-without-continue|${line}`);
|
|
22277
|
+
ctx.shouldRestartWithoutContinue = true;
|
|
22278
|
+
ctx.isFatal = true;
|
|
22279
|
+
await exitAgent();
|
|
22280
|
+
break;
|
|
22281
|
+
}
|
|
22282
|
+
if (cli === "codex") {
|
|
22283
|
+
const sessionId = extractSessionId(line);
|
|
22284
|
+
if (sessionId) {
|
|
22285
|
+
logger.debug(`heartbeat|session|captured session ID: ${sessionId}`);
|
|
22286
|
+
await storeSessionForCwd(workingDir, sessionId);
|
|
22287
|
+
}
|
|
22288
|
+
}
|
|
22289
|
+
}
|
|
22290
|
+
} catch (error) {
|
|
22291
|
+
logger.debug(`heartbeat|error: ${error}`);
|
|
22292
|
+
}
|
|
22293
|
+
}, 800);
|
|
22294
|
+
const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
|
|
22295
|
+
shell.onExit(cleanupHeartbeat);
|
|
21826
22296
|
if (exitOnIdle)
|
|
21827
22297
|
ctx.idleWaiter.wait(exitOnIdle).then(async () => {
|
|
21828
22298
|
await pidStore.updateStatus(shell.pid, "idle").catch(() => null);
|
|
21829
22299
|
if (isStillWorkingQ()) {
|
|
21830
|
-
logger.warn(
|
|
22300
|
+
logger.warn(`[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet`);
|
|
21831
22301
|
return;
|
|
21832
22302
|
}
|
|
21833
|
-
logger.info(
|
|
22303
|
+
logger.info(`[${cli}-yes] ${cli} is idle, exiting...`);
|
|
21834
22304
|
await exitAgent();
|
|
21835
22305
|
});
|
|
21836
|
-
|
|
21837
|
-
|
|
22306
|
+
const stdinStream = new ReadableStream({
|
|
22307
|
+
start(controller) {
|
|
22308
|
+
process.stdin.resume();
|
|
22309
|
+
const dataHandler = (chunk) => {
|
|
22310
|
+
try {
|
|
22311
|
+
controller.enqueue(chunk);
|
|
22312
|
+
} catch (err) {}
|
|
22313
|
+
};
|
|
22314
|
+
const endHandler = () => {
|
|
22315
|
+
controller.close();
|
|
22316
|
+
};
|
|
22317
|
+
const errorHandler = (err) => {
|
|
22318
|
+
controller.error(err);
|
|
22319
|
+
};
|
|
22320
|
+
process.stdin.on("data", dataHandler);
|
|
22321
|
+
process.stdin.on("end", endHandler);
|
|
22322
|
+
process.stdin.on("close", endHandler);
|
|
22323
|
+
process.stdin.on("error", errorHandler);
|
|
22324
|
+
},
|
|
22325
|
+
cancel(reason) {
|
|
22326
|
+
process.stdin.pause();
|
|
22327
|
+
}
|
|
22328
|
+
});
|
|
22329
|
+
let aborted2 = false;
|
|
22330
|
+
await src_default(stdinStream).map((buffer2) => {
|
|
22331
|
+
const str = buffer2.toString();
|
|
22332
|
+
const CTRL_Z = "\x1A";
|
|
22333
|
+
const CTRL_C = "\x03";
|
|
22334
|
+
if (!aborted2 && str === CTRL_Z) {
|
|
22335
|
+
return "";
|
|
22336
|
+
}
|
|
22337
|
+
if (!aborted2 && !ctx.stdinReady.isReady && str === CTRL_C) {
|
|
22338
|
+
logger.error("User aborted: SIGINT");
|
|
21838
22339
|
shell.kill("SIGINT");
|
|
21839
|
-
pendingExitCode.resolve(
|
|
21840
|
-
|
|
21841
|
-
|
|
22340
|
+
pendingExitCode.resolve(130);
|
|
22341
|
+
aborted2 = true;
|
|
22342
|
+
return str;
|
|
22343
|
+
}
|
|
22344
|
+
return str;
|
|
21842
22345
|
}).onStart(async function promptOnStart() {
|
|
21843
22346
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21844
22347
|
if (prompt)
|
|
@@ -21866,15 +22369,62 @@ ${prompt}` : prefix;
|
|
|
21866
22369
|
}).run();
|
|
21867
22370
|
}).catch(() => f.run());
|
|
21868
22371
|
}).by(function consoleResponder(e) {
|
|
21869
|
-
|
|
21870
|
-
|
|
21871
|
-
|
|
21872
|
-
|
|
21873
|
-
|
|
21874
|
-
|
|
21875
|
-
|
|
21876
|
-
|
|
21877
|
-
|
|
22372
|
+
let lastRendered = "";
|
|
22373
|
+
return e.forEach((chunk) => {
|
|
22374
|
+
terminalRender.write(chunk);
|
|
22375
|
+
if (chunk.includes("\x1B[c") || chunk.includes("\x1B[0c")) {
|
|
22376
|
+
shell.write("\x1B[?1;2c");
|
|
22377
|
+
if (verbose) {
|
|
22378
|
+
logger.debug("device|respond DA: VT100 with Advanced Video Option");
|
|
22379
|
+
}
|
|
22380
|
+
return;
|
|
22381
|
+
}
|
|
22382
|
+
if (process.stdin.isTTY)
|
|
22383
|
+
return;
|
|
22384
|
+
if (!chunk.includes("\x1B[6n"))
|
|
22385
|
+
return;
|
|
22386
|
+
const { col, row } = terminalRender.getCursorPosition();
|
|
22387
|
+
shell.write(`\x1B[${row};${col}R`);
|
|
22388
|
+
logger.debug(`cursor|respond position: row=${String(row)}, col=${String(col)}`);
|
|
22389
|
+
}).forEach(async (line, lineIndex) => {
|
|
22390
|
+
const rendered = terminalRender.tail(24);
|
|
22391
|
+
if (rendered === lastRendered)
|
|
22392
|
+
return;
|
|
22393
|
+
logger.debug(`stdout|${line}`);
|
|
22394
|
+
if (conf.ready?.some((rx) => line.match(rx))) {
|
|
22395
|
+
logger.debug(`ready |${line}`);
|
|
22396
|
+
if (cli === "gemini" && lineIndex <= 80)
|
|
22397
|
+
return;
|
|
22398
|
+
ctx.stdinReady.ready();
|
|
22399
|
+
ctx.stdinFirstReady.ready();
|
|
22400
|
+
}
|
|
22401
|
+
if (conf.enter?.some((rx) => line.match(rx))) {
|
|
22402
|
+
logger.debug(`sendEnter matched|${line}`);
|
|
22403
|
+
return await sendEnter(ctx.messageContext, 400);
|
|
22404
|
+
}
|
|
22405
|
+
const typeingRespondMatched = Object.entries(conf.typingRespond ?? {}).filter(([_sendString, onThePatterns]) => onThePatterns.some((rx) => line.match(rx)));
|
|
22406
|
+
const typingResponded = typeingRespondMatched.length && await src_default(typeingRespondMatched).map(async ([sendString]) => await sendMessage3(ctx.messageContext, sendString, { waitForReady: false })).toCount();
|
|
22407
|
+
if (typingResponded)
|
|
22408
|
+
return;
|
|
22409
|
+
if (conf.fatal?.some((rx) => line.match(rx))) {
|
|
22410
|
+
logger.debug(`fatal |${line}`);
|
|
22411
|
+
ctx.isFatal = true;
|
|
22412
|
+
await exitAgent();
|
|
22413
|
+
}
|
|
22414
|
+
if (conf.restartWithoutContinueArg?.some((rx) => line.match(rx))) {
|
|
22415
|
+
logger.debug(`restart-without-continue|${line}`);
|
|
22416
|
+
ctx.shouldRestartWithoutContinue = true;
|
|
22417
|
+
ctx.isFatal = true;
|
|
22418
|
+
await exitAgent();
|
|
22419
|
+
}
|
|
22420
|
+
if (cli === "codex") {
|
|
22421
|
+
const sessionId = extractSessionId(line);
|
|
22422
|
+
if (sessionId) {
|
|
22423
|
+
logger.debug(`session|captured session ID: ${sessionId}`);
|
|
22424
|
+
await storeSessionForCwd(workingDir, sessionId);
|
|
22425
|
+
}
|
|
22426
|
+
}
|
|
22427
|
+
});
|
|
21878
22428
|
}).by((s) => removeControlCharactersFromStdout ? s.map((e) => removeControlCharacters(e)) : s).by(createTerminatorStream(pendingExitCode.promise)).to(fromWritable2(process.stdout));
|
|
21879
22429
|
await saveLogFile(ctx.logPaths.logPath, terminalRender.render());
|
|
21880
22430
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21898,7 +22448,7 @@ ${prompt}` : prefix;
|
|
|
21898
22448
|
}, 5000))
|
|
21899
22449
|
]);
|
|
21900
22450
|
}
|
|
21901
|
-
function
|
|
22451
|
+
function getTerminalDimensions2() {
|
|
21902
22452
|
if (!process.stdout.isTTY)
|
|
21903
22453
|
return { cols: 80, rows: 24 };
|
|
21904
22454
|
return {
|
|
@@ -21910,7 +22460,7 @@ ${prompt}` : prefix;
|
|
|
21910
22460
|
function sleep3(ms2) {
|
|
21911
22461
|
return new Promise((resolve5) => setTimeout(resolve5, ms2));
|
|
21912
22462
|
}
|
|
21913
|
-
var config2,
|
|
22463
|
+
var config2, CLIS_CONFIG3;
|
|
21914
22464
|
var init_ts = __esm(async () => {
|
|
21915
22465
|
init_execa();
|
|
21916
22466
|
init_dist();
|
|
@@ -21923,14 +22473,13 @@ var init_ts = __esm(async () => {
|
|
|
21923
22473
|
init_messaging();
|
|
21924
22474
|
init_logging();
|
|
21925
22475
|
init_context();
|
|
21926
|
-
|
|
21927
|
-
init_streamHelpers();
|
|
22476
|
+
init_agentRegistry();
|
|
21928
22477
|
await __promiseAll([
|
|
21929
22478
|
init_pty(),
|
|
21930
22479
|
init_spawner()
|
|
21931
22480
|
]);
|
|
21932
22481
|
config2 = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21933
|
-
|
|
22482
|
+
CLIS_CONFIG3 = config2.clis;
|
|
21934
22483
|
});
|
|
21935
22484
|
|
|
21936
22485
|
// ts/index.ts
|
|
@@ -21945,13 +22494,12 @@ init_pidStore();
|
|
|
21945
22494
|
init_messaging();
|
|
21946
22495
|
init_logging();
|
|
21947
22496
|
init_context();
|
|
21948
|
-
|
|
21949
|
-
init_streamHelpers();
|
|
22497
|
+
init_agentRegistry();
|
|
21950
22498
|
await __promiseAll([
|
|
21951
22499
|
init_pty(),
|
|
21952
22500
|
init_spawner()
|
|
21953
22501
|
]);
|
|
21954
|
-
import {
|
|
22502
|
+
import { fromWritable } from "from-node-stream";
|
|
21955
22503
|
import { mkdir as mkdir7, readFile as readFile3, writeFile as writeFile5 } from "fs/promises";
|
|
21956
22504
|
import path13 from "path";
|
|
21957
22505
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
@@ -22014,7 +22562,11 @@ async function agentYes({
|
|
|
22014
22562
|
stdinFirstReady.ready();
|
|
22015
22563
|
});
|
|
22016
22564
|
const nextStdout = new ReadyManager;
|
|
22565
|
+
if (verbose)
|
|
22566
|
+
logger.debug(`[stdin] isTTY: ${process.stdin.isTTY}, setRawMode available: ${!!process.stdin.setRawMode}`);
|
|
22017
22567
|
process.stdin.setRawMode?.(true);
|
|
22568
|
+
if (verbose)
|
|
22569
|
+
logger.debug(`[stdin] Raw mode set, isRaw: ${process.stdin.isRaw}`);
|
|
22018
22570
|
const shellOutputStream = new TransformStream;
|
|
22019
22571
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
22020
22572
|
logger.debug(`Using ${ptyPackage} for pseudo terminal management.`);
|
|
@@ -22131,7 +22683,11 @@ ${prompt}` : prefix;
|
|
|
22131
22683
|
install,
|
|
22132
22684
|
ptyOptions
|
|
22133
22685
|
});
|
|
22134
|
-
|
|
22686
|
+
try {
|
|
22687
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args: cliArgs, prompt, cwd: workingDir });
|
|
22688
|
+
} catch (error) {
|
|
22689
|
+
logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
|
|
22690
|
+
}
|
|
22135
22691
|
const logPaths = await initializeLogPaths(pidStore, shell.pid);
|
|
22136
22692
|
setupDebugLogging(logPaths.debuggingLogsPath);
|
|
22137
22693
|
const ctx = new AgentContext({
|
|
@@ -22143,6 +22699,19 @@ ${prompt}` : prefix;
|
|
|
22143
22699
|
verbose,
|
|
22144
22700
|
robust
|
|
22145
22701
|
});
|
|
22702
|
+
try {
|
|
22703
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22704
|
+
pid: shell.pid,
|
|
22705
|
+
context: ctx,
|
|
22706
|
+
cwd: workingDir,
|
|
22707
|
+
cli,
|
|
22708
|
+
prompt,
|
|
22709
|
+
startTime: Date.now(),
|
|
22710
|
+
stdoutBuffer: []
|
|
22711
|
+
});
|
|
22712
|
+
} catch (error) {
|
|
22713
|
+
logger.warn(`[agentRegistry] Failed to register agent ${shell.pid}:`, error);
|
|
22714
|
+
}
|
|
22146
22715
|
sleep2(1e4).then(() => {
|
|
22147
22716
|
if (!ctx.stdinReady.isReady)
|
|
22148
22717
|
ctx.stdinReady.ready();
|
|
@@ -22152,16 +22721,22 @@ ${prompt}` : prefix;
|
|
|
22152
22721
|
const pendingExitCode = Promise.withResolvers();
|
|
22153
22722
|
async function onData(data) {
|
|
22154
22723
|
await outputWriter.write(data);
|
|
22724
|
+
globalAgentRegistry.appendStdout(shell.pid, data);
|
|
22155
22725
|
}
|
|
22156
22726
|
shell.onData(onData);
|
|
22157
22727
|
shell.onExit(async function onExit2({ exitCode: exitCode2 }) {
|
|
22728
|
+
globalAgentRegistry.unregister(shell.pid);
|
|
22158
22729
|
ctx.stdinReady.unready();
|
|
22159
22730
|
const agentCrashed = exitCode2 !== 0;
|
|
22160
22731
|
if (ctx.shouldRestartWithoutContinue) {
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22732
|
+
try {
|
|
22733
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22734
|
+
exitReason: "restarted",
|
|
22735
|
+
exitCode: exitCode2 ?? undefined
|
|
22736
|
+
});
|
|
22737
|
+
} catch (error) {
|
|
22738
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22739
|
+
}
|
|
22165
22740
|
ctx.shouldRestartWithoutContinue = false;
|
|
22166
22741
|
ctx.isFatal = false;
|
|
22167
22742
|
const cliCommand = cliConf?.binary || cli;
|
|
@@ -22177,7 +22752,25 @@ ${prompt}` : prefix;
|
|
|
22177
22752
|
env: ptyEnv
|
|
22178
22753
|
};
|
|
22179
22754
|
shell = pty_default.spawn(bin, args, restartPtyOptions);
|
|
22180
|
-
|
|
22755
|
+
try {
|
|
22756
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args, prompt, cwd: workingDir });
|
|
22757
|
+
} catch (error) {
|
|
22758
|
+
logger.warn(`[pidStore] Failed to register restarted process ${shell.pid}:`, error);
|
|
22759
|
+
}
|
|
22760
|
+
ctx.shell = shell;
|
|
22761
|
+
try {
|
|
22762
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22763
|
+
pid: shell.pid,
|
|
22764
|
+
context: ctx,
|
|
22765
|
+
cwd: workingDir,
|
|
22766
|
+
cli,
|
|
22767
|
+
prompt,
|
|
22768
|
+
startTime: Date.now(),
|
|
22769
|
+
stdoutBuffer: []
|
|
22770
|
+
});
|
|
22771
|
+
} catch (error) {
|
|
22772
|
+
logger.warn(`[agentRegistry] Failed to register restarted agent ${shell.pid}:`, error);
|
|
22773
|
+
}
|
|
22181
22774
|
shell.onData(onData);
|
|
22182
22775
|
shell.onExit(onExit2);
|
|
22183
22776
|
return;
|
|
@@ -22188,16 +22781,24 @@ ${prompt}` : prefix;
|
|
|
22188
22781
|
return;
|
|
22189
22782
|
}
|
|
22190
22783
|
if (ctx.isFatal) {
|
|
22784
|
+
try {
|
|
22785
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22786
|
+
exitReason: "fatal",
|
|
22787
|
+
exitCode: exitCode2 ?? undefined
|
|
22788
|
+
});
|
|
22789
|
+
} catch (error) {
|
|
22790
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22791
|
+
}
|
|
22792
|
+
return pendingExitCode.resolve(exitCode2);
|
|
22793
|
+
}
|
|
22794
|
+
try {
|
|
22191
22795
|
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22192
|
-
exitReason: "
|
|
22796
|
+
exitReason: "restarted",
|
|
22193
22797
|
exitCode: exitCode2 ?? undefined
|
|
22194
22798
|
});
|
|
22195
|
-
|
|
22799
|
+
} catch (error) {
|
|
22800
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22196
22801
|
}
|
|
22197
|
-
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22198
|
-
exitReason: "restarted",
|
|
22199
|
-
exitCode: exitCode2 ?? undefined
|
|
22200
|
-
});
|
|
22201
22802
|
logger.info(`${cli} crashed, restarting...`);
|
|
22202
22803
|
let restoreArgs = conf.restoreArgs;
|
|
22203
22804
|
if (cli === "codex") {
|
|
@@ -22216,16 +22817,38 @@ ${prompt}` : prefix;
|
|
|
22216
22817
|
env: ptyEnv
|
|
22217
22818
|
};
|
|
22218
22819
|
shell = pty_default.spawn(cli, restoreArgs, restorePtyOptions);
|
|
22219
|
-
|
|
22820
|
+
try {
|
|
22821
|
+
await pidStore.registerProcess({ pid: shell.pid, cli, args: restoreArgs, prompt, cwd: workingDir });
|
|
22822
|
+
} catch (error) {
|
|
22823
|
+
logger.warn(`[pidStore] Failed to register restored process ${shell.pid}:`, error);
|
|
22824
|
+
}
|
|
22825
|
+
ctx.shell = shell;
|
|
22826
|
+
try {
|
|
22827
|
+
globalAgentRegistry.register(shell.pid, {
|
|
22828
|
+
pid: shell.pid,
|
|
22829
|
+
context: ctx,
|
|
22830
|
+
cwd: workingDir,
|
|
22831
|
+
cli,
|
|
22832
|
+
prompt,
|
|
22833
|
+
startTime: Date.now(),
|
|
22834
|
+
stdoutBuffer: []
|
|
22835
|
+
});
|
|
22836
|
+
} catch (error) {
|
|
22837
|
+
logger.warn(`[agentRegistry] Failed to register restored agent ${shell.pid}:`, error);
|
|
22838
|
+
}
|
|
22220
22839
|
shell.onData(onData);
|
|
22221
22840
|
shell.onExit(onExit2);
|
|
22222
22841
|
return;
|
|
22223
22842
|
}
|
|
22224
22843
|
const exitReason = agentCrashed ? "crash" : "normal";
|
|
22225
|
-
|
|
22226
|
-
|
|
22227
|
-
|
|
22228
|
-
|
|
22844
|
+
try {
|
|
22845
|
+
await pidStore.updateStatus(shell.pid, "exited", {
|
|
22846
|
+
exitReason,
|
|
22847
|
+
exitCode: exitCode2 ?? undefined
|
|
22848
|
+
});
|
|
22849
|
+
} catch (error) {
|
|
22850
|
+
logger.warn(`[pidStore] Failed to update status for PID ${shell.pid}:`, error);
|
|
22851
|
+
}
|
|
22229
22852
|
return pendingExitCode.resolve(exitCode2);
|
|
22230
22853
|
});
|
|
22231
22854
|
process.stdout.on("resize", () => {
|
|
@@ -22233,23 +22856,111 @@ ${prompt}` : prefix;
|
|
|
22233
22856
|
shell.resize(cols, rows);
|
|
22234
22857
|
});
|
|
22235
22858
|
const terminalRender = new TerminalTextRender;
|
|
22236
|
-
const isStillWorkingQ = () =>
|
|
22859
|
+
const isStillWorkingQ = () => {
|
|
22860
|
+
const rendered = terminalRender.tail(24).replace(/\s+/g, " ");
|
|
22861
|
+
return conf.working?.some((rgx) => rgx.test(rendered));
|
|
22862
|
+
};
|
|
22863
|
+
let lastHeartbeatRendered = "";
|
|
22864
|
+
const heartbeatInterval = setInterval(async () => {
|
|
22865
|
+
try {
|
|
22866
|
+
const rendered = removeControlCharacters(terminalRender.tail(12));
|
|
22867
|
+
if (rendered === lastHeartbeatRendered)
|
|
22868
|
+
return;
|
|
22869
|
+
lastHeartbeatRendered = rendered;
|
|
22870
|
+
const lines2 = rendered.split(`
|
|
22871
|
+
`).filter((line) => line.trim());
|
|
22872
|
+
for (const line of lines2) {
|
|
22873
|
+
if (conf.ready?.some((rx) => rx.test(line))) {
|
|
22874
|
+
logger.debug(`heartbeat|ready |${line}`);
|
|
22875
|
+
ctx.stdinReady.ready();
|
|
22876
|
+
ctx.stdinFirstReady.ready();
|
|
22877
|
+
}
|
|
22878
|
+
if (conf.enter?.some((rx) => rx.test(line))) {
|
|
22879
|
+
logger.debug(`heartbeat|sendEnter matched|${line}`);
|
|
22880
|
+
await sendEnter(ctx.messageContext, 400);
|
|
22881
|
+
continue;
|
|
22882
|
+
}
|
|
22883
|
+
const typeingRespondMatched = Object.entries(conf.typingRespond ?? {}).filter(([_sendString, onThePatterns]) => onThePatterns.some((rx) => rx.test(line)));
|
|
22884
|
+
if (typeingRespondMatched.length) {
|
|
22885
|
+
await src_default(typeingRespondMatched).map(async ([sendString]) => await sendMessage3(ctx.messageContext, sendString, { waitForReady: false })).toCount();
|
|
22886
|
+
continue;
|
|
22887
|
+
}
|
|
22888
|
+
if (conf.fatal?.some((rx) => rx.test(line))) {
|
|
22889
|
+
logger.debug(`heartbeat|fatal |${line}`);
|
|
22890
|
+
ctx.isFatal = true;
|
|
22891
|
+
await exitAgent();
|
|
22892
|
+
break;
|
|
22893
|
+
}
|
|
22894
|
+
if (conf.restartWithoutContinueArg?.some((rx) => rx.test(line))) {
|
|
22895
|
+
logger.debug(`heartbeat|restart-without-continue|${line}`);
|
|
22896
|
+
ctx.shouldRestartWithoutContinue = true;
|
|
22897
|
+
ctx.isFatal = true;
|
|
22898
|
+
await exitAgent();
|
|
22899
|
+
break;
|
|
22900
|
+
}
|
|
22901
|
+
if (cli === "codex") {
|
|
22902
|
+
const sessionId = extractSessionId(line);
|
|
22903
|
+
if (sessionId) {
|
|
22904
|
+
logger.debug(`heartbeat|session|captured session ID: ${sessionId}`);
|
|
22905
|
+
await storeSessionForCwd(workingDir, sessionId);
|
|
22906
|
+
}
|
|
22907
|
+
}
|
|
22908
|
+
}
|
|
22909
|
+
} catch (error) {
|
|
22910
|
+
logger.debug(`heartbeat|error: ${error}`);
|
|
22911
|
+
}
|
|
22912
|
+
}, 800);
|
|
22913
|
+
const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
|
|
22914
|
+
shell.onExit(cleanupHeartbeat);
|
|
22237
22915
|
if (exitOnIdle)
|
|
22238
22916
|
ctx.idleWaiter.wait(exitOnIdle).then(async () => {
|
|
22239
22917
|
await pidStore.updateStatus(shell.pid, "idle").catch(() => null);
|
|
22240
22918
|
if (isStillWorkingQ()) {
|
|
22241
|
-
logger.warn(
|
|
22919
|
+
logger.warn(`[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet`);
|
|
22242
22920
|
return;
|
|
22243
22921
|
}
|
|
22244
|
-
logger.info(
|
|
22922
|
+
logger.info(`[${cli}-yes] ${cli} is idle, exiting...`);
|
|
22245
22923
|
await exitAgent();
|
|
22246
22924
|
});
|
|
22247
|
-
|
|
22248
|
-
|
|
22925
|
+
const stdinStream = new ReadableStream({
|
|
22926
|
+
start(controller) {
|
|
22927
|
+
process.stdin.resume();
|
|
22928
|
+
const dataHandler = (chunk) => {
|
|
22929
|
+
try {
|
|
22930
|
+
controller.enqueue(chunk);
|
|
22931
|
+
} catch (err) {}
|
|
22932
|
+
};
|
|
22933
|
+
const endHandler = () => {
|
|
22934
|
+
controller.close();
|
|
22935
|
+
};
|
|
22936
|
+
const errorHandler = (err) => {
|
|
22937
|
+
controller.error(err);
|
|
22938
|
+
};
|
|
22939
|
+
process.stdin.on("data", dataHandler);
|
|
22940
|
+
process.stdin.on("end", endHandler);
|
|
22941
|
+
process.stdin.on("close", endHandler);
|
|
22942
|
+
process.stdin.on("error", errorHandler);
|
|
22943
|
+
},
|
|
22944
|
+
cancel(reason) {
|
|
22945
|
+
process.stdin.pause();
|
|
22946
|
+
}
|
|
22947
|
+
});
|
|
22948
|
+
let aborted2 = false;
|
|
22949
|
+
await src_default(stdinStream).map((buffer2) => {
|
|
22950
|
+
const str = buffer2.toString();
|
|
22951
|
+
const CTRL_Z = "\x1A";
|
|
22952
|
+
const CTRL_C = "\x03";
|
|
22953
|
+
if (!aborted2 && str === CTRL_Z) {
|
|
22954
|
+
return "";
|
|
22955
|
+
}
|
|
22956
|
+
if (!aborted2 && !ctx.stdinReady.isReady && str === CTRL_C) {
|
|
22957
|
+
logger.error("User aborted: SIGINT");
|
|
22249
22958
|
shell.kill("SIGINT");
|
|
22250
|
-
pendingExitCode.resolve(
|
|
22251
|
-
|
|
22252
|
-
|
|
22959
|
+
pendingExitCode.resolve(130);
|
|
22960
|
+
aborted2 = true;
|
|
22961
|
+
return str;
|
|
22962
|
+
}
|
|
22963
|
+
return str;
|
|
22253
22964
|
}).onStart(async function promptOnStart() {
|
|
22254
22965
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
22255
22966
|
if (prompt)
|
|
@@ -22277,15 +22988,62 @@ ${prompt}` : prefix;
|
|
|
22277
22988
|
}).run();
|
|
22278
22989
|
}).catch(() => f.run());
|
|
22279
22990
|
}).by(function consoleResponder(e) {
|
|
22280
|
-
|
|
22281
|
-
|
|
22282
|
-
|
|
22283
|
-
|
|
22284
|
-
|
|
22285
|
-
|
|
22286
|
-
|
|
22287
|
-
|
|
22288
|
-
|
|
22991
|
+
let lastRendered = "";
|
|
22992
|
+
return e.forEach((chunk) => {
|
|
22993
|
+
terminalRender.write(chunk);
|
|
22994
|
+
if (chunk.includes("\x1B[c") || chunk.includes("\x1B[0c")) {
|
|
22995
|
+
shell.write("\x1B[?1;2c");
|
|
22996
|
+
if (verbose) {
|
|
22997
|
+
logger.debug("device|respond DA: VT100 with Advanced Video Option");
|
|
22998
|
+
}
|
|
22999
|
+
return;
|
|
23000
|
+
}
|
|
23001
|
+
if (process.stdin.isTTY)
|
|
23002
|
+
return;
|
|
23003
|
+
if (!chunk.includes("\x1B[6n"))
|
|
23004
|
+
return;
|
|
23005
|
+
const { col, row } = terminalRender.getCursorPosition();
|
|
23006
|
+
shell.write(`\x1B[${row};${col}R`);
|
|
23007
|
+
logger.debug(`cursor|respond position: row=${String(row)}, col=${String(col)}`);
|
|
23008
|
+
}).forEach(async (line, lineIndex) => {
|
|
23009
|
+
const rendered = terminalRender.tail(24);
|
|
23010
|
+
if (rendered === lastRendered)
|
|
23011
|
+
return;
|
|
23012
|
+
logger.debug(`stdout|${line}`);
|
|
23013
|
+
if (conf.ready?.some((rx) => line.match(rx))) {
|
|
23014
|
+
logger.debug(`ready |${line}`);
|
|
23015
|
+
if (cli === "gemini" && lineIndex <= 80)
|
|
23016
|
+
return;
|
|
23017
|
+
ctx.stdinReady.ready();
|
|
23018
|
+
ctx.stdinFirstReady.ready();
|
|
23019
|
+
}
|
|
23020
|
+
if (conf.enter?.some((rx) => line.match(rx))) {
|
|
23021
|
+
logger.debug(`sendEnter matched|${line}`);
|
|
23022
|
+
return await sendEnter(ctx.messageContext, 400);
|
|
23023
|
+
}
|
|
23024
|
+
const typeingRespondMatched = Object.entries(conf.typingRespond ?? {}).filter(([_sendString, onThePatterns]) => onThePatterns.some((rx) => line.match(rx)));
|
|
23025
|
+
const typingResponded = typeingRespondMatched.length && await src_default(typeingRespondMatched).map(async ([sendString]) => await sendMessage3(ctx.messageContext, sendString, { waitForReady: false })).toCount();
|
|
23026
|
+
if (typingResponded)
|
|
23027
|
+
return;
|
|
23028
|
+
if (conf.fatal?.some((rx) => line.match(rx))) {
|
|
23029
|
+
logger.debug(`fatal |${line}`);
|
|
23030
|
+
ctx.isFatal = true;
|
|
23031
|
+
await exitAgent();
|
|
23032
|
+
}
|
|
23033
|
+
if (conf.restartWithoutContinueArg?.some((rx) => line.match(rx))) {
|
|
23034
|
+
logger.debug(`restart-without-continue|${line}`);
|
|
23035
|
+
ctx.shouldRestartWithoutContinue = true;
|
|
23036
|
+
ctx.isFatal = true;
|
|
23037
|
+
await exitAgent();
|
|
23038
|
+
}
|
|
23039
|
+
if (cli === "codex") {
|
|
23040
|
+
const sessionId = extractSessionId(line);
|
|
23041
|
+
if (sessionId) {
|
|
23042
|
+
logger.debug(`session|captured session ID: ${sessionId}`);
|
|
23043
|
+
await storeSessionForCwd(workingDir, sessionId);
|
|
23044
|
+
}
|
|
23045
|
+
}
|
|
23046
|
+
});
|
|
22289
23047
|
}).by((s) => removeControlCharactersFromStdout ? s.map((e) => removeControlCharacters(e)) : s).by(createTerminatorStream(pendingExitCode.promise)).to(fromWritable(process.stdout));
|
|
22290
23048
|
await saveLogFile(ctx.logPaths.logPath, terminalRender.render());
|
|
22291
23049
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -27688,7 +28446,7 @@ var package_default = {
|
|
|
27688
28446
|
registry: "https://registry.npmjs.org/"
|
|
27689
28447
|
},
|
|
27690
28448
|
scripts: {
|
|
27691
|
-
build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
|
|
28449
|
+
build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun --external=@modelcontextprotocol/sdk",
|
|
27692
28450
|
postbuild: "bun ./ts/postbuild.ts",
|
|
27693
28451
|
demo: "bun run build && bun link && claude-yes -- demo",
|
|
27694
28452
|
dev: "bun ts/index.ts",
|
|
@@ -27702,10 +28460,12 @@ var package_default = {
|
|
|
27702
28460
|
},
|
|
27703
28461
|
dependencies: {
|
|
27704
28462
|
"@snomiao/bun-pty": "^0.3.4",
|
|
28463
|
+
"@snomiao/keyv-sqlite": "^5.0.4",
|
|
27705
28464
|
"bun-pty": "^0.4.8",
|
|
27706
28465
|
"from-node-stream": "^0.1.2"
|
|
27707
28466
|
},
|
|
27708
28467
|
devDependencies: {
|
|
28468
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
27709
28469
|
"@semantic-release/exec": "^7.1.0",
|
|
27710
28470
|
"@types/bun": "^1.3.6",
|
|
27711
28471
|
"@types/jest": "^30.0.0",
|
|
@@ -27728,7 +28488,8 @@ var package_default = {
|
|
|
27728
28488
|
"terminal-render": "^1.3.0",
|
|
27729
28489
|
vitest: "^4.0.17",
|
|
27730
28490
|
winston: "^3.19.0",
|
|
27731
|
-
yargs: "^18.0.0"
|
|
28491
|
+
yargs: "^18.0.0",
|
|
28492
|
+
zod: "^3.23.0"
|
|
27732
28493
|
},
|
|
27733
28494
|
peerDependencies: {
|
|
27734
28495
|
"node-pty": "latest",
|
|
@@ -27930,6 +28691,7 @@ class PidStore2 {
|
|
|
27930
28691
|
cli TEXT NOT NULL,
|
|
27931
28692
|
args TEXT NOT NULL,
|
|
27932
28693
|
prompt TEXT,
|
|
28694
|
+
cwd TEXT NOT NULL,
|
|
27933
28695
|
logFile TEXT NOT NULL,
|
|
27934
28696
|
fifoFile TEXT NOT NULL,
|
|
27935
28697
|
status TEXT NOT NULL DEFAULT 'active',
|
|
@@ -27951,7 +28713,8 @@ class PidStore2 {
|
|
|
27951
28713
|
pid,
|
|
27952
28714
|
cli,
|
|
27953
28715
|
args,
|
|
27954
|
-
prompt
|
|
28716
|
+
prompt,
|
|
28717
|
+
cwd
|
|
27955
28718
|
}) {
|
|
27956
28719
|
const now = Date.now();
|
|
27957
28720
|
const argsJson = JSON.stringify(args);
|
|
@@ -27959,16 +28722,16 @@ class PidStore2 {
|
|
|
27959
28722
|
const fifoFile = this.getFifoPath(pid);
|
|
27960
28723
|
try {
|
|
27961
28724
|
this.db.run(`
|
|
27962
|
-
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
27963
|
-
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
27964
|
-
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
28725
|
+
INSERT INTO pid_records (pid, cli, args, prompt, cwd, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
28726
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
28727
|
+
`, [pid, cli, argsJson, prompt, cwd, logFile, fifoFile, now, now]);
|
|
27965
28728
|
} catch (error) {
|
|
27966
28729
|
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
27967
28730
|
this.db.run(`
|
|
27968
28731
|
UPDATE pid_records
|
|
27969
|
-
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
28732
|
+
SET cli = ?, args = ?, prompt = ?, cwd = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
27970
28733
|
WHERE pid = ?
|
|
27971
|
-
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
28734
|
+
`, [cli, argsJson, prompt, cwd, logFile, fifoFile, now, now, pid]);
|
|
27972
28735
|
} else {
|
|
27973
28736
|
throw error;
|
|
27974
28737
|
}
|
|
@@ -27993,6 +28756,9 @@ class PidStore2 {
|
|
|
27993
28756
|
}
|
|
27994
28757
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
27995
28758
|
}
|
|
28759
|
+
getAllRecords() {
|
|
28760
|
+
return this.db.query("SELECT * FROM pid_records");
|
|
28761
|
+
}
|
|
27996
28762
|
getLogDir() {
|
|
27997
28763
|
return path14.resolve(this.storeDir, "logs");
|
|
27998
28764
|
}
|
|
@@ -28072,6 +28838,12 @@ fifo/
|
|
|
28072
28838
|
}
|
|
28073
28839
|
|
|
28074
28840
|
// ts/cli.ts
|
|
28841
|
+
var rawArgs = process.argv.slice(2);
|
|
28842
|
+
if (rawArgs[0] === "mcp" && rawArgs[1] === "serve") {
|
|
28843
|
+
const { startMcpServer: startMcpServer2 } = await init_mcp_server().then(() => exports_mcp_server);
|
|
28844
|
+
await startMcpServer2();
|
|
28845
|
+
process.exit(0);
|
|
28846
|
+
}
|
|
28075
28847
|
var config3 = parseCliArgs(process.argv);
|
|
28076
28848
|
if (config3.appendPrompt) {
|
|
28077
28849
|
const ipcPath = await PidStore2.findActiveFifo(process.cwd());
|
|
@@ -28126,5 +28898,5 @@ var { exitCode } = await cliYes(config3);
|
|
|
28126
28898
|
console.log("exiting process");
|
|
28127
28899
|
process.exit(exitCode ?? 1);
|
|
28128
28900
|
|
|
28129
|
-
//# debugId=
|
|
28901
|
+
//# debugId=138DDE1799AB280064756E2164756E21
|
|
28130
28902
|
//# sourceMappingURL=cli.js.map
|