evolcore 0.0.23 → 0.0.25

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 (245) hide show
  1. package/CHANGELOG.md +583 -516
  2. package/LICENSE +21 -21
  3. package/README.md +455 -453
  4. package/bin/codex-managed-acl.ps1 +160 -155
  5. package/bin/codex-managed-hook.mjs +209 -92
  6. package/bin/ec-safe-output.js +327 -245
  7. package/bin/ec.js +29 -29
  8. package/bin/install-codex-managed-hooks.mjs +555 -544
  9. package/dist/agents/baseagent-availability.js +4 -4
  10. package/dist/agents/baseagent.js +29 -1
  11. package/dist/agents/claude-runner.js +152 -14
  12. package/dist/agents/codex/app-server-client.js +18 -8
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +215 -0
  15. package/dist/agents/codex-runner.js +445 -63
  16. package/dist/agents/ecagent-runner.js +31 -16
  17. package/dist/agents/gemini-runner.js +82 -4
  18. package/dist/agents/runner-types.js +1 -1
  19. package/dist/aun/aid/agentmd.js +56 -4
  20. package/dist/aun/aid/index.js +1 -0
  21. package/dist/aun/aid/managed-operation.js +80 -6
  22. package/dist/aun/aid/store.js +41 -0
  23. package/dist/aun/msg/managed-operation.js +6 -1
  24. package/dist/aun/outbox.js +56 -18
  25. package/dist/aun/rpc/client.js +4 -5
  26. package/dist/aun/storage/client.js +4 -1
  27. package/dist/aun/storage/index.js +1 -1
  28. package/dist/channels/aun.js +147 -76
  29. package/dist/channels/daemon.js +7 -1
  30. package/dist/channels/dingtalk.js +1 -0
  31. package/dist/channels/feishu.js +10 -4
  32. package/dist/channels/wecom.js +2 -1
  33. package/dist/cli/agent-command.js +214 -89
  34. package/dist/cli/agent-create.js +576 -0
  35. package/dist/cli/agent.js +129 -676
  36. package/dist/cli/aun-commands.js +419 -313
  37. package/dist/cli/bench.js +20 -20
  38. package/dist/cli/config.js +20 -20
  39. package/dist/cli/contact.js +10 -10
  40. package/dist/cli/ctl-command.js +22 -20
  41. package/dist/cli/daemon-commands.js +163 -32
  42. package/dist/cli/fs-command.js +67 -67
  43. package/dist/cli/handoff-command.js +7 -7
  44. package/dist/cli/index.js +79 -79
  45. package/dist/cli/link-rules.js +21 -21
  46. package/dist/cli/managed-command-guard.js +3 -0
  47. package/dist/cli/menu-client.js +11 -11
  48. package/dist/cli/net-check.js +22 -22
  49. package/dist/cli/queue-command.js +29 -29
  50. package/dist/cli/response.js +30 -30
  51. package/dist/cli/restart-monitor.js +462 -38
  52. package/dist/cli/stats.js +161 -51
  53. package/dist/cli/trigger-command.js +56 -56
  54. package/dist/config/builtin-roles.js +3 -0
  55. package/dist/config/config-manager.js +15 -0
  56. package/dist/config/config-operation-service.js +20 -3
  57. package/dist/config/resolved-config-op.js +39 -1
  58. package/dist/core/auth/auth-gateway.js +3 -2
  59. package/dist/core/auth/authorization-audit.js +72 -19
  60. package/dist/core/auth/operation-authorizer.js +125 -7
  61. package/dist/core/auth/operation-catalog.js +26 -2
  62. package/dist/core/auth/remote-access-store.js +3 -2
  63. package/dist/core/baseagent-loader.js +4 -4
  64. package/dist/core/bootstrap-messages.js +39 -18
  65. package/dist/core/bootstrap-service.js +32 -26
  66. package/dist/core/capability/capability-manager.js +8 -4
  67. package/dist/core/capability/providers/codex-capability-provider.js +1 -1
  68. package/dist/core/command/agent-control.js +60 -26
  69. package/dist/core/command/cli-intent-parser.js +18 -0
  70. package/dist/core/command/command-handler.js +173 -36
  71. package/dist/core/command/menu-catalog.js +4 -1
  72. package/dist/core/command/menu-handler.js +315 -75
  73. package/dist/core/command/menu-protocol.js +7 -2
  74. package/dist/core/command/slash-gate.js +1 -3
  75. package/dist/core/command/slash-handler.js +166 -57
  76. package/dist/core/data-migration.js +5 -15
  77. package/dist/core/event-catalog.js +8 -0
  78. package/dist/core/evolagent.js +3 -3
  79. package/dist/core/handoff/runtime.js +3 -1
  80. package/dist/core/handoff/store.js +7 -1
  81. package/dist/core/message/im-renderer.js +13 -6
  82. package/dist/core/message/message-bridge.js +5 -36
  83. package/dist/core/message/message-utils.js +6 -3
  84. package/dist/core/message/response-engine.js +85 -27
  85. package/dist/core/model/catalog-service.js +3 -1
  86. package/dist/core/model/model-catalog.js +10 -0
  87. package/dist/core/model/model-permission.js +4 -1
  88. package/dist/core/permission/approval-gateway.js +169 -33
  89. package/dist/core/permission/tool-policy.js +56 -10
  90. package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
  91. package/dist/core/session/session-manager.js +49 -13
  92. package/dist/core/session/session-renew.js +1 -0
  93. package/dist/index.js +327 -134
  94. package/dist/ipc.js +68 -21
  95. package/dist/paths.js +23 -1
  96. package/dist/stats/billing.js +18 -4
  97. package/dist/stats/db.js +159 -159
  98. package/dist/stats/eck-vars.js +9 -9
  99. package/dist/stats/query.js +139 -139
  100. package/dist/stats/role-budget.js +6 -6
  101. package/dist/stats/writer.js +51 -51
  102. package/dist/utils/atomic-write.js +26 -2
  103. package/dist/utils/avatar-upload.js +282 -23
  104. package/dist/utils/cross-platform.js +436 -1
  105. package/dist/utils/error-dict.json +160 -160
  106. package/dist/utils/error-utils.js +11 -4
  107. package/dist/utils/macos-autostart.js +22 -22
  108. package/dist/utils/model-prices.jsonl +23 -20
  109. package/dist/utils/npm-ops.js +24 -1
  110. package/dist/utils/welcome.js +22 -22
  111. package/dist/utils/windows-autostart.js +1 -1
  112. package/ecagent/LICENSE +21 -21
  113. package/ecagent/NOTICE +11 -11
  114. package/ecagent/README.md +61 -61
  115. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  116. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  117. package/ecagent/dist/harness/messages.js +7 -7
  118. package/kits/docs/GUIDE.md +20 -20
  119. package/kits/docs/INDEX.md +66 -66
  120. package/kits/docs/aun/CHEATSHEET.md +19 -19
  121. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  122. package/kits/docs/channels/aun.md +56 -56
  123. package/kits/docs/channels/feishu.md +56 -56
  124. package/kits/docs/context-assembly.md +365 -364
  125. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  126. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  127. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  128. package/kits/docs/eck_templates/runtime.template.md +19 -19
  129. package/kits/docs/evolcore/INDEX.md +71 -69
  130. package/kits/docs/evolcore/agent-create.md +170 -156
  131. package/kits/docs/evolcore/agent.md +83 -73
  132. package/kits/docs/evolcore/aid.md +64 -62
  133. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
  134. package/kits/docs/evolcore/config.md +195 -195
  135. package/kits/docs/evolcore/contact.md +68 -68
  136. package/kits/docs/evolcore/ctl.md +46 -46
  137. package/kits/docs/evolcore/event.md +216 -216
  138. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  139. package/kits/docs/evolcore/fs.md +110 -110
  140. package/kits/docs/evolcore/group-collaboration.md +243 -243
  141. package/kits/docs/evolcore/group-fs.md +17 -17
  142. package/kits/docs/evolcore/group-rules.md +251 -251
  143. package/kits/docs/evolcore/group.md +152 -152
  144. package/kits/docs/evolcore/menu-client.md +34 -34
  145. package/kits/docs/evolcore/model.md +50 -50
  146. package/kits/docs/evolcore/msg.md +165 -165
  147. package/kits/docs/evolcore/response.md +75 -75
  148. package/kits/docs/evolcore/rpc.md +37 -37
  149. package/kits/docs/evolcore/self-summary.md +29 -29
  150. package/kits/docs/evolcore/stats.md +83 -83
  151. package/kits/docs/evolcore/storage.md +50 -50
  152. package/kits/docs/evolcore/trigger.md +575 -575
  153. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  154. package/kits/docs/identity/PATH_OPS.md +16 -16
  155. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  156. package/kits/docs/identity/identity-tools.md +26 -26
  157. package/kits/docs/path-registry.md +62 -62
  158. package/kits/docs/prompt-loading-architecture.md +270 -269
  159. package/kits/docs/venues/aun-group.md +45 -45
  160. package/kits/docs/venues/aun-private.md +10 -10
  161. package/kits/docs/venues/client-desktop.md +10 -10
  162. package/kits/docs/venues/client-mobile.md +10 -10
  163. package/kits/docs/venues/feishu-group.md +13 -13
  164. package/kits/docs/venues/feishu-private.md +9 -9
  165. package/kits/docs/venues/group.md +25 -25
  166. package/kits/docs/venues/private.md +10 -10
  167. package/kits/eck_manifest.auxiliary.json +43 -43
  168. package/kits/eck_manifest.json +195 -183
  169. package/kits/eck_message_manifest.json +74 -74
  170. package/kits/migrations/README-role-config-v4.md +32 -32
  171. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  172. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  173. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  174. package/kits/migrations/rename-config-file.mjs +99 -99
  175. package/kits/rules/01-overview.md +162 -162
  176. package/kits/rules/02-navigation.md +96 -96
  177. package/kits/rules/03-identity.md +39 -37
  178. package/kits/rules/04-relation.md +75 -75
  179. package/kits/rules/05-venue.md +60 -60
  180. package/kits/rules/06-channel.md +63 -63
  181. package/kits/schemas/_meta.json +53 -53
  182. package/kits/schemas/agent-config.schema.1.json +177 -177
  183. package/kits/schemas/agent-config.schema.10.json +395 -395
  184. package/kits/schemas/agent-config.schema.11.json +421 -421
  185. package/kits/schemas/agent-config.schema.12.json +427 -427
  186. package/kits/schemas/agent-config.schema.2.json +239 -239
  187. package/kits/schemas/agent-config.schema.3.json +119 -119
  188. package/kits/schemas/agent-config.schema.4.json +208 -208
  189. package/kits/schemas/agent-config.schema.5.json +326 -326
  190. package/kits/schemas/agent-config.schema.6.json +322 -322
  191. package/kits/schemas/agent-config.schema.7.json +303 -303
  192. package/kits/schemas/agent-config.schema.8.json +304 -304
  193. package/kits/schemas/agent-config.schema.9.json +364 -364
  194. package/kits/schemas/contact-book.schema.1.json +36 -36
  195. package/kits/schemas/contact-book.schema.2.json +43 -43
  196. package/kits/schemas/contact-book.schema.3.json +67 -67
  197. package/kits/schemas/daemon.schema.1.json +91 -91
  198. package/kits/schemas/daemon.schema.2.json +101 -101
  199. package/kits/schemas/daemon.schema.3.json +123 -123
  200. package/kits/schemas/daemon.schema.4.json +136 -136
  201. package/kits/schemas/daemon.schema.5.json +135 -135
  202. package/kits/schemas/daemon.schema.6.json +131 -131
  203. package/kits/schemas/defaults.schema.1.json +81 -81
  204. package/kits/schemas/defaults.schema.2.json +85 -85
  205. package/kits/schemas/defaults.schema.3.json +73 -73
  206. package/kits/schemas/defaults.schema.4.json +107 -107
  207. package/kits/schemas/defaults.schema.5.json +119 -119
  208. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  209. package/kits/schemas/migrations/README.md +30 -30
  210. package/kits/schemas/relation-config.schema.1.json +158 -158
  211. package/kits/schemas/relation-config.schema.2.json +73 -73
  212. package/kits/schemas/relation-config.schema.3.json +50 -50
  213. package/kits/schemas/relation-config.schema.4.json +47 -47
  214. package/kits/schemas/relation-config.schema.5.json +47 -47
  215. package/kits/schemas/relation-config.schema.6.json +46 -46
  216. package/kits/schemas/relation-config.schema.7.json +59 -59
  217. package/kits/schemas/relation-config.schema.8.json +103 -103
  218. package/kits/schemas/role-config.schema.1.json +201 -201
  219. package/kits/schemas/role-registry.schema.1.json +35 -35
  220. package/kits/schemas/single-session.schema.1.json +31 -31
  221. package/kits/schemas/single-session.schema.2.json +57 -57
  222. package/kits/schemas/single-session.schema.3.json +32 -32
  223. package/kits/templates/bootstrap-welcome.md +17 -17
  224. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  225. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  226. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  227. package/kits/templates/message-fragments/inject-default.md +2 -2
  228. package/kits/templates/message-fragments/item.md +2 -2
  229. package/kits/templates/roles/admin.json +96 -82
  230. package/kits/templates/roles/member.json +97 -96
  231. package/kits/templates/roles/owner.json +9 -9
  232. package/kits/templates/roles/visitor.json +86 -85
  233. package/kits/templates/system-fragments/baseagent.md +14 -14
  234. package/kits/templates/system-fragments/bootstrap.md +38 -29
  235. package/kits/templates/system-fragments/channel.md +64 -64
  236. package/kits/templates/system-fragments/commands.md +28 -28
  237. package/kits/templates/system-fragments/identity.md +13 -13
  238. package/kits/templates/system-fragments/relation.md +19 -19
  239. package/kits/templates/system-fragments/session.md +59 -59
  240. package/kits/templates/system-fragments/venue.md +31 -31
  241. package/package.json +98 -94
  242. package/AGENTS.md +0 -62
  243. package/dist/utils/codex-cli.js +0 -43
  244. package/skills/eclink/SKILL.md +0 -84
  245. package/skills/eclink/agents/openai.yaml +0 -4
@@ -137,25 +137,25 @@ function _queryAggregatedDaily(evolcoreHome, granularity, filter) {
137
137
  if (!db)
138
138
  return [];
139
139
  try {
140
- const sql = `
141
- SELECT
142
- ${periodExpr} AS period,
143
- SUM(input_tokens) AS input_tokens,
144
- SUM(output_tokens) AS output_tokens,
145
- SUM(cache_creation_tokens) AS cache_creation_tokens,
146
- SUM(cache_read_tokens) AS cache_read_tokens,
147
- SUM(cache_hit_tokens) AS cache_hit_tokens,
148
- SUM(cache_miss_tokens) AS cache_miss_tokens,
149
- SUM(image_tokens) AS image_tokens,
150
- SUM(total_context_tokens) AS total_context_tokens,
151
- SUM(turns) AS turns,
152
- SUM(calls) AS call_count,
153
- COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
154
- COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
155
- COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
156
- COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
157
- FROM usage_daily ${clause}
158
- GROUP BY ${periodExpr}
140
+ const sql = `
141
+ SELECT
142
+ ${periodExpr} AS period,
143
+ SUM(input_tokens) AS input_tokens,
144
+ SUM(output_tokens) AS output_tokens,
145
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
146
+ SUM(cache_read_tokens) AS cache_read_tokens,
147
+ SUM(cache_hit_tokens) AS cache_hit_tokens,
148
+ SUM(cache_miss_tokens) AS cache_miss_tokens,
149
+ SUM(image_tokens) AS image_tokens,
150
+ SUM(total_context_tokens) AS total_context_tokens,
151
+ SUM(turns) AS turns,
152
+ SUM(calls) AS call_count,
153
+ COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
154
+ COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
155
+ COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
156
+ COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
157
+ FROM usage_daily ${clause}
158
+ GROUP BY ${periodExpr}
159
159
  `;
160
160
  const rows = db.prepare(sql).all(...params);
161
161
  if (groupCol) {
@@ -180,45 +180,45 @@ function _queryAggregatedEvents(evolcoreHome, granularity, filter) {
180
180
  let sql;
181
181
  if (groupCol) {
182
182
  // 非时间维度:按字段分组
183
- sql = `
184
- SELECT
185
- ${groupCol} AS period,
186
- SUM(input_tokens) AS input_tokens,
187
- SUM(output_tokens) AS output_tokens,
188
- SUM(cache_creation_tokens) AS cache_creation_tokens,
189
- SUM(cache_read_tokens) AS cache_read_tokens,
190
- SUM(COALESCE(cache_hit_tokens,0)) AS cache_hit_tokens,
191
- SUM(COALESCE(cache_miss_tokens,0)) AS cache_miss_tokens,
192
- SUM(COALESCE(image_tokens,0)) AS image_tokens,
193
- SUM(COALESCE(total_context_tokens,0)) AS total_context_tokens,
194
- SUM(turns) AS turns,
195
- COUNT(*) AS call_count
196
- FROM usage_events ${clause}
197
- GROUP BY ${groupCol} ORDER BY (input_tokens + output_tokens) DESC
183
+ sql = `
184
+ SELECT
185
+ ${groupCol} AS period,
186
+ SUM(input_tokens) AS input_tokens,
187
+ SUM(output_tokens) AS output_tokens,
188
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
189
+ SUM(cache_read_tokens) AS cache_read_tokens,
190
+ SUM(COALESCE(cache_hit_tokens,0)) AS cache_hit_tokens,
191
+ SUM(COALESCE(cache_miss_tokens,0)) AS cache_miss_tokens,
192
+ SUM(COALESCE(image_tokens,0)) AS image_tokens,
193
+ SUM(COALESCE(total_context_tokens,0)) AS total_context_tokens,
194
+ SUM(turns) AS turns,
195
+ COUNT(*) AS call_count
196
+ FROM usage_events ${clause}
197
+ GROUP BY ${groupCol} ORDER BY (input_tokens + output_tokens) DESC
198
198
  `;
199
199
  }
200
200
  else {
201
201
  // 时间维度:strftime 分组
202
202
  const fmt = GRAN_FMT[granularity] || GRAN_FMT.day;
203
- sql = `
204
- SELECT
205
- strftime('${fmt}', ts/1000, 'unixepoch', 'localtime') AS period,
206
- SUM(input_tokens) AS input_tokens,
207
- SUM(output_tokens) AS output_tokens,
208
- SUM(cache_creation_tokens) AS cache_creation_tokens,
209
- SUM(cache_read_tokens) AS cache_read_tokens,
210
- SUM(COALESCE(cache_hit_tokens,0)) AS cache_hit_tokens,
211
- SUM(COALESCE(cache_miss_tokens,0)) AS cache_miss_tokens,
212
- SUM(COALESCE(image_tokens,0)) AS image_tokens,
213
- SUM(COALESCE(total_context_tokens,0)) AS total_context_tokens,
214
- SUM(turns) AS turns,
215
- COUNT(*) AS call_count,
216
- COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
217
- COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
218
- COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
219
- COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
220
- FROM usage_events ${clause}
221
- GROUP BY period ORDER BY period
203
+ sql = `
204
+ SELECT
205
+ strftime('${fmt}', ts/1000, 'unixepoch', 'localtime') AS period,
206
+ SUM(input_tokens) AS input_tokens,
207
+ SUM(output_tokens) AS output_tokens,
208
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
209
+ SUM(cache_read_tokens) AS cache_read_tokens,
210
+ SUM(COALESCE(cache_hit_tokens,0)) AS cache_hit_tokens,
211
+ SUM(COALESCE(cache_miss_tokens,0)) AS cache_miss_tokens,
212
+ SUM(COALESCE(image_tokens,0)) AS image_tokens,
213
+ SUM(COALESCE(total_context_tokens,0)) AS total_context_tokens,
214
+ SUM(turns) AS turns,
215
+ COUNT(*) AS call_count,
216
+ COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
217
+ COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
218
+ COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
219
+ COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
220
+ FROM usage_events ${clause}
221
+ GROUP BY period ORDER BY period
222
222
  `;
223
223
  }
224
224
  // 收集所有相关 DB 的原始行,再按 period 合并
@@ -295,17 +295,17 @@ export function querySessionSummary(evolcoreHome, sessionId) {
295
295
  cost_official_usd: 0, cost_official_cny: 0, cost_gateway_usd: 0, cost_gateway_cny: 0,
296
296
  usd: 0, cny: 0,
297
297
  };
298
- const sql = `
299
- SELECT
300
- COALESCE(SUM(input_tokens), 0) AS input_tokens,
301
- COALESCE(SUM(output_tokens), 0) AS output_tokens,
302
- COALESCE(SUM(cache_creation_tokens), 0) AS cache_creation_tokens,
303
- COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,
304
- COUNT(*) AS calls,
305
- COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
306
- COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
307
- COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
308
- COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
298
+ const sql = `
299
+ SELECT
300
+ COALESCE(SUM(input_tokens), 0) AS input_tokens,
301
+ COALESCE(SUM(output_tokens), 0) AS output_tokens,
302
+ COALESCE(SUM(cache_creation_tokens), 0) AS cache_creation_tokens,
303
+ COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,
304
+ COUNT(*) AS calls,
305
+ COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
306
+ COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
307
+ COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
308
+ COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
309
309
  FROM usage_events WHERE session_id = ?`;
310
310
  const acc = { ...empty };
311
311
  for (const dbPath of _relevantDbs(evolcoreHome, {})) {
@@ -355,11 +355,11 @@ export function queryContextBreakdown(evolcoreHome, sessionId) {
355
355
  /** Top-N 对端(按 token 总量排序)。读预聚合表 usage_daily。 */
356
356
  export function queryTopPeers(evolcoreHome, filter, limit = 10) {
357
357
  const { clause, params } = _buildDailyWhere(filter);
358
- const sql = `
359
- SELECT peer_key, SUM(input_tokens+output_tokens) AS total_tokens,
360
- SUM(calls) AS call_count
361
- FROM usage_daily ${clause}
362
- GROUP BY peer_key ORDER BY total_tokens DESC LIMIT ${limit}
358
+ const sql = `
359
+ SELECT peer_key, SUM(input_tokens+output_tokens) AS total_tokens,
360
+ SUM(calls) AS call_count
361
+ FROM usage_daily ${clause}
362
+ GROUP BY peer_key ORDER BY total_tokens DESC LIMIT ${limit}
363
363
  `;
364
364
  const db = openReadonlyDb(getDbPath(evolcoreHome));
365
365
  if (!db)
@@ -374,11 +374,11 @@ export function queryTopPeers(evolcoreHome, filter, limit = 10) {
374
374
  /** Top-N 模型(按 token 总量排序)。读预聚合表 usage_daily。 */
375
375
  export function queryTopModels(evolcoreHome, filter, limit = 10) {
376
376
  const { clause, params } = _buildDailyWhere(filter);
377
- const sql = `
378
- SELECT model, SUM(input_tokens+output_tokens) AS total_tokens,
379
- SUM(calls) AS call_count
380
- FROM usage_daily ${clause}
381
- GROUP BY model ORDER BY total_tokens DESC LIMIT ${limit}
377
+ const sql = `
378
+ SELECT model, SUM(input_tokens+output_tokens) AS total_tokens,
379
+ SUM(calls) AS call_count
380
+ FROM usage_daily ${clause}
381
+ GROUP BY model ORDER BY total_tokens DESC LIMIT ${limit}
382
382
  `;
383
383
  const db = openReadonlyDb(getDbPath(evolcoreHome));
384
384
  if (!db)
@@ -446,29 +446,29 @@ export function queryPeerList(evolcoreHome, opts) {
446
446
  if (!db)
447
447
  return [];
448
448
  try {
449
- const listSql = `
450
- SELECT peer_key,
451
- SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
452
- SUM(cache_creation_tokens) AS cache_creation_tokens,
453
- SUM(cache_read_tokens) AS cache_read_tokens,
454
- SUM(input_tokens+output_tokens+cache_read_tokens+cache_creation_tokens) AS total_tokens,
455
- SUM(calls) AS calls,
456
- COUNT(DISTINCT session_id) AS session_count,
457
- MIN(day) AS first_day, MAX(day) AS last_day,
458
- MAX(peer_type) AS peer_type
459
- FROM usage_daily ${peerCond}
460
- GROUP BY peer_key ORDER BY total_tokens DESC LIMIT ${limit}
449
+ const listSql = `
450
+ SELECT peer_key,
451
+ SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
452
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
453
+ SUM(cache_read_tokens) AS cache_read_tokens,
454
+ SUM(input_tokens+output_tokens+cache_read_tokens+cache_creation_tokens) AS total_tokens,
455
+ SUM(calls) AS calls,
456
+ COUNT(DISTINCT session_id) AS session_count,
457
+ MIN(day) AS first_day, MAX(day) AS last_day,
458
+ MAX(peer_type) AS peer_type
459
+ FROM usage_daily ${peerCond}
460
+ GROUP BY peer_key ORDER BY total_tokens DESC LIMIT ${limit}
461
461
  `;
462
462
  const rows = db.prepare(listSql).all(...listParams);
463
463
  // 每个 peer 的成本:按 (peer_key, model, billing_fn) 分组算 calcCost 累加。
464
- const costSql = `
465
- SELECT peer_key, model, COALESCE(billing_fn,'') AS billing_fn,
466
- SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
467
- SUM(cache_creation_tokens) AS cache_creation_tokens, SUM(cache_read_tokens) AS cache_read_tokens,
468
- SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
469
- SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens
470
- FROM usage_daily ${peerCond}
471
- GROUP BY peer_key, model, billing_fn
464
+ const costSql = `
465
+ SELECT peer_key, model, COALESCE(billing_fn,'') AS billing_fn,
466
+ SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
467
+ SUM(cache_creation_tokens) AS cache_creation_tokens, SUM(cache_read_tokens) AS cache_read_tokens,
468
+ SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
469
+ SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens
470
+ FROM usage_daily ${peerCond}
471
+ GROUP BY peer_key, model, billing_fn
472
472
  `;
473
473
  const costByPeer = new Map();
474
474
  for (const r of db.prepare(costSql).all(...listParams)) {
@@ -519,17 +519,17 @@ export function querySummary(evolcoreHome, opts) {
519
519
  if (!db)
520
520
  return empty;
521
521
  try {
522
- const row = db.prepare(`
523
- SELECT
524
- SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
525
- SUM(cache_creation_tokens) AS cache_creation_tokens,
526
- SUM(cache_read_tokens) AS cache_read_tokens,
527
- SUM(calls) AS calls,
528
- COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
529
- COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
530
- COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
531
- COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
532
- FROM usage_daily ${clause}
522
+ const row = db.prepare(`
523
+ SELECT
524
+ SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
525
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
526
+ SUM(cache_read_tokens) AS cache_read_tokens,
527
+ SUM(calls) AS calls,
528
+ COALESCE(SUM(cost_official_usd), 0) AS cost_official_usd,
529
+ COALESCE(SUM(cost_official_cny), 0) AS cost_official_cny,
530
+ COALESCE(SUM(cost_gateway_usd), 0) AS cost_gateway_usd,
531
+ COALESCE(SUM(cost_gateway_cny), 0) AS cost_gateway_cny
532
+ FROM usage_daily ${clause}
533
533
  `).get(...params);
534
534
  if (!row || row.calls == null)
535
535
  return empty;
@@ -571,28 +571,28 @@ export function queryPeerDaily(evolcoreHome, opts) {
571
571
  if (!db)
572
572
  return [];
573
573
  try {
574
- const sql = `
575
- SELECT day AS period,
576
- SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
577
- SUM(cache_creation_tokens) AS cache_creation_tokens,
578
- SUM(cache_read_tokens) AS cache_read_tokens,
579
- SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
580
- SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens,
581
- SUM(turns) AS turns, SUM(calls) AS call_count
582
- FROM usage_daily ${where}
583
- GROUP BY day ORDER BY day
574
+ const sql = `
575
+ SELECT day AS period,
576
+ SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
577
+ SUM(cache_creation_tokens) AS cache_creation_tokens,
578
+ SUM(cache_read_tokens) AS cache_read_tokens,
579
+ SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
580
+ SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens,
581
+ SUM(turns) AS turns, SUM(calls) AS call_count
582
+ FROM usage_daily ${where}
583
+ GROUP BY day ORDER BY day
584
584
  `;
585
585
  const periodMap = new Map();
586
586
  for (const r of db.prepare(sql).all(...qParams))
587
587
  periodMap.set(r.period, r);
588
- const costSql = `
589
- SELECT day AS period, model, COALESCE(billing_fn,'') AS billing_fn,
590
- SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
591
- SUM(cache_creation_tokens) AS cache_creation_tokens, SUM(cache_read_tokens) AS cache_read_tokens,
592
- SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
593
- SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens
594
- FROM usage_daily ${where}
595
- GROUP BY day, model, billing_fn
588
+ const costSql = `
589
+ SELECT day AS period, model, COALESCE(billing_fn,'') AS billing_fn,
590
+ SUM(input_tokens) AS input_tokens, SUM(output_tokens) AS output_tokens,
591
+ SUM(cache_creation_tokens) AS cache_creation_tokens, SUM(cache_read_tokens) AS cache_read_tokens,
592
+ SUM(cache_hit_tokens) AS cache_hit_tokens, SUM(cache_miss_tokens) AS cache_miss_tokens,
593
+ SUM(image_tokens) AS image_tokens, SUM(total_context_tokens) AS total_context_tokens
594
+ FROM usage_daily ${where}
595
+ GROUP BY day, model, billing_fn
596
596
  `;
597
597
  const costMap = new Map();
598
598
  const byPeriod = new Map();
@@ -674,26 +674,26 @@ export function queryMessageAggregated(evolcoreHome, granularity, filter) {
674
674
  let sql;
675
675
  if (groupCol) {
676
676
  const col = groupCol === 'model' ? 'agent_aid' : groupCol; // model 无意义,降级 agent
677
- sql = `
678
- SELECT ${col} AS period,
679
- SUM(CASE WHEN direction='in' THEN 1 ELSE 0 END) AS msg_in,
680
- SUM(CASE WHEN direction='out' THEN 1 ELSE 0 END) AS msg_out,
681
- SUM(CASE WHEN direction='in' THEN bytes ELSE 0 END) AS bytes_in,
682
- SUM(CASE WHEN direction='out' THEN bytes ELSE 0 END) AS bytes_out
683
- FROM message_events ${clause}
684
- GROUP BY ${col} ORDER BY (bytes_in + bytes_out) DESC
677
+ sql = `
678
+ SELECT ${col} AS period,
679
+ SUM(CASE WHEN direction='in' THEN 1 ELSE 0 END) AS msg_in,
680
+ SUM(CASE WHEN direction='out' THEN 1 ELSE 0 END) AS msg_out,
681
+ SUM(CASE WHEN direction='in' THEN bytes ELSE 0 END) AS bytes_in,
682
+ SUM(CASE WHEN direction='out' THEN bytes ELSE 0 END) AS bytes_out
683
+ FROM message_events ${clause}
684
+ GROUP BY ${col} ORDER BY (bytes_in + bytes_out) DESC
685
685
  `;
686
686
  }
687
687
  else {
688
688
  const fmt = GRAN_FMT[granularity] || GRAN_FMT.day;
689
- sql = `
690
- SELECT strftime('${fmt}', ts/1000, 'unixepoch', 'localtime') AS period,
691
- SUM(CASE WHEN direction='in' THEN 1 ELSE 0 END) AS msg_in,
692
- SUM(CASE WHEN direction='out' THEN 1 ELSE 0 END) AS msg_out,
693
- SUM(CASE WHEN direction='in' THEN bytes ELSE 0 END) AS bytes_in,
694
- SUM(CASE WHEN direction='out' THEN bytes ELSE 0 END) AS bytes_out
695
- FROM message_events ${clause}
696
- GROUP BY period ORDER BY period
689
+ sql = `
690
+ SELECT strftime('${fmt}', ts/1000, 'unixepoch', 'localtime') AS period,
691
+ SUM(CASE WHEN direction='in' THEN 1 ELSE 0 END) AS msg_in,
692
+ SUM(CASE WHEN direction='out' THEN 1 ELSE 0 END) AS msg_out,
693
+ SUM(CASE WHEN direction='in' THEN bytes ELSE 0 END) AS bytes_in,
694
+ SUM(CASE WHEN direction='out' THEN bytes ELSE 0 END) AS bytes_out
695
+ FROM message_events ${clause}
696
+ GROUP BY period ORDER BY period
697
697
  `;
698
698
  }
699
699
  const periodMap = new Map();
@@ -137,12 +137,12 @@ function queryPeriodUsage(evolcoreHome, opts) {
137
137
  where.push('usage_subject_key = ?');
138
138
  params.push(opts.usageSubjectKey);
139
139
  }
140
- const row = db.prepare(`
141
- SELECT
142
- COALESCE(SUM(${prefix}_cny), 0) AS cny,
143
- COALESCE(SUM(${prefix}_usd), 0) AS usd
144
- FROM usage_events
145
- WHERE ${where.join(' AND ')}
140
+ const row = db.prepare(`
141
+ SELECT
142
+ COALESCE(SUM(${prefix}_cny), 0) AS cny,
143
+ COALESCE(SUM(${prefix}_usd), 0) AS usd
144
+ FROM usage_events
145
+ WHERE ${where.join(' AND ')}
146
146
  `).get(...params);
147
147
  return {
148
148
  cny: Number(row?.cny ?? 0),
@@ -48,43 +48,43 @@ function isSchemaMismatchError(error) {
48
48
  function writeUsageEvent(db, event, prices) {
49
49
  // 明细 INSERT + rollup UPSERT 包进同一事务:进程在两者间崩溃也不会让 rollup 与明细漂移。
50
50
  db.exec('BEGIN');
51
- db.prepare(`
52
- INSERT INTO usage_events
53
- (ts, agent_aid, peer_key, usage_subject_key, role, peer_type, session_id, model, billing_fn,
54
- input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
55
- cache_hit_tokens, cache_miss_tokens, image_tokens, total_context_tokens,
56
- turns, duration_ms, context_window_pct,
57
- cost_official_usd, cost_official_cny, cost_gateway_usd, cost_gateway_cny)
58
- VALUES
59
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
51
+ db.prepare(`
52
+ INSERT INTO usage_events
53
+ (ts, agent_aid, peer_key, usage_subject_key, role, peer_type, session_id, model, billing_fn,
54
+ input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
55
+ cache_hit_tokens, cache_miss_tokens, image_tokens, total_context_tokens,
56
+ turns, duration_ms, context_window_pct,
57
+ cost_official_usd, cost_official_cny, cost_gateway_usd, cost_gateway_cny)
58
+ VALUES
59
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
60
60
  `).run(event.ts, event.agent_aid, event.peer_key, event.usage_subject_key ?? event.peer_key ?? '', event.role ?? '', event.peer_type ?? null, event.session_id ?? null, event.model, event.billing_fn, event.input_tokens, event.output_tokens, event.cache_creation_tokens, event.cache_read_tokens, event.cache_hit_tokens ?? null, event.cache_miss_tokens ?? null, event.image_tokens ?? null, event.total_context_tokens ?? null, event.turns, event.duration_ms ?? null, event.context_window_pct ?? null, prices.official?.usd ?? null, prices.official?.cny ?? null, prices.gateway?.usd ?? null, prices.gateway?.cny ?? null);
61
61
  // 写时增量:累加到日级预聚合表(grain 与 db.ts rebuildDailyRollup 一致)。
62
- db.prepare(`
63
- INSERT INTO usage_daily
64
- (day, agent_aid, peer_key, peer_type, session_id, model, billing_fn,
65
- input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
66
- cache_hit_tokens, cache_miss_tokens, image_tokens, total_context_tokens,
67
- turns, calls,
68
- cost_official_usd, cost_official_cny, cost_gateway_usd, cost_gateway_cny)
69
- VALUES
70
- (strftime('%Y-%m-%d', ?/1000, 'unixepoch', 'localtime'),
71
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)
72
- ON CONFLICT(day, agent_aid, peer_key, session_id, model, billing_fn) DO UPDATE SET
73
- peer_type = excluded.peer_type,
74
- input_tokens = input_tokens + excluded.input_tokens,
75
- output_tokens = output_tokens + excluded.output_tokens,
76
- cache_creation_tokens = cache_creation_tokens + excluded.cache_creation_tokens,
77
- cache_read_tokens = cache_read_tokens + excluded.cache_read_tokens,
78
- cache_hit_tokens = cache_hit_tokens + excluded.cache_hit_tokens,
79
- cache_miss_tokens = cache_miss_tokens + excluded.cache_miss_tokens,
80
- image_tokens = image_tokens + excluded.image_tokens,
81
- total_context_tokens = total_context_tokens + excluded.total_context_tokens,
82
- turns = turns + excluded.turns,
83
- calls = calls + 1,
84
- cost_official_usd = COALESCE(cost_official_usd, 0) + COALESCE(excluded.cost_official_usd, 0),
85
- cost_official_cny = COALESCE(cost_official_cny, 0) + COALESCE(excluded.cost_official_cny, 0),
86
- cost_gateway_usd = COALESCE(cost_gateway_usd, 0) + COALESCE(excluded.cost_gateway_usd, 0),
87
- cost_gateway_cny = COALESCE(cost_gateway_cny, 0) + COALESCE(excluded.cost_gateway_cny, 0)
62
+ db.prepare(`
63
+ INSERT INTO usage_daily
64
+ (day, agent_aid, peer_key, peer_type, session_id, model, billing_fn,
65
+ input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens,
66
+ cache_hit_tokens, cache_miss_tokens, image_tokens, total_context_tokens,
67
+ turns, calls,
68
+ cost_official_usd, cost_official_cny, cost_gateway_usd, cost_gateway_cny)
69
+ VALUES
70
+ (strftime('%Y-%m-%d', ?/1000, 'unixepoch', 'localtime'),
71
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)
72
+ ON CONFLICT(day, agent_aid, peer_key, session_id, model, billing_fn) DO UPDATE SET
73
+ peer_type = excluded.peer_type,
74
+ input_tokens = input_tokens + excluded.input_tokens,
75
+ output_tokens = output_tokens + excluded.output_tokens,
76
+ cache_creation_tokens = cache_creation_tokens + excluded.cache_creation_tokens,
77
+ cache_read_tokens = cache_read_tokens + excluded.cache_read_tokens,
78
+ cache_hit_tokens = cache_hit_tokens + excluded.cache_hit_tokens,
79
+ cache_miss_tokens = cache_miss_tokens + excluded.cache_miss_tokens,
80
+ image_tokens = image_tokens + excluded.image_tokens,
81
+ total_context_tokens = total_context_tokens + excluded.total_context_tokens,
82
+ turns = turns + excluded.turns,
83
+ calls = calls + 1,
84
+ cost_official_usd = COALESCE(cost_official_usd, 0) + COALESCE(excluded.cost_official_usd, 0),
85
+ cost_official_cny = COALESCE(cost_official_cny, 0) + COALESCE(excluded.cost_official_cny, 0),
86
+ cost_gateway_usd = COALESCE(cost_gateway_usd, 0) + COALESCE(excluded.cost_gateway_usd, 0),
87
+ cost_gateway_cny = COALESCE(cost_gateway_cny, 0) + COALESCE(excluded.cost_gateway_cny, 0)
88
88
  `).run(event.ts, event.agent_aid, event.peer_key, event.peer_type ?? '', event.session_id ?? '', event.model, event.billing_fn, event.input_tokens, event.output_tokens, event.cache_creation_tokens, event.cache_read_tokens, event.cache_hit_tokens ?? 0, event.cache_miss_tokens ?? 0, event.image_tokens ?? 0, event.total_context_tokens ?? 0, event.turns, prices.official?.usd ?? null, prices.official?.cny ?? null, prices.gateway?.usd ?? null, prices.gateway?.cny ?? null);
89
89
  db.exec('COMMIT');
90
90
  }
@@ -93,12 +93,12 @@ export function insertContextBreakdown(evolcoreHome, bd) {
93
93
  if (!db)
94
94
  return;
95
95
  try {
96
- db.prepare(`
97
- INSERT INTO context_breakdown
98
- (ts, agent_aid, session_id, turn_count, model, max_tokens,
99
- system_prompt, system_tools, mcp_tools, custom_agents,
100
- memory_files, skills, messages, free_space, total_estimated)
101
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
96
+ db.prepare(`
97
+ INSERT INTO context_breakdown
98
+ (ts, agent_aid, session_id, turn_count, model, max_tokens,
99
+ system_prompt, system_tools, mcp_tools, custom_agents,
100
+ memory_files, skills, messages, free_space, total_estimated)
101
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
102
102
  `).run(bd.ts, bd.agent_aid, bd.session_id, bd.turn_count, bd.model, bd.max_tokens, bd.system_prompt ?? null, bd.system_tools ?? null, bd.mcp_tools ?? null, bd.custom_agents ?? null, bd.memory_files ?? null, bd.skills ?? null, bd.messages ?? null, bd.free_space ?? null, bd.total_estimated ?? null);
103
103
  }
104
104
  catch (e) {
@@ -110,10 +110,10 @@ export function insertMessageEvent(evolcoreHome, event) {
110
110
  if (!db)
111
111
  return;
112
112
  try {
113
- db.prepare(`
114
- INSERT INTO message_events
115
- (ts, agent_aid, peer_key, direction, msg_type, bytes, encrypted, chatmode)
116
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
113
+ db.prepare(`
114
+ INSERT INTO message_events
115
+ (ts, agent_aid, peer_key, direction, msg_type, bytes, encrypted, chatmode)
116
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
117
117
  `).run(event.ts, event.agent_aid, event.peer_key, event.direction, event.msg_type ?? null, event.bytes, event.encrypted ? 1 : 0, event.chatmode ?? null);
118
118
  }
119
119
  catch (e) {
@@ -128,12 +128,12 @@ export function insertModelCalls(evolcoreHome, rows) {
128
128
  if (!db)
129
129
  return;
130
130
  try {
131
- const stmt = db.prepare(`
132
- INSERT INTO model_calls
133
- (ts, task_id, session_id, agent_session_id, agent_aid, peer_key, call_index, model,
134
- request_id, message_id, input_tokens, output_tokens, cache_creation_tokens,
135
- cache_read_tokens, context_tokens, max_tokens, auto_compact_tokens, degraded)
136
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
131
+ const stmt = db.prepare(`
132
+ INSERT INTO model_calls
133
+ (ts, task_id, session_id, agent_session_id, agent_aid, peer_key, call_index, model,
134
+ request_id, message_id, input_tokens, output_tokens, cache_creation_tokens,
135
+ cache_read_tokens, context_tokens, max_tokens, auto_compact_tokens, degraded)
136
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
137
137
  `);
138
138
  db.exec('BEGIN');
139
139
  for (const r of rows) {
@@ -69,8 +69,32 @@ export function atomicWrite(filePath, content) {
69
69
  }
70
70
  }
71
71
  // The final rename atomically replaces the old target without an absent-path
72
- // window.
73
- fs.renameSync(tmp, filePath);
72
+ // window. Windows H-class projections can keep the destination pathname
73
+ // open while a sandbox is starting; replacing that directory entry then
74
+ // fails with EPERM. In that narrow case, preserve the target inode and write
75
+ // in place. The hot backup above still provides the previous full version.
76
+ try {
77
+ fs.renameSync(tmp, filePath);
78
+ }
79
+ catch (error) {
80
+ const code = error.code;
81
+ if (process.platform !== 'win32' || code !== 'EPERM')
82
+ throw error;
83
+ const detachedHot = `${hot}.${process.pid}.fallback.tmp`;
84
+ try {
85
+ // refreshHotBackup may have used a hard link. Detach that backup before
86
+ // the in-place write, otherwise updating the live inode would update the
87
+ // hot backup as well.
88
+ fs.copyFileSync(filePath, detachedHot);
89
+ fs.rmSync(hot, { force: true });
90
+ fs.renameSync(detachedHot, hot);
91
+ stableWrite(filePath, content);
92
+ }
93
+ finally {
94
+ fs.rmSync(detachedHot, { force: true });
95
+ fs.rmSync(tmp, { force: true });
96
+ }
97
+ }
74
98
  }
75
99
  export function atomicWriteJson(filePath, value) {
76
100
  atomicWrite(filePath, JSON.stringify(value, null, 2) + '\n');