claude-yes 1.34.0 → 1.35.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 +222 -85
- package/dist/index.js +110 -42
- package/package.json +4 -3
- package/ts/pidStore.ts +152 -47
package/dist/cli.js
CHANGED
|
@@ -20732,24 +20732,81 @@ var init_fifo = __esm(() => {
|
|
|
20732
20732
|
});
|
|
20733
20733
|
|
|
20734
20734
|
// ts/pidStore.ts
|
|
20735
|
-
import Datastore from "@seald-io/nedb";
|
|
20736
20735
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
20737
20736
|
import path9 from "path";
|
|
20738
20737
|
|
|
20738
|
+
class SqliteAdapter {
|
|
20739
|
+
db;
|
|
20740
|
+
async init(dbPath) {
|
|
20741
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
20742
|
+
try {
|
|
20743
|
+
const { Database } = await import("bun:sqlite");
|
|
20744
|
+
this.db = new Database(dbPath);
|
|
20745
|
+
} catch (error) {
|
|
20746
|
+
logger.warn("[pidStore] bun:sqlite not available, falling back to better-sqlite3");
|
|
20747
|
+
const Database = (await import("better-sqlite3")).default;
|
|
20748
|
+
this.db = new Database(dbPath);
|
|
20749
|
+
}
|
|
20750
|
+
} else {
|
|
20751
|
+
const Database = (await import("better-sqlite3")).default;
|
|
20752
|
+
this.db = new Database(dbPath);
|
|
20753
|
+
}
|
|
20754
|
+
}
|
|
20755
|
+
query(sql, params = []) {
|
|
20756
|
+
if (typeof this.db.prepare === "function") {
|
|
20757
|
+
return this.db.prepare(sql).all(params);
|
|
20758
|
+
} else {
|
|
20759
|
+
return this.db.query(sql).all(params);
|
|
20760
|
+
}
|
|
20761
|
+
}
|
|
20762
|
+
run(sql, params = []) {
|
|
20763
|
+
if (typeof this.db.prepare === "function") {
|
|
20764
|
+
return this.db.prepare(sql).run(params);
|
|
20765
|
+
} else {
|
|
20766
|
+
this.db.run(sql, params);
|
|
20767
|
+
return {};
|
|
20768
|
+
}
|
|
20769
|
+
}
|
|
20770
|
+
close() {
|
|
20771
|
+
if (this.db.close) {
|
|
20772
|
+
this.db.close();
|
|
20773
|
+
}
|
|
20774
|
+
}
|
|
20775
|
+
}
|
|
20776
|
+
|
|
20739
20777
|
class PidStore {
|
|
20740
20778
|
db;
|
|
20741
20779
|
baseDir;
|
|
20780
|
+
dbPath;
|
|
20742
20781
|
constructor(workingDir) {
|
|
20743
20782
|
this.baseDir = path9.resolve(workingDir, ".agent-yes");
|
|
20783
|
+
this.dbPath = path9.join(this.baseDir, "pid.sqlite");
|
|
20744
20784
|
}
|
|
20745
20785
|
async init() {
|
|
20746
20786
|
await mkdir3(path9.join(this.baseDir, "logs"), { recursive: true });
|
|
20747
20787
|
await mkdir3(path9.join(this.baseDir, "fifo"), { recursive: true });
|
|
20748
|
-
this.db = new
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
|
|
20752
|
-
|
|
20788
|
+
this.db = new SqliteAdapter;
|
|
20789
|
+
await this.db.init(this.dbPath);
|
|
20790
|
+
this.db.run("PRAGMA journal_mode=WAL");
|
|
20791
|
+
this.db.run("PRAGMA synchronous=NORMAL");
|
|
20792
|
+
this.db.run("PRAGMA cache_size=1000");
|
|
20793
|
+
this.db.run("PRAGMA temp_store=memory");
|
|
20794
|
+
this.db.run(`
|
|
20795
|
+
CREATE TABLE IF NOT EXISTS pid_records (
|
|
20796
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20797
|
+
pid INTEGER NOT NULL UNIQUE,
|
|
20798
|
+
cli TEXT NOT NULL,
|
|
20799
|
+
args TEXT NOT NULL,
|
|
20800
|
+
prompt TEXT,
|
|
20801
|
+
logFile TEXT NOT NULL,
|
|
20802
|
+
fifoFile TEXT NOT NULL,
|
|
20803
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
20804
|
+
exitReason TEXT NOT NULL DEFAULT '',
|
|
20805
|
+
exitCode INTEGER,
|
|
20806
|
+
startedAt INTEGER NOT NULL,
|
|
20807
|
+
updatedAt INTEGER NOT NULL
|
|
20808
|
+
)
|
|
20809
|
+
`);
|
|
20753
20810
|
await this.cleanStaleRecords();
|
|
20754
20811
|
}
|
|
20755
20812
|
async registerProcess({
|
|
@@ -20759,29 +20816,43 @@ class PidStore {
|
|
|
20759
20816
|
prompt
|
|
20760
20817
|
}) {
|
|
20761
20818
|
const now = Date.now();
|
|
20762
|
-
const
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
|
|
20773
|
-
|
|
20774
|
-
|
|
20819
|
+
const argsJson = JSON.stringify(args);
|
|
20820
|
+
const logFile = this.getLogPath(pid);
|
|
20821
|
+
const fifoFile = this.getFifoPath(pid);
|
|
20822
|
+
try {
|
|
20823
|
+
this.db.run(`
|
|
20824
|
+
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
20825
|
+
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
20826
|
+
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
20827
|
+
} catch (error) {
|
|
20828
|
+
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
20829
|
+
this.db.run(`
|
|
20830
|
+
UPDATE pid_records
|
|
20831
|
+
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
20832
|
+
WHERE pid = ?
|
|
20833
|
+
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
20834
|
+
} else {
|
|
20835
|
+
throw error;
|
|
20836
|
+
}
|
|
20837
|
+
}
|
|
20838
|
+
const result = this.db.query("SELECT * FROM pid_records WHERE pid = ?", [pid])[0];
|
|
20839
|
+
if (!result) {
|
|
20840
|
+
const allRecords = this.db.query("SELECT * FROM pid_records");
|
|
20841
|
+
logger.error(`[pidStore] Failed to find record for PID ${pid}. All records:`, allRecords);
|
|
20842
|
+
throw new Error(`Failed to register process ${pid}`);
|
|
20843
|
+
}
|
|
20775
20844
|
logger.debug(`[pidStore] Registered process ${pid}`);
|
|
20776
|
-
return
|
|
20845
|
+
return result;
|
|
20777
20846
|
}
|
|
20778
20847
|
async updateStatus(pid, status, extra) {
|
|
20779
|
-
const
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20848
|
+
const updatedAt = Date.now();
|
|
20849
|
+
const exitReason = extra?.exitReason || "";
|
|
20850
|
+
const exitCode = extra?.exitCode;
|
|
20851
|
+
if (exitCode !== undefined) {
|
|
20852
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, exitCode = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, exitCode, updatedAt, pid]);
|
|
20853
|
+
} else {
|
|
20854
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, updatedAt, pid]);
|
|
20855
|
+
}
|
|
20785
20856
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20786
20857
|
}
|
|
20787
20858
|
getLogPath(pid) {
|
|
@@ -20791,25 +20862,23 @@ class PidStore {
|
|
|
20791
20862
|
return path9.resolve(this.baseDir, "fifo", `${pid}.stdin`);
|
|
20792
20863
|
}
|
|
20793
20864
|
async cleanStaleRecords() {
|
|
20794
|
-
const activeRecords =
|
|
20795
|
-
status: { $ne: "exited" }
|
|
20796
|
-
});
|
|
20865
|
+
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
20797
20866
|
for (const record of activeRecords) {
|
|
20798
20867
|
if (!this.isProcessAlive(record.pid)) {
|
|
20799
|
-
|
|
20800
|
-
$set: {
|
|
20801
|
-
status: "exited",
|
|
20802
|
-
exitReason: "stale-cleanup",
|
|
20803
|
-
updatedAt: Date.now()
|
|
20804
|
-
}
|
|
20805
|
-
}, {});
|
|
20868
|
+
this.db.run("UPDATE pid_records SET status = 'exited', exitReason = 'stale-cleanup', updatedAt = ? WHERE pid = ?", [Date.now(), record.pid]);
|
|
20806
20869
|
logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
|
|
20807
20870
|
}
|
|
20808
20871
|
}
|
|
20809
20872
|
}
|
|
20810
20873
|
async close() {
|
|
20811
|
-
|
|
20812
|
-
|
|
20874
|
+
try {
|
|
20875
|
+
this.db.run("PRAGMA optimize");
|
|
20876
|
+
this.db.run("VACUUM");
|
|
20877
|
+
} catch (error) {
|
|
20878
|
+
logger.warn("[pidStore] Failed to optimize database:", error);
|
|
20879
|
+
}
|
|
20880
|
+
this.db.close();
|
|
20881
|
+
logger.debug("[pidStore] Database optimized and closed");
|
|
20813
20882
|
}
|
|
20814
20883
|
isProcessAlive(pid) {
|
|
20815
20884
|
try {
|
|
@@ -20822,10 +20891,9 @@ class PidStore {
|
|
|
20822
20891
|
static async findActiveFifo(workingDir) {
|
|
20823
20892
|
const store = new PidStore(workingDir);
|
|
20824
20893
|
await store.init();
|
|
20825
|
-
const records =
|
|
20894
|
+
const records = store.db.query("SELECT * FROM pid_records WHERE status != 'exited' ORDER BY startedAt DESC LIMIT 1");
|
|
20826
20895
|
await store.close();
|
|
20827
|
-
|
|
20828
|
-
return sorted[0]?.fifoFile ?? null;
|
|
20896
|
+
return records[0]?.fifoFile ?? null;
|
|
20829
20897
|
}
|
|
20830
20898
|
}
|
|
20831
20899
|
var init_pidStore = __esm(() => {
|
|
@@ -27688,7 +27756,7 @@ var package_default = {
|
|
|
27688
27756
|
registry: "https://registry.npmjs.org/"
|
|
27689
27757
|
},
|
|
27690
27758
|
scripts: {
|
|
27691
|
-
build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external
|
|
27759
|
+
build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=better-sqlite3 --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
|
|
27692
27760
|
postbuild: "bun ./ts/postbuild.ts",
|
|
27693
27761
|
demo: "bun run build && bun link && claude-yes -- demo",
|
|
27694
27762
|
dev: "bun ts/index.ts",
|
|
@@ -27700,9 +27768,9 @@ var package_default = {
|
|
|
27700
27768
|
test: "bun test --coverage"
|
|
27701
27769
|
},
|
|
27702
27770
|
dependencies: {
|
|
27703
|
-
"@seald-io/nedb": "^4.0.4",
|
|
27704
27771
|
"@snomiao/bun-pty": "^0.3.4",
|
|
27705
27772
|
"bun-pty": "^0.4.8",
|
|
27773
|
+
"better-sqlite3": "^12.1.0",
|
|
27706
27774
|
"from-node-stream": "^0.1.2"
|
|
27707
27775
|
},
|
|
27708
27776
|
devDependencies: {
|
|
@@ -27714,6 +27782,7 @@ var package_default = {
|
|
|
27714
27782
|
"@types/bun": "^1.3.6",
|
|
27715
27783
|
"@types/jest": "^30.0.0",
|
|
27716
27784
|
"@types/ms": "^2.1.0",
|
|
27785
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
27717
27786
|
"@types/node": "^25.0.10",
|
|
27718
27787
|
"@types/yargs": "^17.0.35",
|
|
27719
27788
|
"cpu-wait": "^0.0.10",
|
|
@@ -27924,24 +27993,81 @@ var logger2 = import_winston3.default.createLogger({
|
|
|
27924
27993
|
|
|
27925
27994
|
// ts/pidStore.ts
|
|
27926
27995
|
init_logger();
|
|
27927
|
-
import Datastore2 from "@seald-io/nedb";
|
|
27928
27996
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
27929
27997
|
import path12 from "path";
|
|
27930
27998
|
|
|
27999
|
+
class SqliteAdapter2 {
|
|
28000
|
+
db;
|
|
28001
|
+
async init(dbPath) {
|
|
28002
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
28003
|
+
try {
|
|
28004
|
+
const { Database } = await import("bun:sqlite");
|
|
28005
|
+
this.db = new Database(dbPath);
|
|
28006
|
+
} catch (error) {
|
|
28007
|
+
logger.warn("[pidStore] bun:sqlite not available, falling back to better-sqlite3");
|
|
28008
|
+
const Database = (await import("better-sqlite3")).default;
|
|
28009
|
+
this.db = new Database(dbPath);
|
|
28010
|
+
}
|
|
28011
|
+
} else {
|
|
28012
|
+
const Database = (await import("better-sqlite3")).default;
|
|
28013
|
+
this.db = new Database(dbPath);
|
|
28014
|
+
}
|
|
28015
|
+
}
|
|
28016
|
+
query(sql, params = []) {
|
|
28017
|
+
if (typeof this.db.prepare === "function") {
|
|
28018
|
+
return this.db.prepare(sql).all(params);
|
|
28019
|
+
} else {
|
|
28020
|
+
return this.db.query(sql).all(params);
|
|
28021
|
+
}
|
|
28022
|
+
}
|
|
28023
|
+
run(sql, params = []) {
|
|
28024
|
+
if (typeof this.db.prepare === "function") {
|
|
28025
|
+
return this.db.prepare(sql).run(params);
|
|
28026
|
+
} else {
|
|
28027
|
+
this.db.run(sql, params);
|
|
28028
|
+
return {};
|
|
28029
|
+
}
|
|
28030
|
+
}
|
|
28031
|
+
close() {
|
|
28032
|
+
if (this.db.close) {
|
|
28033
|
+
this.db.close();
|
|
28034
|
+
}
|
|
28035
|
+
}
|
|
28036
|
+
}
|
|
28037
|
+
|
|
27931
28038
|
class PidStore2 {
|
|
27932
28039
|
db;
|
|
27933
28040
|
baseDir;
|
|
28041
|
+
dbPath;
|
|
27934
28042
|
constructor(workingDir) {
|
|
27935
28043
|
this.baseDir = path12.resolve(workingDir, ".agent-yes");
|
|
28044
|
+
this.dbPath = path12.join(this.baseDir, "pid.sqlite");
|
|
27936
28045
|
}
|
|
27937
28046
|
async init() {
|
|
27938
28047
|
await mkdir6(path12.join(this.baseDir, "logs"), { recursive: true });
|
|
27939
28048
|
await mkdir6(path12.join(this.baseDir, "fifo"), { recursive: true });
|
|
27940
|
-
this.db = new
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
28049
|
+
this.db = new SqliteAdapter2;
|
|
28050
|
+
await this.db.init(this.dbPath);
|
|
28051
|
+
this.db.run("PRAGMA journal_mode=WAL");
|
|
28052
|
+
this.db.run("PRAGMA synchronous=NORMAL");
|
|
28053
|
+
this.db.run("PRAGMA cache_size=1000");
|
|
28054
|
+
this.db.run("PRAGMA temp_store=memory");
|
|
28055
|
+
this.db.run(`
|
|
28056
|
+
CREATE TABLE IF NOT EXISTS pid_records (
|
|
28057
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28058
|
+
pid INTEGER NOT NULL UNIQUE,
|
|
28059
|
+
cli TEXT NOT NULL,
|
|
28060
|
+
args TEXT NOT NULL,
|
|
28061
|
+
prompt TEXT,
|
|
28062
|
+
logFile TEXT NOT NULL,
|
|
28063
|
+
fifoFile TEXT NOT NULL,
|
|
28064
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
28065
|
+
exitReason TEXT NOT NULL DEFAULT '',
|
|
28066
|
+
exitCode INTEGER,
|
|
28067
|
+
startedAt INTEGER NOT NULL,
|
|
28068
|
+
updatedAt INTEGER NOT NULL
|
|
28069
|
+
)
|
|
28070
|
+
`);
|
|
27945
28071
|
await this.cleanStaleRecords();
|
|
27946
28072
|
}
|
|
27947
28073
|
async registerProcess({
|
|
@@ -27951,29 +28077,43 @@ class PidStore2 {
|
|
|
27951
28077
|
prompt
|
|
27952
28078
|
}) {
|
|
27953
28079
|
const now = Date.now();
|
|
27954
|
-
const
|
|
27955
|
-
|
|
27956
|
-
|
|
27957
|
-
|
|
27958
|
-
|
|
27959
|
-
|
|
27960
|
-
|
|
27961
|
-
|
|
27962
|
-
|
|
27963
|
-
|
|
27964
|
-
|
|
27965
|
-
|
|
27966
|
-
|
|
28080
|
+
const argsJson = JSON.stringify(args);
|
|
28081
|
+
const logFile = this.getLogPath(pid);
|
|
28082
|
+
const fifoFile = this.getFifoPath(pid);
|
|
28083
|
+
try {
|
|
28084
|
+
this.db.run(`
|
|
28085
|
+
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
28086
|
+
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
28087
|
+
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
28088
|
+
} catch (error) {
|
|
28089
|
+
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
28090
|
+
this.db.run(`
|
|
28091
|
+
UPDATE pid_records
|
|
28092
|
+
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
28093
|
+
WHERE pid = ?
|
|
28094
|
+
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
28095
|
+
} else {
|
|
28096
|
+
throw error;
|
|
28097
|
+
}
|
|
28098
|
+
}
|
|
28099
|
+
const result = this.db.query("SELECT * FROM pid_records WHERE pid = ?", [pid])[0];
|
|
28100
|
+
if (!result) {
|
|
28101
|
+
const allRecords = this.db.query("SELECT * FROM pid_records");
|
|
28102
|
+
logger.error(`[pidStore] Failed to find record for PID ${pid}. All records:`, allRecords);
|
|
28103
|
+
throw new Error(`Failed to register process ${pid}`);
|
|
28104
|
+
}
|
|
27967
28105
|
logger.debug(`[pidStore] Registered process ${pid}`);
|
|
27968
|
-
return
|
|
28106
|
+
return result;
|
|
27969
28107
|
}
|
|
27970
28108
|
async updateStatus(pid, status, extra) {
|
|
27971
|
-
const
|
|
27972
|
-
|
|
27973
|
-
|
|
27974
|
-
|
|
27975
|
-
|
|
27976
|
-
|
|
28109
|
+
const updatedAt = Date.now();
|
|
28110
|
+
const exitReason = extra?.exitReason || "";
|
|
28111
|
+
const exitCode = extra?.exitCode;
|
|
28112
|
+
if (exitCode !== undefined) {
|
|
28113
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, exitCode = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, exitCode, updatedAt, pid]);
|
|
28114
|
+
} else {
|
|
28115
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, updatedAt, pid]);
|
|
28116
|
+
}
|
|
27977
28117
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
27978
28118
|
}
|
|
27979
28119
|
getLogPath(pid) {
|
|
@@ -27983,25 +28123,23 @@ class PidStore2 {
|
|
|
27983
28123
|
return path12.resolve(this.baseDir, "fifo", `${pid}.stdin`);
|
|
27984
28124
|
}
|
|
27985
28125
|
async cleanStaleRecords() {
|
|
27986
|
-
const activeRecords =
|
|
27987
|
-
status: { $ne: "exited" }
|
|
27988
|
-
});
|
|
28126
|
+
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
27989
28127
|
for (const record of activeRecords) {
|
|
27990
28128
|
if (!this.isProcessAlive(record.pid)) {
|
|
27991
|
-
|
|
27992
|
-
$set: {
|
|
27993
|
-
status: "exited",
|
|
27994
|
-
exitReason: "stale-cleanup",
|
|
27995
|
-
updatedAt: Date.now()
|
|
27996
|
-
}
|
|
27997
|
-
}, {});
|
|
28129
|
+
this.db.run("UPDATE pid_records SET status = 'exited', exitReason = 'stale-cleanup', updatedAt = ? WHERE pid = ?", [Date.now(), record.pid]);
|
|
27998
28130
|
logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
|
|
27999
28131
|
}
|
|
28000
28132
|
}
|
|
28001
28133
|
}
|
|
28002
28134
|
async close() {
|
|
28003
|
-
|
|
28004
|
-
|
|
28135
|
+
try {
|
|
28136
|
+
this.db.run("PRAGMA optimize");
|
|
28137
|
+
this.db.run("VACUUM");
|
|
28138
|
+
} catch (error) {
|
|
28139
|
+
logger.warn("[pidStore] Failed to optimize database:", error);
|
|
28140
|
+
}
|
|
28141
|
+
this.db.close();
|
|
28142
|
+
logger.debug("[pidStore] Database optimized and closed");
|
|
28005
28143
|
}
|
|
28006
28144
|
isProcessAlive(pid) {
|
|
28007
28145
|
try {
|
|
@@ -28014,10 +28152,9 @@ class PidStore2 {
|
|
|
28014
28152
|
static async findActiveFifo(workingDir) {
|
|
28015
28153
|
const store = new PidStore2(workingDir);
|
|
28016
28154
|
await store.init();
|
|
28017
|
-
const records =
|
|
28155
|
+
const records = store.db.query("SELECT * FROM pid_records WHERE status != 'exited' ORDER BY startedAt DESC LIMIT 1");
|
|
28018
28156
|
await store.close();
|
|
28019
|
-
|
|
28020
|
-
return sorted[0]?.fifoFile ?? null;
|
|
28157
|
+
return records[0]?.fifoFile ?? null;
|
|
28021
28158
|
}
|
|
28022
28159
|
}
|
|
28023
28160
|
|
|
@@ -28050,5 +28187,5 @@ var { exitCode } = await cliYes(config3);
|
|
|
28050
28187
|
console.log("exiting process");
|
|
28051
28188
|
process.exit(exitCode ?? 1);
|
|
28052
28189
|
|
|
28053
|
-
//# debugId=
|
|
28190
|
+
//# debugId=C4007A87ED18C3B264756E2164756E21
|
|
28054
28191
|
//# sourceMappingURL=cli.js.map
|
package/dist/index.js
CHANGED
|
@@ -20730,24 +20730,81 @@ var init_fifo = __esm(() => {
|
|
|
20730
20730
|
});
|
|
20731
20731
|
|
|
20732
20732
|
// ts/pidStore.ts
|
|
20733
|
-
import Datastore from "@seald-io/nedb";
|
|
20734
20733
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
20735
20734
|
import path9 from "path";
|
|
20736
20735
|
|
|
20736
|
+
class SqliteAdapter {
|
|
20737
|
+
db;
|
|
20738
|
+
async init(dbPath) {
|
|
20739
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
20740
|
+
try {
|
|
20741
|
+
const { Database } = await import("bun:sqlite");
|
|
20742
|
+
this.db = new Database(dbPath);
|
|
20743
|
+
} catch (error) {
|
|
20744
|
+
logger.warn("[pidStore] bun:sqlite not available, falling back to better-sqlite3");
|
|
20745
|
+
const Database = (await import("better-sqlite3")).default;
|
|
20746
|
+
this.db = new Database(dbPath);
|
|
20747
|
+
}
|
|
20748
|
+
} else {
|
|
20749
|
+
const Database = (await import("better-sqlite3")).default;
|
|
20750
|
+
this.db = new Database(dbPath);
|
|
20751
|
+
}
|
|
20752
|
+
}
|
|
20753
|
+
query(sql, params = []) {
|
|
20754
|
+
if (typeof this.db.prepare === "function") {
|
|
20755
|
+
return this.db.prepare(sql).all(params);
|
|
20756
|
+
} else {
|
|
20757
|
+
return this.db.query(sql).all(params);
|
|
20758
|
+
}
|
|
20759
|
+
}
|
|
20760
|
+
run(sql, params = []) {
|
|
20761
|
+
if (typeof this.db.prepare === "function") {
|
|
20762
|
+
return this.db.prepare(sql).run(params);
|
|
20763
|
+
} else {
|
|
20764
|
+
this.db.run(sql, params);
|
|
20765
|
+
return {};
|
|
20766
|
+
}
|
|
20767
|
+
}
|
|
20768
|
+
close() {
|
|
20769
|
+
if (this.db.close) {
|
|
20770
|
+
this.db.close();
|
|
20771
|
+
}
|
|
20772
|
+
}
|
|
20773
|
+
}
|
|
20774
|
+
|
|
20737
20775
|
class PidStore {
|
|
20738
20776
|
db;
|
|
20739
20777
|
baseDir;
|
|
20778
|
+
dbPath;
|
|
20740
20779
|
constructor(workingDir) {
|
|
20741
20780
|
this.baseDir = path9.resolve(workingDir, ".agent-yes");
|
|
20781
|
+
this.dbPath = path9.join(this.baseDir, "pid.sqlite");
|
|
20742
20782
|
}
|
|
20743
20783
|
async init() {
|
|
20744
20784
|
await mkdir3(path9.join(this.baseDir, "logs"), { recursive: true });
|
|
20745
20785
|
await mkdir3(path9.join(this.baseDir, "fifo"), { recursive: true });
|
|
20746
|
-
this.db = new
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
20786
|
+
this.db = new SqliteAdapter;
|
|
20787
|
+
await this.db.init(this.dbPath);
|
|
20788
|
+
this.db.run("PRAGMA journal_mode=WAL");
|
|
20789
|
+
this.db.run("PRAGMA synchronous=NORMAL");
|
|
20790
|
+
this.db.run("PRAGMA cache_size=1000");
|
|
20791
|
+
this.db.run("PRAGMA temp_store=memory");
|
|
20792
|
+
this.db.run(`
|
|
20793
|
+
CREATE TABLE IF NOT EXISTS pid_records (
|
|
20794
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20795
|
+
pid INTEGER NOT NULL UNIQUE,
|
|
20796
|
+
cli TEXT NOT NULL,
|
|
20797
|
+
args TEXT NOT NULL,
|
|
20798
|
+
prompt TEXT,
|
|
20799
|
+
logFile TEXT NOT NULL,
|
|
20800
|
+
fifoFile TEXT NOT NULL,
|
|
20801
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
20802
|
+
exitReason TEXT NOT NULL DEFAULT '',
|
|
20803
|
+
exitCode INTEGER,
|
|
20804
|
+
startedAt INTEGER NOT NULL,
|
|
20805
|
+
updatedAt INTEGER NOT NULL
|
|
20806
|
+
)
|
|
20807
|
+
`);
|
|
20751
20808
|
await this.cleanStaleRecords();
|
|
20752
20809
|
}
|
|
20753
20810
|
async registerProcess({
|
|
@@ -20757,29 +20814,43 @@ class PidStore {
|
|
|
20757
20814
|
prompt
|
|
20758
20815
|
}) {
|
|
20759
20816
|
const now = Date.now();
|
|
20760
|
-
const
|
|
20761
|
-
|
|
20762
|
-
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
|
|
20817
|
+
const argsJson = JSON.stringify(args);
|
|
20818
|
+
const logFile = this.getLogPath(pid);
|
|
20819
|
+
const fifoFile = this.getFifoPath(pid);
|
|
20820
|
+
try {
|
|
20821
|
+
this.db.run(`
|
|
20822
|
+
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
20823
|
+
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
20824
|
+
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
20825
|
+
} catch (error) {
|
|
20826
|
+
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
20827
|
+
this.db.run(`
|
|
20828
|
+
UPDATE pid_records
|
|
20829
|
+
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
20830
|
+
WHERE pid = ?
|
|
20831
|
+
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
20832
|
+
} else {
|
|
20833
|
+
throw error;
|
|
20834
|
+
}
|
|
20835
|
+
}
|
|
20836
|
+
const result = this.db.query("SELECT * FROM pid_records WHERE pid = ?", [pid])[0];
|
|
20837
|
+
if (!result) {
|
|
20838
|
+
const allRecords = this.db.query("SELECT * FROM pid_records");
|
|
20839
|
+
logger.error(`[pidStore] Failed to find record for PID ${pid}. All records:`, allRecords);
|
|
20840
|
+
throw new Error(`Failed to register process ${pid}`);
|
|
20841
|
+
}
|
|
20773
20842
|
logger.debug(`[pidStore] Registered process ${pid}`);
|
|
20774
|
-
return
|
|
20843
|
+
return result;
|
|
20775
20844
|
}
|
|
20776
20845
|
async updateStatus(pid, status, extra) {
|
|
20777
|
-
const
|
|
20778
|
-
|
|
20779
|
-
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20846
|
+
const updatedAt = Date.now();
|
|
20847
|
+
const exitReason = extra?.exitReason || "";
|
|
20848
|
+
const exitCode = extra?.exitCode;
|
|
20849
|
+
if (exitCode !== undefined) {
|
|
20850
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, exitCode = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, exitCode, updatedAt, pid]);
|
|
20851
|
+
} else {
|
|
20852
|
+
this.db.run("UPDATE pid_records SET status = ?, exitReason = ?, updatedAt = ? WHERE pid = ?", [status, exitReason, updatedAt, pid]);
|
|
20853
|
+
}
|
|
20783
20854
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
20784
20855
|
}
|
|
20785
20856
|
getLogPath(pid) {
|
|
@@ -20789,25 +20860,23 @@ class PidStore {
|
|
|
20789
20860
|
return path9.resolve(this.baseDir, "fifo", `${pid}.stdin`);
|
|
20790
20861
|
}
|
|
20791
20862
|
async cleanStaleRecords() {
|
|
20792
|
-
const activeRecords =
|
|
20793
|
-
status: { $ne: "exited" }
|
|
20794
|
-
});
|
|
20863
|
+
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
20795
20864
|
for (const record of activeRecords) {
|
|
20796
20865
|
if (!this.isProcessAlive(record.pid)) {
|
|
20797
|
-
|
|
20798
|
-
$set: {
|
|
20799
|
-
status: "exited",
|
|
20800
|
-
exitReason: "stale-cleanup",
|
|
20801
|
-
updatedAt: Date.now()
|
|
20802
|
-
}
|
|
20803
|
-
}, {});
|
|
20866
|
+
this.db.run("UPDATE pid_records SET status = 'exited', exitReason = 'stale-cleanup', updatedAt = ? WHERE pid = ?", [Date.now(), record.pid]);
|
|
20804
20867
|
logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
|
|
20805
20868
|
}
|
|
20806
20869
|
}
|
|
20807
20870
|
}
|
|
20808
20871
|
async close() {
|
|
20809
|
-
|
|
20810
|
-
|
|
20872
|
+
try {
|
|
20873
|
+
this.db.run("PRAGMA optimize");
|
|
20874
|
+
this.db.run("VACUUM");
|
|
20875
|
+
} catch (error) {
|
|
20876
|
+
logger.warn("[pidStore] Failed to optimize database:", error);
|
|
20877
|
+
}
|
|
20878
|
+
this.db.close();
|
|
20879
|
+
logger.debug("[pidStore] Database optimized and closed");
|
|
20811
20880
|
}
|
|
20812
20881
|
isProcessAlive(pid) {
|
|
20813
20882
|
try {
|
|
@@ -20820,10 +20889,9 @@ class PidStore {
|
|
|
20820
20889
|
static async findActiveFifo(workingDir) {
|
|
20821
20890
|
const store = new PidStore(workingDir);
|
|
20822
20891
|
await store.init();
|
|
20823
|
-
const records =
|
|
20892
|
+
const records = store.db.query("SELECT * FROM pid_records WHERE status != 'exited' ORDER BY startedAt DESC LIMIT 1");
|
|
20824
20893
|
await store.close();
|
|
20825
|
-
|
|
20826
|
-
return sorted[0]?.fifoFile ?? null;
|
|
20894
|
+
return records[0]?.fifoFile ?? null;
|
|
20827
20895
|
}
|
|
20828
20896
|
}
|
|
20829
20897
|
var init_pidStore = __esm(() => {
|
|
@@ -21654,5 +21722,5 @@ export {
|
|
|
21654
21722
|
CLIS_CONFIG
|
|
21655
21723
|
};
|
|
21656
21724
|
|
|
21657
|
-
//# debugId=
|
|
21725
|
+
//# debugId=9A92FE5B1254037264756E2164756E21
|
|
21658
21726
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"registry": "https://registry.npmjs.org/"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
|
-
"build": "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external
|
|
65
|
+
"build": "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=better-sqlite3 --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
|
|
66
66
|
"postbuild": "bun ./ts/postbuild.ts",
|
|
67
67
|
"demo": "bun run build && bun link && claude-yes -- demo",
|
|
68
68
|
"dev": "bun ts/index.ts",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"test": "bun test --coverage"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@seald-io/nedb": "^4.0.4",
|
|
78
77
|
"@snomiao/bun-pty": "^0.3.4",
|
|
78
|
+
"better-sqlite3": "^12.1.0",
|
|
79
79
|
"bun-pty": "^0.4.8",
|
|
80
80
|
"from-node-stream": "^0.1.2"
|
|
81
81
|
},
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"@semantic-release/exec": "^7.1.0",
|
|
86
86
|
"@semantic-release/git": "^10.0.1",
|
|
87
87
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
88
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
88
89
|
"@types/bun": "^1.3.6",
|
|
89
90
|
"@types/jest": "^30.0.0",
|
|
90
91
|
"@types/ms": "^2.1.0",
|
package/ts/pidStore.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import Datastore from "@seald-io/nedb";
|
|
2
1
|
import { mkdir } from "fs/promises";
|
|
3
2
|
import path from "path";
|
|
4
3
|
import { logger } from "./logger.ts";
|
|
5
4
|
|
|
6
5
|
export interface PidRecord {
|
|
6
|
+
id?: number;
|
|
7
7
|
pid: number;
|
|
8
8
|
cli: string;
|
|
9
|
-
args: string
|
|
9
|
+
args: string;
|
|
10
10
|
prompt?: string;
|
|
11
11
|
logFile: string;
|
|
12
12
|
fifoFile: string;
|
|
@@ -17,23 +17,95 @@ export interface PidRecord {
|
|
|
17
17
|
updatedAt: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// Direct SQLite implementation to avoid Kysely compatibility issues
|
|
21
|
+
class SqliteAdapter {
|
|
22
|
+
private db: any;
|
|
23
|
+
|
|
24
|
+
async init(dbPath: string) {
|
|
25
|
+
if (typeof globalThis.Bun !== "undefined") {
|
|
26
|
+
try {
|
|
27
|
+
const { Database } = await import("bun:sqlite");
|
|
28
|
+
this.db = new Database(dbPath);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.warn("[pidStore] bun:sqlite not available, falling back to better-sqlite3");
|
|
31
|
+
const Database = (await import("better-sqlite3")).default;
|
|
32
|
+
this.db = new Database(dbPath);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
const Database = (await import("better-sqlite3")).default;
|
|
36
|
+
this.db = new Database(dbPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
query(sql: string, params: any[] = []): any[] {
|
|
41
|
+
if (typeof this.db.prepare === "function") {
|
|
42
|
+
// better-sqlite3 style
|
|
43
|
+
return this.db.prepare(sql).all(params);
|
|
44
|
+
} else {
|
|
45
|
+
// bun:sqlite style
|
|
46
|
+
return this.db.query(sql).all(params);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
run(sql: string, params: any[] = []): { lastInsertRowid?: number; changes?: number } {
|
|
51
|
+
if (typeof this.db.prepare === "function") {
|
|
52
|
+
// better-sqlite3 style
|
|
53
|
+
return this.db.prepare(sql).run(params);
|
|
54
|
+
} else {
|
|
55
|
+
// bun:sqlite style
|
|
56
|
+
this.db.run(sql, params);
|
|
57
|
+
return {}; // Bun doesn't return metadata in the same way
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
close() {
|
|
62
|
+
if (this.db.close) {
|
|
63
|
+
this.db.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
20
68
|
export class PidStore {
|
|
21
|
-
protected db!:
|
|
69
|
+
protected db!: SqliteAdapter;
|
|
22
70
|
private baseDir: string;
|
|
71
|
+
private dbPath: string;
|
|
23
72
|
|
|
24
73
|
constructor(workingDir: string) {
|
|
25
74
|
this.baseDir = path.resolve(workingDir, ".agent-yes");
|
|
75
|
+
this.dbPath = path.join(this.baseDir, "pid.sqlite");
|
|
26
76
|
}
|
|
27
77
|
|
|
28
78
|
async init(): Promise<void> {
|
|
29
79
|
await mkdir(path.join(this.baseDir, "logs"), { recursive: true });
|
|
30
80
|
await mkdir(path.join(this.baseDir, "fifo"), { recursive: true });
|
|
31
81
|
|
|
32
|
-
this.db = new
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
82
|
+
this.db = new SqliteAdapter();
|
|
83
|
+
await this.db.init(this.dbPath);
|
|
84
|
+
|
|
85
|
+
// Enable WAL mode for better concurrency and performance
|
|
86
|
+
this.db.run("PRAGMA journal_mode=WAL");
|
|
87
|
+
this.db.run("PRAGMA synchronous=NORMAL");
|
|
88
|
+
this.db.run("PRAGMA cache_size=1000");
|
|
89
|
+
this.db.run("PRAGMA temp_store=memory");
|
|
90
|
+
|
|
91
|
+
// Create table if it doesn't exist
|
|
92
|
+
this.db.run(`
|
|
93
|
+
CREATE TABLE IF NOT EXISTS pid_records (
|
|
94
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
95
|
+
pid INTEGER NOT NULL UNIQUE,
|
|
96
|
+
cli TEXT NOT NULL,
|
|
97
|
+
args TEXT NOT NULL,
|
|
98
|
+
prompt TEXT,
|
|
99
|
+
logFile TEXT NOT NULL,
|
|
100
|
+
fifoFile TEXT NOT NULL,
|
|
101
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
102
|
+
exitReason TEXT NOT NULL DEFAULT '',
|
|
103
|
+
exitCode INTEGER,
|
|
104
|
+
startedAt INTEGER NOT NULL,
|
|
105
|
+
updatedAt INTEGER NOT NULL
|
|
106
|
+
)
|
|
107
|
+
`);
|
|
108
|
+
|
|
37
109
|
await this.cleanStaleRecords();
|
|
38
110
|
}
|
|
39
111
|
|
|
@@ -49,21 +121,40 @@ export class PidStore {
|
|
|
49
121
|
prompt?: string;
|
|
50
122
|
}): Promise<PidRecord> {
|
|
51
123
|
const now = Date.now();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
124
|
+
const argsJson = JSON.stringify(args);
|
|
125
|
+
const logFile = this.getLogPath(pid);
|
|
126
|
+
const fifoFile = this.getFifoPath(pid);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
this.db.run(`
|
|
130
|
+
INSERT INTO pid_records (pid, cli, args, prompt, logFile, fifoFile, status, exitReason, startedAt, updatedAt)
|
|
131
|
+
VALUES (?, ?, ?, ?, ?, ?, 'active', '', ?, ?)
|
|
132
|
+
`, [pid, cli, argsJson, prompt, logFile, fifoFile, now, now]);
|
|
133
|
+
} catch (error: any) {
|
|
134
|
+
// Handle unique constraint violation by updating existing record
|
|
135
|
+
if (error.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
|
136
|
+
this.db.run(`
|
|
137
|
+
UPDATE pid_records
|
|
138
|
+
SET cli = ?, args = ?, prompt = ?, logFile = ?, fifoFile = ?, status = 'active', exitReason = '', startedAt = ?, updatedAt = ?
|
|
139
|
+
WHERE pid = ?
|
|
140
|
+
`, [cli, argsJson, prompt, logFile, fifoFile, now, now, pid]);
|
|
141
|
+
} else {
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Fetch the record
|
|
147
|
+
const result = this.db.query("SELECT * FROM pid_records WHERE pid = ?", [pid])[0];
|
|
148
|
+
|
|
149
|
+
if (!result) {
|
|
150
|
+
// Log all records for debugging
|
|
151
|
+
const allRecords = this.db.query("SELECT * FROM pid_records");
|
|
152
|
+
logger.error(`[pidStore] Failed to find record for PID ${pid}. All records:`, allRecords);
|
|
153
|
+
throw new Error(`Failed to register process ${pid}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
65
156
|
logger.debug(`[pidStore] Registered process ${pid}`);
|
|
66
|
-
return
|
|
157
|
+
return result;
|
|
67
158
|
}
|
|
68
159
|
|
|
69
160
|
async updateStatus(
|
|
@@ -71,12 +162,22 @@ export class PidStore {
|
|
|
71
162
|
status: PidRecord["status"],
|
|
72
163
|
extra?: { exitReason?: string; exitCode?: number },
|
|
73
164
|
): Promise<void> {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
165
|
+
const updatedAt = Date.now();
|
|
166
|
+
const exitReason = extra?.exitReason || "";
|
|
167
|
+
const exitCode = extra?.exitCode;
|
|
168
|
+
|
|
169
|
+
if (exitCode !== undefined) {
|
|
170
|
+
this.db.run(
|
|
171
|
+
"UPDATE pid_records SET status = ?, exitReason = ?, exitCode = ?, updatedAt = ? WHERE pid = ?",
|
|
172
|
+
[status, exitReason, exitCode, updatedAt, pid]
|
|
173
|
+
);
|
|
174
|
+
} else {
|
|
175
|
+
this.db.run(
|
|
176
|
+
"UPDATE pid_records SET status = ?, exitReason = ?, updatedAt = ? WHERE pid = ?",
|
|
177
|
+
[status, exitReason, updatedAt, pid]
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
80
181
|
logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
|
|
81
182
|
}
|
|
82
183
|
|
|
@@ -89,30 +190,31 @@ export class PidStore {
|
|
|
89
190
|
}
|
|
90
191
|
|
|
91
192
|
async cleanStaleRecords(): Promise<void> {
|
|
92
|
-
const activeRecords =
|
|
93
|
-
|
|
94
|
-
});
|
|
193
|
+
const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
|
|
194
|
+
|
|
95
195
|
for (const record of activeRecords) {
|
|
96
196
|
if (!this.isProcessAlive(record.pid)) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
$set: {
|
|
101
|
-
status: "exited" as const,
|
|
102
|
-
exitReason: "stale-cleanup",
|
|
103
|
-
updatedAt: Date.now(),
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{},
|
|
197
|
+
this.db.run(
|
|
198
|
+
"UPDATE pid_records SET status = 'exited', exitReason = 'stale-cleanup', updatedAt = ? WHERE pid = ?",
|
|
199
|
+
[Date.now(), record.pid]
|
|
107
200
|
);
|
|
201
|
+
|
|
108
202
|
logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
|
|
109
203
|
}
|
|
110
204
|
}
|
|
111
205
|
}
|
|
112
206
|
|
|
113
207
|
async close(): Promise<void> {
|
|
114
|
-
|
|
115
|
-
|
|
208
|
+
// Optimize the database (equivalent to compacting in nedb)
|
|
209
|
+
try {
|
|
210
|
+
this.db.run("PRAGMA optimize");
|
|
211
|
+
this.db.run("VACUUM");
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger.warn("[pidStore] Failed to optimize database:", error);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.db.close();
|
|
217
|
+
logger.debug("[pidStore] Database optimized and closed");
|
|
116
218
|
}
|
|
117
219
|
|
|
118
220
|
private isProcessAlive(pid: number): boolean {
|
|
@@ -127,9 +229,12 @@ export class PidStore {
|
|
|
127
229
|
static async findActiveFifo(workingDir: string): Promise<string | null> {
|
|
128
230
|
const store = new PidStore(workingDir);
|
|
129
231
|
await store.init();
|
|
130
|
-
|
|
232
|
+
|
|
233
|
+
const records = store.db.query(
|
|
234
|
+
"SELECT * FROM pid_records WHERE status != 'exited' ORDER BY startedAt DESC LIMIT 1"
|
|
235
|
+
);
|
|
236
|
+
|
|
131
237
|
await store.close();
|
|
132
|
-
|
|
133
|
-
return sorted[0]?.fifoFile ?? null;
|
|
238
|
+
return records[0]?.fifoFile ?? null;
|
|
134
239
|
}
|
|
135
|
-
}
|
|
240
|
+
}
|