harness-bujang 0.5.6 → 0.5.7

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.
Files changed (2) hide show
  1. package/dist/index.js +34 -44
  2. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -925,9 +925,8 @@ console.log(' \u2713 Transferred ' + total + ' messages');
925
925
  import * as http from "http";
926
926
  import * as path5 from "path";
927
927
  import * as fs5 from "fs";
928
- import { execFile, spawn } from "child_process";
929
- import { promisify } from "util";
930
- var execFileP = promisify(execFile);
928
+ import { spawn } from "child_process";
929
+ import Database from "better-sqlite3";
931
930
  var c4 = {
932
931
  bold: (s) => `\x1B[1m${s}\x1B[22m`,
933
932
  dim: (s) => `\x1B[2m${s}\x1B[22m`,
@@ -938,34 +937,37 @@ var c4 = {
938
937
  };
939
938
  async function runChat(args) {
940
939
  const opts = parseArgs3(args);
940
+ const dbPath = resolveDbPath(opts.target);
941
+ const dbIsNew = !fs5.existsSync(dbPath);
942
+ if (dbIsNew) fs5.mkdirSync(path5.dirname(dbPath), { recursive: true });
943
+ let db;
941
944
  try {
942
- await execFileP("sqlite3", ["--version"]);
943
- } catch {
945
+ db = new Database(dbPath);
946
+ } catch (err) {
944
947
  console.log();
945
- console.log(c4.red("\u2716 The `sqlite3` command-line tool is required for `bujang chat`."));
948
+ console.log(c4.red("\u2716 Failed to open chat DB at " + dbPath));
949
+ console.log(" " + c4.dim(String(err)));
946
950
  console.log();
947
- console.log(" macOS: already installed");
948
- console.log(" Ubuntu/WSL: " + c4.bold("sudo apt-get install sqlite3"));
949
- console.log(" Fedora: " + c4.bold("sudo dnf install sqlite"));
950
- console.log(" Windows: https://www.sqlite.org/download.html (sqlite-tools-win-x64)");
951
+ console.log(" This usually means better-sqlite3 could not load its native binding.");
952
+ console.log(" Try " + c4.bold("npm i -g harness-bujang@latest") + " to fetch a fresh prebuild.");
951
953
  console.log();
952
954
  process.exitCode = 1;
953
955
  return;
954
956
  }
955
- const dbPath = resolveDbPath(opts.target);
956
- if (!fs5.existsSync(dbPath)) {
957
- fs5.mkdirSync(path5.dirname(dbPath), { recursive: true });
958
- await runSql(dbPath, SCHEMA_SQL);
957
+ db.pragma("journal_mode = WAL");
958
+ db.exec(SCHEMA_SQL);
959
+ if (dbIsNew) {
959
960
  const seedId = `seed-${Date.now()}`;
960
- await runSql(
961
- dbPath,
961
+ db.prepare(
962
962
  `INSERT INTO harness_messages (id, "from", "to", type, message, severity)
963
- VALUES ('${seedId}', '\uBD80\uC7A5', '\uB300\uD45C\uB2D8', 'info', '\uD1A1\uBC29\uC774 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCCAB \uBA85\uB839\uC744 \uB0B4\uB824\uC8FC\uC138\uC694.', 'info');`
964
- );
963
+ VALUES (?, ?, ?, ?, ?, ?)`
964
+ ).run(seedId, "\uBD80\uC7A5", "\uB300\uD45C\uB2D8", "info", "\uD1A1\uBC29\uC774 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCCAB \uBA85\uB839\uC744 \uB0B4\uB824\uC8FC\uC138\uC694.", "info");
965
965
  console.log(c4.dim(` created empty chat DB at ${dbPath}`));
966
- } else {
967
- await runSql(dbPath, SCHEMA_SQL);
968
966
  }
967
+ const insertStmt = db.prepare(
968
+ `INSERT INTO harness_messages (id, "from", "to", type, message, severity)
969
+ VALUES (?, ?, ?, ?, ?, ?)`
970
+ );
969
971
  const port = await findOpenPort(opts.port);
970
972
  const server = http.createServer(async (req, res) => {
971
973
  const url2 = new URL(req.url ?? "/", `http://localhost:${port}`);
@@ -977,7 +979,7 @@ async function runChat(args) {
977
979
  if (req.method === "GET" && url2.pathname === "/api/messages") {
978
980
  const days = parseInt(url2.searchParams.get("days") ?? "7", 10);
979
981
  try {
980
- const rows = await readMessages(dbPath, days);
982
+ const rows = readMessages(db, days);
981
983
  res.writeHead(200, { "content-type": "application/json" });
982
984
  res.end(JSON.stringify({ data: rows }));
983
985
  } catch (err) {
@@ -1001,11 +1003,7 @@ async function runChat(args) {
1001
1003
  res.end(JSON.stringify({ error: "message is required" }));
1002
1004
  return;
1003
1005
  }
1004
- await runSql(
1005
- dbPath,
1006
- `INSERT INTO harness_messages (id, "from", "to", type, message, severity)
1007
- VALUES (${q(id)}, ${q(from)}, ${q(to)}, ${q(type)}, ${q(message)}, ${q(severity)});`
1008
- );
1006
+ insertStmt.run(id, from, to, type, message, severity);
1009
1007
  res.writeHead(200, { "content-type": "application/json" });
1010
1008
  res.end(JSON.stringify({ data: { id } }));
1011
1009
  } catch (err) {
@@ -1031,6 +1029,7 @@ async function runChat(args) {
1031
1029
  console.log();
1032
1030
  console.log(c4.dim(" bye \u{1F44B}"));
1033
1031
  server.close();
1032
+ db.close();
1034
1033
  process.exit(0);
1035
1034
  });
1036
1035
  }
@@ -1095,18 +1094,15 @@ function readBody(req) {
1095
1094
  req.on("error", reject);
1096
1095
  });
1097
1096
  }
1098
- async function readMessages(dbPath, days) {
1099
- const sql = `
1100
- SELECT id, timestamp, "from" AS sender, "to" AS recipient, type, message, severity
1101
- FROM harness_messages
1102
- WHERE timestamp >= datetime('now', '-${Math.max(1, days | 0)} day')
1103
- ORDER BY timestamp ASC;
1104
- `;
1105
- const { stdout } = await execFileP("sqlite3", ["-json", dbPath, sql], {
1106
- maxBuffer: 32 * 1024 * 1024
1107
- });
1108
- if (!stdout.trim()) return [];
1109
- const raw = JSON.parse(stdout);
1097
+ function readMessages(db, days) {
1098
+ const safeDays = Math.max(1, days | 0);
1099
+ const stmt = db.prepare(
1100
+ `SELECT id, timestamp, "from" AS sender, "to" AS recipient, type, message, severity
1101
+ FROM harness_messages
1102
+ WHERE timestamp >= datetime('now', '-' || ? || ' day')
1103
+ ORDER BY timestamp ASC`
1104
+ );
1105
+ const raw = stmt.all(safeDays);
1110
1106
  return raw.map((r) => ({
1111
1107
  id: r.id,
1112
1108
  timestamp: r.timestamp,
@@ -1117,12 +1113,6 @@ async function readMessages(dbPath, days) {
1117
1113
  severity: r.severity
1118
1114
  }));
1119
1115
  }
1120
- async function runSql(dbPath, sql) {
1121
- await execFileP("sqlite3", [dbPath, sql], { maxBuffer: 1024 * 1024 });
1122
- }
1123
- function q(value) {
1124
- return `'${value.replace(/'/g, "''")}'`;
1125
- }
1126
1116
  var SCHEMA_SQL = `
1127
1117
  CREATE TABLE IF NOT EXISTS harness_messages (
1128
1118
  id TEXT PRIMARY KEY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-bujang",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "description": "Install the Harness-Bujang multi-agent harness into any project — Director, 7 specialist teams, real-time chat-room UI. Korean and English personas. Works with Claude Code, Cursor, Cline, Aider, or any tool that reads .claude/agents/.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -47,6 +47,7 @@
47
47
  "prepublishOnly": "npm run build"
48
48
  },
49
49
  "devDependencies": {
50
+ "@types/better-sqlite3": "^7.6.10",
50
51
  "@types/node": "^20.11.0",
51
52
  "tsup": "^8.3.0",
52
53
  "tsx": "^4.19.0",
@@ -56,6 +57,7 @@
56
57
  "node": ">=20"
57
58
  },
58
59
  "dependencies": {
59
- "@inquirer/prompts": "^8.4.2"
60
+ "@inquirer/prompts": "^8.4.2",
61
+ "better-sqlite3": "^11.7.0"
60
62
  }
61
63
  }