claude-yes 1.35.0 → 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 +240 -54
- package/dist/index.js +143 -20
- package/package.json +1 -1
- package/ts/cli.ts +39 -9
- package/ts/index.ts +18 -5
- package/ts/parseCliArgs.spec.ts +17 -0
- package/ts/parseCliArgs.ts +11 -5
- 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}`);
|
|
20638
20644
|
return null;
|
|
20639
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);
|
|
20717
|
+
return null;
|
|
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,14 @@ 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
|
+
},
|
|
21142
|
+
enter: [
|
|
21143
|
+
/^.{0,4} Approve /
|
|
21144
|
+
]
|
|
21031
21145
|
}
|
|
21032
21146
|
}
|
|
21033
21147
|
});
|
|
@@ -21218,7 +21332,7 @@ __export(exports_ts, {
|
|
|
21218
21332
|
CLIS_CONFIG: () => CLIS_CONFIG2
|
|
21219
21333
|
});
|
|
21220
21334
|
import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
|
|
21221
|
-
import { mkdir as mkdir7, readFile as readFile4, writeFile as
|
|
21335
|
+
import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile7 } from "fs/promises";
|
|
21222
21336
|
import path13 from "path";
|
|
21223
21337
|
async function agentYes2({
|
|
21224
21338
|
cli,
|
|
@@ -21565,15 +21679,15 @@ ${prompt}` : prefix;
|
|
|
21565
21679
|
}).by((s) => {
|
|
21566
21680
|
if (!useFifo)
|
|
21567
21681
|
return s;
|
|
21568
|
-
const
|
|
21569
|
-
if (!
|
|
21682
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21683
|
+
if (!ipcResult)
|
|
21570
21684
|
return s;
|
|
21571
|
-
pendingExitCode.promise.finally(() =>
|
|
21685
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21572
21686
|
process.stderr.write(`
|
|
21573
21687
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21574
21688
|
|
|
21575
21689
|
`);
|
|
21576
|
-
return s.merge(
|
|
21690
|
+
return s.merge(ipcResult.stream);
|
|
21577
21691
|
}).onStart(async function promptOnStart() {
|
|
21578
21692
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21579
21693
|
if (prompt)
|
|
@@ -21595,7 +21709,7 @@ ${prompt}` : prefix;
|
|
|
21595
21709
|
return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21596
21710
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21597
21711
|
return f.forEach(async (chars) => {
|
|
21598
|
-
await
|
|
21712
|
+
await writeFile7(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21599
21713
|
}).run();
|
|
21600
21714
|
}).catch(() => f.run());
|
|
21601
21715
|
}).by(function consoleResponder(e) {
|
|
@@ -21667,7 +21781,7 @@ ${prompt}` : prefix;
|
|
|
21667
21781
|
})).to(fromWritable2(process.stdout));
|
|
21668
21782
|
if (logPath) {
|
|
21669
21783
|
await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21670
|
-
await
|
|
21784
|
+
await writeFile7(logPath, terminalRender.render()).catch(() => null);
|
|
21671
21785
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21672
21786
|
}
|
|
21673
21787
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21679,7 +21793,7 @@ ${prompt}` : prefix;
|
|
|
21679
21793
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21680
21794
|
const logFilePath = path13.resolve(logFile);
|
|
21681
21795
|
await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21682
|
-
await
|
|
21796
|
+
await writeFile7(logFilePath, terminalRender.render());
|
|
21683
21797
|
}
|
|
21684
21798
|
return { exitCode, logs: terminalRender.render() };
|
|
21685
21799
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21698,6 +21812,15 @@ ${prompt}` : prefix;
|
|
|
21698
21812
|
resolve5();
|
|
21699
21813
|
}, 1000))
|
|
21700
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
|
+
]);
|
|
21701
21824
|
}
|
|
21702
21825
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21703
21826
|
if (waitForReady)
|
|
@@ -21769,7 +21892,7 @@ init_pidStore();
|
|
|
21769
21892
|
await init_pty();
|
|
21770
21893
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21771
21894
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21772
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21895
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21773
21896
|
import path11 from "path";
|
|
21774
21897
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21775
21898
|
var CLIS_CONFIG = config.clis;
|
|
@@ -22118,15 +22241,15 @@ ${prompt}` : prefix;
|
|
|
22118
22241
|
}).by((s) => {
|
|
22119
22242
|
if (!useFifo)
|
|
22120
22243
|
return s;
|
|
22121
|
-
const
|
|
22122
|
-
if (!
|
|
22244
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
22245
|
+
if (!ipcResult)
|
|
22123
22246
|
return s;
|
|
22124
|
-
pendingExitCode.promise.finally(() =>
|
|
22247
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
22125
22248
|
process.stderr.write(`
|
|
22126
22249
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
22127
22250
|
|
|
22128
22251
|
`);
|
|
22129
|
-
return s.merge(
|
|
22252
|
+
return s.merge(ipcResult.stream);
|
|
22130
22253
|
}).onStart(async function promptOnStart() {
|
|
22131
22254
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
22132
22255
|
if (prompt)
|
|
@@ -22148,7 +22271,7 @@ ${prompt}` : prefix;
|
|
|
22148
22271
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
22149
22272
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
22150
22273
|
return f.forEach(async (chars) => {
|
|
22151
|
-
await
|
|
22274
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
22152
22275
|
}).run();
|
|
22153
22276
|
}).catch(() => f.run());
|
|
22154
22277
|
}).by(function consoleResponder(e) {
|
|
@@ -22220,7 +22343,7 @@ ${prompt}` : prefix;
|
|
|
22220
22343
|
})).to(fromWritable(process.stdout));
|
|
22221
22344
|
if (logPath) {
|
|
22222
22345
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
22223
|
-
await
|
|
22346
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
22224
22347
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
22225
22348
|
}
|
|
22226
22349
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -22232,7 +22355,7 @@ ${prompt}` : prefix;
|
|
|
22232
22355
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
22233
22356
|
const logFilePath = path11.resolve(logFile);
|
|
22234
22357
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
22235
|
-
await
|
|
22358
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
22236
22359
|
}
|
|
22237
22360
|
return { exitCode, logs: terminalRender.render() };
|
|
22238
22361
|
async function sendEnter(waitms = 1000) {
|
|
@@ -22251,6 +22374,15 @@ ${prompt}` : prefix;
|
|
|
22251
22374
|
resolve();
|
|
22252
22375
|
}, 1000))
|
|
22253
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
|
+
]);
|
|
22254
22386
|
}
|
|
22255
22387
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
22256
22388
|
if (waitForReady)
|
|
@@ -24129,13 +24261,13 @@ function stringWidth3(string, options = {}) {
|
|
|
24129
24261
|
}
|
|
24130
24262
|
|
|
24131
24263
|
// node_modules/y18n/build/lib/platform-shims/node.js
|
|
24132
|
-
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as
|
|
24264
|
+
import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile5 } from "fs";
|
|
24133
24265
|
import { format as format3 } from "util";
|
|
24134
24266
|
import { resolve as resolve3 } from "path";
|
|
24135
24267
|
var node_default = {
|
|
24136
24268
|
fs: {
|
|
24137
24269
|
readFileSync: readFileSync4,
|
|
24138
|
-
writeFile:
|
|
24270
|
+
writeFile: writeFile5
|
|
24139
24271
|
},
|
|
24140
24272
|
format: format3,
|
|
24141
24273
|
resolve: resolve3,
|
|
@@ -27844,8 +27976,8 @@ var package_default = {
|
|
|
27844
27976
|
|
|
27845
27977
|
// ts/parseCliArgs.ts
|
|
27846
27978
|
function parseCliArgs(argv) {
|
|
27847
|
-
const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/-yes$/, "") || undefined;
|
|
27848
|
-
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", {
|
|
27979
|
+
const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/^ay$/, "").replace(/-yes$/, "") || undefined;
|
|
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", {
|
|
27849
27981
|
type: "boolean",
|
|
27850
27982
|
default: true,
|
|
27851
27983
|
description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
|
|
@@ -27893,11 +28025,12 @@ function parseCliArgs(argv) {
|
|
|
27893
28025
|
alias: "c"
|
|
27894
28026
|
}).option("append-prompt", {
|
|
27895
28027
|
type: "string",
|
|
27896
|
-
description: "Send a prompt to the active agent's
|
|
27897
|
-
}).option("
|
|
28028
|
+
description: "Send a prompt to the active agent's stdin in current directory"
|
|
28029
|
+
}).option("stdpush", {
|
|
27898
28030
|
type: "boolean",
|
|
27899
|
-
description: "Enable
|
|
27900
|
-
default: false
|
|
28031
|
+
description: "Enable external input stream to push additional data to stdin",
|
|
28032
|
+
default: false,
|
|
28033
|
+
alias: ["ipc", "fifo"]
|
|
27901
28034
|
}).positional("cli", {
|
|
27902
28035
|
describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
|
|
27903
28036
|
type: "string",
|
|
@@ -27958,7 +28091,7 @@ function parseCliArgs(argv) {
|
|
|
27958
28091
|
return {
|
|
27959
28092
|
cwd: process.cwd(),
|
|
27960
28093
|
env: process.env,
|
|
27961
|
-
cli: cliName || parsedArgv.cli || parsedArgv._[0]?.toString()?.replace?.(/-yes$/, ""),
|
|
28094
|
+
cli: cliName || parsedArgv.cli || (dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : undefined),
|
|
27962
28095
|
cliArgs: cliArgsForSpawn,
|
|
27963
28096
|
prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || undefined,
|
|
27964
28097
|
install: parsedArgv.install,
|
|
@@ -27970,7 +28103,7 @@ function parseCliArgs(argv) {
|
|
|
27970
28103
|
resume: parsedArgv.continue,
|
|
27971
28104
|
useSkills: parsedArgv.useSkills,
|
|
27972
28105
|
appendPrompt: parsedArgv.appendPrompt,
|
|
27973
|
-
useFifo: parsedArgv.fifo
|
|
28106
|
+
useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo
|
|
27974
28107
|
};
|
|
27975
28108
|
}
|
|
27976
28109
|
|
|
@@ -27993,7 +28126,7 @@ var logger2 = import_winston3.default.createLogger({
|
|
|
27993
28126
|
|
|
27994
28127
|
// ts/pidStore.ts
|
|
27995
28128
|
init_logger();
|
|
27996
|
-
import { mkdir as mkdir6 } from "fs/promises";
|
|
28129
|
+
import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
|
|
27997
28130
|
import path12 from "path";
|
|
27998
28131
|
|
|
27999
28132
|
class SqliteAdapter2 {
|
|
@@ -28037,15 +28170,16 @@ class SqliteAdapter2 {
|
|
|
28037
28170
|
|
|
28038
28171
|
class PidStore2 {
|
|
28039
28172
|
db;
|
|
28040
|
-
|
|
28173
|
+
storeDir;
|
|
28041
28174
|
dbPath;
|
|
28042
28175
|
constructor(workingDir) {
|
|
28043
|
-
this.
|
|
28044
|
-
this.dbPath = path12.join(this.
|
|
28176
|
+
this.storeDir = path12.resolve(workingDir, ".agent-yes");
|
|
28177
|
+
this.dbPath = path12.join(this.storeDir, "pid.sqlite");
|
|
28045
28178
|
}
|
|
28046
28179
|
async init() {
|
|
28047
|
-
await mkdir6(path12.join(this.
|
|
28048
|
-
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();
|
|
28049
28183
|
this.db = new SqliteAdapter2;
|
|
28050
28184
|
await this.db.init(this.dbPath);
|
|
28051
28185
|
this.db.run("PRAGMA journal_mode=WAL");
|
|
@@ -28117,10 +28251,14 @@ class PidStore2 {
|
|
|
28117
28251
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
28118
28252
|
}
|
|
28119
28253
|
getLogPath(pid) {
|
|
28120
|
-
return path12.resolve(this.
|
|
28254
|
+
return path12.resolve(this.storeDir, "logs", `${pid}.log`);
|
|
28121
28255
|
}
|
|
28122
28256
|
getFifoPath(pid) {
|
|
28123
|
-
|
|
28257
|
+
if (process.platform === "win32") {
|
|
28258
|
+
return `\\\\.\\pipe\\agent-yes-${pid}`;
|
|
28259
|
+
} else {
|
|
28260
|
+
return path12.resolve(this.storeDir, "fifo", `${pid}.stdin`);
|
|
28261
|
+
}
|
|
28124
28262
|
}
|
|
28125
28263
|
async cleanStaleRecords() {
|
|
28126
28264
|
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
@@ -28149,6 +28287,28 @@ class PidStore2 {
|
|
|
28149
28287
|
return false;
|
|
28150
28288
|
}
|
|
28151
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
|
+
}
|
|
28152
28312
|
static async findActiveFifo(workingDir) {
|
|
28153
28313
|
const store = new PidStore2(workingDir);
|
|
28154
28314
|
await store.init();
|
|
@@ -28161,16 +28321,42 @@ class PidStore2 {
|
|
|
28161
28321
|
// ts/cli.ts
|
|
28162
28322
|
var config3 = parseCliArgs(process.argv);
|
|
28163
28323
|
if (config3.appendPrompt) {
|
|
28164
|
-
const
|
|
28165
|
-
if (!
|
|
28166
|
-
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}`);
|
|
28167
28358
|
process.exit(1);
|
|
28168
28359
|
}
|
|
28169
|
-
const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
|
|
28170
|
-
const fd = openSync(fifoPath, "w");
|
|
28171
|
-
writeFileSync2(fd, config3.appendPrompt + "\r");
|
|
28172
|
-
closeSync(fd);
|
|
28173
|
-
console.log(`Sent prompt to ${fifoPath}`);
|
|
28174
28360
|
process.exit(0);
|
|
28175
28361
|
}
|
|
28176
28362
|
if (!config3.cli) {
|
|
@@ -28187,5 +28373,5 @@ var { exitCode } = await cliYes(config3);
|
|
|
28187
28373
|
console.log("exiting process");
|
|
28188
28374
|
process.exit(exitCode ?? 1);
|
|
28189
28375
|
|
|
28190
|
-
//# debugId=
|
|
28376
|
+
//# debugId=2519B84A9286C6F364756E2164756E21
|
|
28191
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}`);
|
|
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;
|
|
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,14 @@ 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
|
+
},
|
|
21140
|
+
enter: [
|
|
21141
|
+
/^.{0,4} Approve /
|
|
21142
|
+
]
|
|
21029
21143
|
}
|
|
21030
21144
|
}
|
|
21031
21145
|
});
|
|
@@ -21192,7 +21306,7 @@ init_pidStore();
|
|
|
21192
21306
|
await init_pty();
|
|
21193
21307
|
var import_winston2 = __toESM(require_winston(), 1);
|
|
21194
21308
|
import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
|
|
21195
|
-
import { mkdir as mkdir5, readFile as readFile3, writeFile as
|
|
21309
|
+
import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
21196
21310
|
import path11 from "path";
|
|
21197
21311
|
var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
|
|
21198
21312
|
var CLIS_CONFIG = config.clis;
|
|
@@ -21541,15 +21655,15 @@ ${prompt}` : prefix;
|
|
|
21541
21655
|
}).by((s) => {
|
|
21542
21656
|
if (!useFifo)
|
|
21543
21657
|
return s;
|
|
21544
|
-
const
|
|
21545
|
-
if (!
|
|
21658
|
+
const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
|
|
21659
|
+
if (!ipcResult)
|
|
21546
21660
|
return s;
|
|
21547
|
-
pendingExitCode.promise.finally(() =>
|
|
21661
|
+
pendingExitCode.promise.finally(() => ipcResult.cleanup());
|
|
21548
21662
|
process.stderr.write(`
|
|
21549
21663
|
Append prompts: ${cli}-yes --append-prompt '...'
|
|
21550
21664
|
|
|
21551
21665
|
`);
|
|
21552
|
-
return s.merge(
|
|
21666
|
+
return s.merge(ipcResult.stream);
|
|
21553
21667
|
}).onStart(async function promptOnStart() {
|
|
21554
21668
|
logger.debug("Sending prompt message: " + JSON.stringify(prompt));
|
|
21555
21669
|
if (prompt)
|
|
@@ -21571,7 +21685,7 @@ ${prompt}` : prefix;
|
|
|
21571
21685
|
return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
21572
21686
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
21573
21687
|
return f.forEach(async (chars) => {
|
|
21574
|
-
await
|
|
21688
|
+
await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
21575
21689
|
}).run();
|
|
21576
21690
|
}).catch(() => f.run());
|
|
21577
21691
|
}).by(function consoleResponder(e) {
|
|
@@ -21643,7 +21757,7 @@ ${prompt}` : prefix;
|
|
|
21643
21757
|
})).to(fromWritable(process.stdout));
|
|
21644
21758
|
if (logPath) {
|
|
21645
21759
|
await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
|
|
21646
|
-
await
|
|
21760
|
+
await writeFile4(logPath, terminalRender.render()).catch(() => null);
|
|
21647
21761
|
logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
|
|
21648
21762
|
}
|
|
21649
21763
|
const exitCode = await pendingExitCode.promise;
|
|
@@ -21655,7 +21769,7 @@ ${prompt}` : prefix;
|
|
|
21655
21769
|
logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
|
|
21656
21770
|
const logFilePath = path11.resolve(logFile);
|
|
21657
21771
|
await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
21658
|
-
await
|
|
21772
|
+
await writeFile4(logFilePath, terminalRender.render());
|
|
21659
21773
|
}
|
|
21660
21774
|
return { exitCode, logs: terminalRender.render() };
|
|
21661
21775
|
async function sendEnter(waitms = 1000) {
|
|
@@ -21674,6 +21788,15 @@ ${prompt}` : prefix;
|
|
|
21674
21788
|
resolve();
|
|
21675
21789
|
}, 1000))
|
|
21676
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
|
+
]);
|
|
21677
21800
|
}
|
|
21678
21801
|
async function sendMessage3(message, { waitForReady = true } = {}) {
|
|
21679
21802
|
if (waitForReady)
|
|
@@ -21722,5 +21845,5 @@ export {
|
|
|
21722
21845
|
CLIS_CONFIG
|
|
21723
21846
|
};
|
|
21724
21847
|
|
|
21725
|
-
//# debugId=
|
|
21848
|
+
//# debugId=6E96076BD519CF5364756E2164756E21
|
|
21726
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.spec.ts
CHANGED
|
@@ -228,4 +228,21 @@ describe("CLI argument parsing", () => {
|
|
|
228
228
|
expect(result.cli).toBe("codex");
|
|
229
229
|
expect(result.prompt).toBe("Implement feature");
|
|
230
230
|
});
|
|
231
|
+
|
|
232
|
+
it("should parse ay -- hello command (ay is wrapper, so CLI is undefined)", () => {
|
|
233
|
+
const result = parseCliArgs([
|
|
234
|
+
"node",
|
|
235
|
+
"/path/to/ay",
|
|
236
|
+
"--",
|
|
237
|
+
"hello",
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
// "ay" is a wrapper script like "agent-yes", so cliName is stripped to undefined
|
|
241
|
+
// cli.ts will default this to "claude" at runtime
|
|
242
|
+
expect(result.cli).toBeUndefined();
|
|
243
|
+
expect(result.cliArgs).toEqual([]);
|
|
244
|
+
expect(result.prompt).toBe("hello");
|
|
245
|
+
expect(result.verbose).toBe(false);
|
|
246
|
+
expect(result.robust).toBe(true);
|
|
247
|
+
});
|
|
231
248
|
});
|
package/ts/parseCliArgs.ts
CHANGED
|
@@ -17,6 +17,7 @@ export function parseCliArgs(argv: string[]) {
|
|
|
17
17
|
.at(-1)
|
|
18
18
|
?.replace(/(\.[jt]s)?$/, "")
|
|
19
19
|
.replace(/^(cli|agent)(-yes$)?/, "")
|
|
20
|
+
.replace(/^ay$/, "") // treat standalone "ay" same as "agent-yes"
|
|
20
21
|
.replace(/-yes$/, "") || undefined;
|
|
21
22
|
|
|
22
23
|
// Parse args with yargs (same logic as cli.ts:16-73)
|
|
@@ -26,6 +27,10 @@ export function parseCliArgs(argv: string[]) {
|
|
|
26
27
|
"$0 claude --idle=30s -- solve all todos in my codebase, commit one by one",
|
|
27
28
|
"Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`",
|
|
28
29
|
)
|
|
30
|
+
.example(
|
|
31
|
+
"$0 claude --stdpush",
|
|
32
|
+
"Run Claude with external stdin input enabled via --append-prompt",
|
|
33
|
+
)
|
|
29
34
|
// TODO: add a --docker option, will tell cli.ts to start docker process with tty and handles all stdio forwarding
|
|
30
35
|
|
|
31
36
|
.option("robust", {
|
|
@@ -90,12 +95,13 @@ export function parseCliArgs(argv: string[]) {
|
|
|
90
95
|
})
|
|
91
96
|
.option("append-prompt", {
|
|
92
97
|
type: "string",
|
|
93
|
-
description: "Send a prompt to the active agent's
|
|
98
|
+
description: "Send a prompt to the active agent's stdin in current directory",
|
|
94
99
|
})
|
|
95
|
-
.option("
|
|
100
|
+
.option("stdpush", {
|
|
96
101
|
type: "boolean",
|
|
97
|
-
description: "Enable
|
|
102
|
+
description: "Enable external input stream to push additional data to stdin",
|
|
98
103
|
default: false,
|
|
104
|
+
alias: ["ipc", "fifo"], // backward compatibility
|
|
99
105
|
})
|
|
100
106
|
.positional("cli", {
|
|
101
107
|
describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
|
|
@@ -174,7 +180,7 @@ export function parseCliArgs(argv: string[]) {
|
|
|
174
180
|
env: process.env as Record<string, string>,
|
|
175
181
|
cli: (cliName ||
|
|
176
182
|
parsedArgv.cli ||
|
|
177
|
-
parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "")) as (typeof SUPPORTED_CLIS)[number],
|
|
183
|
+
(dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : undefined)) as (typeof SUPPORTED_CLIS)[number],
|
|
178
184
|
cliArgs: cliArgsForSpawn,
|
|
179
185
|
prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || undefined,
|
|
180
186
|
install: parsedArgv.install,
|
|
@@ -190,6 +196,6 @@ export function parseCliArgs(argv: string[]) {
|
|
|
190
196
|
resume: parsedArgv.continue, // Note: intentional use resume here to avoid preserved keyword (continue)
|
|
191
197
|
useSkills: parsedArgv.useSkills,
|
|
192
198
|
appendPrompt: parsedArgv.appendPrompt,
|
|
193
|
-
useFifo: parsedArgv.fifo,
|
|
199
|
+
useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo, // Support --stdpush, --ipc, and --fifo (backward compatibility)
|
|
194
200
|
};
|
|
195
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();
|