claude-yes 1.35.1 → 1.36.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 +235 -52
- package/dist/index.js +140 -20
- package/package.json +1 -1
- package/ts/cli.ts +39 -9
- package/ts/index.ts +18 -5
- package/ts/parseCliArgs.ts +9 -4
- package/ts/pidStore.ts +42 -8
package/dist/cli.js
CHANGED
|
@@ -20633,10 +20633,91 @@ import { fromReadable } from "from-node-stream";
|
|
|
20633
20633
|
import { createReadStream as createReadStream2, mkdirSync } from "fs";
|
|
20634
20634
|
import { unlink } from "fs/promises";
|
|
20635
20635
|
import { dirname } from "path";
|
|
20636
|
+
import { createServer } from "net";
|
|
20636
20637
|
function createFifoStream(cli, customPath) {
|
|
20637
|
-
if (process.platform
|
|
20638
|
+
if (process.platform === "win32") {
|
|
20639
|
+
return createWindowsNamedPipe(cli, customPath);
|
|
20640
|
+
} else if (process.platform === "linux") {
|
|
20641
|
+
return createLinuxFifo(cli, customPath);
|
|
20642
|
+
} else {
|
|
20643
|
+
logger.warn(`[${cli}-yes] IPC not supported on platform: ${process.platform}`);
|
|
20644
|
+
return null;
|
|
20645
|
+
}
|
|
20646
|
+
}
|
|
20647
|
+
function createWindowsNamedPipe(cli, customPath) {
|
|
20648
|
+
try {
|
|
20649
|
+
let pipePath;
|
|
20650
|
+
if (customPath) {
|
|
20651
|
+
pipePath = customPath;
|
|
20652
|
+
} else {
|
|
20653
|
+
const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
|
|
20654
|
+
const randomSuffix = Math.random().toString(36).substring(2, 5);
|
|
20655
|
+
pipePath = `\\\\.\\pipe\\agent-yes-${timestamp}${randomSuffix}`;
|
|
20656
|
+
}
|
|
20657
|
+
logger.info(`[${cli}-yes] Creating Windows named pipe at ${pipePath}`);
|
|
20658
|
+
const server = createServer();
|
|
20659
|
+
let connection = null;
|
|
20660
|
+
let isClosing = false;
|
|
20661
|
+
const stream = new ReadableStream({
|
|
20662
|
+
start(controller) {
|
|
20663
|
+
server.on("connection", (socket) => {
|
|
20664
|
+
connection = socket;
|
|
20665
|
+
logger.info(`[${cli}-yes] Client connected to named pipe`);
|
|
20666
|
+
socket.on("data", (chunk) => {
|
|
20667
|
+
const data = chunk.toString();
|
|
20668
|
+
logger.debug(`[${cli}-yes] Received data via named pipe: ${data}`);
|
|
20669
|
+
controller.enqueue(data);
|
|
20670
|
+
});
|
|
20671
|
+
socket.on("end", () => {
|
|
20672
|
+
logger.debug(`[${cli}-yes] Client disconnected from named pipe`);
|
|
20673
|
+
connection = null;
|
|
20674
|
+
});
|
|
20675
|
+
socket.on("error", (error) => {
|
|
20676
|
+
logger.warn(`[${cli}-yes] Named pipe socket error:`, error);
|
|
20677
|
+
if (!isClosing) {
|
|
20678
|
+
controller.error(error);
|
|
20679
|
+
}
|
|
20680
|
+
});
|
|
20681
|
+
});
|
|
20682
|
+
server.on("error", (error) => {
|
|
20683
|
+
logger.warn(`[${cli}-yes] Named pipe server error:`, error);
|
|
20684
|
+
if (!isClosing) {
|
|
20685
|
+
controller.error(error);
|
|
20686
|
+
}
|
|
20687
|
+
});
|
|
20688
|
+
server.listen(pipePath, () => {
|
|
20689
|
+
logger.info(`[${cli}-yes] Named pipe server listening at ${pipePath}`);
|
|
20690
|
+
});
|
|
20691
|
+
},
|
|
20692
|
+
cancel() {
|
|
20693
|
+
isClosing = true;
|
|
20694
|
+
if (connection) {
|
|
20695
|
+
connection.end();
|
|
20696
|
+
}
|
|
20697
|
+
server.close();
|
|
20698
|
+
}
|
|
20699
|
+
});
|
|
20700
|
+
const cleanup = async () => {
|
|
20701
|
+
isClosing = true;
|
|
20702
|
+
if (connection) {
|
|
20703
|
+
connection.end();
|
|
20704
|
+
}
|
|
20705
|
+
server.close();
|
|
20706
|
+
logger.info(`[${cli}-yes] Cleaned up Windows named pipe at ${pipePath}`);
|
|
20707
|
+
};
|
|
20708
|
+
process.on("exit", () => cleanup().catch(() => null));
|
|
20709
|
+
process.on("SIGINT", () => cleanup().catch(() => null));
|
|
20710
|
+
process.on("SIGTERM", () => cleanup().catch(() => null));
|
|
20711
|
+
return {
|
|
20712
|
+
stream,
|
|
20713
|
+
cleanup
|
|
20714
|
+
};
|
|
20715
|
+
} catch (error) {
|
|
20716
|
+
logger.warn(`[${cli}-yes] Failed to create Windows named pipe:`, error);
|
|
20638
20717
|
return null;
|
|
20639
20718
|
}
|
|
20719
|
+
}
|
|
20720
|
+
function createLinuxFifo(cli, customPath) {
|
|
20640
20721
|
let fifoPath = null;
|
|
20641
20722
|
let fifoStream = null;
|
|
20642
20723
|
try {
|
|
@@ -20732,7 +20813,7 @@ var init_fifo = __esm(() => {
|
|
|
20732
20813
|
});
|
|
20733
20814
|
|
|
20734
20815
|
// ts/pidStore.ts
|
|
20735
|
-
import { mkdir as mkdir3 } from "fs/promises";
|
|
20816
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
20736
20817
|
import path9 from "path";
|
|
20737
20818
|
|
|
20738
20819
|
class SqliteAdapter {
|
|
@@ -20776,15 +20857,16 @@ class SqliteAdapter {
|
|
|
20776
20857
|
|
|
20777
20858
|
class PidStore {
|
|
20778
20859
|
db;
|
|
20779
|
-
|
|
20860
|
+
storeDir;
|
|
20780
20861
|
dbPath;
|
|
20781
20862
|
constructor(workingDir) {
|
|
20782
|
-
this.
|
|
20783
|
-
this.dbPath = path9.join(this.
|
|
20863
|
+
this.storeDir = path9.resolve(workingDir, ".agent-yes");
|
|
20864
|
+
this.dbPath = path9.join(this.storeDir, "pid.sqlite");
|
|
20784
20865
|
}
|
|
20785
20866
|
async init() {
|
|
20786
|
-
await mkdir3(path9.join(this.
|
|
20787
|
-
await mkdir3(path9.join(this.
|
|
20867
|
+
await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
|
|
20868
|
+
await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
|
|
20869
|
+
await this.ensureGitignore();
|
|
20788
20870
|
this.db = new SqliteAdapter;
|
|
20789
20871
|
await this.db.init(this.dbPath);
|
|
20790
20872
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -20856,10 +20938,14 @@ class PidStore {
|
|
|
20856
20938
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20857
20939
|
}
|
|
20858
20940
|
getLogPath(pid) {
|
|
20859
|
-
return path9.resolve(this.
|
|
20941
|
+
return path9.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
20860
20942
|
}
|
|
20861
20943
|
getFifoPath(pid) {
|
|
20862
|
-
|
|
20944
|
+
if (process.platform === "win32") {
|
|
20945
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
20946
|
+
} else {
|
|
20947
|
+
return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
20948
|
+
}
|
|
20863
20949
|
}
|
|
20864
20950
|
async cleanStaleRecords() {
|
|
20865
20951
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -20888,6 +20974,28 @@ class PidStore {
|
|
|
20888
20974
|
return false;
|
|
20889
20975
|
}
|
|
20890
20976
|
}
|
|
20977
|
+
async ensureGitignore() {
|
|
20978
|
+
const gitignorePath = path9.join(this.storeDir, ".gitignore");
|
|
20979
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
20980
|
+
# Ignore all log files and runtime data
|
|
20981
|
+
logs/
|
|
20982
|
+
fifo/
|
|
20983
|
+
*.sqlite
|
|
20984
|
+
*.sqlite-*
|
|
20985
|
+
*.log
|
|
20986
|
+
*.raw.log
|
|
20987
|
+
*.lines.log
|
|
20988
|
+
*.debug.log
|
|
20989
|
+
`;
|
|
20990
|
+
try {
|
|
20991
|
+
await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
20992
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
20993
|
+
} catch (error) {
|
|
20994
|
+
if (error.code !== "EEXIST") {
|
|
20995
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
20996
|
+
}
|
|
20997
|
+
}
|
|
20998
|
+
}
|
|
20891
20999
|
static async findActiveFifo(workingDir) {
|
|
20892
21000
|
const store = new PidStore(workingDir);
|
|
20893
21001
|
await store.init();
|
|
@@ -21026,8 +21134,11 @@ function getDefaultConfig() {
|
|
|
21026
21134
|
fatal: []
|
|
21027
21135
|
},
|
|
21028
21136
|
amp: {
|
|
21029
|
-
help: "",
|
|
21030
|
-
install:
|
|
21137
|
+
help: "https://ampcode.com/",
|
|
21138
|
+
install: {
|
|
21139
|
+
bash: "curl -fsSL https://ampcode.com/install.sh | bash",
|
|
21140
|
+
npm: "npm i -g @sourcegraph/amp"
|
|
21141
|
+
},
|
|
21031
21142
|
enter: [
|
|
21032
21143
|
/^.{0,4} Approve /
|
|
21033
21144
|
]
|
|
@@ -21221,7 +21332,7 @@ __export(exports_ts, {
|
|
|
21221
21332
|
CLIS_CONFIG: () => CLIS_CONFIG2
|
|
21222
21333
|
});
|
|
21223
21334
|
import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
|
|
21224
|
-
import { mkdir as mkdir7, readFile as readFile4, writeFile as
|
|
21335
|
+
import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile7 } from "fs/promises";
|
|
21225
21336
|
import path13 from "path";
|
|
21226
21337
|
async function agentYes2({
|
|
21227
21338
|
cli,
|
|
@@ -21568,15 +21679,15 @@ ${prompt}` : prefix;
|
|
|
21568
21679
|
}).by((s) => {
|
|
21569
21680
|
if (!useFifo)
|
|
21570
21681
|
return s;
|
|
21571
|
-
const
|
|
21572
|
-
if (!
|
|
21682
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21683
|
+
if (!ipcResult)
|
|
21573
21684
|
return s;
|
|
21574
|
-
pendingExitCode.promise.finally(() =>
|
|
21685
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21575
21686
|
process.stderr.write(`
|
|
21576
21687
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21577
21688
|
|
|
21578
21689
|
`);
|
|
21579
|
-
return s.merge(
|
|
21690
|
+
return s.merge(ipcResult.stream);
|
|
21580
21691
|
}).onStart(async function promptOnStart() {
|
|
21581
21692
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21582
21693
|
if (prompt)
|
|
@@ -21598,7 +21709,7 @@ ${prompt}` : prefix;
|
|
|
21598
21709
|
return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21599
21710
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21600
21711
|
return f.forEach(async (chars) => {
|
|
21601
|
-
await
|
|
21712
|
+
await writeFile7(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21602
21713
|
}).run();
|
|
21603
21714
|
}).catch(() => f.run());
|
|
21604
21715
|
}).by(function consoleResponder(e) {
|
|
@@ -21670,7 +21781,7 @@ ${prompt}` : prefix;
|
|
|
21670
21781
|
})).to(fromWritable2(process.stdout));
|
|
21671
21782
|
if (logPath) {
|
|
21672
21783
|
await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21673
|
-
await
|
|
21784
|
+
await writeFile7(logPath, terminalRender.render()).catch(() => null);
|
|
21674
21785
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21675
21786
|
}
|
|
21676
21787
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21682,7 +21793,7 @@ ${prompt}` : prefix;
|
|
|
21682
21793
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21683
21794
|
const logFilePath = path13.resolve(logFile);
|
|
21684
21795
|
await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21685
|
-
await
|
|
21796
|
+
await writeFile7(logFilePath, terminalRender.render());
|
|
21686
21797
|
}
|
|
21687
21798
|
return { exitCode, logs: terminalRender.render() };
|
|
21688
21799
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21701,6 +21812,15 @@ ${prompt}` : prefix;
|
|
|
21701
21812
|
resolve5();
|
|
21702
21813
|
}, 1000))
|
|
21703
21814
|
]);
|
|
21815
|
+
await Promise.race([
|
|
21816
|
+
nextStdout.wait(),
|
|
21817
|
+
new Promise((resolve5) => setTimeout(() => {
|
|
21818
|
+
if (!nextStdout.ready) {
|
|
21819
|
+
shell.write("\r");
|
|
21820
|
+
}
|
|
21821
|
+
resolve5();
|
|
21822
|
+
}, 3000))
|
|
21823
|
+
]);
|
|
21704
21824
|
}
|
|
21705
21825
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21706
21826
|
if (waitForReady)
|
|
@@ -21772,7 +21892,7 @@ init_pidStore();
|
|
|
21772
21892
|
await init_pty();
|
|
21773
21893
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21774
21894
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21775
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21895
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21776
21896
|
import path11 from "path";
|
|
21777
21897
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21778
21898
|
var CLIS_CONFIG = config.clis;
|
|
@@ -22121,15 +22241,15 @@ ${prompt}` : prefix;
|
|
|
22121
22241
|
}).by((s) => {
|
|
22122
22242
|
if (!useFifo)
|
|
22123
22243
|
return s;
|
|
22124
|
-
const
|
|
22125
|
-
if (!
|
|
22244
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
22245
|
+
if (!ipcResult)
|
|
22126
22246
|
return s;
|
|
22127
|
-
pendingExitCode.promise.finally(() =>
|
|
22247
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
22128
22248
|
process.stderr.write(`
|
|
22129
22249
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
22130
22250
|
|
|
22131
22251
|
`);
|
|
22132
|
-
return s.merge(
|
|
22252
|
+
return s.merge(ipcResult.stream);
|
|
22133
22253
|
}).onStart(async function promptOnStart() {
|
|
22134
22254
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
22135
22255
|
if (prompt)
|
|
@@ -22151,7 +22271,7 @@ ${prompt}` : prefix;
|
|
|
22151
22271
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
22152
22272
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
22153
22273
|
return f.forEach(async (chars) => {
|
|
22154
|
-
await
|
|
22274
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
22155
22275
|
}).run();
|
|
22156
22276
|
}).catch(() => f.run());
|
|
22157
22277
|
}).by(function consoleResponder(e) {
|
|
@@ -22223,7 +22343,7 @@ ${prompt}` : prefix;
|
|
|
22223
22343
|
})).to(fromWritable(process.stdout));
|
|
22224
22344
|
if (logPath) {
|
|
22225
22345
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
22226
|
-
await
|
|
22346
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
22227
22347
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
22228
22348
|
}
|
|
22229
22349
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -22235,7 +22355,7 @@ ${prompt}` : prefix;
|
|
|
22235
22355
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
22236
22356
|
const logFilePath = path11.resolve(logFile);
|
|
22237
22357
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
22238
|
-
await
|
|
22358
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
22239
22359
|
}
|
|
22240
22360
|
return { exitCode, logs: terminalRender.render() };
|
|
22241
22361
|
async function sendEnter(waitms = 1000) {
|
|
@@ -22254,6 +22374,15 @@ ${prompt}` : prefix;
|
|
|
22254
22374
|
resolve();
|
|
22255
22375
|
}, 1000))
|
|
22256
22376
|
]);
|
|
22377
|
+
await Promise.race([
|
|
22378
|
+
nextStdout.wait(),
|
|
22379
|
+
new Promise((resolve) => setTimeout(() => {
|
|
22380
|
+
if (!nextStdout.ready) {
|
|
22381
|
+
shell.write("\r");
|
|
22382
|
+
}
|
|
22383
|
+
resolve();
|
|
22384
|
+
}, 3000))
|
|
22385
|
+
]);
|
|
22257
22386
|
}
|
|
22258
22387
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
22259
22388
|
if (waitForReady)
|
|
@@ -24132,13 +24261,13 @@ function stringWidth3(string, options = {}) {
|
|
|
24132
24261
|
}
|
|
24133
24262
|
|
|
24134
24263
|
// node_modules/y18n/build/lib/platform-shims/node.js
|
|
24135
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
24264
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile5 } from "fs";
|
|
24136
24265
|
import { format as format3 } from "util";
|
|
24137
24266
|
import { resolve as resolve3 } from "path";
|
|
24138
24267
|
var node_default = {
|
|
24139
24268
|
fs: {
|
|
24140
24269
|
readFileSync: readFileSync4,
|
|
24141
|
-
writeFile:
|
|
24270
|
+
writeFile: writeFile5
|
|
24142
24271
|
},
|
|
24143
24272
|
format: format3,
|
|
24144
24273
|
resolve: resolve3,
|
|
@@ -27848,7 +27977,7 @@ var package_default = {
|
|
|
27848
27977
|
// ts/parseCliArgs.ts
|
|
27849
27978
|
function parseCliArgs(argv) {
|
|
27850
27979
|
const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/^ay$/, "").replace(/-yes$/, "") || undefined;
|
|
27851
|
-
const parsedArgv = yargs_default(hideBin(argv)).usage("Usage: $0 [cli] [agent-yes args] [agent-cli args] [--] [prompts...]").example("$0 claude --idle=30s -- solve all todos in my codebase, commit one by one", "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`").option("robust", {
|
|
27980
|
+
const parsedArgv = yargs_default(hideBin(argv)).usage("Usage: $0 [cli] [agent-yes args] [agent-cli args] [--] [prompts...]").example("$0 claude --idle=30s -- solve all todos in my codebase, commit one by one", "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`").example("$0 claude --stdpush", "Run Claude with external stdin input enabled via --append-prompt").option("robust", {
|
|
27852
27981
|
type: "boolean",
|
|
27853
27982
|
default: true,
|
|
27854
27983
|
description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
|
|
@@ -27896,11 +28025,12 @@ function parseCliArgs(argv) {
|
|
|
27896
28025
|
alias: "c"
|
|
27897
28026
|
}).option("append-prompt", {
|
|
27898
28027
|
type: "string",
|
|
27899
|
-
description: "Send a prompt to the active agent's
|
|
27900
|
-
}).option("
|
|
28028
|
+
description: "Send a prompt to the active agent's stdin in current directory"
|
|
28029
|
+
}).option("stdpush", {
|
|
27901
28030
|
type: "boolean",
|
|
27902
|
-
description: "Enable
|
|
27903
|
-
default: false
|
|
28031
|
+
description: "Enable external input stream to push additional data to stdin",
|
|
28032
|
+
default: false,
|
|
28033
|
+
alias: ["ipc", "fifo"]
|
|
27904
28034
|
}).positional("cli", {
|
|
27905
28035
|
describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
|
|
27906
28036
|
type: "string",
|
|
@@ -27973,7 +28103,7 @@ function parseCliArgs(argv) {
|
|
|
27973
28103
|
resume: parsedArgv.continue,
|
|
27974
28104
|
useSkills: parsedArgv.useSkills,
|
|
27975
28105
|
appendPrompt: parsedArgv.appendPrompt,
|
|
27976
|
-
useFifo: parsedArgv.fifo
|
|
28106
|
+
useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo
|
|
27977
28107
|
};
|
|
27978
28108
|
}
|
|
27979
28109
|
|
|
@@ -27996,7 +28126,7 @@ var logger2 = import_winston3.default.createLogger({
|
|
|
27996
28126
|
|
|
27997
28127
|
// ts/pidStore.ts
|
|
27998
28128
|
init_logger();
|
|
27999
|
-
import { mkdir as mkdir6 } from "fs/promises";
|
|
28129
|
+
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
28000
28130
|
import path12 from "path";
|
|
28001
28131
|
|
|
28002
28132
|
class SqliteAdapter2 {
|
|
@@ -28040,15 +28170,16 @@ class SqliteAdapter2 {
|
|
|
28040
28170
|
|
|
28041
28171
|
class PidStore2 {
|
|
28042
28172
|
db;
|
|
28043
|
-
|
|
28173
|
+
storeDir;
|
|
28044
28174
|
dbPath;
|
|
28045
28175
|
constructor(workingDir) {
|
|
28046
|
-
this.
|
|
28047
|
-
this.dbPath = path12.join(this.
|
|
28176
|
+
this.storeDir = path12.resolve(workingDir, ".agent-yes");
|
|
28177
|
+
this.dbPath = path12.join(this.storeDir, "pid.sqlite");
|
|
28048
28178
|
}
|
|
28049
28179
|
async init() {
|
|
28050
|
-
await mkdir6(path12.join(this.
|
|
28051
|
-
await mkdir6(path12.join(this.
|
|
28180
|
+
await mkdir6(path12.join(this.storeDir, "logs"), { recursive: true });
|
|
28181
|
+
await mkdir6(path12.join(this.storeDir, "fifo"), { recursive: true });
|
|
28182
|
+
await this.ensureGitignore();
|
|
28052
28183
|
this.db = new SqliteAdapter2;
|
|
28053
28184
|
await this.db.init(this.dbPath);
|
|
28054
28185
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -28120,10 +28251,14 @@ class PidStore2 {
|
|
|
28120
28251
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
28121
28252
|
}
|
|
28122
28253
|
getLogPath(pid) {
|
|
28123
|
-
return path12.resolve(this.
|
|
28254
|
+
return path12.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
28124
28255
|
}
|
|
28125
28256
|
getFifoPath(pid) {
|
|
28126
|
-
|
|
28257
|
+
if (process.platform === "win32") {
|
|
28258
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
28259
|
+
} else {
|
|
28260
|
+
return path12.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
28261
|
+
}
|
|
28127
28262
|
}
|
|
28128
28263
|
async cleanStaleRecords() {
|
|
28129
28264
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -28152,6 +28287,28 @@ class PidStore2 {
|
|
|
28152
28287
|
return false;
|
|
28153
28288
|
}
|
|
28154
28289
|
}
|
|
28290
|
+
async ensureGitignore() {
|
|
28291
|
+
const gitignorePath = path12.join(this.storeDir, ".gitignore");
|
|
28292
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
28293
|
+
# Ignore all log files and runtime data
|
|
28294
|
+
logs/
|
|
28295
|
+
fifo/
|
|
28296
|
+
*.sqlite
|
|
28297
|
+
*.sqlite-*
|
|
28298
|
+
*.log
|
|
28299
|
+
*.raw.log
|
|
28300
|
+
*.lines.log
|
|
28301
|
+
*.debug.log
|
|
28302
|
+
`;
|
|
28303
|
+
try {
|
|
28304
|
+
await writeFile6(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
28305
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
28306
|
+
} catch (error) {
|
|
28307
|
+
if (error.code !== "EEXIST") {
|
|
28308
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
28309
|
+
}
|
|
28310
|
+
}
|
|
28311
|
+
}
|
|
28155
28312
|
static async findActiveFifo(workingDir) {
|
|
28156
28313
|
const store = new PidStore2(workingDir);
|
|
28157
28314
|
await store.init();
|
|
@@ -28164,16 +28321,42 @@ class PidStore2 {
|
|
|
28164
28321
|
// ts/cli.ts
|
|
28165
28322
|
var config3 = parseCliArgs(process.argv);
|
|
28166
28323
|
if (config3.appendPrompt) {
|
|
28167
|
-
const
|
|
28168
|
-
if (!
|
|
28169
|
-
console.error("No active agent with
|
|
28324
|
+
const ipcPath = await PidStore2.findActiveFifo(process.cwd());
|
|
28325
|
+
if (!ipcPath) {
|
|
28326
|
+
console.error("No active agent with IPC found in current directory.");
|
|
28327
|
+
process.exit(1);
|
|
28328
|
+
}
|
|
28329
|
+
try {
|
|
28330
|
+
if (process.platform === "win32") {
|
|
28331
|
+
const { connect } = await import("net");
|
|
28332
|
+
await new Promise((resolve5, reject) => {
|
|
28333
|
+
const client = connect(ipcPath);
|
|
28334
|
+
client.on("connect", () => {
|
|
28335
|
+
client.write(config3.appendPrompt + "\r");
|
|
28336
|
+
client.end();
|
|
28337
|
+
console.log(`Sent prompt to Windows named pipe: ${ipcPath}`);
|
|
28338
|
+
resolve5();
|
|
28339
|
+
});
|
|
28340
|
+
client.on("error", (error) => {
|
|
28341
|
+
console.error(`Failed to connect to named pipe: ${error}`);
|
|
28342
|
+
reject(error);
|
|
28343
|
+
});
|
|
28344
|
+
setTimeout(() => {
|
|
28345
|
+
client.destroy();
|
|
28346
|
+
reject(new Error("Connection timeout"));
|
|
28347
|
+
}, 5000);
|
|
28348
|
+
});
|
|
28349
|
+
} else {
|
|
28350
|
+
const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
|
|
28351
|
+
const fd = openSync(ipcPath, "w");
|
|
28352
|
+
writeFileSync2(fd, config3.appendPrompt + "\r");
|
|
28353
|
+
closeSync(fd);
|
|
28354
|
+
console.log(`Sent prompt to FIFO: ${ipcPath}`);
|
|
28355
|
+
}
|
|
28356
|
+
} catch (error) {
|
|
28357
|
+
console.error(`Failed to send prompt: ${error}`);
|
|
28170
28358
|
process.exit(1);
|
|
28171
28359
|
}
|
|
28172
|
-
const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
|
|
28173
|
-
const fd = openSync(fifoPath, "w");
|
|
28174
|
-
writeFileSync2(fd, config3.appendPrompt + "\r");
|
|
28175
|
-
closeSync(fd);
|
|
28176
|
-
console.log(`Sent prompt to ${fifoPath}`);
|
|
28177
28360
|
process.exit(0);
|
|
28178
28361
|
}
|
|
28179
28362
|
if (!config3.cli) {
|
|
@@ -28190,5 +28373,5 @@ var { exitCode } = await cliYes(config3);
|
|
|
28190
28373
|
console.log("exiting process");
|
|
28191
28374
|
process.exit(exitCode ?? 1);
|
|
28192
28375
|
|
|
28193
|
-
//# debugId=
|
|
28376
|
+
//# debugId=2519B84A9286C6F364756E2164756E21
|
|
28194
28377
|
//# sourceMappingURL=cli.js.map
|
package/dist/index.js
CHANGED
|
@@ -20631,10 +20631,91 @@ import { fromReadable } from "from-node-stream";
|
|
|
20631
20631
|
import { createReadStream as createReadStream2, mkdirSync } from "fs";
|
|
20632
20632
|
import { unlink } from "fs/promises";
|
|
20633
20633
|
import { dirname } from "path";
|
|
20634
|
+
import { createServer } from "net";
|
|
20634
20635
|
function createFifoStream(cli, customPath) {
|
|
20635
|
-
if (process.platform
|
|
20636
|
+
if (process.platform === "win32") {
|
|
20637
|
+
return createWindowsNamedPipe(cli, customPath);
|
|
20638
|
+
} else if (process.platform === "linux") {
|
|
20639
|
+
return createLinuxFifo(cli, customPath);
|
|
20640
|
+
} else {
|
|
20641
|
+
logger.warn(`[${cli}-yes] IPC not supported on platform: ${process.platform}`);
|
|
20642
|
+
return null;
|
|
20643
|
+
}
|
|
20644
|
+
}
|
|
20645
|
+
function createWindowsNamedPipe(cli, customPath) {
|
|
20646
|
+
try {
|
|
20647
|
+
let pipePath;
|
|
20648
|
+
if (customPath) {
|
|
20649
|
+
pipePath = customPath;
|
|
20650
|
+
} else {
|
|
20651
|
+
const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
|
|
20652
|
+
const randomSuffix = Math.random().toString(36).substring(2, 5);
|
|
20653
|
+
pipePath = `\\\\.\\pipe\\agent-yes-${timestamp}${randomSuffix}`;
|
|
20654
|
+
}
|
|
20655
|
+
logger.info(`[${cli}-yes] Creating Windows named pipe at ${pipePath}`);
|
|
20656
|
+
const server = createServer();
|
|
20657
|
+
let connection = null;
|
|
20658
|
+
let isClosing = false;
|
|
20659
|
+
const stream = new ReadableStream({
|
|
20660
|
+
start(controller) {
|
|
20661
|
+
server.on("connection", (socket) => {
|
|
20662
|
+
connection = socket;
|
|
20663
|
+
logger.info(`[${cli}-yes] Client connected to named pipe`);
|
|
20664
|
+
socket.on("data", (chunk) => {
|
|
20665
|
+
const data = chunk.toString();
|
|
20666
|
+
logger.debug(`[${cli}-yes] Received data via named pipe: ${data}`);
|
|
20667
|
+
controller.enqueue(data);
|
|
20668
|
+
});
|
|
20669
|
+
socket.on("end", () => {
|
|
20670
|
+
logger.debug(`[${cli}-yes] Client disconnected from named pipe`);
|
|
20671
|
+
connection = null;
|
|
20672
|
+
});
|
|
20673
|
+
socket.on("error", (error) => {
|
|
20674
|
+
logger.warn(`[${cli}-yes] Named pipe socket error:`, error);
|
|
20675
|
+
if (!isClosing) {
|
|
20676
|
+
controller.error(error);
|
|
20677
|
+
}
|
|
20678
|
+
});
|
|
20679
|
+
});
|
|
20680
|
+
server.on("error", (error) => {
|
|
20681
|
+
logger.warn(`[${cli}-yes] Named pipe server error:`, error);
|
|
20682
|
+
if (!isClosing) {
|
|
20683
|
+
controller.error(error);
|
|
20684
|
+
}
|
|
20685
|
+
});
|
|
20686
|
+
server.listen(pipePath, () => {
|
|
20687
|
+
logger.info(`[${cli}-yes] Named pipe server listening at ${pipePath}`);
|
|
20688
|
+
});
|
|
20689
|
+
},
|
|
20690
|
+
cancel() {
|
|
20691
|
+
isClosing = true;
|
|
20692
|
+
if (connection) {
|
|
20693
|
+
connection.end();
|
|
20694
|
+
}
|
|
20695
|
+
server.close();
|
|
20696
|
+
}
|
|
20697
|
+
});
|
|
20698
|
+
const cleanup = async () => {
|
|
20699
|
+
isClosing = true;
|
|
20700
|
+
if (connection) {
|
|
20701
|
+
connection.end();
|
|
20702
|
+
}
|
|
20703
|
+
server.close();
|
|
20704
|
+
logger.info(`[${cli}-yes] Cleaned up Windows named pipe at ${pipePath}`);
|
|
20705
|
+
};
|
|
20706
|
+
process.on("exit", () => cleanup().catch(() => null));
|
|
20707
|
+
process.on("SIGINT", () => cleanup().catch(() => null));
|
|
20708
|
+
process.on("SIGTERM", () => cleanup().catch(() => null));
|
|
20709
|
+
return {
|
|
20710
|
+
stream,
|
|
20711
|
+
cleanup
|
|
20712
|
+
};
|
|
20713
|
+
} catch (error) {
|
|
20714
|
+
logger.warn(`[${cli}-yes] Failed to create Windows named pipe:`, error);
|
|
20636
20715
|
return null;
|
|
20637
20716
|
}
|
|
20717
|
+
}
|
|
20718
|
+
function createLinuxFifo(cli, customPath) {
|
|
20638
20719
|
let fifoPath = null;
|
|
20639
20720
|
let fifoStream = null;
|
|
20640
20721
|
try {
|
|
@@ -20730,7 +20811,7 @@ var init_fifo = __esm(() => {
|
|
|
20730
20811
|
});
|
|
20731
20812
|
|
|
20732
20813
|
// ts/pidStore.ts
|
|
20733
|
-
import { mkdir as mkdir3 } from "fs/promises";
|
|
20814
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
20734
20815
|
import path9 from "path";
|
|
20735
20816
|
|
|
20736
20817
|
class SqliteAdapter {
|
|
@@ -20774,15 +20855,16 @@ class SqliteAdapter {
|
|
|
20774
20855
|
|
|
20775
20856
|
class PidStore {
|
|
20776
20857
|
db;
|
|
20777
|
-
|
|
20858
|
+
storeDir;
|
|
20778
20859
|
dbPath;
|
|
20779
20860
|
constructor(workingDir) {
|
|
20780
|
-
this.
|
|
20781
|
-
this.dbPath = path9.join(this.
|
|
20861
|
+
this.storeDir = path9.resolve(workingDir, ".agent-yes");
|
|
20862
|
+
this.dbPath = path9.join(this.storeDir, "pid.sqlite");
|
|
20782
20863
|
}
|
|
20783
20864
|
async init() {
|
|
20784
|
-
await mkdir3(path9.join(this.
|
|
20785
|
-
await mkdir3(path9.join(this.
|
|
20865
|
+
await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
|
|
20866
|
+
await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
|
|
20867
|
+
await this.ensureGitignore();
|
|
20786
20868
|
this.db = new SqliteAdapter;
|
|
20787
20869
|
await this.db.init(this.dbPath);
|
|
20788
20870
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -20854,10 +20936,14 @@ class PidStore {
|
|
|
20854
20936
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20855
20937
|
}
|
|
20856
20938
|
getLogPath(pid) {
|
|
20857
|
-
return path9.resolve(this.
|
|
20939
|
+
return path9.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
20858
20940
|
}
|
|
20859
20941
|
getFifoPath(pid) {
|
|
20860
|
-
|
|
20942
|
+
if (process.platform === "win32") {
|
|
20943
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
20944
|
+
} else {
|
|
20945
|
+
return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
20946
|
+
}
|
|
20861
20947
|
}
|
|
20862
20948
|
async cleanStaleRecords() {
|
|
20863
20949
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -20886,6 +20972,28 @@ class PidStore {
|
|
|
20886
20972
|
return false;
|
|
20887
20973
|
}
|
|
20888
20974
|
}
|
|
20975
|
+
async ensureGitignore() {
|
|
20976
|
+
const gitignorePath = path9.join(this.storeDir, ".gitignore");
|
|
20977
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
20978
|
+
# Ignore all log files and runtime data
|
|
20979
|
+
logs/
|
|
20980
|
+
fifo/
|
|
20981
|
+
*.sqlite
|
|
20982
|
+
*.sqlite-*
|
|
20983
|
+
*.log
|
|
20984
|
+
*.raw.log
|
|
20985
|
+
*.lines.log
|
|
20986
|
+
*.debug.log
|
|
20987
|
+
`;
|
|
20988
|
+
try {
|
|
20989
|
+
await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
20990
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
20991
|
+
} catch (error) {
|
|
20992
|
+
if (error.code !== "EEXIST") {
|
|
20993
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
20994
|
+
}
|
|
20995
|
+
}
|
|
20996
|
+
}
|
|
20889
20997
|
static async findActiveFifo(workingDir) {
|
|
20890
20998
|
const store = new PidStore(workingDir);
|
|
20891
20999
|
await store.init();
|
|
@@ -21024,8 +21132,11 @@ function getDefaultConfig() {
|
|
|
21024
21132
|
fatal: []
|
|
21025
21133
|
},
|
|
21026
21134
|
amp: {
|
|
21027
|
-
help: "",
|
|
21028
|
-
install:
|
|
21135
|
+
help: "https://ampcode.com/",
|
|
21136
|
+
install: {
|
|
21137
|
+
bash: "curl -fsSL https://ampcode.com/install.sh | bash",
|
|
21138
|
+
npm: "npm i -g @sourcegraph/amp"
|
|
21139
|
+
},
|
|
21029
21140
|
enter: [
|
|
21030
21141
|
/^.{0,4} Approve /
|
|
21031
21142
|
]
|
|
@@ -21195,7 +21306,7 @@ init_pidStore();
|
|
|
21195
21306
|
await init_pty();
|
|
21196
21307
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21197
21308
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21198
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21309
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21199
21310
|
import path11 from "path";
|
|
21200
21311
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21201
21312
|
var CLIS_CONFIG = config.clis;
|
|
@@ -21544,15 +21655,15 @@ ${prompt}` : prefix;
|
|
|
21544
21655
|
}).by((s) => {
|
|
21545
21656
|
if (!useFifo)
|
|
21546
21657
|
return s;
|
|
21547
|
-
const
|
|
21548
|
-
if (!
|
|
21658
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21659
|
+
if (!ipcResult)
|
|
21549
21660
|
return s;
|
|
21550
|
-
pendingExitCode.promise.finally(() =>
|
|
21661
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21551
21662
|
process.stderr.write(`
|
|
21552
21663
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21553
21664
|
|
|
21554
21665
|
`);
|
|
21555
|
-
return s.merge(
|
|
21666
|
+
return s.merge(ipcResult.stream);
|
|
21556
21667
|
}).onStart(async function promptOnStart() {
|
|
21557
21668
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21558
21669
|
if (prompt)
|
|
@@ -21574,7 +21685,7 @@ ${prompt}` : prefix;
|
|
|
21574
21685
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21575
21686
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21576
21687
|
return f.forEach(async (chars) => {
|
|
21577
|
-
await
|
|
21688
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21578
21689
|
}).run();
|
|
21579
21690
|
}).catch(() => f.run());
|
|
21580
21691
|
}).by(function consoleResponder(e) {
|
|
@@ -21646,7 +21757,7 @@ ${prompt}` : prefix;
|
|
|
21646
21757
|
})).to(fromWritable(process.stdout));
|
|
21647
21758
|
if (logPath) {
|
|
21648
21759
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21649
|
-
await
|
|
21760
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
21650
21761
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21651
21762
|
}
|
|
21652
21763
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21658,7 +21769,7 @@ ${prompt}` : prefix;
|
|
|
21658
21769
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21659
21770
|
const logFilePath = path11.resolve(logFile);
|
|
21660
21771
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21661
|
-
await
|
|
21772
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
21662
21773
|
}
|
|
21663
21774
|
return { exitCode, logs: terminalRender.render() };
|
|
21664
21775
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21677,6 +21788,15 @@ ${prompt}` : prefix;
|
|
|
21677
21788
|
resolve();
|
|
21678
21789
|
}, 1000))
|
|
21679
21790
|
]);
|
|
21791
|
+
await Promise.race([
|
|
21792
|
+
nextStdout.wait(),
|
|
21793
|
+
new Promise((resolve) => setTimeout(() => {
|
|
21794
|
+
if (!nextStdout.ready) {
|
|
21795
|
+
shell.write("\r");
|
|
21796
|
+
}
|
|
21797
|
+
resolve();
|
|
21798
|
+
}, 3000))
|
|
21799
|
+
]);
|
|
21680
21800
|
}
|
|
21681
21801
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21682
21802
|
if (waitForReady)
|
|
@@ -21725,5 +21845,5 @@ export {
|
|
|
21725
21845
|
CLIS_CONFIG
|
|
21726
21846
|
};
|
|
21727
21847
|
|
|
21728
|
-
//# debugId=
|
|
21848
|
+
//# debugId=6E96076BD519CF5364756E2164756E21
|
|
21729
21849
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/ts/cli.ts
CHANGED
|
@@ -10,18 +10,48 @@ import { PidStore } from "./pidStore.ts";
|
|
|
10
10
|
// Parse CLI arguments
|
|
11
11
|
const config = parseCliArgs(process.argv);
|
|
12
12
|
|
|
13
|
-
// Handle --append-prompt: write to active FIFO and exit
|
|
13
|
+
// Handle --append-prompt: write to active IPC (FIFO/Named Pipe) and exit
|
|
14
14
|
if (config.appendPrompt) {
|
|
15
|
-
const
|
|
16
|
-
if (!
|
|
17
|
-
console.error("No active agent with
|
|
15
|
+
const ipcPath = await PidStore.findActiveFifo(process.cwd());
|
|
16
|
+
if (!ipcPath) {
|
|
17
|
+
console.error("No active agent with IPC found in current directory.");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
if (process.platform === "win32") {
|
|
23
|
+
// Windows named pipe
|
|
24
|
+
const { connect } = await import("net");
|
|
25
|
+
await new Promise<void>((resolve, reject) => {
|
|
26
|
+
const client = connect(ipcPath);
|
|
27
|
+
client.on('connect', () => {
|
|
28
|
+
client.write(config.appendPrompt + "\r");
|
|
29
|
+
client.end();
|
|
30
|
+
console.log(`Sent prompt to Windows named pipe: ${ipcPath}`);
|
|
31
|
+
resolve();
|
|
32
|
+
});
|
|
33
|
+
client.on('error', (error) => {
|
|
34
|
+
console.error(`Failed to connect to named pipe: ${error}`);
|
|
35
|
+
reject(error);
|
|
36
|
+
});
|
|
37
|
+
// Timeout after 5 seconds
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
client.destroy();
|
|
40
|
+
reject(new Error('Connection timeout'));
|
|
41
|
+
}, 5000);
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
// Linux FIFO (original implementation)
|
|
45
|
+
const { writeFileSync, openSync, closeSync } = await import("fs");
|
|
46
|
+
const fd = openSync(ipcPath, "w");
|
|
47
|
+
writeFileSync(fd, config.appendPrompt + "\r");
|
|
48
|
+
closeSync(fd);
|
|
49
|
+
console.log(`Sent prompt to FIFO: ${ipcPath}`);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`Failed to send prompt: ${error}`);
|
|
18
53
|
process.exit(1);
|
|
19
54
|
}
|
|
20
|
-
const { writeFileSync, openSync, closeSync } = await import("fs");
|
|
21
|
-
const fd = openSync(fifoPath, "w");
|
|
22
|
-
writeFileSync(fd, config.appendPrompt + "\r");
|
|
23
|
-
closeSync(fd);
|
|
24
|
-
console.log(`Sent prompt to ${fifoPath}`);
|
|
25
55
|
process.exit(0);
|
|
26
56
|
}
|
|
27
57
|
|
package/ts/index.ts
CHANGED
|
@@ -580,14 +580,14 @@ export default async function agentYes({
|
|
|
580
580
|
});
|
|
581
581
|
})
|
|
582
582
|
|
|
583
|
-
// read from
|
|
583
|
+
// read from IPC stream if available (FIFO on Linux, Named Pipes on Windows)
|
|
584
584
|
.by((s) => {
|
|
585
585
|
if (!useFifo) return s;
|
|
586
|
-
const
|
|
587
|
-
if (!
|
|
588
|
-
pendingExitCode.promise.finally(() =>
|
|
586
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
587
|
+
if (!ipcResult) return s;
|
|
588
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
589
589
|
process.stderr.write(`\n Append prompts: ${cli}-yes --append-prompt '...'\n\n`);
|
|
590
|
-
return s.merge(
|
|
590
|
+
return s.merge(ipcResult.stream);
|
|
591
591
|
})
|
|
592
592
|
|
|
593
593
|
// .map((e) => e.replaceAll('\x1a', '')) // remove ctrl+z from user's input, to prevent bug (but this seems bug)
|
|
@@ -808,6 +808,19 @@ export default async function agentYes({
|
|
|
808
808
|
}, 1000),
|
|
809
809
|
),
|
|
810
810
|
]);
|
|
811
|
+
|
|
812
|
+
// retry the second time if not received any output in 3 second after sending Enter
|
|
813
|
+
await Promise.race([
|
|
814
|
+
nextStdout.wait(),
|
|
815
|
+
new Promise<void>((resolve) =>
|
|
816
|
+
setTimeout(() => {
|
|
817
|
+
if (!nextStdout.ready) {
|
|
818
|
+
shell.write("\r");
|
|
819
|
+
}
|
|
820
|
+
resolve();
|
|
821
|
+
}, 3000),
|
|
822
|
+
),
|
|
823
|
+
]);
|
|
811
824
|
}
|
|
812
825
|
|
|
813
826
|
async function sendMessage(message: string, { waitForReady = true } = {}) {
|
package/ts/parseCliArgs.ts
CHANGED
|
@@ -27,6 +27,10 @@ export function parseCliArgs(argv: string[]) {
|
|
|
27
27
|
"$0 claude --idle=30s -- solve all todos in my codebase, commit one by one",
|
|
28
28
|
"Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`",
|
|
29
29
|
)
|
|
30
|
+
.example(
|
|
31
|
+
"$0 claude --stdpush",
|
|
32
|
+
"Run Claude with external stdin input enabled via --append-prompt",
|
|
33
|
+
)
|
|
30
34
|
// TODO: add a --docker option, will tell cli.ts to start docker process with tty and handles all stdio forwarding
|
|
31
35
|
|
|
32
36
|
.option("robust", {
|
|
@@ -91,12 +95,13 @@ export function parseCliArgs(argv: string[]) {
|
|
|
91
95
|
})
|
|
92
96
|
.option("append-prompt", {
|
|
93
97
|
type: "string",
|
|
94
|
-
description: "Send a prompt to the active agent's
|
|
98
|
+
description: "Send a prompt to the active agent's stdin in current directory",
|
|
95
99
|
})
|
|
96
|
-
.option("
|
|
100
|
+
.option("stdpush", {
|
|
97
101
|
type: "boolean",
|
|
98
|
-
description: "Enable
|
|
102
|
+
description: "Enable external input stream to push additional data to stdin",
|
|
99
103
|
default: false,
|
|
104
|
+
alias: ["ipc", "fifo"], // backward compatibility
|
|
100
105
|
})
|
|
101
106
|
.positional("cli", {
|
|
102
107
|
describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
|
|
@@ -191,6 +196,6 @@ export function parseCliArgs(argv: string[]) {
|
|
|
191
196
|
resume: parsedArgv.continue, // Note: intentional use resume here to avoid preserved keyword (continue)
|
|
192
197
|
useSkills: parsedArgv.useSkills,
|
|
193
198
|
appendPrompt: parsedArgv.appendPrompt,
|
|
194
|
-
useFifo: parsedArgv.fifo,
|
|
199
|
+
useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo, // Support --stdpush, --ipc, and --fifo (backward compatibility)
|
|
195
200
|
};
|
|
196
201
|
}
|
package/ts/pidStore.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir } from "fs/promises";
|
|
1
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { logger } from "./logger.ts";
|
|
4
4
|
|
|
@@ -67,17 +67,20 @@ class SqliteAdapter {
|
|
|
67
67
|
|
|
68
68
|
export class PidStore {
|
|
69
69
|
protected db!: SqliteAdapter;
|
|
70
|
-
private
|
|
70
|
+
private storeDir: string;
|
|
71
71
|
private dbPath: string;
|
|
72
72
|
|
|
73
73
|
constructor(workingDir: string) {
|
|
74
|
-
this.
|
|
75
|
-
this.dbPath = path.join(this.
|
|
74
|
+
this.storeDir = path.resolve(workingDir, ".agent-yes");
|
|
75
|
+
this.dbPath = path.join(this.storeDir, "pid.sqlite");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
async init(): Promise<void> {
|
|
79
|
-
await mkdir(path.join(this.
|
|
80
|
-
await mkdir(path.join(this.
|
|
79
|
+
await mkdir(path.join(this.storeDir, "logs"), { recursive: true });
|
|
80
|
+
await mkdir(path.join(this.storeDir, "fifo"), { recursive: true });
|
|
81
|
+
|
|
82
|
+
// Auto-generate .gitignore for .agent-yes directory
|
|
83
|
+
await this.ensureGitignore();
|
|
81
84
|
|
|
82
85
|
this.db = new SqliteAdapter();
|
|
83
86
|
await this.db.init(this.dbPath);
|
|
@@ -182,11 +185,17 @@ export class PidStore {
|
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
getLogPath(pid: number): string {
|
|
185
|
-
return path.resolve(this.
|
|
188
|
+
return path.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
getFifoPath(pid: number): string {
|
|
189
|
-
|
|
192
|
+
if (process.platform === "win32") {
|
|
193
|
+
// Windows named pipe format
|
|
194
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
195
|
+
} else {
|
|
196
|
+
// Linux FIFO file path
|
|
197
|
+
return path.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
198
|
+
}
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
async cleanStaleRecords(): Promise<void> {
|
|
@@ -226,6 +235,31 @@ export class PidStore {
|
|
|
226
235
|
}
|
|
227
236
|
}
|
|
228
237
|
|
|
238
|
+
private async ensureGitignore(): Promise<void> {
|
|
239
|
+
const gitignorePath = path.join(this.storeDir, ".gitignore");
|
|
240
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
241
|
+
# Ignore all log files and runtime data
|
|
242
|
+
logs/
|
|
243
|
+
fifo/
|
|
244
|
+
*.sqlite
|
|
245
|
+
*.sqlite-*
|
|
246
|
+
*.log
|
|
247
|
+
*.raw.log
|
|
248
|
+
*.lines.log
|
|
249
|
+
*.debug.log
|
|
250
|
+
`;
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
await writeFile(gitignorePath, gitignoreContent, { flag: 'wx' }); // wx = create only if doesn't exist
|
|
254
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
255
|
+
} catch (error: any) {
|
|
256
|
+
if (error.code !== 'EEXIST') {
|
|
257
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
258
|
+
}
|
|
259
|
+
// If file exists, that's fine - don't overwrite existing gitignore
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
229
263
|
static async findActiveFifo(workingDir: string): Promise<string | null> {
|
|
230
264
|
const store = new PidStore(workingDir);
|
|
231
265
|
await store.init();
|