@whispering233/ai-editor-db 0.0.20 → 0.0.26

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 (73) hide show
  1. package/dist/connection.js +2 -2
  2. package/dist/connection.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/migrations/002_event_timeline.js +1 -1
  6. package/dist/migrations/002_event_timeline.js.map +1 -1
  7. package/dist/migrations/003_timepoint.js +8 -8
  8. package/dist/migrations/003_timepoint.js.map +1 -1
  9. package/dist/migrations/004_setting_tags.js +2 -2
  10. package/dist/migrations/004_setting_tags.js.map +1 -1
  11. package/dist/migrations/005_reference.js +2 -2
  12. package/dist/migrations/005_reference.js.map +1 -1
  13. package/dist/migrations/index.d.ts +2 -2
  14. package/dist/migrations/index.d.ts.map +1 -1
  15. package/dist/migrations/index.js +7 -7
  16. package/dist/migrations/index.js.map +1 -1
  17. package/dist/queries/chat.d.ts +20 -20
  18. package/dist/queries/chat.d.ts.map +1 -1
  19. package/dist/queries/chat.js +105 -59
  20. package/dist/queries/chat.js.map +1 -1
  21. package/dist/queries/compute-state.d.ts +9 -9
  22. package/dist/queries/compute-state.d.ts.map +1 -1
  23. package/dist/queries/compute-state.js +22 -28
  24. package/dist/queries/compute-state.js.map +1 -1
  25. package/dist/queries/delta.d.ts +21 -21
  26. package/dist/queries/delta.d.ts.map +1 -1
  27. package/dist/queries/delta.js +110 -63
  28. package/dist/queries/delta.js.map +1 -1
  29. package/dist/queries/entity.d.ts +50 -46
  30. package/dist/queries/entity.d.ts.map +1 -1
  31. package/dist/queries/entity.js +226 -137
  32. package/dist/queries/entity.js.map +1 -1
  33. package/dist/queries/migration.d.ts +31 -31
  34. package/dist/queries/migration.d.ts.map +1 -1
  35. package/dist/queries/migration.js +43 -44
  36. package/dist/queries/migration.js.map +1 -1
  37. package/dist/queries/outline-ops.d.ts +22 -22
  38. package/dist/queries/outline-ops.d.ts.map +1 -1
  39. package/dist/queries/outline-ops.js +35 -42
  40. package/dist/queries/outline-ops.js.map +1 -1
  41. package/dist/queries/relation.d.ts +18 -18
  42. package/dist/queries/relation.d.ts.map +1 -1
  43. package/dist/queries/relation.js +115 -84
  44. package/dist/queries/relation.js.map +1 -1
  45. package/dist/queries/trash.d.ts +10 -10
  46. package/dist/queries/trash.d.ts.map +1 -1
  47. package/dist/queries/trash.js +75 -48
  48. package/dist/queries/trash.js.map +1 -1
  49. package/dist/query-db.d.ts +5 -0
  50. package/dist/query-db.d.ts.map +1 -0
  51. package/dist/query-db.js +22 -0
  52. package/dist/query-db.js.map +1 -0
  53. package/dist/schema.d.ts +8 -20
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +13 -85
  56. package/dist/schema.js.map +1 -1
  57. package/dist/storage/atomic.d.ts +8 -8
  58. package/dist/storage/atomic.d.ts.map +1 -1
  59. package/dist/storage/atomic.js +10 -11
  60. package/dist/storage/atomic.js.map +1 -1
  61. package/dist/storage/outline.d.ts +14 -14
  62. package/dist/storage/outline.d.ts.map +1 -1
  63. package/dist/storage/outline.js +17 -18
  64. package/dist/storage/outline.js.map +1 -1
  65. package/dist/storage/project.d.ts +11 -11
  66. package/dist/storage/project.d.ts.map +1 -1
  67. package/dist/storage/project.js +17 -18
  68. package/dist/storage/project.js.map +1 -1
  69. package/dist/tables.d.ts +718 -0
  70. package/dist/tables.d.ts.map +1 -0
  71. package/dist/tables.js +141 -0
  72. package/dist/tables.js.map +1 -0
  73. package/package.json +3 -2
@@ -1,7 +1,7 @@
1
1
  // @whispering233/ai-editor-db 连接与事务管理(T2.1)
2
2
  //
3
- // better-sqlite3 为同步 API(架构选型:内嵌零配置、同步简单可靠,见 doc/design/architecture.md 第 11 行)。
4
- // 持久化语义(doc/api/data-flow.md 第 51 行):WAL 模式 + synchronous=FULL,写入即时落盘。
3
+ // better-sqlite3 为同步 API(架构选型:内嵌零配置、同步简单可靠,见 第 11 行)。
4
+ // 持久化语义( 第 51 行):WAL 模式 + synchronous=FULL,写入即时落盘。
5
5
  import Database from "better-sqlite3";
6
6
  import { createTables } from "./schema.js";
7
7
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,iFAAiF;AACjF,uEAAuE;AAEvE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,EAAM;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACZ,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAI,EAAM,EAAE,EAAW;IACpD,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,sDAAsD;AACtD,mDAAmD;AAEnD,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,YAAY,CAAC,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,EAAM;IAClC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACZ,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAI,EAAM,EAAE,EAAW;IACpD,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9B,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @whispering233/ai-editor-db 入口:导出建表(schema)、连接(connection)、对话历史查询(queries/chat)与
2
- // JSON 存储(storage/:outline.json / project.json 原子读写,T2.2)、增量迁移(migrations/,E5)
2
+ // JSON 存储(storage/:outline.json / project.json 原子读写,T2.2)、增量迁移(migrations/)
3
3
  export * from "./schema.js";
4
4
  export * from "./connection.js";
5
5
  export * from "./storage/atomic.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,+EAA+E;AAC/E,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4EAA4E;AAC5E,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oBAAoB,CAAC"}
@@ -1,4 +1,4 @@
1
- // 迁移 002:时间轴事件(决策 26)——entities 表 type CHECK 扩为 5 种 + 新增 sort_order 列
1
+ // 迁移 002:时间轴事件——entities 表 type CHECK 扩为 5 种 + 新增 sort_order 列
2
2
  //
3
3
  // 背景:v1 的 entities.type CHECK 不含 'event',且无 sort_order 列(时间轴事件全局线性序)。
4
4
  // SQLite 的 CHECK 约束无法 ALTER 修改——必须「建新表 → 拷数据 → drop 旧表 → rename」四步。
@@ -1 +1 @@
1
- {"version":3,"file":"002_event_timeline.js","sourceRoot":"","sources":["../../src/migrations/002_event_timeline.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,gEAAgE;AAChE,gEAAgE;AAKhE,6HAA6H;AAC7H,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,eAAe;IACb,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,CAAC,EAAM,EAAE,EAAE;QACb,6CAA6C;QAC7C,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzB,gEAAgE;QAChE,EAAE,CAAC,IAAI,CACL;qFAC+E,CAChF,CAAC;QACF,SAAS;QACT,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC/B,oBAAoB;QACpB,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;CACkB,CAAC"}
1
+ {"version":3,"file":"002_event_timeline.js","sourceRoot":"","sources":["../../src/migrations/002_event_timeline.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,gEAAgE;AAChE,gEAAgE;AAKhE,6HAA6H;AAC7H,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,eAAe;IACb,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,CAAC,EAAM,EAAE,EAAE;QAChB,6CAA6C;QAC1C,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5B,gEAAgE;QAC7D,EAAE,CAAC,IAAI,CACL;qFAC+E,CAChF,CAAC;QACL,SAAS;QACN,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAClC,oBAAoB;QACjB,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;CACkB,CAAC"}
@@ -1,4 +1,4 @@
1
- // 迁移 003:时间标签点实体化(G2,决策 26 修订)——entities CHECK 扩为 6 种(含 timepoint)
1
+ // 迁移 003:时间标签点实体化(G2)——entities CHECK 扩为 6 种(含 timepoint)
2
2
  // + 旧 event.data.time_label 迁移为 timepoint 实体 + occurs_at 挂载关系
3
3
  //
4
4
  // 背景:v2 的 time_label 是 event.data 内的纯文本字段(F1-F9 形态,仅展示不解析)。
@@ -13,16 +13,16 @@
13
13
  //
14
14
  // 数据迁移语义(与 002 只做换表不同,003 在 up 内完成全部数据动作):
15
15
  // 1. 读全部**未软删** event(软删事件完全跳过:不建 timepoint、不建关系、不改 data),
16
- // 按事件全局线性序(sort_order 升序、NULL 沉底、id 稳定次序)逐条处理
16
+ // 按事件全局线性序(sort_order 升序、NULL 沉底、id 稳定次序)逐条处理
17
17
  // 2. 解析 data JSON 取 time_label(trim 后非空才视为标签;非字符串/坏 JSON/空串 → 未挂载,
18
- // 不建关系、不改 data——防御,不做宽松猜测)
18
+ // 不建关系、不改 data——防御,不做宽松猜测)
19
19
  // 3. 按 trim 后标签值聚合:**同名合并为同一 timepoint**(id 沿用 createEntity 的
20
- // generateEntityId 机制 → tp- 前缀,name = 标签文本,data = '{}'),sort_order 按
21
- // 各组首个事件在列表中的出现序赋 0..n-1
20
+ // generateEntityId 机制 → tp- 前缀,name = 标签文本,data = '{}'),sort_order 按
21
+ // 各组首个事件在列表中的出现序赋 0..n-1
22
22
  // 4. 每个带标签事件建一条 occurs_at 关系(source=timepoint、target=event,id 沿用
23
- // generateId("rel-") 机制,与 createRelation 同款)
23
+ // generateId("rel-") 机制,与 createRelation 同款)
24
24
  // 5. 从这些事件的 data 中移除 time_label 键并刷新 updated_at(迁移改写数据——版本戳
25
- // 刷新使旧提案快照自动失效,与决策 14 语义一致)
25
+ // 刷新使旧提案快照自动失效,与一致)
26
26
  //
27
27
  // 幂等性:迁移只执行一次(runMigrations 以 user_version 门控:版本已到 3 不再执行)。
28
28
  //
@@ -55,7 +55,7 @@ export default {
55
55
  db.exec("DROP TABLE entities");
56
56
  // 4. 新表更名为 entities(此后才能 prepare 针对 entities 的语句)
57
57
  db.exec("ALTER TABLE entities_v3 RENAME TO entities");
58
- // 迁移时间戳:应用层 ISO 8601 统一写入(schema.md 时间约定,不用 SQLite datetime('now'))
58
+ // 迁移时间戳:应用层 ISO 8601 统一写入( 时间约定,不用 SQLite datetime('now'))
59
59
  const now = nowIso();
60
60
  // 5. 数据迁移:time_label → timepoint + occurs_at(全部在 runMigrations 事务内)
61
61
  const events = db
@@ -1 +1 @@
1
- {"version":3,"file":"003_timepoint.js","sourceRoot":"","sources":["../../src/migrations/003_timepoint.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,8DAA8D;AAC9D,EAAE;AACF,4DAA4D;AAC5D,uDAAuD;AACvD,uEAAuE;AACvE,8CAA8C;AAC9C,EAAE;AACF,uEAAuE;AACvE,iEAAiE;AACjE,kEAAkE;AAClE,iDAAiD;AACjD,EAAE;AACF,2CAA2C;AAC3C,2DAA2D;AAC3D,iDAAiD;AACjD,mEAAmE;AACnE,8BAA8B;AAC9B,8DAA8D;AAC9D,wEAAwE;AACxE,4BAA4B;AAC5B,iEAAiE;AACjE,gDAAgD;AAChD,4DAA4D;AAC5D,+BAA+B;AAC/B,EAAE;AACF,4DAA4D;AAC5D,EAAE;AACF,uDAAuD;AACvD,2DAA2D;AAI3D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,6HAA6H;AAC7H,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,eAAe;IACb,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,CAAC,EAAM,EAAE,EAAE;QACb,kCAAkC;QAClC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzB,qDAAqD;QACrD,EAAE,CAAC,IAAI,CACL;iGAC2F,CAC5F,CAAC;QACF,SAAS;QACT,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC/B,kDAAkD;QAClD,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAEtD,oEAAoE;QACpE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;QAErB,oEAAoE;QACpE,MAAM,MAAM,GAAG,EAAE;aACd,OAAO,CACN;6DACqD,CACtD;aACA,GAAG,EAA0C,CAAC;QAEjD,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAChC;iDAC2C,CAC5C,CAAC;QACF,MAAM,cAAc,GAAG,EAAE,CAAC,OAAO,CAC/B;iEAC2D,CAC5D,CAAC;QACF,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC;QAEhG,sCAAsC;QACtC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;QACnD,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,sDAAsD;YACtD,IAAI,MAAM,GAAY,IAAI,CAAC;YAC3B,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACnC,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,GAAG,IAAI,CAAC;gBAChB,CAAC;YACH,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,SAAS;YACrF,MAAM,MAAM,GAAG,MAAiC,CAAC;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YAChC,iDAAiD;YACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAS;YAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAE1B,IAAI,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,6EAA6E;gBAC7E,IAAI,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;gBACrC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACjC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBACrD,SAAS,IAAI,CAAC,CAAC;YACjB,CAAC;YACD,yEAAyE;YACzE,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACjE,6DAA6D;YAC7D,OAAO,MAAM,CAAC,UAAU,CAAC;YACzB,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;CACkB,CAAC"}
1
+ {"version":3,"file":"003_timepoint.js","sourceRoot":"","sources":["../../src/migrations/003_timepoint.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,8DAA8D;AAC9D,EAAE;AACF,4DAA4D;AAC5D,uDAAuD;AACvD,uEAAuE;AACvE,8CAA8C;AAC9C,EAAE;AACF,uEAAuE;AACvE,iEAAiE;AACjE,kEAAkE;AAClE,iDAAiD;AACjD,EAAE;AACF,2CAA2C;AAC3C,2DAA2D;AAC3D,8CAA8C;AAC9C,mEAAmE;AACnE,2BAA2B;AAC3B,8DAA8D;AAC9D,qEAAqE;AACrE,yBAAyB;AACzB,iEAAiE;AACjE,6CAA6C;AAC7C,4DAA4D;AAC5D,oBAAoB;AACpB,EAAE;AACF,4DAA4D;AAC5D,EAAE;AACF,uDAAuD;AACvD,2DAA2D;AAI3D,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,6HAA6H;AAC7H,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,eAAe;IACb,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,CAAC,EAAM,EAAE,EAAE;QAChB,kCAAkC;QAC/B,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5B,qDAAqD;QAClD,EAAE,CAAC,IAAI,CACL;iGAC2F,CAC5F,CAAC;QACL,SAAS;QACN,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAClC,kDAAkD;QAC/C,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAEzD,2DAA2D;QACxD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;QAExB,oEAAoE;QACjE,MAAM,MAAM,GAAG,EAAE;aACd,OAAO,CACN;6DACqD,CACtD;aACA,GAAG,EAA0C,CAAC;QAEjD,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAChC;iDAC2C,CAC5C,CAAC;QACF,MAAM,cAAc,GAAG,EAAE,CAAC,OAAO,CAC/B;iEAC2D,CAC5D,CAAC;QACF,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC;QAEnG,sCAAsC;QACnC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;QACnD,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAChC,sDAAsD;YACjD,IAAI,MAAM,GAAY,IAAI,CAAC;YAC3B,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACnC,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClC,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,GAAG,IAAI,CAAC;gBAChB,CAAC;YACH,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,SAAS;YACrF,MAAM,MAAM,GAAG,MAAiC,CAAC;YACjD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;YACrC,iDAAiD;YAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAS;YAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAE1B,IAAI,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC9B,6EAA6E;gBACtE,IAAI,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;gBACrC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACjC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBACrD,SAAS,IAAI,CAAC,CAAC;YACjB,CAAC;YACN,yEAAyE;YACpE,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACtE,6DAA6D;YACxD,OAAO,MAAM,CAAC,UAAU,CAAC;YACzB,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;CACkB,CAAC"}
@@ -1,4 +1,4 @@
1
- // 迁移 004:设定分类字段 tags 落地 + rules 恢复规则条款语义(决策 31 K2 修订,2026-08)
1
+ // 迁移 004:设定分类字段 tags 落地 + rules 恢复规则条款语义( K2 修订,2026-08)
2
2
  //
3
3
  // 背景:批次五 J1 曾把 setting.data.rules 复用为分类标签(UI 显示「标签」);用户复核
4
4
  // 裁决(K2):分类与规则条款是两种语义——**tags 承接分类(新字段 data.tags: string[]),
@@ -9,7 +9,7 @@
9
9
  // - 仅 type='setting';data 坏 JSON → 跳过(防御,不做宽松猜测)
10
10
  // - rules 为字符串数组且非空 → tags = 既有 tags(理论无)∪ rules,移除 rules 键
11
11
  // - rules 空/缺失/非字符串数组 → data 原样(新语义下无规则条款即无字段)
12
- // - 改写数据刷新 updated_at(迁移改写数据——版本戳刷新使旧提案快照自动失效,决策 14 语义)
12
+ // - 改写数据刷新 updated_at(迁移改写数据——版本戳刷新使旧提案快照自动失效)
13
13
  // 幂等性:runMigrations 以 user_version 门控(版本已到 4 不再执行)。
14
14
  import { nowIso } from "../storage/atomic.js";
15
15
  /** data 字段 JSON 迁移(用户裁决:旧 rules 值 = 分类标签 → tags) */
@@ -1 +1 @@
1
- {"version":3,"file":"004_setting_tags.js","sourceRoot":"","sources":["../../src/migrations/004_setting_tags.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,0DAA0D;AAC1D,6DAA6D;AAC7D,iDAAiD;AACjD,wCAAwC;AACxC,EAAE;AACF,8CAA8C;AAC9C,iDAAiD;AACjD,4DAA4D;AAC5D,+CAA+C;AAC/C,wDAAwD;AACxD,oDAAoD;AAIpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,oDAAoD;AACpD,MAAM,YAAY,GAAc;IAC9B,OAAO,EAAE,CAAC;IACV,EAAE,CAAC,EAAM;QACP,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,sDAAsD,CAAC;aAC/D,GAAG,EAAyC,CAAC;QAChD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,gBAAgB;YAC5B,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,SAAS;YACrF,MAAM,GAAG,GAAG,MAAiC,CAAC;YAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC9F,SAAS,CAAC,8CAA8C;YAC1D,CAAC;YACD,uDAAuD;YACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5G,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAI,KAAkB,CAAC,CAAC;YACjD,OAAO,GAAG,CAAC,KAAK,CAAC;YACjB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"004_setting_tags.js","sourceRoot":"","sources":["../../src/migrations/004_setting_tags.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,0DAA0D;AAC1D,6DAA6D;AAC7D,iDAAiD;AACjD,wCAAwC;AACxC,EAAE;AACF,8CAA8C;AAC9C,iDAAiD;AACjD,4DAA4D;AAC5D,+CAA+C;AAC/C,+CAA+C;AAC/C,oDAAoD;AAIpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,oDAAoD;AACpD,MAAM,YAAY,GAAc;IAC9B,OAAO,EAAE,CAAC;IACV,EAAE,CAAC,EAAM;QACP,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,sDAAsD,CAAC;aAC/D,GAAG,EAAyC,CAAC;QAChD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,gBAAgB;YAC5B,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,SAAS;YACrF,MAAM,GAAG,GAAG,MAAiC,CAAC;YAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC9F,SAAS,CAAC,8CAA8C;YAC1D,CAAC;YACN,uDAAuD;YAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5G,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAI,KAAkB,CAAC,CAAC;YACjD,OAAO,GAAG,CAAC,KAAK,CAAC;YACjB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -1,7 +1,7 @@
1
- // 迁移 005:参考资料实体(决策 36,批次九)——entities 表 type CHECK 扩为 7 种(含 'reference')
1
+ // 迁移 005:参考资料实体(批次九)——entities 表 type CHECK 扩为 7 种(含 'reference')
2
2
  //
3
3
  // 背景:v4 的 entities.type CHECK 不含 'reference'(第 7 种实体类型,参考资料:外部素材/灵感笔记,
4
- // 非本书正文,决策 24 边界)。SQLite 的 CHECK 约束无法 ALTER 修改——必须「建新表 → 拷数据 →
4
+ // 非本书正文, 边界)。SQLite 的 CHECK 约束无法 ALTER 修改——必须「建新表 → 拷数据 →
5
5
  // drop 旧表 → rename」四步(与 002/003 同款模式)。
6
6
  //
7
7
  // 安全性:entities 无外键引用(relation_records/delta_records 均无 FOREIGN KEY 子句),四步换表
@@ -1 +1 @@
1
- {"version":3,"file":"005_reference.js","sourceRoot":"","sources":["../../src/migrations/005_reference.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,uEAAuE;AACvE,+DAA+D;AAC/D,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,kDAAkD;AAKlD,mFAAmF;AACnF,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,MAAM,YAAY,GAAc;IAC9B,OAAO,EAAE,CAAC;IACV,EAAE,CAAC,EAAM;QACP,kCAAkC;QAClC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzB,oDAAoD;QACpD,EAAE,CAAC,IAAI,CACL;iGAC2F,CAC5F,CAAC;QACF,SAAS;QACT,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC/B,oBAAoB;QACpB,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;CACF,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"005_reference.js","sourceRoot":"","sources":["../../src/migrations/005_reference.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,uEAAuE;AACvE,0DAA0D;AAC1D,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,kDAAkD;AAKlD,mFAAmF;AACnF,MAAM,eAAe,GAAG;;;;;;;;;;;CAWvB,CAAC;AAEF,MAAM,YAAY,GAAc;IAC9B,OAAO,EAAE,CAAC;IACV,EAAE,CAAC,EAAM;QACV,kCAAkC;QAC/B,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC5B,oDAAoD;QACjD,EAAE,CAAC,IAAI,CACL;iGAC2F,CAC5F,CAAC;QACL,SAAS;QACN,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAClC,oBAAoB;QACjB,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACxD,CAAC;CACF,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -5,7 +5,7 @@ export interface Migration {
5
5
  /** 迁移逻辑(DDL/数据变更);抛错 → 该迁移事务整体回滚,版本号不变 */
6
6
  up: (db: Db) => void;
7
7
  }
8
- /** 全量迁移集(按 version 升序:002 时间轴事件(决策 26)、003 时间标签点实体化(G2)、
9
- * 004 设定分类字段 tags(决策 31 K2 修订)、005 参考资料 reference(决策 36)) */
8
+ /** 全量迁移集(按 version 升序:002 时间轴事件、003 时间标签点实体化(G2)、
9
+ * 004 设定分类字段 tags( K2 修订)、005 参考资料 reference) */
10
10
  export declare const MIGRATIONS: readonly Migration[];
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAM3C,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;CACtB;AAED;8DAC8D;AAC9D,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAA6D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAM3C,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IACjB,0CAA0C;IACzC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;CACtB;AAED;iDACiD;AACjD,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAA6D,CAAC"}
@@ -1,4 +1,4 @@
1
- // 增量迁移脚本目录(E5:release-review §一 建议动作 2)
1
+ // 增量迁移脚本目录
2
2
  //
3
3
  // **形态**:每个迁移一个 TS 文件(001_xxx.ts → version 1、002_xxx.ts → version 2...),
4
4
  // 文件内 `export default { version, up }` 形态的 Migration 对象;本目录 index.ts 按
@@ -14,17 +14,17 @@
14
14
  // - 按 version 升序逐个执行,每个迁移一个事务(up + setUserVersion 原子提交)
15
15
  // - 整批迁移前自动快照 data.db(`data.db.v{n}.{时间戳}.bak`,不覆盖旧备份)
16
16
  // - 失败 → 该迁移回滚 + 版本停在前一迁移后,下次 open 重试
17
- // - 无迁移路径的旧版本(如 v0 且无 0→1 条目)保持删库重建兜底(决策 13)
17
+ // - 无迁移路径的旧版本(如 v0 且无 0→1 条目)保持删库重建兜底
18
18
  //
19
19
  // **当前状态**:SCHEMA_VERSION = 5;真实迁移 002(v1→v2:entities 表 CHECK 扩为 5 种 +
20
- // sort_order 列,决策 26 时间轴)、003(v2→v3:entities CHECK 扩 6 种含 timepoint +
21
- // event.data.time_label 迁移为 timepoint 实体 + occurs_at 挂载关系,G2 决策 26 修订)。
22
- // v0 库无 0→1 迁移条目,仍走删库重建兜底(决策 13)。
20
+ // sort_order 列, 时间轴)、003(v2→v3:entities CHECK 扩 6 种含 timepoint +
21
+ // event.data.time_label 迁移为 timepoint 实体 + occurs_at 挂载关系,G2)。
22
+ // v0 库无 0→1 迁移条目,仍走删库重建兜底。
23
23
  import migration002 from "./002_event_timeline.js";
24
24
  import migration003 from "./003_timepoint.js";
25
25
  import migration004 from "./004_setting_tags.js";
26
26
  import migration005 from "./005_reference.js";
27
- /** 全量迁移集(按 version 升序:002 时间轴事件(决策 26)、003 时间标签点实体化(G2)、
28
- * 004 设定分类字段 tags(决策 31 K2 修订)、005 参考资料 reference(决策 36)) */
27
+ /** 全量迁移集(按 version 升序:002 时间轴事件、003 时间标签点实体化(G2)、
28
+ * 004 设定分类字段 tags( K2 修订)、005 参考资料 reference) */
29
29
  export const MIGRATIONS = [migration002, migration003, migration004, migration005];
30
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,yDAAyD;AACzD,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,8DAA8D;AAC9D,EAAE;AACF,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,wDAAwD;AACxD,uDAAuD;AACvD,sCAAsC;AACtC,6CAA6C;AAC7C,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,wEAAwE;AACxE,kCAAkC;AAGlC,OAAO,YAAY,MAAM,yBAAyB,CAAC;AACnD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,YAAY,MAAM,uBAAuB,CAAC;AACjD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAS9C;8DAC8D;AAC9D,MAAM,CAAC,MAAM,UAAU,GAAyB,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,EAAE;AACF,yEAAyE;AACzE,uEAAuE;AACvE,yDAAyD;AACzD,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,8DAA8D;AAC9D,EAAE;AACF,8DAA8D;AAC9D,EAAE;AACF,kDAAkD;AAClD,wDAAwD;AACxD,uDAAuD;AACvD,sCAAsC;AACtC,sCAAsC;AACtC,EAAE;AACF,uEAAuE;AACvE,iEAAiE;AACjE,+DAA+D;AAC/D,2BAA2B;AAG3B,OAAO,YAAY,MAAM,yBAAyB,CAAC;AACnD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,YAAY,MAAM,uBAAuB,CAAC;AACjD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAS9C;iDACiD;AACjD,MAAM,CAAC,MAAM,UAAU,GAAyB,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC"}
@@ -1,24 +1,24 @@
1
1
  import { type ChatMessage, type ChatMessageRow, type ChatRole, type ChatSessionSummary } from "@whispering233/ai-editor-shared";
2
2
  import type { Db } from "../connection.js";
3
- /** 会话列表 lastMessage 截断长度(endpoints.md 仅要求「截断」,长度为本实现约定,未入文档契约) */
3
+ /** 会话列表 lastMessage 截断长度( 仅要求「截断」,长度为本实现约定,未入文档) */
4
4
  export declare const SESSION_LAST_MESSAGE_MAX_LEN = 50;
5
5
  /**
6
6
  * 插入一条对话消息。
7
7
  *
8
- * id 生成约定:chat_messages 表 id 无文档前缀(endpoints.md id 约定仅覆盖
8
+ * id 生成约定:chat_messages 表 id 无文档前缀( id 约定仅覆盖
9
9
  * char-/set-/loc-/hook-、sc-/ch-/vol-、proj- 与运行时 prop_/sess_/call_),
10
10
  * 省略 id 时直接用 nanoid 生成(与消息 id 前缀空缺保持一致)。
11
11
  *
12
- * 存储形态转换:row.tool_calls 按 shared 类型契约为「解析后的数组」,
12
+ * 存储形态转换:row.tool_calls 按 shared 类型为「解析后的数组」,
13
13
  * 本函数负责 JSON.stringify 落库(列存 TEXT);created_at 必须由调用方
14
- * 提供 ISO 8601 字符串(应用层写入,决策 18)。
14
+ * 提供 ISO 8601 字符串(应用层写入)。
15
15
  */
16
16
  export declare function insertChatMessage(db: Db, row: Pick<ChatMessageRow, "session_id" | "project_id" | "role" | "created_at"> & Partial<Pick<ChatMessageRow, "id" | "content" | "tool_calls" | "tool_call_id">>): void;
17
17
  /**
18
- * 会话归属迁移(B2.2 审核 P1-1,决策 18/27):
18
+ * 会话归属迁移(B2.2 审核 P1-1):
19
19
  * 跨项目恢复(备份包内 project_id ≠ 当前项目 id)后,chat_messages 的 project_id
20
20
  * 从旧 id 批量迁移为当前项目 id——「保留 id 保会话」的理由在跨项目场景同样成立:
21
- * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(决策 18:会话按 project_id 隔离)。
21
+ * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(会话按 project_id 隔离)。
22
22
  *
23
23
  * @param fromProjectId 备份包内 project.json 的 id(旧归属)
24
24
  * @param toProjectId 当前项目 id(迁移目标;调用方保证两者不等)
@@ -27,7 +27,7 @@ export declare function insertChatMessage(db: Db, row: Pick<ChatMessageRow, "ses
27
27
  export declare function migrateChatMessagesProject(db: Db, fromProjectId: string, toProjectId: string): number;
28
28
  /**
29
29
  * 会话列表(GET /api/v1/chat/sessions):
30
- * - 按 project_id 隔离(决策 18 修订:会话按项目隔离)
30
+ * - 按 project_id 隔离(会话按项目隔离)
31
31
  * - 仅返回含消息的会话;updatedAt = 该会话最后一条消息的 created_at
32
32
  * - 按最后活动时间(updatedAt)倒序,同时间戳按 session_id 升序保证稳定
33
33
  * - lastMessage = 最后一条消息的 content 截断(无 content 时为空串)
@@ -40,7 +40,7 @@ export declare function listSessions(db: Db, projectId: string): ChatSessionSumm
40
40
  export declare function parseToolCalls(json: string | null): unknown[] | null;
41
41
  /**
42
42
  * 消息历史(GET /api/v1/chat/sessions/:id/messages):
43
- * - 按 project_id 隔离(决策 18 修订)
43
+ * - 按 project_id 隔离
44
44
  * - 按 created_at 升序,同时间戳按 rowid(插入序)升序保证稳定
45
45
  * - 存储形态 → API 形态:tool_calls JSON 解析、tool_call_id → toolCallId、snake_case → camelCase
46
46
  */
@@ -48,12 +48,12 @@ export declare function listMessages(db: Db, sessionId: string, projectId: strin
48
48
  /**
49
49
  * 消息历史原始行(S7.6 续聊重建专用):
50
50
  * - listMessages 输出 API 形态(camelCase,供 GET /messages);本函数输出**存储形态**
51
- * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
52
- * loadHistory/restoreSession(决策 18 成对重组),避免 server 层做 API→存储形态反映射。
51
+ * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
52
+ * loadHistory/restoreSession( 成对重组),避免 server 层做 API→存储形态反映射。
53
53
  * - 查询语义与 listMessages 一致:按 project_id 隔离、created_at 升序 + rowid 稳定序。
54
54
  */
55
55
  export declare function listMessageRows(db: Db, sessionId: string, projectId: string): ChatMessageRow[];
56
- /** 成对重组后喂给 LLM 的历史消息形态(决策 18 修订:DeepSeek 要求 tool_call 与 tool 结果严格配对) */
56
+ /** 成对重组后喂给 LLM 的历史消息形态(DeepSeek 要求 tool_call 与 tool 结果严格配对) */
57
57
  export interface ReassembledChatMessage {
58
58
  role: ChatRole;
59
59
  content?: string | null;
@@ -63,23 +63,23 @@ export interface ReassembledChatMessage {
63
63
  toolCallId?: string | null;
64
64
  }
65
65
  /**
66
- * 成对重组历史消息(决策 18 修订:assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
66
+ * 成对重组历史消息(assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
67
67
  *
68
68
  * 用途:服务重启后凭 session_id 重建「继续上次对话」上下文,或会话级滑动窗口裁剪前的重组。
69
- * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型契约为解析后的数组,
69
+ * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型为解析后的数组,
70
70
  * 由调用方先经 parseToolCalls / 直接构造)。
71
71
  *
72
72
  * 算法:
73
73
  * 1. 按 created_at 升序稳定排序(同时间戳保持输入顺序)
74
74
  * 2. 第一遍收集 tool 消息:tool_call_id → content(同一 id 多条结果取最先到达者,防御性处理)
75
75
  * 3. 第二遍顺序扫描:
76
- * - user 消息:原样保留
77
- * - assistant 消息(无 tool_calls):原样保留
78
- * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
79
- * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(决策 18 修订:
80
- * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
81
- * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
82
- * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
76
+ * - user 消息:原样保留
77
+ * - assistant 消息(无 tool_calls):原样保留
78
+ * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
79
+ * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(
80
+ * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
81
+ * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
82
+ * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
83
83
  */
84
84
  export declare function reassembleMessages(rows: ChatMessageRow[]): ReassembledChatMessage[];
85
85
  //# sourceMappingURL=chat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"AASA,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1I,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3C,kEAAkE;AAClE,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,EAAE,EACN,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,YAAY,GAAG,MAAM,GAAG,YAAY,CAAC,GAC5E,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC,GAChF,IAAI,CAcN;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAGrG;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAqC5E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,GAAG,IAAI,CASpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CA6BxF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAsB9F;AAED,wEAAwE;AACxE,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACtB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,sBAAsB,EAAE,CAwCnF"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1I,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAI3C,oDAAoD;AACpD,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,EAAE,EACN,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,YAAY,GAAG,MAAM,GAAG,YAAY,CAAC,GAC5E,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC,GAChF,IAAI,CAcN;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAOrG;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAqC5E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,GAAG,IAAI,CASpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAoCxF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAmC9F;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4CAA4C;IAC3C,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,2DAA2D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,sBAAsB,EAAE,CAwCnF"}
@@ -1,28 +1,43 @@
1
1
  // @whispering233/ai-editor-db 对话历史数据层查询(T2.3)
2
2
  //
3
- // 单一事实来源:doc/database/schema.md(chat_messages 表结构,决策 18)、
4
- // doc/api/endpoints.md(chat/sessions 会话列表、chat/sessions/:id/messages 消息历史)。
5
- // 时间约定(schema.md 第 16 行):created_at 统一 ISO 8601 字符串、由应用层写入,本模块不生成时间。
3
+ // (chat/sessions 会话列表、chat/sessions/:id/messages 消息历史)。
4
+ // 时间约定():created_at 统一 ISO 8601 字符串、由应用层写入,本模块不生成时间。
6
5
  // 注意:本模块只处理 chat_messages 表,不涉及会话元数据——会话列表信息(createdAt/updatedAt/
7
6
  // messageCount/lastMessage)全部由消息行实时聚合得出,无独立会话表。
7
+ //
8
+ // 批次十五(15.4 卡 3):**查询经 queryDb 走 drizzle 构建器**(混合风格 4A)。
9
+ // 语义逐句对照旧实现:
10
+ // - INSERT 命名参数 ↔ insert(chatMessages).values({...})(tool_calls JSON.stringify 落库不变)
11
+ // - UPDATE ... SET project_id ↔ update.set({ project_id }).where(eq(...))
12
+ // - WHERE session_id = ? AND project_id = ? ↔ and(eq,eq);ORDER BY created_at ASC, rowid ASC ↔
13
+ // orderBy(chatMessages.created_at, sql`rowid ASC`)(rowid 为 SQLite 内部列,经 sql 模板原样透传)
14
+ // - listSessions 为相关子查询 + GROUP BY 聚合 + rowid 排序的复合 SQL,**保留 sql 模板**表达
15
+ // (builder 强行翻译需三层嵌套别名,违背 4A「需要 SQL 技巧就原生,不强行翻译」);
16
+ // projectId 两次注入均走 sql 模板参数绑定(安全,防注入)
17
+ // - parseToolCalls / reassembleMessages 为纯函数,不涉及 SQL,未改动
18
+ // - JSON 列 tool_calls 保持 text 模式:drizzle 行读出来是 string,解析防御仍在 parseToolCalls
8
19
  import { nanoid } from "nanoid";
20
+ import { and, eq, sql } from "drizzle-orm";
9
21
  import { truncate } from "@whispering233/ai-editor-shared";
10
- /** 会话列表 lastMessage 截断长度(endpoints.md 仅要求「截断」,长度为本实现约定,未入文档契约) */
22
+ import { queryDb } from "../query-db.js";
23
+ import { chatMessages } from "../tables.js";
24
+ /** 会话列表 lastMessage 截断长度( 仅要求「截断」,长度为本实现约定,未入文档) */
11
25
  export const SESSION_LAST_MESSAGE_MAX_LEN = 50;
12
26
  /**
13
27
  * 插入一条对话消息。
14
28
  *
15
- * id 生成约定:chat_messages 表 id 无文档前缀(endpoints.md id 约定仅覆盖
29
+ * id 生成约定:chat_messages 表 id 无文档前缀( id 约定仅覆盖
16
30
  * char-/set-/loc-/hook-、sc-/ch-/vol-、proj- 与运行时 prop_/sess_/call_),
17
31
  * 省略 id 时直接用 nanoid 生成(与消息 id 前缀空缺保持一致)。
18
32
  *
19
- * 存储形态转换:row.tool_calls 按 shared 类型契约为「解析后的数组」,
33
+ * 存储形态转换:row.tool_calls 按 shared 类型为「解析后的数组」,
20
34
  * 本函数负责 JSON.stringify 落库(列存 TEXT);created_at 必须由调用方
21
- * 提供 ISO 8601 字符串(应用层写入,决策 18)。
35
+ * 提供 ISO 8601 字符串(应用层写入)。
22
36
  */
23
37
  export function insertChatMessage(db, row) {
24
- db.prepare(`INSERT INTO chat_messages (id, session_id, project_id, role, content, tool_calls, tool_call_id, created_at)
25
- VALUES (@id, @session_id, @project_id, @role, @content, @tool_calls, @tool_call_id, @created_at)`).run({
38
+ queryDb(db)
39
+ .insert(chatMessages)
40
+ .values({
26
41
  id: row.id ?? nanoid(),
27
42
  session_id: row.session_id,
28
43
  project_id: row.project_id,
@@ -31,50 +46,57 @@ export function insertChatMessage(db, row) {
31
46
  tool_calls: row.tool_calls == null ? null : JSON.stringify(row.tool_calls),
32
47
  tool_call_id: row.tool_call_id ?? null,
33
48
  created_at: row.created_at,
34
- });
49
+ })
50
+ .run();
35
51
  }
36
52
  /**
37
- * 会话归属迁移(B2.2 审核 P1-1,决策 18/27):
53
+ * 会话归属迁移(B2.2 审核 P1-1):
38
54
  * 跨项目恢复(备份包内 project_id ≠ 当前项目 id)后,chat_messages 的 project_id
39
55
  * 从旧 id 批量迁移为当前项目 id——「保留 id 保会话」的理由在跨项目场景同样成立:
40
- * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(决策 18:会话按 project_id 隔离)。
56
+ * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(会话按 project_id 隔离)。
41
57
  *
42
58
  * @param fromProjectId 备份包内 project.json 的 id(旧归属)
43
59
  * @param toProjectId 当前项目 id(迁移目标;调用方保证两者不等)
44
60
  * @returns 受影响行数(0 = 无该旧 id 的消息;重复执行幂等——第二次起返回 0)
45
61
  */
46
62
  export function migrateChatMessagesProject(db, fromProjectId, toProjectId) {
47
- const info = db.prepare("UPDATE chat_messages SET project_id = ? WHERE project_id = ?").run(toProjectId, fromProjectId);
63
+ const info = queryDb(db)
64
+ .update(chatMessages)
65
+ .set({ project_id: toProjectId })
66
+ .where(eq(chatMessages.project_id, fromProjectId))
67
+ .run();
48
68
  return info.changes;
49
69
  }
50
70
  /**
51
71
  * 会话列表(GET /api/v1/chat/sessions):
52
- * - 按 project_id 隔离(决策 18 修订:会话按项目隔离)
72
+ * - 按 project_id 隔离(会话按项目隔离)
53
73
  * - 仅返回含消息的会话;updatedAt = 该会话最后一条消息的 created_at
54
74
  * - 按最后活动时间(updatedAt)倒序,同时间戳按 session_id 升序保证稳定
55
75
  * - lastMessage = 最后一条消息的 content 截断(无 content 时为空串)
56
76
  */
57
77
  export function listSessions(db, projectId) {
58
- const rows = db
59
- .prepare(`SELECT
60
- t.session_id AS id,
61
- t.message_count,
62
- t.created_at,
63
- t.updated_at,
64
- (SELECT lm.content FROM chat_messages lm
65
- WHERE lm.session_id = t.session_id AND lm.project_id = ?
66
- ORDER BY lm.created_at DESC, lm.rowid DESC LIMIT 1) AS last_content
67
- FROM (
68
- SELECT session_id,
69
- COUNT(*) AS message_count,
70
- MIN(created_at) AS created_at,
71
- MAX(created_at) AS updated_at
72
- FROM chat_messages
73
- WHERE project_id = ?
74
- GROUP BY session_id
75
- ) t
76
- ORDER BY t.updated_at DESC, t.session_id ASC`)
77
- .all(projectId, projectId);
78
+ // 相关子查询(取每会话最后一条消息)+ GROUP BY 聚合(count/min/max)的复合 SQL:
79
+ // sql 模板表达(4A 混合风格),projectId 两次注入走参数绑定
80
+ const rows = queryDb(db).all(sql `
81
+ SELECT
82
+ t.session_id AS id,
83
+ t.message_count,
84
+ t.created_at,
85
+ t.updated_at,
86
+ (SELECT lm.content FROM chat_messages lm
87
+ WHERE lm.session_id = t.session_id AND lm.project_id = ${projectId}
88
+ ORDER BY lm.created_at DESC, lm.rowid DESC LIMIT 1) AS last_content
89
+ FROM (
90
+ SELECT session_id,
91
+ COUNT(*) AS message_count,
92
+ MIN(created_at) AS created_at,
93
+ MAX(created_at) AS updated_at
94
+ FROM chat_messages
95
+ WHERE project_id = ${projectId}
96
+ GROUP BY session_id
97
+ ) t
98
+ ORDER BY t.updated_at DESC, t.session_id ASC
99
+ `);
78
100
  return rows.map((r) => ({
79
101
  id: r.id,
80
102
  lastMessage: truncate(r.last_content ?? "", SESSION_LAST_MESSAGE_MAX_LEN),
@@ -101,17 +123,26 @@ export function parseToolCalls(json) {
101
123
  }
102
124
  /**
103
125
  * 消息历史(GET /api/v1/chat/sessions/:id/messages):
104
- * - 按 project_id 隔离(决策 18 修订)
126
+ * - 按 project_id 隔离
105
127
  * - 按 created_at 升序,同时间戳按 rowid(插入序)升序保证稳定
106
128
  * - 存储形态 → API 形态:tool_calls JSON 解析、tool_call_id → toolCallId、snake_case → camelCase
107
129
  */
108
130
  export function listMessages(db, sessionId, projectId) {
109
- const rows = db
110
- .prepare(`SELECT id, session_id, project_id, role, content, tool_calls, tool_call_id, created_at
111
- FROM chat_messages
112
- WHERE session_id = ? AND project_id = ?
113
- ORDER BY created_at ASC, rowid ASC`)
114
- .all(sessionId, projectId);
131
+ const rows = queryDb(db)
132
+ .select({
133
+ id: chatMessages.id,
134
+ session_id: chatMessages.session_id,
135
+ project_id: chatMessages.project_id,
136
+ role: chatMessages.role,
137
+ content: chatMessages.content,
138
+ tool_calls: chatMessages.tool_calls,
139
+ tool_call_id: chatMessages.tool_call_id,
140
+ created_at: chatMessages.created_at,
141
+ })
142
+ .from(chatMessages)
143
+ .where(and(eq(chatMessages.session_id, sessionId), eq(chatMessages.project_id, projectId)))
144
+ .orderBy(chatMessages.created_at, sql `rowid ASC`)
145
+ .all();
115
146
  return rows.map((r) => ({
116
147
  id: r.id,
117
148
  sessionId: r.session_id,
@@ -126,40 +157,55 @@ export function listMessages(db, sessionId, projectId) {
126
157
  /**
127
158
  * 消息历史原始行(S7.6 续聊重建专用):
128
159
  * - listMessages 输出 API 形态(camelCase,供 GET /messages);本函数输出**存储形态**
129
- * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
130
- * loadHistory/restoreSession(决策 18 成对重组),避免 server 层做 API→存储形态反映射。
160
+ * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
161
+ * loadHistory/restoreSession( 成对重组),避免 server 层做 API→存储形态反映射。
131
162
  * - 查询语义与 listMessages 一致:按 project_id 隔离、created_at 升序 + rowid 稳定序。
132
163
  */
133
164
  export function listMessageRows(db, sessionId, projectId) {
134
- const rows = db
135
- .prepare(`SELECT id, session_id, project_id, role, content, tool_calls, tool_call_id, created_at
136
- FROM chat_messages
137
- WHERE session_id = ? AND project_id = ?
138
- ORDER BY created_at ASC, rowid ASC`)
139
- .all(sessionId, projectId);
165
+ const rows = queryDb(db)
166
+ .select({
167
+ id: chatMessages.id,
168
+ session_id: chatMessages.session_id,
169
+ project_id: chatMessages.project_id,
170
+ role: chatMessages.role,
171
+ content: chatMessages.content,
172
+ tool_calls: chatMessages.tool_calls,
173
+ tool_call_id: chatMessages.tool_call_id,
174
+ created_at: chatMessages.created_at,
175
+ })
176
+ .from(chatMessages)
177
+ .where(and(eq(chatMessages.session_id, sessionId), eq(chatMessages.project_id, projectId)))
178
+ .orderBy(chatMessages.created_at, sql `rowid ASC`)
179
+ .all();
140
180
  return rows.map((r) => ({
141
- ...r,
181
+ id: r.id,
182
+ session_id: r.session_id,
183
+ project_id: r.project_id,
184
+ role: r.role,
185
+ content: r.content,
142
186
  tool_calls: parseToolCalls(r.tool_calls), // TEXT 列 → 解析后的数组(NULL/损坏 → null)
187
+ tool_call_id: r.tool_call_id,
188
+ created_at: r.created_at,
143
189
  }));
144
190
  }
145
191
  /**
146
- * 成对重组历史消息(决策 18 修订:assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
192
+ * 成对重组历史消息(assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
147
193
  *
148
194
  * 用途:服务重启后凭 session_id 重建「继续上次对话」上下文,或会话级滑动窗口裁剪前的重组。
149
- * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型契约为解析后的数组,
195
+ * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型为解析后的数组,
150
196
  * 由调用方先经 parseToolCalls / 直接构造)。
151
197
  *
152
198
  * 算法:
153
199
  * 1. 按 created_at 升序稳定排序(同时间戳保持输入顺序)
154
200
  * 2. 第一遍收集 tool 消息:tool_call_id → content(同一 id 多条结果取最先到达者,防御性处理)
155
201
  * 3. 第二遍顺序扫描:
156
- * - user 消息:原样保留
157
- * - assistant 消息(无 tool_calls):原样保留
158
- * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
159
- * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(决策 18 修订:
160
- * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
161
- * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
162
- * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
202
+ * - user 消息:原样保留
203
+ * - assistant 消息(无 tool_calls):原样保留
204
+ * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
205
+ * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(
206
+ * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
207
+ * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
208
+ * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
163
209
  */
164
210
  export function reassembleMessages(rows) {
165
211
  // 1. 按 created_at 升序稳定排序
@@ -1 +1 @@
1
- {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"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"}