xtrm-tools 0.5.22 → 0.5.24

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.
@@ -56907,6 +56907,84 @@ function createDocsCommand() {
56907
56907
  var import_node_child_process8 = require("child_process");
56908
56908
  var import_node_fs5 = require("fs");
56909
56909
  var import_node_path6 = require("path");
56910
+ var KIND_LABELS = {
56911
+ "hook.edit_gate.allow": { label: "EDIT+", color: kleur_default.green },
56912
+ "hook.edit_gate.block": { label: "EDIT-", color: kleur_default.red },
56913
+ "hook.commit_gate.allow": { label: "CMIT+", color: kleur_default.green },
56914
+ "hook.commit_gate.block": { label: "CMIT-", color: kleur_default.red },
56915
+ "hook.stop_gate.allow": { label: "STOP+", color: kleur_default.green },
56916
+ "hook.stop_gate.block": { label: "STOP-", color: kleur_default.red },
56917
+ "hook.memory_gate.acked": { label: "MEMO+", color: kleur_default.green },
56918
+ "hook.memory_gate.triggered": { label: "MEMO-", color: kleur_default.yellow },
56919
+ "hook.worktree_boundary.block": { label: "WTRE-", color: kleur_default.red },
56920
+ "bd.claimed": { label: "CLMD ", color: kleur_default.cyan },
56921
+ "bd.closed": { label: "CLSD ", color: kleur_default.green },
56922
+ "bd.auto_committed": { label: "ACMT+", color: kleur_default.cyan }
56923
+ };
56924
+ function getLabel(kind, outcome) {
56925
+ const def = KIND_LABELS[kind];
56926
+ if (!def) {
56927
+ const short = (kind.split(".").pop() ?? "UNKN").slice(0, 4).toUpperCase();
56928
+ const label = `${short}${outcome === "block" ? "-" : "+"}`.padEnd(5);
56929
+ return outcome === "block" ? kleur_default.red(label) : kleur_default.green(label);
56930
+ }
56931
+ if (kind === "bd.auto_committed") {
56932
+ return outcome === "block" ? kleur_default.red("ACMT-") : kleur_default.cyan("ACMT+");
56933
+ }
56934
+ return def.color(def.label);
56935
+ }
56936
+ var SESSION_COLORS = [
56937
+ kleur_default.blue,
56938
+ kleur_default.green,
56939
+ kleur_default.yellow,
56940
+ kleur_default.cyan,
56941
+ kleur_default.magenta
56942
+ ];
56943
+ function buildSessionColorMap(events) {
56944
+ const map2 = /* @__PURE__ */ new Map();
56945
+ for (const ev of events) {
56946
+ if (!map2.has(ev.session_id)) {
56947
+ map2.set(ev.session_id, SESSION_COLORS[map2.size % SESSION_COLORS.length]);
56948
+ }
56949
+ }
56950
+ return map2;
56951
+ }
56952
+ function extendSessionColorMap(map2, events) {
56953
+ for (const ev of events) {
56954
+ if (!map2.has(ev.session_id)) {
56955
+ map2.set(ev.session_id, SESSION_COLORS[map2.size % SESSION_COLORS.length]);
56956
+ }
56957
+ }
56958
+ }
56959
+ function fmtTime(created_at) {
56960
+ try {
56961
+ const d = new Date(created_at);
56962
+ if (isNaN(d.getTime())) return created_at.slice(11, 19) || "??:??:??";
56963
+ return d.toLocaleTimeString("en-GB", { hour12: false });
56964
+ } catch {
56965
+ return created_at.slice(11, 19) || "??:??:??";
56966
+ }
56967
+ }
56968
+ function buildDetail(event) {
56969
+ const parts = [];
56970
+ if (event.tool_name) parts.push(kleur_default.dim(`tool=${event.tool_name}`));
56971
+ if (event.issue_id) parts.push(kleur_default.yellow(`issue=${event.issue_id}`));
56972
+ if (event.worktree) parts.push(kleur_default.dim(`wt=${event.worktree}`));
56973
+ return parts.join(" ") || kleur_default.dim("\u2014");
56974
+ }
56975
+ function formatEventLine(event, colorMap) {
56976
+ const time3 = kleur_default.dim(fmtTime(event.created_at));
56977
+ const colorFn = colorMap.get(event.session_id) ?? kleur_default.white;
56978
+ const session = colorFn(event.session_id.slice(0, 8));
56979
+ const label = getLabel(event.kind, event.outcome);
56980
+ const detail = buildDetail(event);
56981
+ return `${time3} ${session} ${label} ${detail}`;
56982
+ }
56983
+ function printHeader() {
56984
+ const h = kleur_default.dim;
56985
+ console.log(` ${h("TIME ")} ${h("SESSION ")} ${h("LABEL")} ${h("DETAIL")}`);
56986
+ console.log(` ${kleur_default.dim("\u2500".repeat(72))}`);
56987
+ }
56910
56988
  function findProjectRoot(cwd) {
56911
56989
  let dir = cwd;
56912
56990
  for (let i = 0; i < 10; i++) {
@@ -56921,8 +56999,7 @@ function parseBdTable(output, columns2) {
56921
56999
  const lines = output.split("\n").map((l) => l.trim()).filter(Boolean);
56922
57000
  const sepIdx = lines.findIndex((l) => /^[-+\s]+$/.test(l) && l.includes("-"));
56923
57001
  if (sepIdx < 1) return [];
56924
- const dataLines = lines.slice(sepIdx + 1).filter((l) => !l.startsWith("("));
56925
- return dataLines.map((line) => {
57002
+ return lines.slice(sepIdx + 1).filter((l) => !l.startsWith("(")).map((line) => {
56926
57003
  const cells = line.split("|").map((c) => c.trim());
56927
57004
  const row = {};
56928
57005
  columns2.forEach((col2, i) => {
@@ -56931,20 +57008,34 @@ function parseBdTable(output, columns2) {
56931
57008
  return row;
56932
57009
  });
56933
57010
  }
56934
- function queryEvents(cwd, whereExtra, limit) {
56935
- const cols = "id, created_at, runtime, session_id, worktree, layer, kind, outcome, tool_name, issue_id";
56936
- const colNames = ["id", "created_at", "runtime", "session_id", "worktree", "layer", "kind", "outcome", "tool_name", "issue_id"];
56937
- const where = whereExtra ? `WHERE ${whereExtra}` : "";
56938
- const sql = `SELECT ${cols} FROM xtrm_events ${where} ORDER BY created_at ASC, id ASC LIMIT ${limit}`;
56939
- const result = (0, import_node_child_process8.spawnSync)("bd", ["sql", sql], {
57011
+ var COLS = "seq, id, created_at, runtime, session_id, worktree, layer, kind, outcome, tool_name, issue_id";
57012
+ var COL_NAMES = ["seq", "id", "created_at", "runtime", "session_id", "worktree", "layer", "kind", "outcome", "tool_name", "issue_id"];
57013
+ var ADD_SEQ_SQL = `ALTER TABLE xtrm_events ADD COLUMN seq INT NOT NULL AUTO_INCREMENT, ADD UNIQUE KEY uk_seq (seq)`;
57014
+ function queryEvents(cwd, where, limit) {
57015
+ const sql = `SELECT ${COLS} FROM xtrm_events${where ? ` WHERE ${where}` : ""} ORDER BY seq ASC LIMIT ${limit}`;
57016
+ let result = (0, import_node_child_process8.spawnSync)("bd", ["sql", sql], {
56940
57017
  cwd,
56941
57018
  stdio: ["pipe", "pipe", "pipe"],
56942
57019
  encoding: "utf8",
56943
57020
  timeout: 8e3
56944
57021
  });
57022
+ if (result.status !== 0) {
57023
+ (0, import_node_child_process8.spawnSync)("bd", ["sql", ADD_SEQ_SQL], {
57024
+ cwd,
57025
+ stdio: ["pipe", "pipe", "pipe"],
57026
+ encoding: "utf8",
57027
+ timeout: 5e3
57028
+ });
57029
+ result = (0, import_node_child_process8.spawnSync)("bd", ["sql", sql], {
57030
+ cwd,
57031
+ stdio: ["pipe", "pipe", "pipe"],
57032
+ encoding: "utf8",
57033
+ timeout: 8e3
57034
+ });
57035
+ }
56945
57036
  if (result.status !== 0) return [];
56946
- const rows = parseBdTable(result.stdout, colNames);
56947
- return rows.map((r) => ({
57037
+ return parseBdTable(result.stdout, COL_NAMES).map((r) => ({
57038
+ seq: parseInt(r.seq, 10) || 0,
56948
57039
  id: r.id,
56949
57040
  created_at: r.created_at,
56950
57041
  runtime: r.runtime,
@@ -56957,52 +57048,9 @@ function queryEvents(cwd, whereExtra, limit) {
56957
57048
  issue_id: r.issue_id === "<nil>" || !r.issue_id ? null : r.issue_id
56958
57049
  }));
56959
57050
  }
56960
- function fmtTime(created_at) {
56961
- try {
56962
- const d = new Date(created_at);
56963
- if (isNaN(d.getTime())) return created_at.slice(11, 19) || "??:??:??";
56964
- return d.toLocaleTimeString("en-GB", { hour12: false });
56965
- } catch {
56966
- return created_at.slice(11, 19) || "??:??:??";
56967
- }
56968
- }
56969
- function fmtKind(kind, outcome) {
56970
- const dot = outcome === "block" ? kleur_default.red("\u25CF") : kleur_default.green("\u25CB");
56971
- const label = kind.padEnd(36);
56972
- const colored = outcome === "block" ? kleur_default.red(label) : kleur_default.green(label);
56973
- return `${dot} ${colored}`;
56974
- }
56975
- function fmtSession(sessionId) {
56976
- const short = sessionId.length > 8 ? sessionId.slice(0, 8) : sessionId;
56977
- return kleur_default.dim(short);
56978
- }
56979
- function fmtMeta(event) {
56980
- const parts = [];
56981
- if (event.tool_name) parts.push(kleur_default.cyan(event.tool_name.padEnd(10)));
56982
- if (event.issue_id) parts.push(kleur_default.yellow(event.issue_id));
56983
- if (event.worktree) parts.push(kleur_default.dim(`[${event.worktree}]`));
56984
- return parts.join(" ") || kleur_default.dim("\u2014");
56985
- }
56986
- function printEvent(event) {
56987
- const time3 = kleur_default.dim(`[${fmtTime(event.created_at)}]`);
56988
- const session = fmtSession(event.session_id);
56989
- const kind = fmtKind(event.kind, event.outcome);
56990
- const meta3 = fmtMeta(event);
56991
- console.log(` ${time3} ${session} ${kind} ${meta3}`);
56992
- }
56993
- function printHeader() {
56994
- const h = kleur_default.dim;
56995
- const col2 = (s, w) => s.padEnd(w);
56996
- console.log(
56997
- ` ${h(col2("[TIME]", 10))} ${h(col2("SESSION", 10))} ${h("\u25CF/\u25CB")} ${h(col2("KIND", 37))} ${h("TOOL/ISSUE")}`
56998
- );
56999
- console.log(` ${kleur_default.dim("\u2500".repeat(90))}`);
57000
- }
57001
- function buildWhereClause(opts, sinceTs) {
57051
+ function buildWhere(opts, baseClause) {
57002
57052
  const clauses = [];
57003
- if (sinceTs) {
57004
- clauses.push(`created_at >= '${sinceTs}'`);
57005
- }
57053
+ if (baseClause) clauses.push(baseClause);
57006
57054
  if (opts.session) {
57007
57055
  const s = opts.session.replace(/'/g, "''");
57008
57056
  clauses.push(`session_id LIKE '${s}%'`);
@@ -57013,37 +57061,34 @@ function buildWhereClause(opts, sinceTs) {
57013
57061
  }
57014
57062
  return clauses.join(" AND ");
57015
57063
  }
57016
- function watch(cwd, opts) {
57017
- const seenIds = /* @__PURE__ */ new Set();
57018
- let lastTs = null;
57064
+ function follow(cwd, opts) {
57019
57065
  const fiveMinsAgo = new Date(Date.now() - 5 * 60 * 1e3).toISOString().replace("T", " ").slice(0, 19);
57020
- const initialWhere = buildWhereClause(opts, fiveMinsAgo);
57021
- const initial = queryEvents(cwd, initialWhere, 200);
57066
+ const initial = queryEvents(cwd, buildWhere(opts, `created_at >= '${fiveMinsAgo}'`), 200);
57067
+ const colorMap = buildSessionColorMap(initial);
57068
+ let lastSeq = 0;
57022
57069
  if (initial.length > 0) {
57023
57070
  for (const ev of initial) {
57024
- seenIds.add(ev.id);
57025
- if (!lastTs || ev.created_at > lastTs) lastTs = ev.created_at;
57071
+ if (ev.seq > lastSeq) lastSeq = ev.seq;
57026
57072
  if (opts.json) {
57027
57073
  console.log(JSON.stringify(ev));
57028
57074
  } else {
57029
- printEvent(ev);
57075
+ console.log(" " + formatEventLine(ev, colorMap));
57030
57076
  }
57031
57077
  }
57032
- } else {
57033
- if (!opts.json) console.log(kleur_default.dim(" (no recent events \u2014 waiting for new ones)\n"));
57078
+ } else if (!opts.json) {
57079
+ console.log(kleur_default.dim(" (no recent events \u2014 waiting for new ones)\n"));
57034
57080
  }
57035
57081
  const interval = setInterval(() => {
57036
- const overlapTs = lastTs ? new Date(new Date(lastTs.replace(" +0000 UTC", "Z")).getTime() - 2e3).toISOString().replace("T", " ").slice(0, 19) : new Date(Date.now() - 1e4).toISOString().replace("T", " ").slice(0, 19);
57037
- const where = buildWhereClause(opts, overlapTs);
57038
- const events = queryEvents(cwd, where, 50);
57039
- const newEvents = events.filter((ev) => !seenIds.has(ev.id));
57040
- for (const ev of newEvents) {
57041
- seenIds.add(ev.id);
57042
- if (!lastTs || ev.created_at > lastTs) lastTs = ev.created_at;
57043
- if (opts.json) {
57044
- console.log(JSON.stringify(ev));
57045
- } else {
57046
- printEvent(ev);
57082
+ const events = queryEvents(cwd, buildWhere(opts, `seq > ${lastSeq}`), 50);
57083
+ if (events.length > 0) {
57084
+ extendSessionColorMap(colorMap, events);
57085
+ for (const ev of events) {
57086
+ if (ev.seq > lastSeq) lastSeq = ev.seq;
57087
+ if (opts.json) {
57088
+ console.log(JSON.stringify(ev));
57089
+ } else {
57090
+ console.log(" " + formatEventLine(ev, colorMap));
57091
+ }
57047
57092
  }
57048
57093
  }
57049
57094
  }, 2e3);
@@ -57054,7 +57099,7 @@ function watch(cwd, opts) {
57054
57099
  });
57055
57100
  }
57056
57101
  function createDebugCommand() {
57057
- return new Command("debug").description("Watch xtrm hook and bd lifecycle events in real time").option("--all", "Show full history instead of watching", false).option("--session <id>", "Filter by session ID (prefix match)").option("--type <layer>", "Filter by layer: gate | bd").option("--json", "Output raw JSON lines", false).action((opts) => {
57102
+ return new Command("debug").description("Watch xtrm hook and bd lifecycle events in real time").option("-f, --follow", "Follow new events (default when no other mode set)", false).option("--all", "Show full history and exit", false).option("--session <id>", "Filter by session ID (prefix match)").option("--type <layer>", "Filter by layer: gate | bd").option("--json", "Output raw JSON lines", false).action((opts) => {
57058
57103
  const cwd = process.cwd();
57059
57104
  const root = findProjectRoot(cwd);
57060
57105
  if (!root) {
@@ -57067,31 +57112,31 @@ function createDebugCommand() {
57067
57112
  if (opts.all) {
57068
57113
  console.log(kleur_default.dim(" Showing full history\n"));
57069
57114
  } else {
57070
- console.log(kleur_default.dim(" Watching for events \u2014 Ctrl+C to stop\n"));
57115
+ console.log(kleur_default.dim(" Following events \u2014 Ctrl+C to stop\n"));
57071
57116
  }
57072
57117
  printHeader();
57073
57118
  }
57074
57119
  if (opts.all) {
57075
- const where = buildWhereClause(opts, null);
57076
- const events = queryEvents(root, where, 200);
57120
+ const events = queryEvents(root, buildWhere(opts, ""), 200);
57077
57121
  if (events.length === 0) {
57078
57122
  if (!opts.json) {
57079
57123
  console.log(kleur_default.dim("\n No events recorded yet."));
57080
57124
  console.log(kleur_default.dim(" Events appear here as hooks fire and bd lifecycle runs.\n"));
57081
57125
  }
57082
57126
  } else {
57127
+ const colorMap = buildSessionColorMap(events);
57083
57128
  for (const ev of events) {
57084
57129
  if (opts.json) {
57085
57130
  console.log(JSON.stringify(ev));
57086
57131
  } else {
57087
- printEvent(ev);
57132
+ console.log(" " + formatEventLine(ev, colorMap));
57088
57133
  }
57089
57134
  }
57090
57135
  if (!opts.json) console.log("");
57091
57136
  }
57092
57137
  return;
57093
57138
  }
57094
- watch(root, opts);
57139
+ follow(root, opts);
57095
57140
  });
57096
57141
  }
57097
57142