evolcore 0.0.25 → 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 (231) hide show
  1. package/CHANGELOG.md +607 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +160 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +40 -29
  8. package/bin/install-codex-managed-hooks.mjs +582 -555
  9. package/dist/agents/baseagent.js +96 -46
  10. package/dist/agents/claude-runner.js +50 -12
  11. package/dist/agents/codex/app-server-client.js +13 -5
  12. package/dist/agents/codex/catalog.js +1 -1
  13. package/dist/agents/codex/diagnostics.js +34 -1
  14. package/dist/agents/codex-runner.js +121 -38
  15. package/dist/agents/ecagent-runner.js +4 -9
  16. package/dist/agents/gemini-runner.js +2 -7
  17. package/dist/agents/runner-types.js +25 -17
  18. package/dist/aun/aid/agentmd.js +81 -8
  19. package/dist/aun/aid/client.js +1 -1
  20. package/dist/aun/aid/identity.js +1 -1
  21. package/dist/aun/aid/index.js +1 -1
  22. package/dist/aun/aid/store.js +17 -13
  23. package/dist/aun/menu-client.js +74 -0
  24. package/dist/aun/msg/group.js +1 -1
  25. package/dist/aun/msg/managed-operation.js +1 -1
  26. package/dist/aun/msg/p2p.js +6 -1
  27. package/dist/aun/msg/upload.js +30 -22
  28. package/dist/channels/aun.js +329 -94
  29. package/dist/cli/agent-command.js +105 -84
  30. package/dist/cli/agent-create.js +112 -10
  31. package/dist/cli/agent.js +16 -5
  32. package/dist/cli/aun-commands.js +297 -296
  33. package/dist/cli/bench.js +20 -20
  34. package/dist/cli/config.js +47 -28
  35. package/dist/cli/contact.js +70 -13
  36. package/dist/cli/ctl-command.js +22 -22
  37. package/dist/cli/daemon-commands.js +105 -40
  38. package/dist/cli/diag.js +31 -0
  39. package/dist/cli/fs-command.js +67 -67
  40. package/dist/cli/handoff-command.js +41 -9
  41. package/dist/cli/index.js +83 -77
  42. package/dist/cli/link-rules.js +21 -21
  43. package/dist/cli/managed-command-guard.js +3 -0
  44. package/dist/cli/menu-client.js +46 -31
  45. package/dist/cli/net-check.js +22 -22
  46. package/dist/cli/queue-command.js +29 -29
  47. package/dist/cli/response.js +30 -30
  48. package/dist/cli/restart-monitor.js +87 -40
  49. package/dist/cli/stats.js +51 -51
  50. package/dist/cli/trigger-command.js +56 -56
  51. package/dist/config/builtin-roles.js +1 -0
  52. package/dist/config/config-operation-service.js +145 -0
  53. package/dist/config/contact-operation-service.js +96 -7
  54. package/dist/config/resolved-config-op.js +27 -7
  55. package/dist/core/agent-application-service.js +2 -1
  56. package/dist/core/auth/authorization-audit.js +20 -12
  57. package/dist/core/auth/operation-authorizer.js +25 -4
  58. package/dist/core/auth/operation-catalog.js +35 -4
  59. package/dist/core/auth/remote-access-store.js +40 -1
  60. package/dist/core/bootstrap-service.js +1 -1
  61. package/dist/core/command/command-handler.js +83 -26
  62. package/dist/core/command/diag-service.js +118 -0
  63. package/dist/core/command/menu-catalog.js +12 -3
  64. package/dist/core/command/menu-handler.js +47 -26
  65. package/dist/core/command/menu-protocol.js +5 -0
  66. package/dist/core/command/menu-token-store.js +41 -8
  67. package/dist/core/command/slash-gate.js +34 -4
  68. package/dist/core/command/slash-handler.js +86 -21
  69. package/dist/core/handoff/runtime.js +205 -27
  70. package/dist/core/handoff/store.js +193 -4
  71. package/dist/core/message/im-renderer.js +72 -21
  72. package/dist/core/message/message-bridge.js +69 -9
  73. package/dist/core/message/message-queue.js +26 -0
  74. package/dist/core/message/message-utils.js +1 -0
  75. package/dist/core/message/response-engine.js +47 -28
  76. package/dist/core/model/catalog-service.js +79 -49
  77. package/dist/core/model/context-window-suffix.js +33 -0
  78. package/dist/core/model/model-catalog.js +1 -1
  79. package/dist/core/model/model-permission.js +12 -3
  80. package/dist/core/permission/ec-command-parser.js +51 -12
  81. package/dist/core/permission/sandbox-runtime.js +36 -14
  82. package/dist/core/permission/tool-policy.js +2 -1
  83. package/dist/index.js +280 -163
  84. package/dist/ipc.js +54 -2
  85. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  86. package/dist/stats/billing.js +41 -15
  87. package/dist/stats/db.js +159 -159
  88. package/dist/stats/eck-vars.js +9 -9
  89. package/dist/stats/price-resolver.js +28 -10
  90. package/dist/stats/query.js +139 -139
  91. package/dist/stats/role-budget.js +6 -6
  92. package/dist/stats/writer.js +51 -51
  93. package/dist/utils/cross-platform.js +30 -1
  94. package/dist/utils/error-dict.json +160 -160
  95. package/dist/utils/error-utils.js +21 -0
  96. package/dist/utils/evolcore-version.js +129 -0
  97. package/dist/utils/logger.js +3 -1
  98. package/dist/utils/macos-autostart.js +22 -22
  99. package/dist/utils/model-prices.jsonl +23 -23
  100. package/dist/utils/npm-ops.js +176 -35
  101. package/dist/utils/welcome.js +22 -22
  102. package/ecagent/LICENSE +21 -21
  103. package/ecagent/NOTICE +11 -11
  104. package/ecagent/README.md +61 -61
  105. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  106. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  107. package/ecagent/dist/harness/messages.js +7 -7
  108. package/kits/docs/GUIDE.md +20 -20
  109. package/kits/docs/INDEX.md +66 -66
  110. package/kits/docs/aun/CHEATSHEET.md +19 -19
  111. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  112. package/kits/docs/channels/aun.md +56 -56
  113. package/kits/docs/channels/feishu.md +56 -56
  114. package/kits/docs/context-assembly.md +364 -364
  115. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  116. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  117. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  118. package/kits/docs/eck_templates/runtime.template.md +19 -19
  119. package/kits/docs/evolcore/INDEX.md +71 -71
  120. package/kits/docs/evolcore/agent-create.md +170 -165
  121. package/kits/docs/evolcore/agent.md +66 -66
  122. package/kits/docs/evolcore/aid.md +60 -60
  123. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  124. package/kits/docs/evolcore/config.md +202 -195
  125. package/kits/docs/evolcore/contact.md +75 -68
  126. package/kits/docs/evolcore/ctl.md +46 -46
  127. package/kits/docs/evolcore/event.md +216 -216
  128. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  129. package/kits/docs/evolcore/fs.md +110 -110
  130. package/kits/docs/evolcore/group-collaboration.md +243 -243
  131. package/kits/docs/evolcore/group-fs.md +17 -17
  132. package/kits/docs/evolcore/group-rules.md +251 -251
  133. package/kits/docs/evolcore/group.md +152 -152
  134. package/kits/docs/evolcore/menu-client.md +42 -34
  135. package/kits/docs/evolcore/model.md +50 -50
  136. package/kits/docs/evolcore/msg.md +166 -165
  137. package/kits/docs/evolcore/response.md +75 -75
  138. package/kits/docs/evolcore/rpc.md +37 -37
  139. package/kits/docs/evolcore/self-summary.md +29 -29
  140. package/kits/docs/evolcore/stats.md +83 -83
  141. package/kits/docs/evolcore/storage.md +50 -50
  142. package/kits/docs/evolcore/trigger.md +575 -575
  143. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  144. package/kits/docs/identity/PATH_OPS.md +16 -16
  145. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  146. package/kits/docs/identity/identity-tools.md +26 -26
  147. package/kits/docs/path-registry.md +62 -62
  148. package/kits/docs/prompt-loading-architecture.md +269 -269
  149. package/kits/docs/venues/aun-group.md +45 -45
  150. package/kits/docs/venues/aun-private.md +10 -10
  151. package/kits/docs/venues/client-desktop.md +10 -10
  152. package/kits/docs/venues/client-mobile.md +10 -10
  153. package/kits/docs/venues/feishu-group.md +13 -13
  154. package/kits/docs/venues/feishu-private.md +9 -9
  155. package/kits/docs/venues/group.md +37 -25
  156. package/kits/docs/venues/private.md +10 -10
  157. package/kits/eck_manifest.auxiliary.json +43 -43
  158. package/kits/eck_manifest.json +190 -190
  159. package/kits/eck_message_manifest.json +74 -74
  160. package/kits/migrations/README-role-config-v4.md +32 -32
  161. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  162. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  163. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  164. package/kits/migrations/rename-config-file.mjs +99 -99
  165. package/kits/rules/01-overview.md +162 -162
  166. package/kits/rules/02-navigation.md +96 -96
  167. package/kits/rules/03-identity.md +36 -36
  168. package/kits/rules/04-relation.md +75 -75
  169. package/kits/rules/05-venue.md +60 -60
  170. package/kits/rules/06-channel.md +63 -63
  171. package/kits/schemas/_meta.json +53 -53
  172. package/kits/schemas/agent-config.schema.1.json +177 -177
  173. package/kits/schemas/agent-config.schema.10.json +395 -395
  174. package/kits/schemas/agent-config.schema.11.json +421 -421
  175. package/kits/schemas/agent-config.schema.12.json +427 -427
  176. package/kits/schemas/agent-config.schema.2.json +239 -239
  177. package/kits/schemas/agent-config.schema.3.json +119 -119
  178. package/kits/schemas/agent-config.schema.4.json +208 -208
  179. package/kits/schemas/agent-config.schema.5.json +326 -326
  180. package/kits/schemas/agent-config.schema.6.json +322 -322
  181. package/kits/schemas/agent-config.schema.7.json +303 -303
  182. package/kits/schemas/agent-config.schema.8.json +304 -304
  183. package/kits/schemas/agent-config.schema.9.json +364 -364
  184. package/kits/schemas/contact-book.schema.1.json +36 -36
  185. package/kits/schemas/contact-book.schema.2.json +43 -43
  186. package/kits/schemas/contact-book.schema.3.json +67 -67
  187. package/kits/schemas/daemon.schema.1.json +91 -91
  188. package/kits/schemas/daemon.schema.2.json +101 -101
  189. package/kits/schemas/daemon.schema.3.json +123 -123
  190. package/kits/schemas/daemon.schema.4.json +136 -136
  191. package/kits/schemas/daemon.schema.5.json +135 -135
  192. package/kits/schemas/daemon.schema.6.json +131 -131
  193. package/kits/schemas/defaults.schema.1.json +81 -81
  194. package/kits/schemas/defaults.schema.2.json +85 -85
  195. package/kits/schemas/defaults.schema.3.json +73 -73
  196. package/kits/schemas/defaults.schema.4.json +107 -107
  197. package/kits/schemas/defaults.schema.5.json +119 -119
  198. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  199. package/kits/schemas/migrations/README.md +30 -30
  200. package/kits/schemas/relation-config.schema.1.json +158 -158
  201. package/kits/schemas/relation-config.schema.2.json +73 -73
  202. package/kits/schemas/relation-config.schema.3.json +50 -50
  203. package/kits/schemas/relation-config.schema.4.json +47 -47
  204. package/kits/schemas/relation-config.schema.5.json +47 -47
  205. package/kits/schemas/relation-config.schema.6.json +46 -46
  206. package/kits/schemas/relation-config.schema.7.json +59 -59
  207. package/kits/schemas/relation-config.schema.8.json +103 -103
  208. package/kits/schemas/role-config.schema.1.json +201 -201
  209. package/kits/schemas/role-registry.schema.1.json +35 -35
  210. package/kits/schemas/single-session.schema.1.json +31 -31
  211. package/kits/schemas/single-session.schema.2.json +57 -57
  212. package/kits/schemas/single-session.schema.3.json +32 -32
  213. package/kits/templates/bootstrap-welcome.md +17 -17
  214. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  215. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  216. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  217. package/kits/templates/message-fragments/inject-default.md +2 -2
  218. package/kits/templates/message-fragments/item.md +2 -2
  219. package/kits/templates/roles/admin.json +92 -92
  220. package/kits/templates/roles/member.json +96 -96
  221. package/kits/templates/roles/owner.json +9 -9
  222. package/kits/templates/roles/visitor.json +85 -85
  223. package/kits/templates/system-fragments/baseagent.md +14 -14
  224. package/kits/templates/system-fragments/bootstrap.md +31 -29
  225. package/kits/templates/system-fragments/channel.md +64 -64
  226. package/kits/templates/system-fragments/commands.md +28 -28
  227. package/kits/templates/system-fragments/identity.md +13 -13
  228. package/kits/templates/system-fragments/relation.md +19 -19
  229. package/kits/templates/system-fragments/session.md +59 -59
  230. package/kits/templates/system-fragments/venue.md +31 -31
  231. package/package.json +100 -98
@@ -27,15 +27,15 @@ function _calcTodayCosts(evolcoreHome, agentAid, peerKey) {
27
27
  params.push(peerKey);
28
28
  }
29
29
  try {
30
- const row = db.prepare(`
31
- SELECT
32
- SUM(input_tokens) AS input,
33
- SUM(output_tokens) AS output,
34
- SUM(cache_read_tokens) AS cacheRead,
35
- COUNT(*) AS calls,
36
- COALESCE(SUM(cost_gateway_usd), 0) AS usd,
37
- COALESCE(SUM(cost_gateway_cny), 0) AS cny
38
- FROM usage_events WHERE ${conds.join(' AND ')}
30
+ const row = db.prepare(`
31
+ SELECT
32
+ SUM(input_tokens) AS input,
33
+ SUM(output_tokens) AS output,
34
+ SUM(cache_read_tokens) AS cacheRead,
35
+ COUNT(*) AS calls,
36
+ COALESCE(SUM(cost_gateway_usd), 0) AS usd,
37
+ COALESCE(SUM(cost_gateway_cny), 0) AS cny
38
+ FROM usage_events WHERE ${conds.join(' AND ')}
39
39
  `).get(...params);
40
40
  return {
41
41
  usd: row?.usd ?? 0,
@@ -2,7 +2,7 @@
2
2
  * price-resolver.ts — 统一价格解析逻辑,支持官方价格和网关价格。
3
3
  * 供 writer.ts 写入时调用,供 rebuild 命令回填历史数据。
4
4
  */
5
- import { resolvePriceRow, BILLING_FNS } from './billing.js';
5
+ import { resolvePriceRow, modelLookupKeys, BILLING_FNS } from './billing.js';
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
8
  /** Keep wire/log metadata readable while preserving full precision in storage. */
@@ -44,10 +44,28 @@ function loadGatewayPrices(evolcoreHome) {
44
44
  */
45
45
  function resolveGatewayPriceRow(evolcoreHome, model, ts) {
46
46
  const prices = loadGatewayPrices(evolcoreHome);
47
- const candidates = prices.filter(p => p.model === model && p.effective_from <= ts);
48
- if (!candidates.length)
47
+ // 精确匹配优先(允许给某个窗口变体单独定价),再回落到基础 ID。
48
+ for (const key of modelLookupKeys(evolcoreHome, model)) {
49
+ const candidates = prices.filter(p => p.model === key && p.effective_from <= ts);
50
+ if (candidates.length) {
51
+ return candidates.reduce((a, b) => a.effective_from >= b.effective_from ? a : b);
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+ /**
57
+ * 从网关价格 Map 里取价:Map 的键是网关原样下发的 ID(可能带 `[1m]` 后缀),
58
+ * 而 usage 事件记录的可能是基础 ID,反之亦然——两侧都要按候选键链匹配。
59
+ */
60
+ function pickGatewayQuad(evolcoreHome, map, model) {
61
+ if (!map)
49
62
  return null;
50
- return candidates.reduce((a, b) => a.effective_from >= b.effective_from ? a : b);
63
+ for (const key of modelLookupKeys(evolcoreHome, model)) {
64
+ const quad = map.get(key);
65
+ if (quad)
66
+ return quad;
67
+ }
68
+ return null;
51
69
  }
52
70
  /**
53
71
  * 从 PriceQuad 构造一个符合 billing.ts 规范的 PriceRecord。
@@ -80,9 +98,9 @@ export function resolvePrices(evolcoreHome, event, gatewayPricing) {
80
98
  // ── 1. 官方价格(Official Price)──────────────────────────────────────────
81
99
  let officialCost = null;
82
100
  // 优先级 1: 网关接口返回的 pricing 字段
83
- if (gatewayPricing?.official.has(event.model)) {
84
- const quad = gatewayPricing.official.get(event.model);
85
- const priceRow = priceQuadToRecord(event.model, event.ts, quad, event.billing_fn);
101
+ const officialQuad = pickGatewayQuad(evolcoreHome, gatewayPricing?.official, event.model);
102
+ if (officialQuad) {
103
+ const priceRow = priceQuadToRecord(event.model, event.ts, officialQuad, event.billing_fn);
86
104
  const fn = BILLING_FNS[event.billing_fn];
87
105
  if (fn) {
88
106
  officialCost = fn(event, priceRow);
@@ -109,9 +127,9 @@ export function resolvePrices(evolcoreHome, event, gatewayPricing) {
109
127
  }
110
128
  }
111
129
  // 优先级 2: 网关接口返回的 effective_pricing 字段
112
- if (!gatewayCost && gatewayPricing?.gateway.has(event.model)) {
113
- const quad = gatewayPricing.gateway.get(event.model);
114
- const priceRow = priceQuadToRecord(event.model, event.ts, quad, event.billing_fn);
130
+ const gatewayQuad = gatewayCost ? null : pickGatewayQuad(evolcoreHome, gatewayPricing?.gateway, event.model);
131
+ if (gatewayQuad) {
132
+ const priceRow = priceQuadToRecord(event.model, event.ts, gatewayQuad, event.billing_fn);
115
133
  const fn = BILLING_FNS[event.billing_fn];
116
134
  if (fn) {
117
135
  gatewayCost = fn(event, priceRow);
@@ -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) {
@@ -449,7 +449,10 @@ export function resolveCliEntry(packageRoot) {
449
449
  try {
450
450
  const require = createRequire(path.join(packageRoot, 'package.json'));
451
451
  const tsxUrl = pathToFileURL(require.resolve('tsx')).href;
452
- return { args: ['--import', tsxUrl, sourceEntry], usingSource: true, entry: sourceEntry };
452
+ const imports = process.platform === 'win32'
453
+ ? ['--import', 'data:text/javascript,globalThis.process.geteuid=()=>-1', '--import', tsxUrl]
454
+ : ['--import', tsxUrl];
455
+ return { args: [...imports, sourceEntry], usingSource: true, entry: sourceEntry };
453
456
  }
454
457
  catch {
455
458
  // tsx missing (e.g. `npm prune --production`): fall through to dist.
@@ -488,11 +491,37 @@ export function encodePath(projectPath) {
488
491
  /**
489
492
  * Cross-platform process liveness check.
490
493
  */
494
+ function readLinuxProcessState(pid) {
495
+ if (process.platform !== 'linux')
496
+ return null;
497
+ try {
498
+ const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
499
+ // The comm field may contain ')', so use the final closing parenthesis.
500
+ const closeParen = stat.lastIndexOf(')');
501
+ if (closeParen < 0)
502
+ return null;
503
+ return stat.slice(closeParen + 2, closeParen + 3) || null;
504
+ }
505
+ catch {
506
+ // Keep the kill(0) fallback below for permission and procfs races.
507
+ return null;
508
+ }
509
+ }
510
+ /** Return the Linux proc state (for example Z, D, S, or R), when available. */
511
+ export function getProcessState(pid) {
512
+ if (!Number.isInteger(pid) || pid <= 0)
513
+ return null;
514
+ return readLinuxProcessState(pid);
515
+ }
491
516
  export function isProcessRunning(pid) {
492
517
  if (!Number.isInteger(pid) || pid <= 0)
493
518
  return false;
494
519
  if (isWindows)
495
520
  return isWindowsProcessRunning(pid);
521
+ // A zombie has exited; only its unreaped process-table entry remains. A
522
+ // kill(pid, 0) probe alone reports such an entry as alive on Linux.
523
+ if (readLinuxProcessState(pid) === 'Z')
524
+ return false;
496
525
  try {
497
526
  process.kill(pid, 0);
498
527
  return true;