claude-yes 1.35.1 → 1.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +245 -54
- package/dist/index.js +150 -22
- 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,12 +20633,94 @@ 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;
|
|
20723
|
+
logger.debug(`[${cli}-yes] Creating Linux FIFO with customPath: ${customPath}`);
|
|
20642
20724
|
try {
|
|
20643
20725
|
if (customPath) {
|
|
20644
20726
|
fifoPath = customPath;
|
|
@@ -20647,12 +20729,19 @@ function createFifoStream(cli, customPath) {
|
|
|
20647
20729
|
const randomSuffix = Math.random().toString(36).substring(2, 5);
|
|
20648
20730
|
fifoPath = `/tmp/agent-yes-${timestamp}${randomSuffix}.stdin`;
|
|
20649
20731
|
}
|
|
20650
|
-
|
|
20651
|
-
|
|
20732
|
+
try {
|
|
20733
|
+
mkdirSync(dirname(fifoPath), { recursive: true });
|
|
20734
|
+
} catch (dirError) {
|
|
20735
|
+
logger.warn(`[${cli}-yes] Failed to create FIFO directory: ${dirError}`);
|
|
20736
|
+
return null;
|
|
20737
|
+
}
|
|
20738
|
+
const escapedPath = fifoPath.replace(/'/g, `'"'"'`);
|
|
20739
|
+
const mkfifoResult = execaCommandSync(`mkfifo '${escapedPath}'`, {
|
|
20652
20740
|
reject: false
|
|
20653
20741
|
});
|
|
20654
20742
|
if (mkfifoResult.exitCode !== 0) {
|
|
20655
20743
|
logger.warn(`[${cli}-yes] mkfifo command failed with exit code ${mkfifoResult.exitCode}`);
|
|
20744
|
+
logger.warn(`[${cli}-yes] Command: mkfifo '${escapedPath}'`);
|
|
20656
20745
|
if (mkfifoResult.stderr) {
|
|
20657
20746
|
logger.warn(`[${cli}-yes] mkfifo stderr: ${mkfifoResult.stderr}`);
|
|
20658
20747
|
}
|
|
@@ -20732,7 +20821,7 @@ var init_fifo = __esm(() => {
|
|
|
20732
20821
|
});
|
|
20733
20822
|
|
|
20734
20823
|
// ts/pidStore.ts
|
|
20735
|
-
import { mkdir as mkdir3 } from "fs/promises";
|
|
20824
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
20736
20825
|
import path9 from "path";
|
|
20737
20826
|
|
|
20738
20827
|
class SqliteAdapter {
|
|
@@ -20776,15 +20865,16 @@ class SqliteAdapter {
|
|
|
20776
20865
|
|
|
20777
20866
|
class PidStore {
|
|
20778
20867
|
db;
|
|
20779
|
-
|
|
20868
|
+
storeDir;
|
|
20780
20869
|
dbPath;
|
|
20781
20870
|
constructor(workingDir) {
|
|
20782
|
-
this.
|
|
20783
|
-
this.dbPath = path9.join(this.
|
|
20871
|
+
this.storeDir = path9.resolve(workingDir, ".agent-yes");
|
|
20872
|
+
this.dbPath = path9.join(this.storeDir, "pid.sqlite");
|
|
20784
20873
|
}
|
|
20785
20874
|
async init() {
|
|
20786
|
-
await mkdir3(path9.join(this.
|
|
20787
|
-
await mkdir3(path9.join(this.
|
|
20875
|
+
await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
|
|
20876
|
+
await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
|
|
20877
|
+
await this.ensureGitignore();
|
|
20788
20878
|
this.db = new SqliteAdapter;
|
|
20789
20879
|
await this.db.init(this.dbPath);
|
|
20790
20880
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -20856,10 +20946,14 @@ class PidStore {
|
|
|
20856
20946
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20857
20947
|
}
|
|
20858
20948
|
getLogPath(pid) {
|
|
20859
|
-
return path9.resolve(this.
|
|
20949
|
+
return path9.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
20860
20950
|
}
|
|
20861
20951
|
getFifoPath(pid) {
|
|
20862
|
-
|
|
20952
|
+
if (process.platform === "win32") {
|
|
20953
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
20954
|
+
} else {
|
|
20955
|
+
return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
20956
|
+
}
|
|
20863
20957
|
}
|
|
20864
20958
|
async cleanStaleRecords() {
|
|
20865
20959
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -20888,6 +20982,28 @@ class PidStore {
|
|
|
20888
20982
|
return false;
|
|
20889
20983
|
}
|
|
20890
20984
|
}
|
|
20985
|
+
async ensureGitignore() {
|
|
20986
|
+
const gitignorePath = path9.join(this.storeDir, ".gitignore");
|
|
20987
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
20988
|
+
# Ignore all log files and runtime data
|
|
20989
|
+
logs/
|
|
20990
|
+
fifo/
|
|
20991
|
+
*.sqlite
|
|
20992
|
+
*.sqlite-*
|
|
20993
|
+
*.log
|
|
20994
|
+
*.raw.log
|
|
20995
|
+
*.lines.log
|
|
20996
|
+
*.debug.log
|
|
20997
|
+
`;
|
|
20998
|
+
try {
|
|
20999
|
+
await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
21000
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
21001
|
+
} catch (error) {
|
|
21002
|
+
if (error.code !== "EEXIST") {
|
|
21003
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
21004
|
+
}
|
|
21005
|
+
}
|
|
21006
|
+
}
|
|
20891
21007
|
static async findActiveFifo(workingDir) {
|
|
20892
21008
|
const store = new PidStore(workingDir);
|
|
20893
21009
|
await store.init();
|
|
@@ -21026,8 +21142,11 @@ function getDefaultConfig() {
|
|
|
21026
21142
|
fatal: []
|
|
21027
21143
|
},
|
|
21028
21144
|
amp: {
|
|
21029
|
-
help: "",
|
|
21030
|
-
install:
|
|
21145
|
+
help: "https://ampcode.com/",
|
|
21146
|
+
install: {
|
|
21147
|
+
bash: "curl -fsSL https://ampcode.com/install.sh | bash",
|
|
21148
|
+
npm: "npm i -g @sourcegraph/amp"
|
|
21149
|
+
},
|
|
21031
21150
|
enter: [
|
|
21032
21151
|
/^.{0,4} Approve /
|
|
21033
21152
|
]
|
|
@@ -21221,7 +21340,7 @@ __export(exports_ts, {
|
|
|
21221
21340
|
CLIS_CONFIG: () => CLIS_CONFIG2
|
|
21222
21341
|
});
|
|
21223
21342
|
import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
|
|
21224
|
-
import { mkdir as mkdir7, readFile as readFile4, writeFile as
|
|
21343
|
+
import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile7 } from "fs/promises";
|
|
21225
21344
|
import path13 from "path";
|
|
21226
21345
|
async function agentYes2({
|
|
21227
21346
|
cli,
|
|
@@ -21568,15 +21687,15 @@ ${prompt}` : prefix;
|
|
|
21568
21687
|
}).by((s) => {
|
|
21569
21688
|
if (!useFifo)
|
|
21570
21689
|
return s;
|
|
21571
|
-
const
|
|
21572
|
-
if (!
|
|
21690
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21691
|
+
if (!ipcResult)
|
|
21573
21692
|
return s;
|
|
21574
|
-
pendingExitCode.promise.finally(() =>
|
|
21693
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21575
21694
|
process.stderr.write(`
|
|
21576
21695
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21577
21696
|
|
|
21578
21697
|
`);
|
|
21579
|
-
return s.merge(
|
|
21698
|
+
return s.merge(ipcResult.stream);
|
|
21580
21699
|
}).onStart(async function promptOnStart() {
|
|
21581
21700
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21582
21701
|
if (prompt)
|
|
@@ -21598,7 +21717,7 @@ ${prompt}` : prefix;
|
|
|
21598
21717
|
return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21599
21718
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21600
21719
|
return f.forEach(async (chars) => {
|
|
21601
|
-
await
|
|
21720
|
+
await writeFile7(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21602
21721
|
}).run();
|
|
21603
21722
|
}).catch(() => f.run());
|
|
21604
21723
|
}).by(function consoleResponder(e) {
|
|
@@ -21670,7 +21789,7 @@ ${prompt}` : prefix;
|
|
|
21670
21789
|
})).to(fromWritable2(process.stdout));
|
|
21671
21790
|
if (logPath) {
|
|
21672
21791
|
await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21673
|
-
await
|
|
21792
|
+
await writeFile7(logPath, terminalRender.render()).catch(() => null);
|
|
21674
21793
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21675
21794
|
}
|
|
21676
21795
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21682,7 +21801,7 @@ ${prompt}` : prefix;
|
|
|
21682
21801
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21683
21802
|
const logFilePath = path13.resolve(logFile);
|
|
21684
21803
|
await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21685
|
-
await
|
|
21804
|
+
await writeFile7(logFilePath, terminalRender.render());
|
|
21686
21805
|
}
|
|
21687
21806
|
return { exitCode, logs: terminalRender.render() };
|
|
21688
21807
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21701,6 +21820,15 @@ ${prompt}` : prefix;
|
|
|
21701
21820
|
resolve5();
|
|
21702
21821
|
}, 1000))
|
|
21703
21822
|
]);
|
|
21823
|
+
await Promise.race([
|
|
21824
|
+
nextStdout.wait(),
|
|
21825
|
+
new Promise((resolve5) => setTimeout(() => {
|
|
21826
|
+
if (!nextStdout.ready) {
|
|
21827
|
+
shell.write("\r");
|
|
21828
|
+
}
|
|
21829
|
+
resolve5();
|
|
21830
|
+
}, 3000))
|
|
21831
|
+
]);
|
|
21704
21832
|
}
|
|
21705
21833
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21706
21834
|
if (waitForReady)
|
|
@@ -21772,7 +21900,7 @@ init_pidStore();
|
|
|
21772
21900
|
await init_pty();
|
|
21773
21901
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21774
21902
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21775
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21903
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21776
21904
|
import path11 from "path";
|
|
21777
21905
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21778
21906
|
var CLIS_CONFIG = config.clis;
|
|
@@ -22121,15 +22249,15 @@ ${prompt}` : prefix;
|
|
|
22121
22249
|
}).by((s) => {
|
|
22122
22250
|
if (!useFifo)
|
|
22123
22251
|
return s;
|
|
22124
|
-
const
|
|
22125
|
-
if (!
|
|
22252
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
22253
|
+
if (!ipcResult)
|
|
22126
22254
|
return s;
|
|
22127
|
-
pendingExitCode.promise.finally(() =>
|
|
22255
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
22128
22256
|
process.stderr.write(`
|
|
22129
22257
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
22130
22258
|
|
|
22131
22259
|
`);
|
|
22132
|
-
return s.merge(
|
|
22260
|
+
return s.merge(ipcResult.stream);
|
|
22133
22261
|
}).onStart(async function promptOnStart() {
|
|
22134
22262
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
22135
22263
|
if (prompt)
|
|
@@ -22151,7 +22279,7 @@ ${prompt}` : prefix;
|
|
|
22151
22279
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
22152
22280
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
22153
22281
|
return f.forEach(async (chars) => {
|
|
22154
|
-
await
|
|
22282
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
22155
22283
|
}).run();
|
|
22156
22284
|
}).catch(() => f.run());
|
|
22157
22285
|
}).by(function consoleResponder(e) {
|
|
@@ -22223,7 +22351,7 @@ ${prompt}` : prefix;
|
|
|
22223
22351
|
})).to(fromWritable(process.stdout));
|
|
22224
22352
|
if (logPath) {
|
|
22225
22353
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
22226
|
-
await
|
|
22354
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
22227
22355
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
22228
22356
|
}
|
|
22229
22357
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -22235,7 +22363,7 @@ ${prompt}` : prefix;
|
|
|
22235
22363
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
22236
22364
|
const logFilePath = path11.resolve(logFile);
|
|
22237
22365
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
22238
|
-
await
|
|
22366
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
22239
22367
|
}
|
|
22240
22368
|
return { exitCode, logs: terminalRender.render() };
|
|
22241
22369
|
async function sendEnter(waitms = 1000) {
|
|
@@ -22254,6 +22382,15 @@ ${prompt}` : prefix;
|
|
|
22254
22382
|
resolve();
|
|
22255
22383
|
}, 1000))
|
|
22256
22384
|
]);
|
|
22385
|
+
await Promise.race([
|
|
22386
|
+
nextStdout.wait(),
|
|
22387
|
+
new Promise((resolve) => setTimeout(() => {
|
|
22388
|
+
if (!nextStdout.ready) {
|
|
22389
|
+
shell.write("\r");
|
|
22390
|
+
}
|
|
22391
|
+
resolve();
|
|
22392
|
+
}, 3000))
|
|
22393
|
+
]);
|
|
22257
22394
|
}
|
|
22258
22395
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
22259
22396
|
if (waitForReady)
|
|
@@ -24132,13 +24269,13 @@ function stringWidth3(string, options = {}) {
|
|
|
24132
24269
|
}
|
|
24133
24270
|
|
|
24134
24271
|
// node_modules/y18n/build/lib/platform-shims/node.js
|
|
24135
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
24272
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile5 } from "fs";
|
|
24136
24273
|
import { format as format3 } from "util";
|
|
24137
24274
|
import { resolve as resolve3 } from "path";
|
|
24138
24275
|
var node_default = {
|
|
24139
24276
|
fs: {
|
|
24140
24277
|
readFileSync: readFileSync4,
|
|
24141
|
-
writeFile:
|
|
24278
|
+
writeFile: writeFile5
|
|
24142
24279
|
},
|
|
24143
24280
|
format: format3,
|
|
24144
24281
|
resolve: resolve3,
|
|
@@ -27848,7 +27985,7 @@ var package_default = {
|
|
|
27848
27985
|
// ts/parseCliArgs.ts
|
|
27849
27986
|
function parseCliArgs(argv) {
|
|
27850
27987
|
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", {
|
|
27988
|
+
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
27989
|
type: "boolean",
|
|
27853
27990
|
default: true,
|
|
27854
27991
|
description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
|
|
@@ -27896,11 +28033,12 @@ function parseCliArgs(argv) {
|
|
|
27896
28033
|
alias: "c"
|
|
27897
28034
|
}).option("append-prompt", {
|
|
27898
28035
|
type: "string",
|
|
27899
|
-
description: "Send a prompt to the active agent's
|
|
27900
|
-
}).option("
|
|
28036
|
+
description: "Send a prompt to the active agent's stdin in current directory"
|
|
28037
|
+
}).option("stdpush", {
|
|
27901
28038
|
type: "boolean",
|
|
27902
|
-
description: "Enable
|
|
27903
|
-
default: false
|
|
28039
|
+
description: "Enable external input stream to push additional data to stdin",
|
|
28040
|
+
default: false,
|
|
28041
|
+
alias: ["ipc", "fifo"]
|
|
27904
28042
|
}).positional("cli", {
|
|
27905
28043
|
describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
|
|
27906
28044
|
type: "string",
|
|
@@ -27973,7 +28111,7 @@ function parseCliArgs(argv) {
|
|
|
27973
28111
|
resume: parsedArgv.continue,
|
|
27974
28112
|
useSkills: parsedArgv.useSkills,
|
|
27975
28113
|
appendPrompt: parsedArgv.appendPrompt,
|
|
27976
|
-
useFifo: parsedArgv.fifo
|
|
28114
|
+
useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo
|
|
27977
28115
|
};
|
|
27978
28116
|
}
|
|
27979
28117
|
|
|
@@ -27996,7 +28134,7 @@ var logger2 = import_winston3.default.createLogger({
|
|
|
27996
28134
|
|
|
27997
28135
|
// ts/pidStore.ts
|
|
27998
28136
|
init_logger();
|
|
27999
|
-
import { mkdir as mkdir6 } from "fs/promises";
|
|
28137
|
+
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
28000
28138
|
import path12 from "path";
|
|
28001
28139
|
|
|
28002
28140
|
class SqliteAdapter2 {
|
|
@@ -28040,15 +28178,16 @@ class SqliteAdapter2 {
|
|
|
28040
28178
|
|
|
28041
28179
|
class PidStore2 {
|
|
28042
28180
|
db;
|
|
28043
|
-
|
|
28181
|
+
storeDir;
|
|
28044
28182
|
dbPath;
|
|
28045
28183
|
constructor(workingDir) {
|
|
28046
|
-
this.
|
|
28047
|
-
this.dbPath = path12.join(this.
|
|
28184
|
+
this.storeDir = path12.resolve(workingDir, ".agent-yes");
|
|
28185
|
+
this.dbPath = path12.join(this.storeDir, "pid.sqlite");
|
|
28048
28186
|
}
|
|
28049
28187
|
async init() {
|
|
28050
|
-
await mkdir6(path12.join(this.
|
|
28051
|
-
await mkdir6(path12.join(this.
|
|
28188
|
+
await mkdir6(path12.join(this.storeDir, "logs"), { recursive: true });
|
|
28189
|
+
await mkdir6(path12.join(this.storeDir, "fifo"), { recursive: true });
|
|
28190
|
+
await this.ensureGitignore();
|
|
28052
28191
|
this.db = new SqliteAdapter2;
|
|
28053
28192
|
await this.db.init(this.dbPath);
|
|
28054
28193
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -28120,10 +28259,14 @@ class PidStore2 {
|
|
|
28120
28259
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
28121
28260
|
}
|
|
28122
28261
|
getLogPath(pid) {
|
|
28123
|
-
return path12.resolve(this.
|
|
28262
|
+
return path12.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
28124
28263
|
}
|
|
28125
28264
|
getFifoPath(pid) {
|
|
28126
|
-
|
|
28265
|
+
if (process.platform === "win32") {
|
|
28266
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
28267
|
+
} else {
|
|
28268
|
+
return path12.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
28269
|
+
}
|
|
28127
28270
|
}
|
|
28128
28271
|
async cleanStaleRecords() {
|
|
28129
28272
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -28152,6 +28295,28 @@ class PidStore2 {
|
|
|
28152
28295
|
return false;
|
|
28153
28296
|
}
|
|
28154
28297
|
}
|
|
28298
|
+
async ensureGitignore() {
|
|
28299
|
+
const gitignorePath = path12.join(this.storeDir, ".gitignore");
|
|
28300
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
28301
|
+
# Ignore all log files and runtime data
|
|
28302
|
+
logs/
|
|
28303
|
+
fifo/
|
|
28304
|
+
*.sqlite
|
|
28305
|
+
*.sqlite-*
|
|
28306
|
+
*.log
|
|
28307
|
+
*.raw.log
|
|
28308
|
+
*.lines.log
|
|
28309
|
+
*.debug.log
|
|
28310
|
+
`;
|
|
28311
|
+
try {
|
|
28312
|
+
await writeFile6(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
28313
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
28314
|
+
} catch (error) {
|
|
28315
|
+
if (error.code !== "EEXIST") {
|
|
28316
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
28317
|
+
}
|
|
28318
|
+
}
|
|
28319
|
+
}
|
|
28155
28320
|
static async findActiveFifo(workingDir) {
|
|
28156
28321
|
const store = new PidStore2(workingDir);
|
|
28157
28322
|
await store.init();
|
|
@@ -28164,16 +28329,42 @@ class PidStore2 {
|
|
|
28164
28329
|
// ts/cli.ts
|
|
28165
28330
|
var config3 = parseCliArgs(process.argv);
|
|
28166
28331
|
if (config3.appendPrompt) {
|
|
28167
|
-
const
|
|
28168
|
-
if (!
|
|
28169
|
-
console.error("No active agent with
|
|
28332
|
+
const ipcPath = await PidStore2.findActiveFifo(process.cwd());
|
|
28333
|
+
if (!ipcPath) {
|
|
28334
|
+
console.error("No active agent with IPC found in current directory.");
|
|
28335
|
+
process.exit(1);
|
|
28336
|
+
}
|
|
28337
|
+
try {
|
|
28338
|
+
if (process.platform === "win32") {
|
|
28339
|
+
const { connect } = await import("net");
|
|
28340
|
+
await new Promise((resolve5, reject) => {
|
|
28341
|
+
const client = connect(ipcPath);
|
|
28342
|
+
client.on("connect", () => {
|
|
28343
|
+
client.write(config3.appendPrompt + "\r");
|
|
28344
|
+
client.end();
|
|
28345
|
+
console.log(`Sent prompt to Windows named pipe: ${ipcPath}`);
|
|
28346
|
+
resolve5();
|
|
28347
|
+
});
|
|
28348
|
+
client.on("error", (error) => {
|
|
28349
|
+
console.error(`Failed to connect to named pipe: ${error}`);
|
|
28350
|
+
reject(error);
|
|
28351
|
+
});
|
|
28352
|
+
setTimeout(() => {
|
|
28353
|
+
client.destroy();
|
|
28354
|
+
reject(new Error("Connection timeout"));
|
|
28355
|
+
}, 5000);
|
|
28356
|
+
});
|
|
28357
|
+
} else {
|
|
28358
|
+
const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
|
|
28359
|
+
const fd = openSync(ipcPath, "w");
|
|
28360
|
+
writeFileSync2(fd, config3.appendPrompt + "\r");
|
|
28361
|
+
closeSync(fd);
|
|
28362
|
+
console.log(`Sent prompt to FIFO: ${ipcPath}`);
|
|
28363
|
+
}
|
|
28364
|
+
} catch (error) {
|
|
28365
|
+
console.error(`Failed to send prompt: ${error}`);
|
|
28170
28366
|
process.exit(1);
|
|
28171
28367
|
}
|
|
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
28368
|
process.exit(0);
|
|
28178
28369
|
}
|
|
28179
28370
|
if (!config3.cli) {
|
|
@@ -28190,5 +28381,5 @@ var { exitCode } = await cliYes(config3);
|
|
|
28190
28381
|
console.log("exiting process");
|
|
28191
28382
|
process.exit(exitCode ?? 1);
|
|
28192
28383
|
|
|
28193
|
-
//# debugId=
|
|
28384
|
+
//# debugId=2520933E2CA2793364756E2164756E21
|
|
28194
28385
|
//# sourceMappingURL=cli.js.map
|
package/dist/index.js
CHANGED
|
@@ -20631,12 +20631,94 @@ 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}`);
|
|
20636
20642
|
return null;
|
|
20637
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);
|
|
20715
|
+
return null;
|
|
20716
|
+
}
|
|
20717
|
+
}
|
|
20718
|
+
function createLinuxFifo(cli, customPath) {
|
|
20638
20719
|
let fifoPath = null;
|
|
20639
20720
|
let fifoStream = null;
|
|
20721
|
+
logger.debug(`[${cli}-yes] Creating Linux FIFO with customPath: ${customPath}`);
|
|
20640
20722
|
try {
|
|
20641
20723
|
if (customPath) {
|
|
20642
20724
|
fifoPath = customPath;
|
|
@@ -20645,12 +20727,19 @@ function createFifoStream(cli, customPath) {
|
|
|
20645
20727
|
const randomSuffix = Math.random().toString(36).substring(2, 5);
|
|
20646
20728
|
fifoPath = `/tmp/agent-yes-${timestamp}${randomSuffix}.stdin`;
|
|
20647
20729
|
}
|
|
20648
|
-
|
|
20649
|
-
|
|
20730
|
+
try {
|
|
20731
|
+
mkdirSync(dirname(fifoPath), { recursive: true });
|
|
20732
|
+
} catch (dirError) {
|
|
20733
|
+
logger.warn(`[${cli}-yes] Failed to create FIFO directory: ${dirError}`);
|
|
20734
|
+
return null;
|
|
20735
|
+
}
|
|
20736
|
+
const escapedPath = fifoPath.replace(/'/g, `'"'"'`);
|
|
20737
|
+
const mkfifoResult = execaCommandSync(`mkfifo '${escapedPath}'`, {
|
|
20650
20738
|
reject: false
|
|
20651
20739
|
});
|
|
20652
20740
|
if (mkfifoResult.exitCode !== 0) {
|
|
20653
20741
|
logger.warn(`[${cli}-yes] mkfifo command failed with exit code ${mkfifoResult.exitCode}`);
|
|
20742
|
+
logger.warn(`[${cli}-yes] Command: mkfifo '${escapedPath}'`);
|
|
20654
20743
|
if (mkfifoResult.stderr) {
|
|
20655
20744
|
logger.warn(`[${cli}-yes] mkfifo stderr: ${mkfifoResult.stderr}`);
|
|
20656
20745
|
}
|
|
@@ -20730,7 +20819,7 @@ var init_fifo = __esm(() => {
|
|
|
20730
20819
|
});
|
|
20731
20820
|
|
|
20732
20821
|
// ts/pidStore.ts
|
|
20733
|
-
import { mkdir as mkdir3 } from "fs/promises";
|
|
20822
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
20734
20823
|
import path9 from "path";
|
|
20735
20824
|
|
|
20736
20825
|
class SqliteAdapter {
|
|
@@ -20774,15 +20863,16 @@ class SqliteAdapter {
|
|
|
20774
20863
|
|
|
20775
20864
|
class PidStore {
|
|
20776
20865
|
db;
|
|
20777
|
-
|
|
20866
|
+
storeDir;
|
|
20778
20867
|
dbPath;
|
|
20779
20868
|
constructor(workingDir) {
|
|
20780
|
-
this.
|
|
20781
|
-
this.dbPath = path9.join(this.
|
|
20869
|
+
this.storeDir = path9.resolve(workingDir, ".agent-yes");
|
|
20870
|
+
this.dbPath = path9.join(this.storeDir, "pid.sqlite");
|
|
20782
20871
|
}
|
|
20783
20872
|
async init() {
|
|
20784
|
-
await mkdir3(path9.join(this.
|
|
20785
|
-
await mkdir3(path9.join(this.
|
|
20873
|
+
await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
|
|
20874
|
+
await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
|
|
20875
|
+
await this.ensureGitignore();
|
|
20786
20876
|
this.db = new SqliteAdapter;
|
|
20787
20877
|
await this.db.init(this.dbPath);
|
|
20788
20878
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -20854,10 +20944,14 @@ class PidStore {
|
|
|
20854
20944
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20855
20945
|
}
|
|
20856
20946
|
getLogPath(pid) {
|
|
20857
|
-
return path9.resolve(this.
|
|
20947
|
+
return path9.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
20858
20948
|
}
|
|
20859
20949
|
getFifoPath(pid) {
|
|
20860
|
-
|
|
20950
|
+
if (process.platform === "win32") {
|
|
20951
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
20952
|
+
} else {
|
|
20953
|
+
return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
20954
|
+
}
|
|
20861
20955
|
}
|
|
20862
20956
|
async cleanStaleRecords() {
|
|
20863
20957
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -20886,6 +20980,28 @@ class PidStore {
|
|
|
20886
20980
|
return false;
|
|
20887
20981
|
}
|
|
20888
20982
|
}
|
|
20983
|
+
async ensureGitignore() {
|
|
20984
|
+
const gitignorePath = path9.join(this.storeDir, ".gitignore");
|
|
20985
|
+
const gitignoreContent = `# Auto-generated .gitignore for agent-yes
|
|
20986
|
+
# Ignore all log files and runtime data
|
|
20987
|
+
logs/
|
|
20988
|
+
fifo/
|
|
20989
|
+
*.sqlite
|
|
20990
|
+
*.sqlite-*
|
|
20991
|
+
*.log
|
|
20992
|
+
*.raw.log
|
|
20993
|
+
*.lines.log
|
|
20994
|
+
*.debug.log
|
|
20995
|
+
`;
|
|
20996
|
+
try {
|
|
20997
|
+
await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
|
|
20998
|
+
logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
|
|
20999
|
+
} catch (error) {
|
|
21000
|
+
if (error.code !== "EEXIST") {
|
|
21001
|
+
logger.warn(`[pidStore] Failed to create .gitignore:`, error);
|
|
21002
|
+
}
|
|
21003
|
+
}
|
|
21004
|
+
}
|
|
20889
21005
|
static async findActiveFifo(workingDir) {
|
|
20890
21006
|
const store = new PidStore(workingDir);
|
|
20891
21007
|
await store.init();
|
|
@@ -21024,8 +21140,11 @@ function getDefaultConfig() {
|
|
|
21024
21140
|
fatal: []
|
|
21025
21141
|
},
|
|
21026
21142
|
amp: {
|
|
21027
|
-
help: "",
|
|
21028
|
-
install:
|
|
21143
|
+
help: "https://ampcode.com/",
|
|
21144
|
+
install: {
|
|
21145
|
+
bash: "curl -fsSL https://ampcode.com/install.sh | bash",
|
|
21146
|
+
npm: "npm i -g @sourcegraph/amp"
|
|
21147
|
+
},
|
|
21029
21148
|
enter: [
|
|
21030
21149
|
/^.{0,4} Approve /
|
|
21031
21150
|
]
|
|
@@ -21195,7 +21314,7 @@ init_pidStore();
|
|
|
21195
21314
|
await init_pty();
|
|
21196
21315
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21197
21316
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21198
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21317
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21199
21318
|
import path11 from "path";
|
|
21200
21319
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21201
21320
|
var CLIS_CONFIG = config.clis;
|
|
@@ -21544,15 +21663,15 @@ ${prompt}` : prefix;
|
|
|
21544
21663
|
}).by((s) => {
|
|
21545
21664
|
if (!useFifo)
|
|
21546
21665
|
return s;
|
|
21547
|
-
const
|
|
21548
|
-
if (!
|
|
21666
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21667
|
+
if (!ipcResult)
|
|
21549
21668
|
return s;
|
|
21550
|
-
pendingExitCode.promise.finally(() =>
|
|
21669
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21551
21670
|
process.stderr.write(`
|
|
21552
21671
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21553
21672
|
|
|
21554
21673
|
`);
|
|
21555
|
-
return s.merge(
|
|
21674
|
+
return s.merge(ipcResult.stream);
|
|
21556
21675
|
}).onStart(async function promptOnStart() {
|
|
21557
21676
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21558
21677
|
if (prompt)
|
|
@@ -21574,7 +21693,7 @@ ${prompt}` : prefix;
|
|
|
21574
21693
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21575
21694
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21576
21695
|
return f.forEach(async (chars) => {
|
|
21577
|
-
await
|
|
21696
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21578
21697
|
}).run();
|
|
21579
21698
|
}).catch(() => f.run());
|
|
21580
21699
|
}).by(function consoleResponder(e) {
|
|
@@ -21646,7 +21765,7 @@ ${prompt}` : prefix;
|
|
|
21646
21765
|
})).to(fromWritable(process.stdout));
|
|
21647
21766
|
if (logPath) {
|
|
21648
21767
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21649
|
-
await
|
|
21768
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
21650
21769
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21651
21770
|
}
|
|
21652
21771
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21658,7 +21777,7 @@ ${prompt}` : prefix;
|
|
|
21658
21777
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21659
21778
|
const logFilePath = path11.resolve(logFile);
|
|
21660
21779
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21661
|
-
await
|
|
21780
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
21662
21781
|
}
|
|
21663
21782
|
return { exitCode, logs: terminalRender.render() };
|
|
21664
21783
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21677,6 +21796,15 @@ ${prompt}` : prefix;
|
|
|
21677
21796
|
resolve();
|
|
21678
21797
|
}, 1000))
|
|
21679
21798
|
]);
|
|
21799
|
+
await Promise.race([
|
|
21800
|
+
nextStdout.wait(),
|
|
21801
|
+
new Promise((resolve) => setTimeout(() => {
|
|
21802
|
+
if (!nextStdout.ready) {
|
|
21803
|
+
shell.write("\r");
|
|
21804
|
+
}
|
|
21805
|
+
resolve();
|
|
21806
|
+
}, 3000))
|
|
21807
|
+
]);
|
|
21680
21808
|
}
|
|
21681
21809
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21682
21810
|
if (waitForReady)
|
|
@@ -21725,5 +21853,5 @@ export {
|
|
|
21725
21853
|
CLIS_CONFIG
|
|
21726
21854
|
};
|
|
21727
21855
|
|
|
21728
|
-
//# debugId=
|
|
21856
|
+
//# debugId=581E1D2585250E0F64756E2164756E21
|
|
21729
21857
|
//# 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();
|