@juli-os/ledger 0.1.5 → 0.1.6

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/index.js CHANGED
@@ -224,10 +224,11 @@ CREATE INDEX IF NOT EXISTS idx_runs_session ON runs(session, status);
224
224
  `;
225
225
  var str = (v) => typeof v === "string" ? v : v === null || v === void 0 ? "" : String(v);
226
226
  var num = (v) => typeof v === "number" ? v : Number(v ?? 0);
227
- var dedupPattern = (key) => {
228
- const jsonValue = JSON.stringify(key).slice(1, -1);
229
- return `%"dedup_key":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
227
+ var jsonFieldPattern = (field, value) => {
228
+ const jsonValue = JSON.stringify(value).slice(1, -1);
229
+ return `%"${field}":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
230
230
  };
231
+ var dedupPattern = (key) => jsonFieldPattern("dedup_key", key);
231
232
  var SEQ_PARK_BASE = 1e9;
232
233
  var SEND_STEP_LIKE_CUTOFF = "2026-09-19";
233
234
  var rowToWorkflow = (r) => ({
@@ -352,8 +353,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
352
353
  return getWorkflowById(id);
353
354
  },
354
355
  getWorkflow(id) {
355
- const r = db.prepare("SELECT * FROM workflows WHERE id=?").get(id);
356
- return r ? rowToWorkflow(r) : null;
356
+ return getWorkflowById(id);
357
357
  },
358
358
  listWorkflows(limit = 100, status) {
359
359
  if (status !== void 0 && status !== "") {
@@ -456,8 +456,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
456
456
  }
457
457
  },
458
458
  getStep(id) {
459
- const r = db.prepare(`SELECT ${STEP_COLS} FROM workflow_steps WHERE id=?`).get(id);
460
- return r ? rowToStep(r) : null;
459
+ return getStepById(id);
461
460
  },
462
461
  stepsForWorkflow(id) {
463
462
  return db.prepare(`SELECT ${STEP_COLS} FROM workflow_steps WHERE workflow_id=? ORDER BY seq`).all(id).map(rowToStep);
@@ -528,25 +527,21 @@ var createLedgerStore = (dbPath, deps = {}) => {
528
527
  ).all(status, limit).map(rowToStep);
529
528
  },
530
529
  runningAgentStepForSession(session) {
531
- const r = db.prepare(
532
- `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
530
+ const proj = `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
533
531
  COALESCE(st.title,'') AS title, st.status AS status,
534
532
  COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
535
533
  COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at
536
534
  FROM workflow_steps st
537
- JOIN workflows w ON w.id = st.workflow_id
535
+ JOIN workflows w ON w.id = st.workflow_id`;
536
+ const r = db.prepare(
537
+ `${proj}
538
538
  JOIN runs r ON r.workflow_id = st.workflow_id
539
539
  WHERE st.status='running' AND st.kind IN (${sqlInList(AGENT_STEP_KINDS)}) AND r.session=? AND w.status='running'
540
540
  ORDER BY st.updated_at DESC LIMIT 1`
541
541
  ).get(session);
542
542
  if (r) return rowToStep(r);
543
543
  const r2 = db.prepare(
544
- `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
545
- COALESCE(st.title,'') AS title, st.status AS status,
546
- COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
547
- COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at
548
- FROM workflow_steps st
549
- JOIN workflows w ON w.id = st.workflow_id
544
+ `${proj}
550
545
  WHERE st.status='running' AND st.kind IN (${sqlInList(AGENT_STEP_KINDS)}) AND w.status='running'
551
546
  AND (w.session=? OR COALESCE(json_extract(w.meta,'$.assigned_session'),'')=?)
552
547
  ORDER BY st.updated_at DESC LIMIT 1`
@@ -555,7 +550,8 @@ var createLedgerStore = (dbPath, deps = {}) => {
555
550
  },
556
551
  sessionHasOpenWork(session, excludeWorkflowId) {
557
552
  const anchor = "(session=?1 OR COALESCE(json_extract(meta,'$.assigned_session'),'')=?1 OR id IN (SELECT workflow_id FROM runs WHERE session=?1))";
558
- const sql = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? `SELECT COUNT(*) AS n FROM workflows WHERE status IN ('queued','running') AND ${anchor} AND id != ?2` : `SELECT COUNT(*) AS n FROM workflows WHERE status IN ('queued','running') AND ${anchor}`;
553
+ const openFilter = `status IN (${sqlInList(ACTIVE_WORKFLOW_STATUSES)})`;
554
+ const sql = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? `SELECT COUNT(*) AS n FROM workflows WHERE ${openFilter} AND ${anchor} AND id != ?2` : `SELECT COUNT(*) AS n FROM workflows WHERE ${openFilter} AND ${anchor}`;
559
555
  const row = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? db.prepare(sql).get(session, excludeWorkflowId) : db.prepare(sql).get(session);
560
556
  return Number(row["n"]) > 0;
561
557
  },
@@ -630,7 +626,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
630
626
  /** 自回环守卫查询(2026-09-20 断点十三):message_id 是否命中本引擎已
631
627
  * 发送记录——completed send 步的 output.message_id(email_sent 事件同源
632
628
  * 落账)。进件层据此丢弃投递副本回灌(引擎给轮询邮箱自己发信的 echo)。
633
- * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 dedupPattern
629
+ * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 jsonFieldPattern
634
630
  * 成对转义(message-id 几乎必含 `_`)。 */
635
631
  recordSentMessageId(messageId, meta) {
636
632
  if (messageId === "") return;
@@ -644,8 +640,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
644
640
  `SELECT 1 FROM events WHERE type = 'email_sent' AND entity_type = 'email' AND entity_id = ? LIMIT 1`
645
641
  ).get(messageId);
646
642
  if (registered !== void 0) return true;
647
- const jsonValue = JSON.stringify(messageId).slice(1, -1);
648
- const pattern = `%"message_id":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
643
+ const pattern = jsonFieldPattern("message_id", messageId);
649
644
  const rows = db.prepare(
650
645
  `SELECT output FROM workflow_steps WHERE kind = 'send' AND status = 'completed'
651
646
  AND updated_at < ? AND output LIKE ? ESCAPE '\\'`
@@ -881,18 +876,18 @@ var priceUsage = (rows) => {
881
876
  const key = r.model === "" ? "\uFF08\u672A\u8BB0\u5F55\u6A21\u578B\uFF09" : r.model;
882
877
  let a = accs.get(key);
883
878
  if (a === void 0) {
884
- const p = findPrice(key);
879
+ const p2 = findPrice(key);
885
880
  a = {
886
881
  model: key,
887
- label: p?.label ?? key,
882
+ label: p2?.label ?? key,
888
883
  free: false,
889
- priced: p !== null,
890
884
  calls: 0,
891
885
  inputTokens: 0,
892
886
  cachedTokens: 0,
893
887
  outputTokens: 0,
894
888
  tiersHit: /* @__PURE__ */ new Set(),
895
- cost: { cache: 0, input: 0, output: 0 }
889
+ cost: { cache: 0, input: 0, output: 0 },
890
+ price: p2
896
891
  };
897
892
  accs.set(key, a);
898
893
  }
@@ -900,8 +895,9 @@ var priceUsage = (rows) => {
900
895
  a.inputTokens += r.inputTokens;
901
896
  a.cachedTokens += r.cachedTokens;
902
897
  a.outputTokens += r.outputTokens;
903
- if (!a.priced) continue;
904
- const t = tierOf(findPrice(key), r);
898
+ const p = a.price;
899
+ if (p === null) continue;
900
+ const t = tierOf(p, r);
905
901
  a.tiersHit.add(t.note);
906
902
  if (t.input === 0 && t.output === 0) {
907
903
  a.free = true;
@@ -917,7 +913,7 @@ var priceUsage = (rows) => {
917
913
  model: a.model,
918
914
  label: a.label,
919
915
  free: a.free,
920
- priced: a.priced,
916
+ priced: a.price !== null,
921
917
  calls: a.calls,
922
918
  inputTokens: a.inputTokens,
923
919
  cachedTokens: a.cachedTokens,
@@ -981,11 +977,15 @@ CREATE TABLE IF NOT EXISTS usage_meta (
981
977
  );
982
978
  `;
983
979
  var n = (v) => typeof v === "number" ? v : Number(v ?? 0);
984
- var windowUsageRows = (db, tmuxSession, windows) => {
985
- if (windows.length === 0) return [];
980
+ var windowConds = (tmuxSession, windows) => {
986
981
  const conds = windows.map(() => "(created_at >= ? AND created_at <= ?)").join(" OR ");
987
982
  const params = [tmuxSession];
988
983
  for (const [a, b] of windows) params.push(a, b);
984
+ return { conds, params };
985
+ };
986
+ var windowUsageRows = (db, tmuxSession, windows) => {
987
+ if (windows.length === 0) return [];
988
+ const { conds, params } = windowConds(tmuxSession, windows);
989
989
  return db.prepare(
990
990
  `SELECT model, input_tokens AS i, output_tokens AS o, cached_tokens AS k
991
991
  FROM prompt_usage WHERE source='claude_code' AND tmux_session=? AND (${conds})`
@@ -1077,9 +1077,7 @@ var createUsageStore = (dbPath, now = () => /* @__PURE__ */ new Date()) => {
1077
1077
  },
1078
1078
  perSessionWindows(tmuxSession, windows) {
1079
1079
  if (windows.length === 0) return { count: 0, inputTokens: 0, outputTokens: 0 };
1080
- const conds = windows.map(() => "(created_at >= ? AND created_at <= ?)").join(" OR ");
1081
- const params = [tmuxSession];
1082
- for (const [a, b] of windows) params.push(a, b);
1080
+ const { conds, params } = windowConds(tmuxSession, windows);
1083
1081
  const r = db.prepare(
1084
1082
  `SELECT COUNT(*) AS c, COALESCE(SUM(input_tokens),0) AS i, COALESCE(SUM(output_tokens),0) AS o
1085
1083
  FROM prompt_usage WHERE source='claude_code' AND tmux_session=? AND (${conds})`
@@ -1160,9 +1158,6 @@ var createUsageStore = (dbPath, now = () => /* @__PURE__ */ new Date()) => {
1160
1158
  VALUES (?, ?, '', '') ON CONFLICT(claude_session_id) DO NOTHING`).run(claudeSessionId, tmuxSession);
1161
1159
  },
1162
1160
  ingestProjectTranscripts(claudeProjectsDir) {
1163
- const mapped = new Set(
1164
- db.prepare("SELECT claude_session_id FROM claude_sessions").all().map((r) => String(r["claude_session_id"]))
1165
- );
1166
1161
  let count = 0;
1167
1162
  try {
1168
1163
  const projects = readdirSync(claudeProjectsDir);
@@ -1217,11 +1212,11 @@ var ingestFile = (db, claudeId, transcriptPath) => {
1217
1212
  const newOffset = offset + Buffer.byteLength(complete, "utf8");
1218
1213
  db.exec("BEGIN");
1219
1214
  try {
1215
+ const sess = tmuxOf(db, claudeId);
1220
1216
  for (const line of complete.split("\n")) {
1221
1217
  if (line === "") continue;
1222
1218
  const rec = parseAssistantLine(line);
1223
1219
  if (!rec) continue;
1224
- const sess = tmuxOf(db, claudeId);
1225
1220
  db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1226
1221
  VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1227
1222
  `turn=${String(rec.callContext).slice(0, 40)}`,
@@ -182,10 +182,11 @@ CREATE INDEX IF NOT EXISTS idx_runs_session ON runs(session, status);
182
182
  `;
183
183
  var str = (v) => typeof v === "string" ? v : v === null || v === void 0 ? "" : String(v);
184
184
  var num = (v) => typeof v === "number" ? v : Number(v ?? 0);
185
- var dedupPattern = (key) => {
186
- const jsonValue = JSON.stringify(key).slice(1, -1);
187
- return `%"dedup_key":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
185
+ var jsonFieldPattern = (field, value) => {
186
+ const jsonValue = JSON.stringify(value).slice(1, -1);
187
+ return `%"${field}":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
188
188
  };
189
+ var dedupPattern = (key) => jsonFieldPattern("dedup_key", key);
189
190
  var SEQ_PARK_BASE = 1e9;
190
191
  var SEND_STEP_LIKE_CUTOFF = "2026-09-19";
191
192
  var rowToWorkflow = (r) => ({
@@ -310,8 +311,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
310
311
  return getWorkflowById(id);
311
312
  },
312
313
  getWorkflow(id) {
313
- const r = db.prepare("SELECT * FROM workflows WHERE id=?").get(id);
314
- return r ? rowToWorkflow(r) : null;
314
+ return getWorkflowById(id);
315
315
  },
316
316
  listWorkflows(limit = 100, status) {
317
317
  if (status !== void 0 && status !== "") {
@@ -414,8 +414,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
414
414
  }
415
415
  },
416
416
  getStep(id) {
417
- const r = db.prepare(`SELECT ${STEP_COLS} FROM workflow_steps WHERE id=?`).get(id);
418
- return r ? rowToStep(r) : null;
417
+ return getStepById(id);
419
418
  },
420
419
  stepsForWorkflow(id) {
421
420
  return db.prepare(`SELECT ${STEP_COLS} FROM workflow_steps WHERE workflow_id=? ORDER BY seq`).all(id).map(rowToStep);
@@ -486,25 +485,21 @@ var createLedgerStore = (dbPath, deps = {}) => {
486
485
  ).all(status, limit).map(rowToStep);
487
486
  },
488
487
  runningAgentStepForSession(session) {
489
- const r = db.prepare(
490
- `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
488
+ const proj = `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
491
489
  COALESCE(st.title,'') AS title, st.status AS status,
492
490
  COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
493
491
  COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at
494
492
  FROM workflow_steps st
495
- JOIN workflows w ON w.id = st.workflow_id
493
+ JOIN workflows w ON w.id = st.workflow_id`;
494
+ const r = db.prepare(
495
+ `${proj}
496
496
  JOIN runs r ON r.workflow_id = st.workflow_id
497
497
  WHERE st.status='running' AND st.kind IN (${sqlInList(AGENT_STEP_KINDS)}) AND r.session=? AND w.status='running'
498
498
  ORDER BY st.updated_at DESC LIMIT 1`
499
499
  ).get(session);
500
500
  if (r) return rowToStep(r);
501
501
  const r2 = db.prepare(
502
- `SELECT st.id AS id, st.workflow_id AS workflow_id, st.seq AS seq, st.kind AS kind,
503
- COALESCE(st.title,'') AS title, st.status AS status,
504
- COALESCE(st.input,'') AS input, COALESCE(st.output,'') AS output,
505
- COALESCE(st.summary,'') AS summary, st.updated_at AS updated_at
506
- FROM workflow_steps st
507
- JOIN workflows w ON w.id = st.workflow_id
502
+ `${proj}
508
503
  WHERE st.status='running' AND st.kind IN (${sqlInList(AGENT_STEP_KINDS)}) AND w.status='running'
509
504
  AND (w.session=? OR COALESCE(json_extract(w.meta,'$.assigned_session'),'')=?)
510
505
  ORDER BY st.updated_at DESC LIMIT 1`
@@ -513,7 +508,8 @@ var createLedgerStore = (dbPath, deps = {}) => {
513
508
  },
514
509
  sessionHasOpenWork(session, excludeWorkflowId) {
515
510
  const anchor = "(session=?1 OR COALESCE(json_extract(meta,'$.assigned_session'),'')=?1 OR id IN (SELECT workflow_id FROM runs WHERE session=?1))";
516
- const sql = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? `SELECT COUNT(*) AS n FROM workflows WHERE status IN ('queued','running') AND ${anchor} AND id != ?2` : `SELECT COUNT(*) AS n FROM workflows WHERE status IN ('queued','running') AND ${anchor}`;
511
+ const openFilter = `status IN (${sqlInList(ACTIVE_WORKFLOW_STATUSES)})`;
512
+ const sql = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? `SELECT COUNT(*) AS n FROM workflows WHERE ${openFilter} AND ${anchor} AND id != ?2` : `SELECT COUNT(*) AS n FROM workflows WHERE ${openFilter} AND ${anchor}`;
517
513
  const row = excludeWorkflowId !== void 0 && excludeWorkflowId !== "" ? db.prepare(sql).get(session, excludeWorkflowId) : db.prepare(sql).get(session);
518
514
  return Number(row["n"]) > 0;
519
515
  },
@@ -588,7 +584,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
588
584
  /** 自回环守卫查询(2026-09-20 断点十三):message_id 是否命中本引擎已
589
585
  * 发送记录——completed send 步的 output.message_id(email_sent 事件同源
590
586
  * 落账)。进件层据此丢弃投递副本回灌(引擎给轮询邮箱自己发信的 echo)。
591
- * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 dedupPattern
587
+ * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 jsonFieldPattern
592
588
  * 成对转义(message-id 几乎必含 `_`)。 */
593
589
  recordSentMessageId(messageId, meta) {
594
590
  if (messageId === "") return;
@@ -602,8 +598,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
602
598
  `SELECT 1 FROM events WHERE type = 'email_sent' AND entity_type = 'email' AND entity_id = ? LIMIT 1`
603
599
  ).get(messageId);
604
600
  if (registered !== void 0) return true;
605
- const jsonValue = JSON.stringify(messageId).slice(1, -1);
606
- const pattern = `%"message_id":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
601
+ const pattern = jsonFieldPattern("message_id", messageId);
607
602
  const rows = db.prepare(
608
603
  `SELECT output FROM workflow_steps WHERE kind = 'send' AND status = 'completed'
609
604
  AND updated_at < ? AND output LIKE ? ESCAPE '\\'`
@@ -839,18 +834,18 @@ var priceUsage = (rows) => {
839
834
  const key = r.model === "" ? "\uFF08\u672A\u8BB0\u5F55\u6A21\u578B\uFF09" : r.model;
840
835
  let a = accs.get(key);
841
836
  if (a === void 0) {
842
- const p = findPrice(key);
837
+ const p2 = findPrice(key);
843
838
  a = {
844
839
  model: key,
845
- label: p?.label ?? key,
840
+ label: p2?.label ?? key,
846
841
  free: false,
847
- priced: p !== null,
848
842
  calls: 0,
849
843
  inputTokens: 0,
850
844
  cachedTokens: 0,
851
845
  outputTokens: 0,
852
846
  tiersHit: /* @__PURE__ */ new Set(),
853
- cost: { cache: 0, input: 0, output: 0 }
847
+ cost: { cache: 0, input: 0, output: 0 },
848
+ price: p2
854
849
  };
855
850
  accs.set(key, a);
856
851
  }
@@ -858,8 +853,9 @@ var priceUsage = (rows) => {
858
853
  a.inputTokens += r.inputTokens;
859
854
  a.cachedTokens += r.cachedTokens;
860
855
  a.outputTokens += r.outputTokens;
861
- if (!a.priced) continue;
862
- const t = tierOf(findPrice(key), r);
856
+ const p = a.price;
857
+ if (p === null) continue;
858
+ const t = tierOf(p, r);
863
859
  a.tiersHit.add(t.note);
864
860
  if (t.input === 0 && t.output === 0) {
865
861
  a.free = true;
@@ -875,7 +871,7 @@ var priceUsage = (rows) => {
875
871
  model: a.model,
876
872
  label: a.label,
877
873
  free: a.free,
878
- priced: a.priced,
874
+ priced: a.price !== null,
879
875
  calls: a.calls,
880
876
  inputTokens: a.inputTokens,
881
877
  cachedTokens: a.cachedTokens,
@@ -939,11 +935,15 @@ CREATE TABLE IF NOT EXISTS usage_meta (
939
935
  );
940
936
  `;
941
937
  var n = (v) => typeof v === "number" ? v : Number(v ?? 0);
942
- var windowUsageRows = (db, tmuxSession, windows) => {
943
- if (windows.length === 0) return [];
938
+ var windowConds = (tmuxSession, windows) => {
944
939
  const conds = windows.map(() => "(created_at >= ? AND created_at <= ?)").join(" OR ");
945
940
  const params = [tmuxSession];
946
941
  for (const [a, b] of windows) params.push(a, b);
942
+ return { conds, params };
943
+ };
944
+ var windowUsageRows = (db, tmuxSession, windows) => {
945
+ if (windows.length === 0) return [];
946
+ const { conds, params } = windowConds(tmuxSession, windows);
947
947
  return db.prepare(
948
948
  `SELECT model, input_tokens AS i, output_tokens AS o, cached_tokens AS k
949
949
  FROM prompt_usage WHERE source='claude_code' AND tmux_session=? AND (${conds})`
@@ -1035,9 +1035,7 @@ var createUsageStore = (dbPath, now = () => /* @__PURE__ */ new Date()) => {
1035
1035
  },
1036
1036
  perSessionWindows(tmuxSession, windows) {
1037
1037
  if (windows.length === 0) return { count: 0, inputTokens: 0, outputTokens: 0 };
1038
- const conds = windows.map(() => "(created_at >= ? AND created_at <= ?)").join(" OR ");
1039
- const params = [tmuxSession];
1040
- for (const [a, b] of windows) params.push(a, b);
1038
+ const { conds, params } = windowConds(tmuxSession, windows);
1041
1039
  const r = db.prepare(
1042
1040
  `SELECT COUNT(*) AS c, COALESCE(SUM(input_tokens),0) AS i, COALESCE(SUM(output_tokens),0) AS o
1043
1041
  FROM prompt_usage WHERE source='claude_code' AND tmux_session=? AND (${conds})`
@@ -1118,9 +1116,6 @@ var createUsageStore = (dbPath, now = () => /* @__PURE__ */ new Date()) => {
1118
1116
  VALUES (?, ?, '', '') ON CONFLICT(claude_session_id) DO NOTHING`).run(claudeSessionId, tmuxSession);
1119
1117
  },
1120
1118
  ingestProjectTranscripts(claudeProjectsDir) {
1121
- const mapped = new Set(
1122
- db.prepare("SELECT claude_session_id FROM claude_sessions").all().map((r) => String(r["claude_session_id"]))
1123
- );
1124
1119
  let count = 0;
1125
1120
  try {
1126
1121
  const projects = readdirSync(claudeProjectsDir);
@@ -1175,11 +1170,11 @@ var ingestFile = (db, claudeId, transcriptPath) => {
1175
1170
  const newOffset = offset + Buffer.byteLength(complete, "utf8");
1176
1171
  db.exec("BEGIN");
1177
1172
  try {
1173
+ const sess = tmuxOf(db, claudeId);
1178
1174
  for (const line of complete.split("\n")) {
1179
1175
  if (line === "") continue;
1180
1176
  const rec = parseAssistantLine(line);
1181
1177
  if (!rec) continue;
1182
- const sess = tmuxOf(db, claudeId);
1183
1178
  db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1184
1179
  VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1185
1180
  `turn=${String(rec.callContext).slice(0, 40)}`,
@@ -6,5 +6,3 @@ export type JsonRecord = {
6
6
  };
7
7
  export declare const safeParse: (raw: string | null | undefined) => JsonValue | null;
8
8
  export declare const asRecord: (v: JsonValue | null | undefined) => JsonRecord;
9
- export declare const asString: (v: JsonValue | undefined) => string;
10
- export declare const truncate: (s: string, n: number) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juli-os/ledger",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "juli-os L1 layer: the ledger of record for agent work — workflows, steps, case files, and token usage in one zero-dependency SQLite layer.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",