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 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 Datastore({
20749
- filename: path9.join(this.baseDir, "pid.jsonl"),
20750
- autoload: true
20751
- });
20752
- await this.db.loadDatabaseAsync();
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 record = {
20763
- pid,
20764
- cli,
20765
- args,
20766
- prompt,
20767
- logFile: this.getLogPath(pid),
20768
- fifoFile: this.getFifoPath(pid),
20769
- status: "active",
20770
- exitReason: "",
20771
- startedAt: now,
20772
- updatedAt: now
20773
- };
20774
- await this.db.insertAsync(record);
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 record;
20845
+ return result;
20777
20846
  }
20778
20847
  async updateStatus(pid, status, extra) {
20779
- const update2 = {
20780
- status,
20781
- updatedAt: Date.now(),
20782
- ...extra
20783
- };
20784
- await this.db.updateAsync({ pid }, { $set: update2 }, {});
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 = await this.db.findAsync({
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
- await this.db.updateAsync({ pid: record.pid }, {
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
- await this.db.compactDatafileAsync();
20812
- logger.debug("[pidStore] Database compacted and closed");
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 = await store.db.findAsync({ status: { $ne: "exited" } });
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
- const sorted = records.sort((a2, b) => b.startedAt - a2.startedAt);
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=@seald-io/nedb --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
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 Datastore2({
27941
- filename: path12.join(this.baseDir, "pid.jsonl"),
27942
- autoload: true
27943
- });
27944
- await this.db.loadDatabaseAsync();
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 record = {
27955
- pid,
27956
- cli,
27957
- args,
27958
- prompt,
27959
- logFile: this.getLogPath(pid),
27960
- fifoFile: this.getFifoPath(pid),
27961
- status: "active",
27962
- exitReason: "",
27963
- startedAt: now,
27964
- updatedAt: now
27965
- };
27966
- await this.db.insertAsync(record);
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 record;
28106
+ return result;
27969
28107
  }
27970
28108
  async updateStatus(pid, status, extra) {
27971
- const update2 = {
27972
- status,
27973
- updatedAt: Date.now(),
27974
- ...extra
27975
- };
27976
- await this.db.updateAsync({ pid }, { $set: update2 }, {});
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 = await this.db.findAsync({
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
- await this.db.updateAsync({ pid: record.pid }, {
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
- await this.db.compactDatafileAsync();
28004
- logger.debug("[pidStore] Database compacted and closed");
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 = await store.db.findAsync({ status: { $ne: "exited" } });
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
- const sorted = records.sort((a2, b) => b.startedAt - a2.startedAt);
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=12710EC867DEB2CA64756E2164756E21
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 Datastore({
20747
- filename: path9.join(this.baseDir, "pid.jsonl"),
20748
- autoload: true
20749
- });
20750
- await this.db.loadDatabaseAsync();
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 record = {
20761
- pid,
20762
- cli,
20763
- args,
20764
- prompt,
20765
- logFile: this.getLogPath(pid),
20766
- fifoFile: this.getFifoPath(pid),
20767
- status: "active",
20768
- exitReason: "",
20769
- startedAt: now,
20770
- updatedAt: now
20771
- };
20772
- await this.db.insertAsync(record);
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 record;
20843
+ return result;
20775
20844
  }
20776
20845
  async updateStatus(pid, status, extra) {
20777
- const update2 = {
20778
- status,
20779
- updatedAt: Date.now(),
20780
- ...extra
20781
- };
20782
- await this.db.updateAsync({ pid }, { $set: update2 }, {});
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 = await this.db.findAsync({
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
- await this.db.updateAsync({ pid: record.pid }, {
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
- await this.db.compactDatafileAsync();
20810
- logger.debug("[pidStore] Database compacted and closed");
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 = await store.db.findAsync({ status: { $ne: "exited" } });
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
- const sorted = records.sort((a2, b) => b.startedAt - a2.startedAt);
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=6BCBE693D722CAEF64756E2164756E21
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.34.0",
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=@seald-io/nedb --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
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!: Datastore<PidRecord>;
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 Datastore<PidRecord>({
33
- filename: path.join(this.baseDir, "pid.jsonl"),
34
- autoload: true,
35
- });
36
- await this.db.loadDatabaseAsync();
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 record: PidRecord = {
53
- pid,
54
- cli,
55
- args,
56
- prompt,
57
- logFile: this.getLogPath(pid),
58
- fifoFile: this.getFifoPath(pid),
59
- status: "active",
60
- exitReason: "",
61
- startedAt: now,
62
- updatedAt: now,
63
- };
64
- await this.db.insertAsync(record);
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 record;
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 update: Partial<PidRecord> = {
75
- status,
76
- updatedAt: Date.now(),
77
- ...extra,
78
- };
79
- await this.db.updateAsync({ pid }, { $set: update }, {});
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 = await this.db.findAsync({
93
- status: { $ne: "exited" } as any,
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
- await this.db.updateAsync(
98
- { pid: record.pid },
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
- await this.db.compactDatafileAsync();
115
- logger.debug("[pidStore] Database compacted and closed");
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
- const records = await store.db.findAsync({ status: { $ne: "exited" } as any });
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
- const sorted = records.sort((a, b) => b.startedAt - a.startedAt);
133
- return sorted[0]?.fifoFile ?? null;
238
+ return records[0]?.fifoFile ?? null;
134
239
  }
135
- }
240
+ }