@juli-os/ledger 0.1.3 → 0.1.5

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
@@ -118,10 +118,6 @@ var withOriginal = (cf, o, now) => ({
118
118
  ...cf,
119
119
  original: {
120
120
  from: o.from,
121
- // Sender display name (RFC2047-decoded) — recorded into the case file with
122
- // the original message after the 2026-10-01 Chen Lijun hallucination
123
- // incident: the legitimate source for reply salutations, so the agent is no
124
- // longer forced to invent a name from the address.
125
121
  ...o.fromName !== void 0 && o.fromName !== "" ? { from_name: o.fromName } : {},
126
122
  subject: o.subject,
127
123
  body: o.body,
@@ -232,6 +228,7 @@ var dedupPattern = (key) => {
232
228
  const jsonValue = JSON.stringify(key).slice(1, -1);
233
229
  return `%"dedup_key":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
234
230
  };
231
+ var SEQ_PARK_BASE = 1e9;
235
232
  var SEND_STEP_LIKE_CUTOFF = "2026-09-19";
236
233
  var rowToWorkflow = (r) => ({
237
234
  id: str(r["id"]),
@@ -271,15 +268,23 @@ var rowToEvent = (r) => ({
271
268
  });
272
269
  var pruneImpl = (db, retentionDays, nowIso) => {
273
270
  if (retentionDays <= 0) return { events: 0, workflows: 0 };
274
- const cutoff = new Date(new Date(nowIso).getTime() - retentionDays * 864e5).toISOString();
271
+ const cutoff = rfc3339(new Date(new Date(nowIso).getTime() - retentionDays * 864e5));
275
272
  const ev = db.prepare("DELETE FROM events WHERE ts < ?").run(cutoff);
276
273
  const wfRows = db.prepare(
277
274
  `SELECT id FROM workflows WHERE status IN (${sqlInList(PRUNE_WORKFLOW_STATUSES)}) AND updated_at < ?`
278
275
  ).all(cutoff);
279
276
  let wfCount = 0;
280
277
  for (const r of wfRows) {
281
- db.prepare("DELETE FROM workflow_steps WHERE workflow_id=?").run(r.id);
282
- db.prepare("DELETE FROM workflows WHERE id=?").run(r.id);
278
+ db.exec("BEGIN");
279
+ try {
280
+ db.prepare("DELETE FROM workflow_steps WHERE workflow_id=?").run(r.id);
281
+ db.prepare("DELETE FROM relays WHERE workflow_id=?").run(r.id);
282
+ db.prepare("DELETE FROM workflows WHERE id=?").run(r.id);
283
+ db.exec("COMMIT");
284
+ } catch (e) {
285
+ db.exec("ROLLBACK");
286
+ throw e;
287
+ }
283
288
  wfCount++;
284
289
  }
285
290
  return { events: Number(ev.changes), workflows: wfCount };
@@ -324,7 +329,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
324
329
  r.status AS status, r.created_at AS created_at FROM runs r
325
330
  JOIN workflows w ON w.id = r.workflow_id
326
331
  WHERE r.session=? AND r.status IN ('running','idle') AND w.status='running'
327
- ORDER BY r.created_at DESC LIMIT 1`
332
+ ORDER BY r.created_at DESC, r.rowid DESC LIMIT 1`
328
333
  ).get(session);
329
334
  if (!r) return null;
330
335
  return {
@@ -423,12 +428,16 @@ var createLedgerStore = (dbPath, deps = {}) => {
423
428
  `INSERT INTO workflow_steps (id, workflow_id, seq, kind, title, status, input, updated_at)
424
429
  VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)`
425
430
  );
426
- const shift = db.prepare(
427
- "UPDATE workflow_steps SET seq = seq + ? WHERE workflow_id = ? AND seq >= ?"
431
+ const park = db.prepare(
432
+ `UPDATE workflow_steps SET seq = seq + ${SEQ_PARK_BASE} WHERE workflow_id = ? AND seq >= ?`
433
+ );
434
+ const restore = db.prepare(
435
+ `UPDATE workflow_steps SET seq = seq - ${SEQ_PARK_BASE} + ? WHERE workflow_id = ? AND seq >= ${SEQ_PARK_BASE}`
428
436
  );
429
437
  db.exec("BEGIN");
430
438
  try {
431
- shift.run(steps.length, workflowId, afterSeq + 1);
439
+ park.run(workflowId, afterSeq + 1);
440
+ restore.run(steps.length, workflowId);
432
441
  steps.forEach((st, i) => {
433
442
  insert.run(
434
443
  ids.newId("st"),
@@ -478,7 +487,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
478
487
  },
479
488
  pendingRelays() {
480
489
  return db.prepare(`SELECT id, workflow_id, step_id, session, text, marker, created_at, attempts,
481
- COALESCE(last_error,'') AS last_error FROM relays WHERE delivered_at IS NULL ORDER BY created_at`).all().map((r) => ({
490
+ COALESCE(last_error,'') AS last_error FROM relays WHERE delivered_at IS NULL ORDER BY created_at, rowid`).all().map((r) => ({
482
491
  id: str(r["id"]),
483
492
  workflowId: str(r["workflow_id"]),
484
493
  stepId: str(r["step_id"]),
@@ -599,11 +608,9 @@ var createLedgerStore = (dbPath, deps = {}) => {
599
608
  };
600
609
  },
601
610
  activeRunForSession: (session) => activeRunOf(session),
602
- /** Active dedup: same dedup_key and the workflow still in flight → skip
603
- * creating a duplicate. ⚠ ESCAPE '\' must pair with the escaping: a
604
- * message-id almost always contains `_`; without ESCAPE, `\_` becomes
605
- * "literal backslash + any character", the pattern never matches — and
606
- * dedup fails wholesale (09-07 incident). */
611
+ /** 活跃去重:同 dedup_key 且工作流仍在途 → 跳过重复建流。
612
+ * ⚠ ESCAPE '\' 必须与转义成对:message-id 几乎必含 `_`,漏写 ESCAPE 时
613
+ * `\_` 成了"字面反斜杠+任意字符",模式永不匹配——去重整体失效(09-07 事故)。 */
607
614
  hasActiveDedup(key) {
608
615
  const r = db.prepare(
609
616
  `SELECT 1 FROM workflows WHERE status IN (${sqlInList(DEDUP_WINDOW_STATUSES)})
@@ -611,10 +618,8 @@ var createLedgerStore = (dbPath, deps = {}) => {
611
618
  ).get(dedupPattern(key));
612
619
  return r !== void 0;
613
620
  },
614
- /** Ingested dedup (polling layer): any non-rejected workflow with the same
615
- * dedup_key → this email has already been handled (failed included);
616
- * polling won't fetch it again. Retries go through step retry, not
617
- * re-ingestion. */
621
+ /** 已摄取去重(轮询层):同 dedup_key 存在任何非 rejected 工作流 → 这封
622
+ * 邮件已被处理过(含 failed),轮询不再重复拉取。重试走步骤 retry,不走再摄取。 */
618
623
  hasSeenDedup(key) {
619
624
  const r = db.prepare(
620
625
  `SELECT 1 FROM workflows WHERE status != 'rejected'
@@ -622,14 +627,11 @@ var createLedgerStore = (dbPath, deps = {}) => {
622
627
  ).get(dedupPattern(key));
623
628
  return r !== void 0;
624
629
  },
625
- /** Self-loop guard query (2026-09-20 breakpoint 13): does the message_id
626
- * hit a record this engine already sent — the output.message_id of a
627
- * completed send step (booked from the same source as email_sent events)?
628
- * The intake layer uses this to discard delivery-copy feedback (the echo
629
- * of the engine mailing the polling mailbox itself). LIKE prefilter +
630
- * exact comparison: JSON-encode to the actually stored bytes; %/_/\ are
631
- * escaped in pairs like dedupPattern (a message-id almost always contains
632
- * `_`). */
630
+ /** 自回环守卫查询(2026-09-20 断点十三):message_id 是否命中本引擎已
631
+ * 发送记录——completed send 步的 output.message_id(email_sent 事件同源
632
+ * 落账)。进件层据此丢弃投递副本回灌(引擎给轮询邮箱自己发信的 echo)。
633
+ * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 dedupPattern
634
+ * 成对转义(message-id 几乎必含 `_`)。 */
633
635
  recordSentMessageId(messageId, meta) {
634
636
  if (messageId === "") return;
635
637
  db.prepare(
@@ -717,7 +719,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
717
719
  const placeholders = statuses.map(() => "?").join(",");
718
720
  const r = db.prepare(
719
721
  `SELECT id, run_id, content, status, created_at FROM prompts
720
- WHERE run_id=? AND status IN (${placeholders}) ORDER BY created_at DESC LIMIT 1`
722
+ WHERE run_id=? AND status IN (${placeholders}) ORDER BY created_at DESC, rowid DESC LIMIT 1`
721
723
  ).get(run.id, ...statuses);
722
724
  if (!r) return null;
723
725
  return {
@@ -741,61 +743,59 @@ var PRICING_SOURCE = "https://docs.bigmodel.cn/cn/guide/start/pricing";
741
743
  var PRICING_RETRIEVED_AT = "2026-10-06";
742
744
  var K32 = 32e3;
743
745
  var K200 = 200;
744
- var flat = (input, cache, output, note = "flat rate") => ({ when: {}, input, cache, output, note });
746
+ var flat = (input, cache, output, note = "\u7EDF\u4E00\u4EF7") => ({ when: {}, input, cache, output, note });
745
747
  var BIGMODEL_PRICES = [
746
- // ---- Flagship ----
747
748
  { id: "glm-5.3", label: "GLM-5.3", tiers: [flat(8, 2, 28)] },
748
749
  { id: "glm-5.3-flash", label: "GLM-5.3-Flash", tiers: [flat(0.8, 0.23, 2.8)] },
749
750
  { id: "glm-5.3-flashx", label: "GLM-5.3-FlashX", tiers: [flat(2, 0.57, 7)] },
750
- // ---- Text ----
751
751
  { id: "glm-5.2", label: "GLM-5.2", tiers: [flat(8, 2, 28)] },
752
752
  {
753
753
  id: "glm-5.1",
754
754
  label: "GLM-5.1",
755
755
  tiers: [
756
- { when: { inputLt: K32 }, input: 6, cache: 1.3, output: 24, note: "in<32K" },
757
- { when: { inputGte: K32 }, input: 8, cache: 2, output: 28, note: "in>=32K" }
756
+ { when: { inputLt: K32 }, input: 6, cache: 1.3, output: 24, note: "\u5165<32K" },
757
+ { when: { inputGte: K32 }, input: 8, cache: 2, output: 28, note: "\u5165\u226532K" }
758
758
  ]
759
759
  },
760
760
  {
761
761
  id: "glm-5-turbo",
762
762
  label: "GLM-5-Turbo",
763
763
  tiers: [
764
- { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "in<32K" },
765
- { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "in>=32K" }
764
+ { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "\u5165<32K" },
765
+ { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "\u5165\u226532K" }
766
766
  ]
767
767
  },
768
768
  {
769
769
  id: "glm-5",
770
770
  label: "GLM-5",
771
771
  tiers: [
772
- { when: { inputLt: K32 }, input: 4, cache: 1, output: 18, note: "in<32K" },
773
- { when: { inputGte: K32 }, input: 6, cache: 1.5, output: 22, note: "in>=32K" }
772
+ { when: { inputLt: K32 }, input: 4, cache: 1, output: 18, note: "\u5165<32K" },
773
+ { when: { inputGte: K32 }, input: 6, cache: 1.5, output: 22, note: "\u5165\u226532K" }
774
774
  ]
775
775
  },
776
776
  {
777
777
  id: "glm-4.7",
778
778
  label: "GLM-4.7",
779
779
  tiers: [
780
- { when: { inputLt: K32, outputLt: K200 }, input: 2, cache: 0.4, output: 8, note: "in<32K\xB7out<0.2K" },
781
- { when: { inputLt: K32, outputGte: K200 }, input: 3, cache: 0.6, output: 14, note: "in<32K\xB7out>=0.2K" },
782
- { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 16, note: "in 32K\u2013200K" }
780
+ { when: { inputLt: K32, outputLt: K200 }, input: 2, cache: 0.4, output: 8, note: "\u5165<32K\xB7\u51FA<0.2K" },
781
+ { when: { inputLt: K32, outputGte: K200 }, input: 3, cache: 0.6, output: 14, note: "\u5165<32K\xB7\u51FA\u22650.2K" },
782
+ { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 16, note: "\u516532K\u2013200K" }
783
783
  ]
784
784
  },
785
785
  {
786
786
  id: "glm-4.5-air",
787
787
  label: "GLM-4.5-Air",
788
788
  tiers: [
789
- { when: { inputLt: K32, outputLt: K200 }, input: 0.8, cache: 0.16, output: 2, note: "in<32K\xB7out<0.2K" },
790
- { when: { inputLt: K32, outputGte: K200 }, input: 0.8, cache: 0.16, output: 6, note: "in<32K\xB7out>=0.2K" },
791
- { when: { inputGte: K32 }, input: 1.2, cache: 0.24, output: 8, note: "in 32K\u2013128K" }
789
+ { when: { inputLt: K32, outputLt: K200 }, input: 0.8, cache: 0.16, output: 2, note: "\u5165<32K\xB7\u51FA<0.2K" },
790
+ { when: { inputLt: K32, outputGte: K200 }, input: 0.8, cache: 0.16, output: 6, note: "\u5165<32K\xB7\u51FA\u22650.2K" },
791
+ { when: { inputGte: K32 }, input: 1.2, cache: 0.24, output: 8, note: "\u516532K\u2013128K" }
792
792
  ]
793
793
  },
794
794
  { id: "glm-4.7-flashx", label: "GLM-4.7-FlashX", tiers: [flat(0.5, 0.1, 3)] },
795
- { id: "glm-4.7-flash", label: "GLM-4.7-Flash (free)", tiers: [flat(0, 0, 0, "free")] },
795
+ { id: "glm-4.7-flash", label: "GLM-4.7-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, 0, 0, "\u514D\u8D39")] },
796
796
  { id: "glm-4-plus", label: "GLM-4-Plus", tiers: [flat(5, 2.5, 5)] },
797
797
  { id: "glm-4-air-250414", label: "GLM-4-Air-250414", tiers: [flat(0.5, 0.25, 0.5)] },
798
- { id: "glm-4-air", label: "GLM-4-Air (same price as 250414)", tiers: [flat(0.5, 0.25, 0.5)] },
798
+ { id: "glm-4-air", label: "GLM-4-Air\uFF08\u540C 250414 \u7248\u4EF7\uFF09", tiers: [flat(0.5, 0.25, 0.5)] },
799
799
  { id: "glm-4-airx", label: "GLM-4-AirX", tiers: [flat(10, null, 10)] },
800
800
  { id: "glm-4-long", label: "GLM-4-Long", tiers: [flat(1, 0.5, 1)] },
801
801
  { id: "glm-4-assistant", label: "GLM-4-Assistant", tiers: [flat(5, null, 5)] },
@@ -803,55 +803,53 @@ var BIGMODEL_PRICES = [
803
803
  { id: "glm-z1-airx", label: "GLM-Z1-AirX", tiers: [flat(5, null, 5)] },
804
804
  { id: "glm-z1-flashx", label: "GLM-Z1-FlashX", tiers: [flat(0.1, null, 0.1)] },
805
805
  { id: "glm-4-flashx-250414", label: "GLM-4-FlashX-250414", tiers: [flat(0.1, 0.05, 0.1)] },
806
- { id: "glm-4-flashx", label: "GLM-4-FlashX (same price as 250414)", tiers: [flat(0.1, 0.05, 0.1)] },
807
- { id: "glm-4-flash-250414", label: "GLM-4-Flash-250414 (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
808
- { id: "glm-4-flash", label: "GLM-4-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
809
- { id: "glm-z1-flash", label: "GLM-Z1-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
810
- // ---- Vision ----
806
+ { id: "glm-4-flashx", label: "GLM-4-FlashX\uFF08\u540C 250414 \u7248\u4EF7\uFF09", tiers: [flat(0.1, 0.05, 0.1)] },
807
+ { id: "glm-4-flash-250414", label: "GLM-4-Flash-250414\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
808
+ { id: "glm-4-flash", label: "GLM-4-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
809
+ { id: "glm-z1-flash", label: "GLM-Z1-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
811
810
  { id: "glm-ocr", label: "GLM-OCR", tiers: [flat(0.2, null, 0.2)] },
812
811
  {
813
812
  id: "glm-5v-turbo",
814
813
  label: "GLM-5V-Turbo",
815
814
  tiers: [
816
- { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "in<32K" },
817
- { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "in>=32K" }
815
+ { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "\u5165<32K" },
816
+ { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "\u5165\u226532K" }
818
817
  ]
819
818
  },
820
819
  {
821
820
  id: "glm-4.6v",
822
821
  label: "GLM-4.6V",
823
822
  tiers: [
824
- { when: { inputLt: K32 }, input: 1, cache: 0.2, output: 3, note: "in<32K" },
825
- { when: { inputGte: K32 }, input: 2, cache: 0.4, output: 6, note: "in 32K\u2013128K (above the upper bound folds into the top tier)" }
823
+ { when: { inputLt: K32 }, input: 1, cache: 0.2, output: 3, note: "\u5165<32K" },
824
+ { when: { inputGte: K32 }, input: 2, cache: 0.4, output: 6, note: "\u516532K\u2013128K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
826
825
  ]
827
826
  },
828
827
  {
829
828
  id: "glm-4.6v-flashx",
830
829
  label: "GLM-4.6V-FlashX",
831
830
  tiers: [
832
- { when: { inputLt: K32 }, input: 0.15, cache: 0.03, output: 1.5, note: "in<32K" },
833
- { when: { inputGte: K32 }, input: 0.3, cache: 0.03, output: 3, note: "in 32K\u2013128K (above the upper bound folds into the top tier)" }
831
+ { when: { inputLt: K32 }, input: 0.15, cache: 0.03, output: 1.5, note: "\u5165<32K" },
832
+ { when: { inputGte: K32 }, input: 0.3, cache: 0.03, output: 3, note: "\u516532K\u2013128K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
834
833
  ]
835
834
  },
836
- { id: "glm-4.6v-flash", label: "GLM-4.6V-Flash (free)", tiers: [flat(0, 0, 0, "free")] },
835
+ { id: "glm-4.6v-flash", label: "GLM-4.6V-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, 0, 0, "\u514D\u8D39")] },
837
836
  {
838
837
  id: "glm-4.5v",
839
838
  label: "GLM-4.5V",
840
839
  tiers: [
841
- { when: { inputLt: K32 }, input: 2, cache: 0.4, output: 6, note: "in<32K" },
842
- { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 12, note: "in 32K\u201364K (above the upper bound folds into the top tier)" }
840
+ { when: { inputLt: K32 }, input: 2, cache: 0.4, output: 6, note: "\u5165<32K" },
841
+ { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 12, note: "\u516532K\u201364K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
843
842
  ]
844
843
  },
845
844
  { id: "glm-4v-plus-0111", label: "GLM-4V-Plus-0111", tiers: [flat(4, 2, 4)] },
846
- { id: "glm-4v-plus", label: "GLM-4V-Plus (same price as 0111)", tiers: [flat(4, 2, 4)] },
847
- { id: "glm-4v-flash", label: "GLM-4V-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
845
+ { id: "glm-4v-plus", label: "GLM-4V-Plus\uFF08\u540C 0111 \u7248\u4EF7\uFF09", tiers: [flat(4, 2, 4)] },
846
+ { id: "glm-4v-flash", label: "GLM-4V-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
848
847
  { id: "glm-4.1v-thinking-flashx", label: "GLM-4.1V-Thinking-FlashX", tiers: [flat(2, null, 2)] },
849
- { id: "glm-4.1v-thinking-flash", label: "GLM-4.1V-Thinking-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
850
- // ---- Embeddings / other (single-value prices are input-based; output billed at the same rate as a floor) ----
851
- { id: "embedding-3", label: "Embedding-3", tiers: [flat(0.5, null, 0.5, "single-value \xB7 billed on input")] },
852
- { id: "embedding-2", label: "Embedding-2", tiers: [flat(0.5, null, 0.5, "single-value \xB7 billed on input")] },
853
- { id: "rerank", label: "Rerank", tiers: [flat(0.8, null, 0.8, "single-value")] },
854
- { id: "codegeex-4", label: "CodeGeeX-4", tiers: [flat(0.1, null, 0.1, "single-value")] }
848
+ { id: "glm-4.1v-thinking-flash", label: "GLM-4.1V-Thinking-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
849
+ { id: "embedding-3", label: "Embedding-3", tiers: [flat(0.5, null, 0.5, "\u5355\u503C\u4EF7\u76EE\xB7input \u8BA1")] },
850
+ { id: "embedding-2", label: "Embedding-2", tiers: [flat(0.5, null, 0.5, "\u5355\u503C\u4EF7\u76EE\xB7input \u8BA1")] },
851
+ { id: "rerank", label: "Rerank", tiers: [flat(0.8, null, 0.8, "\u5355\u503C\u4EF7\u76EE")] },
852
+ { id: "codegeex-4", label: "CodeGeeX-4", tiers: [flat(0.1, null, 0.1, "\u5355\u503C\u4EF7\u76EE")] }
855
853
  ];
856
854
  var findPrice = (model) => {
857
855
  const m = model.trim().toLowerCase();
@@ -880,7 +878,7 @@ var priceUsage = (rows) => {
880
878
  const accs = /* @__PURE__ */ new Map();
881
879
  for (const r of rows) {
882
880
  if (r.inputTokens === 0 && r.outputTokens === 0) continue;
883
- const key = r.model === "" ? "(no model recorded)" : r.model;
881
+ const key = r.model === "" ? "\uFF08\u672A\u8BB0\u5F55\u6A21\u578B\uFF09" : r.model;
884
882
  let a = accs.get(key);
885
883
  if (a === void 0) {
886
884
  const p = findPrice(key);
@@ -956,10 +954,9 @@ CREATE TABLE IF NOT EXISTS prompt_usage (
956
954
  note TEXT NOT NULL DEFAULT '',
957
955
  model TEXT NOT NULL DEFAULT '',
958
956
  input_tokens INTEGER NOT NULL DEFAULT 0,
959
- -- cached_tokens: z.ai-convention cache hits (subset of input, wf_66a9b632154d)
960
- -- (fixed in passing during run-13 R1: the original JS-style // comments inside
961
- -- the SQL string are not valid SQLite; db.exec(MIGRATIONS) threw near "/":
962
- -- syntax error and every store-level test in the repo went red)
957
+ -- cached_tokens\uFF1Az.ai \u53E3\u5F84\u7F13\u5B58\u547D\u4E2D\uFF08input \u5B50\u96C6\uFF0Cwf_66a9b632154d\uFF09
958
+ --\uFF08\u5341\u4E09\u8DD1 R1 \u987A\u624B\u4FEE\uFF1A\u539F JS \u98CE\u683C // \u6CE8\u91CA\u5199\u5728 SQL \u4E32\u5185\uFF0CSQLite \u4E0D\u8BA4\uFF0C
959
+ -- db.exec(MIGRATIONS) \u76F4\u63A5\u629B near "/": syntax error\uFF0C\u5168\u4ED3 store \u7EA7\u6D4B\u8BD5\u5C3D\u7EA2\uFF09
963
960
  cached_tokens INTEGER NOT NULL DEFAULT 0,
964
961
  output_tokens INTEGER NOT NULL DEFAULT 0,
965
962
  duration_ms INTEGER NOT NULL DEFAULT 0,
@@ -1217,27 +1214,34 @@ var ingestFile = (db, claudeId, transcriptPath) => {
1217
1214
  if (lastNL < 0) return 0;
1218
1215
  const complete = text.slice(0, lastNL + 1);
1219
1216
  let count = 0;
1220
- for (const line of complete.split("\n")) {
1221
- if (line === "") continue;
1222
- const rec = parseAssistantLine(line);
1223
- if (!rec) continue;
1224
- const sess = tmuxOf(db, claudeId);
1225
- db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1226
- VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1227
- `turn=${String(rec.callContext).slice(0, 40)}`,
1228
- rec.model,
1229
- rec.inputTokens,
1230
- rec.outputTokens,
1231
- rec.cacheRead,
1232
- rec.timestamp,
1233
- sess
1234
- );
1235
- count++;
1236
- }
1237
1217
  const newOffset = offset + Buffer.byteLength(complete, "utf8");
1238
- db.prepare(`INSERT INTO claude_ingest_offset (claude_session_id, byte_offset, last_ingested_at)
1239
- VALUES (?, ?, ?)
1240
- ON CONFLICT(claude_session_id) DO UPDATE SET byte_offset=excluded.byte_offset, last_ingested_at=excluded.last_ingested_at`).run(claudeId, newOffset, (/* @__PURE__ */ new Date()).toISOString());
1218
+ db.exec("BEGIN");
1219
+ try {
1220
+ for (const line of complete.split("\n")) {
1221
+ if (line === "") continue;
1222
+ const rec = parseAssistantLine(line);
1223
+ if (!rec) continue;
1224
+ const sess = tmuxOf(db, claudeId);
1225
+ db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1226
+ VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1227
+ `turn=${String(rec.callContext).slice(0, 40)}`,
1228
+ rec.model,
1229
+ rec.inputTokens,
1230
+ rec.outputTokens,
1231
+ rec.cacheRead,
1232
+ rec.timestamp,
1233
+ sess
1234
+ );
1235
+ count++;
1236
+ }
1237
+ db.prepare(`INSERT INTO claude_ingest_offset (claude_session_id, byte_offset, last_ingested_at)
1238
+ VALUES (?, ?, ?)
1239
+ ON CONFLICT(claude_session_id) DO UPDATE SET byte_offset=excluded.byte_offset, last_ingested_at=excluded.last_ingested_at`).run(claudeId, newOffset, (/* @__PURE__ */ new Date()).toISOString());
1240
+ db.exec("COMMIT");
1241
+ } catch (e) {
1242
+ db.exec("ROLLBACK");
1243
+ throw e;
1244
+ }
1241
1245
  return count;
1242
1246
  } finally {
1243
1247
  closeSync(fd);
@@ -186,6 +186,7 @@ var dedupPattern = (key) => {
186
186
  const jsonValue = JSON.stringify(key).slice(1, -1);
187
187
  return `%"dedup_key":"${jsonValue.replace(/[%_\\]/g, (c) => `\\${c}`)}"%`;
188
188
  };
189
+ var SEQ_PARK_BASE = 1e9;
189
190
  var SEND_STEP_LIKE_CUTOFF = "2026-09-19";
190
191
  var rowToWorkflow = (r) => ({
191
192
  id: str(r["id"]),
@@ -225,15 +226,23 @@ var rowToEvent = (r) => ({
225
226
  });
226
227
  var pruneImpl = (db, retentionDays, nowIso) => {
227
228
  if (retentionDays <= 0) return { events: 0, workflows: 0 };
228
- const cutoff = new Date(new Date(nowIso).getTime() - retentionDays * 864e5).toISOString();
229
+ const cutoff = rfc3339(new Date(new Date(nowIso).getTime() - retentionDays * 864e5));
229
230
  const ev = db.prepare("DELETE FROM events WHERE ts < ?").run(cutoff);
230
231
  const wfRows = db.prepare(
231
232
  `SELECT id FROM workflows WHERE status IN (${sqlInList(PRUNE_WORKFLOW_STATUSES)}) AND updated_at < ?`
232
233
  ).all(cutoff);
233
234
  let wfCount = 0;
234
235
  for (const r of wfRows) {
235
- db.prepare("DELETE FROM workflow_steps WHERE workflow_id=?").run(r.id);
236
- db.prepare("DELETE FROM workflows WHERE id=?").run(r.id);
236
+ db.exec("BEGIN");
237
+ try {
238
+ db.prepare("DELETE FROM workflow_steps WHERE workflow_id=?").run(r.id);
239
+ db.prepare("DELETE FROM relays WHERE workflow_id=?").run(r.id);
240
+ db.prepare("DELETE FROM workflows WHERE id=?").run(r.id);
241
+ db.exec("COMMIT");
242
+ } catch (e) {
243
+ db.exec("ROLLBACK");
244
+ throw e;
245
+ }
237
246
  wfCount++;
238
247
  }
239
248
  return { events: Number(ev.changes), workflows: wfCount };
@@ -278,7 +287,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
278
287
  r.status AS status, r.created_at AS created_at FROM runs r
279
288
  JOIN workflows w ON w.id = r.workflow_id
280
289
  WHERE r.session=? AND r.status IN ('running','idle') AND w.status='running'
281
- ORDER BY r.created_at DESC LIMIT 1`
290
+ ORDER BY r.created_at DESC, r.rowid DESC LIMIT 1`
282
291
  ).get(session);
283
292
  if (!r) return null;
284
293
  return {
@@ -377,12 +386,16 @@ var createLedgerStore = (dbPath, deps = {}) => {
377
386
  `INSERT INTO workflow_steps (id, workflow_id, seq, kind, title, status, input, updated_at)
378
387
  VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)`
379
388
  );
380
- const shift = db.prepare(
381
- "UPDATE workflow_steps SET seq = seq + ? WHERE workflow_id = ? AND seq >= ?"
389
+ const park = db.prepare(
390
+ `UPDATE workflow_steps SET seq = seq + ${SEQ_PARK_BASE} WHERE workflow_id = ? AND seq >= ?`
391
+ );
392
+ const restore = db.prepare(
393
+ `UPDATE workflow_steps SET seq = seq - ${SEQ_PARK_BASE} + ? WHERE workflow_id = ? AND seq >= ${SEQ_PARK_BASE}`
382
394
  );
383
395
  db.exec("BEGIN");
384
396
  try {
385
- shift.run(steps.length, workflowId, afterSeq + 1);
397
+ park.run(workflowId, afterSeq + 1);
398
+ restore.run(steps.length, workflowId);
386
399
  steps.forEach((st, i) => {
387
400
  insert.run(
388
401
  ids.newId("st"),
@@ -432,7 +445,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
432
445
  },
433
446
  pendingRelays() {
434
447
  return db.prepare(`SELECT id, workflow_id, step_id, session, text, marker, created_at, attempts,
435
- COALESCE(last_error,'') AS last_error FROM relays WHERE delivered_at IS NULL ORDER BY created_at`).all().map((r) => ({
448
+ COALESCE(last_error,'') AS last_error FROM relays WHERE delivered_at IS NULL ORDER BY created_at, rowid`).all().map((r) => ({
436
449
  id: str(r["id"]),
437
450
  workflowId: str(r["workflow_id"]),
438
451
  stepId: str(r["step_id"]),
@@ -553,11 +566,9 @@ var createLedgerStore = (dbPath, deps = {}) => {
553
566
  };
554
567
  },
555
568
  activeRunForSession: (session) => activeRunOf(session),
556
- /** Active dedup: same dedup_key and the workflow still in flight → skip
557
- * creating a duplicate. ⚠ ESCAPE '\' must pair with the escaping: a
558
- * message-id almost always contains `_`; without ESCAPE, `\_` becomes
559
- * "literal backslash + any character", the pattern never matches — and
560
- * dedup fails wholesale (09-07 incident). */
569
+ /** 活跃去重:同 dedup_key 且工作流仍在途 → 跳过重复建流。
570
+ * ⚠ ESCAPE '\' 必须与转义成对:message-id 几乎必含 `_`,漏写 ESCAPE 时
571
+ * `\_` 成了"字面反斜杠+任意字符",模式永不匹配——去重整体失效(09-07 事故)。 */
561
572
  hasActiveDedup(key) {
562
573
  const r = db.prepare(
563
574
  `SELECT 1 FROM workflows WHERE status IN (${sqlInList(DEDUP_WINDOW_STATUSES)})
@@ -565,10 +576,8 @@ var createLedgerStore = (dbPath, deps = {}) => {
565
576
  ).get(dedupPattern(key));
566
577
  return r !== void 0;
567
578
  },
568
- /** Ingested dedup (polling layer): any non-rejected workflow with the same
569
- * dedup_key → this email has already been handled (failed included);
570
- * polling won't fetch it again. Retries go through step retry, not
571
- * re-ingestion. */
579
+ /** 已摄取去重(轮询层):同 dedup_key 存在任何非 rejected 工作流 → 这封
580
+ * 邮件已被处理过(含 failed),轮询不再重复拉取。重试走步骤 retry,不走再摄取。 */
572
581
  hasSeenDedup(key) {
573
582
  const r = db.prepare(
574
583
  `SELECT 1 FROM workflows WHERE status != 'rejected'
@@ -576,14 +585,11 @@ var createLedgerStore = (dbPath, deps = {}) => {
576
585
  ).get(dedupPattern(key));
577
586
  return r !== void 0;
578
587
  },
579
- /** Self-loop guard query (2026-09-20 breakpoint 13): does the message_id
580
- * hit a record this engine already sent — the output.message_id of a
581
- * completed send step (booked from the same source as email_sent events)?
582
- * The intake layer uses this to discard delivery-copy feedback (the echo
583
- * of the engine mailing the polling mailbox itself). LIKE prefilter +
584
- * exact comparison: JSON-encode to the actually stored bytes; %/_/\ are
585
- * escaped in pairs like dedupPattern (a message-id almost always contains
586
- * `_`). */
588
+ /** 自回环守卫查询(2026-09-20 断点十三):message_id 是否命中本引擎已
589
+ * 发送记录——completed send 步的 output.message_id(email_sent 事件同源
590
+ * 落账)。进件层据此丢弃投递副本回灌(引擎给轮询邮箱自己发信的 echo)。
591
+ * LIKE 预筛 + 精确比对:JSON 编码取实际存储字节,%/_/\ 照 dedupPattern
592
+ * 成对转义(message-id 几乎必含 `_`)。 */
587
593
  recordSentMessageId(messageId, meta) {
588
594
  if (messageId === "") return;
589
595
  db.prepare(
@@ -671,7 +677,7 @@ var createLedgerStore = (dbPath, deps = {}) => {
671
677
  const placeholders = statuses.map(() => "?").join(",");
672
678
  const r = db.prepare(
673
679
  `SELECT id, run_id, content, status, created_at FROM prompts
674
- WHERE run_id=? AND status IN (${placeholders}) ORDER BY created_at DESC LIMIT 1`
680
+ WHERE run_id=? AND status IN (${placeholders}) ORDER BY created_at DESC, rowid DESC LIMIT 1`
675
681
  ).get(run.id, ...statuses);
676
682
  if (!r) return null;
677
683
  return {
@@ -695,61 +701,59 @@ var PRICING_SOURCE = "https://docs.bigmodel.cn/cn/guide/start/pricing";
695
701
  var PRICING_RETRIEVED_AT = "2026-10-06";
696
702
  var K32 = 32e3;
697
703
  var K200 = 200;
698
- var flat = (input, cache, output, note = "flat rate") => ({ when: {}, input, cache, output, note });
704
+ var flat = (input, cache, output, note = "\u7EDF\u4E00\u4EF7") => ({ when: {}, input, cache, output, note });
699
705
  var BIGMODEL_PRICES = [
700
- // ---- Flagship ----
701
706
  { id: "glm-5.3", label: "GLM-5.3", tiers: [flat(8, 2, 28)] },
702
707
  { id: "glm-5.3-flash", label: "GLM-5.3-Flash", tiers: [flat(0.8, 0.23, 2.8)] },
703
708
  { id: "glm-5.3-flashx", label: "GLM-5.3-FlashX", tiers: [flat(2, 0.57, 7)] },
704
- // ---- Text ----
705
709
  { id: "glm-5.2", label: "GLM-5.2", tiers: [flat(8, 2, 28)] },
706
710
  {
707
711
  id: "glm-5.1",
708
712
  label: "GLM-5.1",
709
713
  tiers: [
710
- { when: { inputLt: K32 }, input: 6, cache: 1.3, output: 24, note: "in<32K" },
711
- { when: { inputGte: K32 }, input: 8, cache: 2, output: 28, note: "in>=32K" }
714
+ { when: { inputLt: K32 }, input: 6, cache: 1.3, output: 24, note: "\u5165<32K" },
715
+ { when: { inputGte: K32 }, input: 8, cache: 2, output: 28, note: "\u5165\u226532K" }
712
716
  ]
713
717
  },
714
718
  {
715
719
  id: "glm-5-turbo",
716
720
  label: "GLM-5-Turbo",
717
721
  tiers: [
718
- { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "in<32K" },
719
- { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "in>=32K" }
722
+ { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "\u5165<32K" },
723
+ { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "\u5165\u226532K" }
720
724
  ]
721
725
  },
722
726
  {
723
727
  id: "glm-5",
724
728
  label: "GLM-5",
725
729
  tiers: [
726
- { when: { inputLt: K32 }, input: 4, cache: 1, output: 18, note: "in<32K" },
727
- { when: { inputGte: K32 }, input: 6, cache: 1.5, output: 22, note: "in>=32K" }
730
+ { when: { inputLt: K32 }, input: 4, cache: 1, output: 18, note: "\u5165<32K" },
731
+ { when: { inputGte: K32 }, input: 6, cache: 1.5, output: 22, note: "\u5165\u226532K" }
728
732
  ]
729
733
  },
730
734
  {
731
735
  id: "glm-4.7",
732
736
  label: "GLM-4.7",
733
737
  tiers: [
734
- { when: { inputLt: K32, outputLt: K200 }, input: 2, cache: 0.4, output: 8, note: "in<32K\xB7out<0.2K" },
735
- { when: { inputLt: K32, outputGte: K200 }, input: 3, cache: 0.6, output: 14, note: "in<32K\xB7out>=0.2K" },
736
- { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 16, note: "in 32K\u2013200K" }
738
+ { when: { inputLt: K32, outputLt: K200 }, input: 2, cache: 0.4, output: 8, note: "\u5165<32K\xB7\u51FA<0.2K" },
739
+ { when: { inputLt: K32, outputGte: K200 }, input: 3, cache: 0.6, output: 14, note: "\u5165<32K\xB7\u51FA\u22650.2K" },
740
+ { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 16, note: "\u516532K\u2013200K" }
737
741
  ]
738
742
  },
739
743
  {
740
744
  id: "glm-4.5-air",
741
745
  label: "GLM-4.5-Air",
742
746
  tiers: [
743
- { when: { inputLt: K32, outputLt: K200 }, input: 0.8, cache: 0.16, output: 2, note: "in<32K\xB7out<0.2K" },
744
- { when: { inputLt: K32, outputGte: K200 }, input: 0.8, cache: 0.16, output: 6, note: "in<32K\xB7out>=0.2K" },
745
- { when: { inputGte: K32 }, input: 1.2, cache: 0.24, output: 8, note: "in 32K\u2013128K" }
747
+ { when: { inputLt: K32, outputLt: K200 }, input: 0.8, cache: 0.16, output: 2, note: "\u5165<32K\xB7\u51FA<0.2K" },
748
+ { when: { inputLt: K32, outputGte: K200 }, input: 0.8, cache: 0.16, output: 6, note: "\u5165<32K\xB7\u51FA\u22650.2K" },
749
+ { when: { inputGte: K32 }, input: 1.2, cache: 0.24, output: 8, note: "\u516532K\u2013128K" }
746
750
  ]
747
751
  },
748
752
  { id: "glm-4.7-flashx", label: "GLM-4.7-FlashX", tiers: [flat(0.5, 0.1, 3)] },
749
- { id: "glm-4.7-flash", label: "GLM-4.7-Flash (free)", tiers: [flat(0, 0, 0, "free")] },
753
+ { id: "glm-4.7-flash", label: "GLM-4.7-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, 0, 0, "\u514D\u8D39")] },
750
754
  { id: "glm-4-plus", label: "GLM-4-Plus", tiers: [flat(5, 2.5, 5)] },
751
755
  { id: "glm-4-air-250414", label: "GLM-4-Air-250414", tiers: [flat(0.5, 0.25, 0.5)] },
752
- { id: "glm-4-air", label: "GLM-4-Air (same price as 250414)", tiers: [flat(0.5, 0.25, 0.5)] },
756
+ { id: "glm-4-air", label: "GLM-4-Air\uFF08\u540C 250414 \u7248\u4EF7\uFF09", tiers: [flat(0.5, 0.25, 0.5)] },
753
757
  { id: "glm-4-airx", label: "GLM-4-AirX", tiers: [flat(10, null, 10)] },
754
758
  { id: "glm-4-long", label: "GLM-4-Long", tiers: [flat(1, 0.5, 1)] },
755
759
  { id: "glm-4-assistant", label: "GLM-4-Assistant", tiers: [flat(5, null, 5)] },
@@ -757,55 +761,53 @@ var BIGMODEL_PRICES = [
757
761
  { id: "glm-z1-airx", label: "GLM-Z1-AirX", tiers: [flat(5, null, 5)] },
758
762
  { id: "glm-z1-flashx", label: "GLM-Z1-FlashX", tiers: [flat(0.1, null, 0.1)] },
759
763
  { id: "glm-4-flashx-250414", label: "GLM-4-FlashX-250414", tiers: [flat(0.1, 0.05, 0.1)] },
760
- { id: "glm-4-flashx", label: "GLM-4-FlashX (same price as 250414)", tiers: [flat(0.1, 0.05, 0.1)] },
761
- { id: "glm-4-flash-250414", label: "GLM-4-Flash-250414 (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
762
- { id: "glm-4-flash", label: "GLM-4-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
763
- { id: "glm-z1-flash", label: "GLM-Z1-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
764
- // ---- Vision ----
764
+ { id: "glm-4-flashx", label: "GLM-4-FlashX\uFF08\u540C 250414 \u7248\u4EF7\uFF09", tiers: [flat(0.1, 0.05, 0.1)] },
765
+ { id: "glm-4-flash-250414", label: "GLM-4-Flash-250414\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
766
+ { id: "glm-4-flash", label: "GLM-4-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
767
+ { id: "glm-z1-flash", label: "GLM-Z1-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
765
768
  { id: "glm-ocr", label: "GLM-OCR", tiers: [flat(0.2, null, 0.2)] },
766
769
  {
767
770
  id: "glm-5v-turbo",
768
771
  label: "GLM-5V-Turbo",
769
772
  tiers: [
770
- { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "in<32K" },
771
- { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "in>=32K" }
773
+ { when: { inputLt: K32 }, input: 5, cache: 1.2, output: 22, note: "\u5165<32K" },
774
+ { when: { inputGte: K32 }, input: 7, cache: 1.8, output: 26, note: "\u5165\u226532K" }
772
775
  ]
773
776
  },
774
777
  {
775
778
  id: "glm-4.6v",
776
779
  label: "GLM-4.6V",
777
780
  tiers: [
778
- { when: { inputLt: K32 }, input: 1, cache: 0.2, output: 3, note: "in<32K" },
779
- { when: { inputGte: K32 }, input: 2, cache: 0.4, output: 6, note: "in 32K\u2013128K (above the upper bound folds into the top tier)" }
781
+ { when: { inputLt: K32 }, input: 1, cache: 0.2, output: 3, note: "\u5165<32K" },
782
+ { when: { inputGte: K32 }, input: 2, cache: 0.4, output: 6, note: "\u516532K\u2013128K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
780
783
  ]
781
784
  },
782
785
  {
783
786
  id: "glm-4.6v-flashx",
784
787
  label: "GLM-4.6V-FlashX",
785
788
  tiers: [
786
- { when: { inputLt: K32 }, input: 0.15, cache: 0.03, output: 1.5, note: "in<32K" },
787
- { when: { inputGte: K32 }, input: 0.3, cache: 0.03, output: 3, note: "in 32K\u2013128K (above the upper bound folds into the top tier)" }
789
+ { when: { inputLt: K32 }, input: 0.15, cache: 0.03, output: 1.5, note: "\u5165<32K" },
790
+ { when: { inputGte: K32 }, input: 0.3, cache: 0.03, output: 3, note: "\u516532K\u2013128K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
788
791
  ]
789
792
  },
790
- { id: "glm-4.6v-flash", label: "GLM-4.6V-Flash (free)", tiers: [flat(0, 0, 0, "free")] },
793
+ { id: "glm-4.6v-flash", label: "GLM-4.6V-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, 0, 0, "\u514D\u8D39")] },
791
794
  {
792
795
  id: "glm-4.5v",
793
796
  label: "GLM-4.5V",
794
797
  tiers: [
795
- { when: { inputLt: K32 }, input: 2, cache: 0.4, output: 6, note: "in<32K" },
796
- { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 12, note: "in 32K\u201364K (above the upper bound folds into the top tier)" }
798
+ { when: { inputLt: K32 }, input: 2, cache: 0.4, output: 6, note: "\u5165<32K" },
799
+ { when: { inputGte: K32 }, input: 4, cache: 0.8, output: 12, note: "\u516532K\u201364K\uFF08\u8D85\u4E0A\u754C\u5E76\u5165\u9AD8\u6863\uFF09" }
797
800
  ]
798
801
  },
799
802
  { id: "glm-4v-plus-0111", label: "GLM-4V-Plus-0111", tiers: [flat(4, 2, 4)] },
800
- { id: "glm-4v-plus", label: "GLM-4V-Plus (same price as 0111)", tiers: [flat(4, 2, 4)] },
801
- { id: "glm-4v-flash", label: "GLM-4V-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
803
+ { id: "glm-4v-plus", label: "GLM-4V-Plus\uFF08\u540C 0111 \u7248\u4EF7\uFF09", tiers: [flat(4, 2, 4)] },
804
+ { id: "glm-4v-flash", label: "GLM-4V-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
802
805
  { id: "glm-4.1v-thinking-flashx", label: "GLM-4.1V-Thinking-FlashX", tiers: [flat(2, null, 2)] },
803
- { id: "glm-4.1v-thinking-flash", label: "GLM-4.1V-Thinking-Flash (free)", tiers: [flat(0, null, 0, "free \xB7 cache unsupported")] },
804
- // ---- Embeddings / other (single-value prices are input-based; output billed at the same rate as a floor) ----
805
- { id: "embedding-3", label: "Embedding-3", tiers: [flat(0.5, null, 0.5, "single-value \xB7 billed on input")] },
806
- { id: "embedding-2", label: "Embedding-2", tiers: [flat(0.5, null, 0.5, "single-value \xB7 billed on input")] },
807
- { id: "rerank", label: "Rerank", tiers: [flat(0.8, null, 0.8, "single-value")] },
808
- { id: "codegeex-4", label: "CodeGeeX-4", tiers: [flat(0.1, null, 0.1, "single-value")] }
806
+ { id: "glm-4.1v-thinking-flash", label: "GLM-4.1V-Thinking-Flash\uFF08\u514D\u8D39\uFF09", tiers: [flat(0, null, 0, "\u514D\u8D39\xB7\u7F13\u5B58\u4E0D\u652F\u6301")] },
807
+ { id: "embedding-3", label: "Embedding-3", tiers: [flat(0.5, null, 0.5, "\u5355\u503C\u4EF7\u76EE\xB7input \u8BA1")] },
808
+ { id: "embedding-2", label: "Embedding-2", tiers: [flat(0.5, null, 0.5, "\u5355\u503C\u4EF7\u76EE\xB7input \u8BA1")] },
809
+ { id: "rerank", label: "Rerank", tiers: [flat(0.8, null, 0.8, "\u5355\u503C\u4EF7\u76EE")] },
810
+ { id: "codegeex-4", label: "CodeGeeX-4", tiers: [flat(0.1, null, 0.1, "\u5355\u503C\u4EF7\u76EE")] }
809
811
  ];
810
812
  var findPrice = (model) => {
811
813
  const m = model.trim().toLowerCase();
@@ -834,7 +836,7 @@ var priceUsage = (rows) => {
834
836
  const accs = /* @__PURE__ */ new Map();
835
837
  for (const r of rows) {
836
838
  if (r.inputTokens === 0 && r.outputTokens === 0) continue;
837
- const key = r.model === "" ? "(no model recorded)" : r.model;
839
+ const key = r.model === "" ? "\uFF08\u672A\u8BB0\u5F55\u6A21\u578B\uFF09" : r.model;
838
840
  let a = accs.get(key);
839
841
  if (a === void 0) {
840
842
  const p = findPrice(key);
@@ -910,10 +912,9 @@ CREATE TABLE IF NOT EXISTS prompt_usage (
910
912
  note TEXT NOT NULL DEFAULT '',
911
913
  model TEXT NOT NULL DEFAULT '',
912
914
  input_tokens INTEGER NOT NULL DEFAULT 0,
913
- -- cached_tokens: z.ai-convention cache hits (subset of input, wf_66a9b632154d)
914
- -- (fixed in passing during run-13 R1: the original JS-style // comments inside
915
- -- the SQL string are not valid SQLite; db.exec(MIGRATIONS) threw near "/":
916
- -- syntax error and every store-level test in the repo went red)
915
+ -- cached_tokens\uFF1Az.ai \u53E3\u5F84\u7F13\u5B58\u547D\u4E2D\uFF08input \u5B50\u96C6\uFF0Cwf_66a9b632154d\uFF09
916
+ --\uFF08\u5341\u4E09\u8DD1 R1 \u987A\u624B\u4FEE\uFF1A\u539F JS \u98CE\u683C // \u6CE8\u91CA\u5199\u5728 SQL \u4E32\u5185\uFF0CSQLite \u4E0D\u8BA4\uFF0C
917
+ -- db.exec(MIGRATIONS) \u76F4\u63A5\u629B near "/": syntax error\uFF0C\u5168\u4ED3 store \u7EA7\u6D4B\u8BD5\u5C3D\u7EA2\uFF09
917
918
  cached_tokens INTEGER NOT NULL DEFAULT 0,
918
919
  output_tokens INTEGER NOT NULL DEFAULT 0,
919
920
  duration_ms INTEGER NOT NULL DEFAULT 0,
@@ -1171,27 +1172,34 @@ var ingestFile = (db, claudeId, transcriptPath) => {
1171
1172
  if (lastNL < 0) return 0;
1172
1173
  const complete = text.slice(0, lastNL + 1);
1173
1174
  let count = 0;
1174
- for (const line of complete.split("\n")) {
1175
- if (line === "") continue;
1176
- const rec = parseAssistantLine(line);
1177
- if (!rec) continue;
1178
- const sess = tmuxOf(db, claudeId);
1179
- db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1180
- VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1181
- `turn=${String(rec.callContext).slice(0, 40)}`,
1182
- rec.model,
1183
- rec.inputTokens,
1184
- rec.outputTokens,
1185
- rec.cacheRead,
1186
- rec.timestamp,
1187
- sess
1188
- );
1189
- count++;
1190
- }
1191
1175
  const newOffset = offset + Buffer.byteLength(complete, "utf8");
1192
- db.prepare(`INSERT INTO claude_ingest_offset (claude_session_id, byte_offset, last_ingested_at)
1193
- VALUES (?, ?, ?)
1194
- ON CONFLICT(claude_session_id) DO UPDATE SET byte_offset=excluded.byte_offset, last_ingested_at=excluded.last_ingested_at`).run(claudeId, newOffset, (/* @__PURE__ */ new Date()).toISOString());
1176
+ db.exec("BEGIN");
1177
+ try {
1178
+ for (const line of complete.split("\n")) {
1179
+ if (line === "") continue;
1180
+ const rec = parseAssistantLine(line);
1181
+ if (!rec) continue;
1182
+ const sess = tmuxOf(db, claudeId);
1183
+ db.prepare(`INSERT INTO prompt_usage (source, note, model, input_tokens, output_tokens, cached_tokens, duration_ms, error, created_at, tmux_session)
1184
+ VALUES ('claude_code', ?, ?, ?, ?, ?, 0, '', ?, ?)`).run(
1185
+ `turn=${String(rec.callContext).slice(0, 40)}`,
1186
+ rec.model,
1187
+ rec.inputTokens,
1188
+ rec.outputTokens,
1189
+ rec.cacheRead,
1190
+ rec.timestamp,
1191
+ sess
1192
+ );
1193
+ count++;
1194
+ }
1195
+ db.prepare(`INSERT INTO claude_ingest_offset (claude_session_id, byte_offset, last_ingested_at)
1196
+ VALUES (?, ?, ?)
1197
+ ON CONFLICT(claude_session_id) DO UPDATE SET byte_offset=excluded.byte_offset, last_ingested_at=excluded.last_ingested_at`).run(claudeId, newOffset, (/* @__PURE__ */ new Date()).toISOString());
1198
+ db.exec("COMMIT");
1199
+ } catch (e) {
1200
+ db.exec("ROLLBACK");
1201
+ throw e;
1202
+ }
1195
1203
  return count;
1196
1204
  } finally {
1197
1205
  closeSync(fd);
@@ -1232,7 +1240,7 @@ function demo() {
1232
1240
  const w1 = store.createWorkflow({ kind: "case", title: "Client inquiry: website redesign", meta: { from: "client@acme.com", message_id: "demo-001" } });
1233
1241
  store.createStep({ workflowId: w1.id, seq: 1, kind: "agent", title: "Understand the request" });
1234
1242
  store.createStep({ workflowId: w1.id, seq: 2, kind: "agent", title: "Draft a proposal" });
1235
- store.setWorkflowStatus(w1.id, "awaiting_approval");
1243
+ store.setWorkflowStatus(w1.id, "running");
1236
1244
  const w2 = store.createWorkflow({ kind: "case", title: "Monthly report automation", meta: { from: "ops@acme.com" } });
1237
1245
  store.setWorkflowStatus(w2.id, "completed");
1238
1246
  const cf = { ...emptyCaseFile(/* @__PURE__ */ new Date()), original: { from: "client@acme.com", subject: "Website redesign" } };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juli-os/ledger",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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",