@kkelly-offical/kkcode 0.1.6 → 0.2.1

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 (163) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +452 -387
  3. package/package.json +50 -46
  4. package/src/agent/agent.mjs +19 -2
  5. package/src/agent/custom-agent-loader.mjs +6 -3
  6. package/src/agent/generator.mjs +2 -2
  7. package/src/agent/prompt/assistant.txt +12 -0
  8. package/src/agent/prompt/bug-hunter.txt +90 -0
  9. package/src/agent/prompt/frontend-designer.txt +58 -58
  10. package/src/agent/prompt/guide.txt +1 -1
  11. package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
  12. package/src/agent/prompt/longagent-coding-agent.txt +37 -37
  13. package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
  14. package/src/agent/prompt/longagent-preview-agent.txt +63 -63
  15. package/src/command/custom-commands.mjs +2 -2
  16. package/src/commands/agent.mjs +1 -1
  17. package/src/commands/background.mjs +145 -4
  18. package/src/commands/chat.mjs +117 -76
  19. package/src/commands/config.mjs +148 -1
  20. package/src/commands/doctor.mjs +30 -6
  21. package/src/commands/init.mjs +32 -6
  22. package/src/commands/longagent.mjs +117 -0
  23. package/src/commands/mcp.mjs +275 -43
  24. package/src/commands/permission.mjs +1 -1
  25. package/src/commands/session.mjs +195 -140
  26. package/src/commands/skill.mjs +63 -0
  27. package/src/commands/theme.mjs +1 -1
  28. package/src/config/defaults.mjs +280 -260
  29. package/src/config/import-config.mjs +1 -1
  30. package/src/config/load-config.mjs +61 -4
  31. package/src/config/schema.mjs +591 -574
  32. package/src/context.mjs +4 -1
  33. package/src/core/constants.mjs +97 -91
  34. package/src/core/types.mjs +1 -1
  35. package/src/github/api.mjs +78 -78
  36. package/src/github/auth.mjs +294 -286
  37. package/src/github/flow.mjs +298 -298
  38. package/src/github/workspace.mjs +225 -212
  39. package/src/index.mjs +84 -82
  40. package/src/knowledge/frontend-aesthetics.txt +38 -38
  41. package/src/mcp/client-http.mjs +139 -141
  42. package/src/mcp/client-sse.mjs +297 -288
  43. package/src/mcp/client-stdio.mjs +534 -533
  44. package/src/mcp/constants.mjs +2 -2
  45. package/src/mcp/registry.mjs +498 -479
  46. package/src/mcp/stdio-framing.mjs +135 -133
  47. package/src/mcp/tool-result.mjs +24 -24
  48. package/src/observability/edit-diagnostics.mjs +449 -0
  49. package/src/observability/index.mjs +42 -42
  50. package/src/observability/metrics.mjs +165 -137
  51. package/src/observability/tracer.mjs +137 -137
  52. package/src/onboarding.mjs +209 -0
  53. package/src/orchestration/background-manager.mjs +567 -372
  54. package/src/orchestration/background-worker.mjs +419 -305
  55. package/src/orchestration/interruption-reason.mjs +21 -0
  56. package/src/orchestration/longagent-manager.mjs +197 -171
  57. package/src/orchestration/stage-scheduler.mjs +733 -728
  58. package/src/orchestration/subagent-router.mjs +7 -1
  59. package/src/orchestration/task-scheduler.mjs +219 -7
  60. package/src/permission/engine.mjs +1 -1
  61. package/src/permission/exec-policy.mjs +370 -370
  62. package/src/permission/file-edit-policy.mjs +108 -0
  63. package/src/permission/prompt.mjs +1 -1
  64. package/src/permission/rules.mjs +116 -7
  65. package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
  66. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
  67. package/src/plugin/hook-bus.mjs +19 -5
  68. package/src/plugin/manifest-loader.mjs +222 -0
  69. package/src/provider/anthropic.mjs +396 -390
  70. package/src/provider/ollama.mjs +7 -1
  71. package/src/provider/openai.mjs +382 -340
  72. package/src/provider/retry-policy.mjs +74 -68
  73. package/src/provider/router.mjs +242 -241
  74. package/src/provider/sse.mjs +104 -104
  75. package/src/provider/wizard.mjs +556 -0
  76. package/src/repl/capability-facade.mjs +30 -0
  77. package/src/repl/command-surface.mjs +23 -0
  78. package/src/repl/controller-entry.mjs +40 -0
  79. package/src/repl/core-shell.mjs +208 -0
  80. package/src/repl/dialog-router.mjs +87 -0
  81. package/src/repl/input-engine.mjs +76 -0
  82. package/src/repl/keymap.mjs +7 -0
  83. package/src/repl/operator-surface.mjs +15 -0
  84. package/src/repl/permission-flow.mjs +49 -0
  85. package/src/repl/runtime-facade.mjs +36 -0
  86. package/src/repl/slash-router.mjs +62 -0
  87. package/src/repl/state-store.mjs +29 -0
  88. package/src/repl/turn-controller.mjs +58 -0
  89. package/src/repl/verification.mjs +23 -0
  90. package/src/repl.mjs +3368 -2929
  91. package/src/rules/load-rules.mjs +3 -3
  92. package/src/runtime.mjs +1 -1
  93. package/src/session/agent-transaction.mjs +86 -0
  94. package/src/session/checkpoint.mjs +302 -302
  95. package/src/session/compaction.mjs +36 -14
  96. package/src/session/engine.mjs +417 -227
  97. package/src/session/longagent-4stage.mjs +467 -460
  98. package/src/session/longagent-hybrid.mjs +1344 -1081
  99. package/src/session/longagent-plan.mjs +376 -365
  100. package/src/session/longagent-project-memory.mjs +53 -53
  101. package/src/session/longagent-scaffold.mjs +291 -291
  102. package/src/session/longagent-task-bus.mjs +138 -54
  103. package/src/session/longagent-utils.mjs +828 -472
  104. package/src/session/longagent.mjs +911 -884
  105. package/src/session/loop.mjs +1005 -905
  106. package/src/session/prompt/agent.txt +25 -0
  107. package/src/session/prompt/anthropic.txt +150 -150
  108. package/src/session/prompt/beast.txt +1 -1
  109. package/src/session/prompt/plan.txt +28 -6
  110. package/src/session/prompt/qwen.txt +46 -46
  111. package/src/session/recovery.mjs +21 -0
  112. package/src/session/rollback.mjs +197 -0
  113. package/src/session/routing-observability.mjs +72 -0
  114. package/src/session/runtime-state.mjs +47 -0
  115. package/src/session/store.mjs +523 -510
  116. package/src/session/system-prompt.mjs +56 -8
  117. package/src/session/task-validator.mjs +267 -267
  118. package/src/session/usability-gates.mjs +2 -2
  119. package/src/skill/builtin/commit.mjs +64 -64
  120. package/src/skill/builtin/design.mjs +76 -76
  121. package/src/skill/generator.mjs +18 -2
  122. package/src/skill/registry.mjs +642 -390
  123. package/src/storage/audit-store.mjs +18 -11
  124. package/src/storage/event-log.mjs +7 -1
  125. package/src/storage/ghost-commit-store.mjs +243 -245
  126. package/src/storage/paths.mjs +13 -0
  127. package/src/theme/default-theme.mjs +1 -1
  128. package/src/theme/markdown.mjs +4 -0
  129. package/src/theme/schema.mjs +1 -1
  130. package/src/theme/status-bar.mjs +162 -158
  131. package/src/tool/audit-wrapper.mjs +18 -2
  132. package/src/tool/edit-transaction.mjs +23 -0
  133. package/src/tool/executor.mjs +26 -1
  134. package/src/tool/file-read-state.mjs +65 -0
  135. package/src/tool/git-auto.mjs +526 -526
  136. package/src/tool/git-full-auto.mjs +487 -478
  137. package/src/tool/mutation-guard.mjs +54 -0
  138. package/src/tool/prompt/edit.txt +3 -3
  139. package/src/tool/prompt/multiedit.txt +1 -0
  140. package/src/tool/prompt/notebookedit.txt +2 -1
  141. package/src/tool/prompt/patch.txt +25 -24
  142. package/src/tool/prompt/read.txt +3 -3
  143. package/src/tool/prompt/sysinfo.txt +29 -0
  144. package/src/tool/prompt/task.txt +66 -4
  145. package/src/tool/prompt/write.txt +2 -2
  146. package/src/tool/question-prompt.mjs +17 -4
  147. package/src/tool/registry.mjs +1701 -1343
  148. package/src/tool/task-tool.mjs +14 -6
  149. package/src/ui/activity-renderer.mjs +667 -664
  150. package/src/ui/repl-background-panel.mjs +7 -0
  151. package/src/ui/repl-capability-panel.mjs +9 -0
  152. package/src/ui/repl-dashboard.mjs +54 -4
  153. package/src/ui/repl-help.mjs +110 -0
  154. package/src/ui/repl-operator-panel.mjs +12 -0
  155. package/src/ui/repl-route-feedback.mjs +35 -0
  156. package/src/ui/repl-status-view.mjs +76 -0
  157. package/src/ui/repl-task-panel.mjs +5 -0
  158. package/src/ui/repl-transcript-panel.mjs +56 -0
  159. package/src/ui/repl-turn-summary.mjs +135 -0
  160. package/src/usage/pricing.mjs +122 -121
  161. package/src/usage/usage-meter.mjs +1 -0
  162. package/src/util/git.mjs +562 -519
  163. package/src/util/template.mjs +6 -1
@@ -1,121 +1,122 @@
1
- import path from "node:path"
2
- import { access, readFile } from "node:fs/promises"
3
- import YAML from "yaml"
4
-
5
- const DEFAULT_PRICING = {
6
- currency: "USD",
7
- per_tokens: 1000000,
8
- models: {
9
- "claude-opus-4-6": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
10
- "claude-opus-4-5": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
11
- "claude-opus-4-1": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
12
- "claude-opus-4": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
13
- "claude-sonnet-4-6": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
14
- "claude-sonnet-4-5": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
15
- "claude-sonnet-4": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
16
- "claude-haiku-4-5": { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 },
17
- "claude-haiku-3-5": { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 },
18
- "gpt-5.3-codex": { input: 15, output: 60, cache_read: 7.5, cache_write: 15 },
19
- "gpt-4o": { input: 2.5, output: 10, cache_read: 1.25, cache_write: 2.5 },
20
- "gpt-4o-mini": { input: 0.15, output: 0.6, cache_read: 0.075, cache_write: 0.15 },
21
- "deepseek-chat": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
22
- "deepseek-coder": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
23
- "deepseek-v3.1-terminus": { input: 0.55, output: 1.65, cache_read: 0.07, cache_write: 0.55 },
24
- "deepseek-v3.2": { input: 0.28, output: 0.41, cache_read: 0.03, cache_write: 0.28 },
25
- "kimi-k2.5": { input: 0.55, output: 2.9, cache_read: 0, cache_write: 0 },
26
- "kimi-k2-0905": { input: 0.55, output: 2.2, cache_read: 0.14, cache_write: 0 },
27
- "qwen-plus": { input: 0.11, output: 1.11, cache_read: 0.02, cache_write: 0 },
28
- "qwen-max": { input: 0.33, output: 1.33, cache_read: 0.07, cache_write: 0 },
29
- "qwen-turbo": { input: 0.04, output: 0.08, cache_read: 0.01, cache_write: 0 },
30
- "qwen3-coder-plus": { input: 0.55, output: 2.2, cache_read: 0.11, cache_write: 0 },
31
- "qwen3-coder-flash": { input: 0.14, output: 0.55, cache_read: 0.03, cache_write: 0 },
32
- "qwen3-coder-480b-a35b": { input: 0.83, output: 3.3, cache_read: 0.17, cache_write: 0 },
33
- "doubao-seed-2.0-code": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
34
- "doubao-seed-2.0-pro": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
35
- "doubao-seed-1.8": { input: 0.11, output: 1.1, cache_read: 0, cache_write: 0 },
36
- "doubao-seed-code": { input: 0.17, output: 1.1, cache_read: 0, cache_write: 0 },
37
- "minimax-m2.5": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
38
- "minimax-m2.5-highspeed": { input: 0.58, output: 2.32, cache_read: 0.03, cache_write: 0 },
39
- "minimax-m2.1": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
40
- "minimax-m2": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
41
- "glm-5": { input: 0.55, output: 3.05, cache_read: 0, cache_write: 0 },
42
- "glm-4.7": { input: 0.41, output: 1.93, cache_read: 0, cache_write: 0 },
43
- "glm-4.6": { input: 0.28, output: 1.1, cache_read: 0, cache_write: 0 }
44
- },
45
- default: {
46
- input: 3,
47
- output: 15,
48
- cache_read: 0.3,
49
- cache_write: 3.75
50
- }
51
- }
52
-
53
- async function exists(file) {
54
- try {
55
- await access(file)
56
- return true
57
- } catch {
58
- return false
59
- }
60
- }
61
-
62
- function parse(file, raw) {
63
- if (file.endsWith(".json")) return JSON.parse(raw)
64
- return YAML.parse(raw)
65
- }
66
-
67
- function resolvePricingPath(configState) {
68
- const projectPath = configState.source.projectRaw?.usage?.pricing_file
69
- if (typeof projectPath === "string" && projectPath.trim()) {
70
- return path.resolve(configState.source.projectDir ?? process.cwd(), projectPath)
71
- }
72
- const userPath = configState.source.userRaw?.usage?.pricing_file
73
- if (typeof userPath === "string" && userPath.trim()) {
74
- return path.resolve(configState.source.userDir ?? process.cwd(), userPath)
75
- }
76
- return null
77
- }
78
-
79
- export async function loadPricing(configState) {
80
- const file = resolvePricingPath(configState)
81
- if (!file || !(await exists(file))) {
82
- return { pricing: DEFAULT_PRICING, source: "default", errors: [] }
83
- }
84
- try {
85
- const raw = await readFile(file, "utf8")
86
- const parsed = parse(file, raw)
87
- const pricing = {
88
- ...DEFAULT_PRICING,
89
- ...parsed,
90
- default: { ...DEFAULT_PRICING.default, ...(parsed.default ?? {}) }
91
- }
92
- return { pricing, source: file, errors: [] }
93
- } catch (error) {
94
- return { pricing: DEFAULT_PRICING, source: "default", errors: [`${file}: ${error.message}`] }
95
- }
96
- }
97
-
98
- function findPricingEntry(models, model) {
99
- if (models[model]) return models[model]
100
- // Fuzzy: try prefix match (e.g. "claude-opus-4-6-20250601" → "claude-opus-4-6")
101
- const m = String(model).toLowerCase()
102
- for (const key of Object.keys(models)) {
103
- if (m.startsWith(key)) return models[key]
104
- }
105
- return null
106
- }
107
-
108
- export function calculateCost(pricing, model, usage) {
109
- const entry = findPricingEntry(pricing.models, model) ?? pricing.default
110
- const per = pricing.per_tokens || 1000000
111
- // All providers normalize input to non-cached tokens only (see provider/*.mjs)
112
- const amount =
113
- ((usage.input || 0) * (entry.input || 0) +
114
- (usage.output || 0) * (entry.output || 0) +
115
- (usage.cacheRead || 0) * (entry.cache_read || 0) +
116
- (usage.cacheWrite || 0) * (entry.cache_write || 0)) /
117
- per
118
- const savings = ((usage.cacheRead || 0) * ((entry.input || 0) - (entry.cache_read || 0))) / per
119
- const unknown = !findPricingEntry(pricing.models, model)
120
- return { amount, savings, unknown, currency: pricing.currency }
121
- }
1
+ import path from "node:path"
2
+ import { access, readFile } from "node:fs/promises"
3
+ import YAML from "yaml"
4
+
5
+ const DEFAULT_PRICING = {
6
+ currency: "USD",
7
+ per_tokens: 1000000,
8
+ models: {
9
+ "claude-opus-4-6": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
10
+ "claude-opus-4-5": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
11
+ "claude-opus-4-1": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
12
+ "claude-opus-4": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
13
+ "claude-sonnet-4-6": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
14
+ "claude-sonnet-4-5": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
15
+ "claude-sonnet-4": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
16
+ "claude-haiku-4-5": { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 },
17
+ "claude-haiku-3-5": { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 },
18
+ "gpt-5.3-codex": { input: 15, output: 60, cache_read: 7.5, cache_write: 15 },
19
+ "gpt-4o": { input: 2.5, output: 10, cache_read: 1.25, cache_write: 2.5 },
20
+ "gpt-4o-mini": { input: 0.15, output: 0.6, cache_read: 0.075, cache_write: 0.15 },
21
+ "deepseek-chat": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
22
+ "deepseek-coder": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
23
+ "deepseek-v3.1-terminus": { input: 0.55, output: 1.65, cache_read: 0.07, cache_write: 0.55 },
24
+ "deepseek-v3.2": { input: 0.28, output: 0.41, cache_read: 0.03, cache_write: 0.28 },
25
+ "kimi-k2.5": { input: 0.55, output: 2.9, cache_read: 0, cache_write: 0 },
26
+ "kimi-k2-0905": { input: 0.55, output: 2.2, cache_read: 0.14, cache_write: 0 },
27
+ "qwen-plus": { input: 0.11, output: 1.11, cache_read: 0.02, cache_write: 0 },
28
+ "qwen-max": { input: 0.33, output: 1.33, cache_read: 0.07, cache_write: 0 },
29
+ "qwen-turbo": { input: 0.04, output: 0.08, cache_read: 0.01, cache_write: 0 },
30
+ "qwen3-coder-plus": { input: 0.55, output: 2.2, cache_read: 0.11, cache_write: 0 },
31
+ "qwen3-coder-flash": { input: 0.14, output: 0.55, cache_read: 0.03, cache_write: 0 },
32
+ "qwen3-coder-480b-a35b": { input: 0.83, output: 3.3, cache_read: 0.17, cache_write: 0 },
33
+ "doubao-seed-2.0-code": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
34
+ "doubao-seed-2.0-pro": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
35
+ "doubao-seed-1.8": { input: 0.11, output: 1.1, cache_read: 0, cache_write: 0 },
36
+ "doubao-seed-code": { input: 0.17, output: 1.1, cache_read: 0, cache_write: 0 },
37
+ "minimax-m2.5": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
38
+ "minimax-m2.5-highspeed": { input: 0.58, output: 2.32, cache_read: 0.03, cache_write: 0 },
39
+ "minimax-m2.1": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
40
+ "minimax-m2": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
41
+ "glm-5": { input: 0.55, output: 3.05, cache_read: 0, cache_write: 0 },
42
+ "glm-4.7": { input: 0.41, output: 1.93, cache_read: 0, cache_write: 0 },
43
+ "glm-4.6": { input: 0.28, output: 1.1, cache_read: 0, cache_write: 0 }
44
+ },
45
+ default: {
46
+ input: 3,
47
+ output: 15,
48
+ cache_read: 0.3,
49
+ cache_write: 3.75
50
+ }
51
+ }
52
+
53
+ async function exists(file) {
54
+ try {
55
+ await access(file)
56
+ return true
57
+ } catch {
58
+ return false
59
+ }
60
+ }
61
+
62
+ function parse(file, raw) {
63
+ if (file.endsWith(".json")) return JSON.parse(raw)
64
+ return YAML.parse(raw)
65
+ }
66
+
67
+ function resolvePricingPath(configState) {
68
+ const projectPath = configState.source.projectRaw?.usage?.pricing_file
69
+ if (typeof projectPath === "string" && projectPath.trim()) {
70
+ return path.resolve(configState.source.projectDir ?? process.cwd(), projectPath)
71
+ }
72
+ const userPath = configState.source.userRaw?.usage?.pricing_file
73
+ if (typeof userPath === "string" && userPath.trim()) {
74
+ return path.resolve(configState.source.userDir ?? process.cwd(), userPath)
75
+ }
76
+ return null
77
+ }
78
+
79
+ export async function loadPricing(configState) {
80
+ const file = resolvePricingPath(configState)
81
+ if (!file || !(await exists(file))) {
82
+ return { pricing: DEFAULT_PRICING, source: "default", errors: [] }
83
+ }
84
+ try {
85
+ const raw = await readFile(file, "utf8")
86
+ const parsed = parse(file, raw)
87
+ const pricing = {
88
+ ...DEFAULT_PRICING,
89
+ ...parsed,
90
+ models: { ...DEFAULT_PRICING.models, ...(parsed.models ?? {}) },
91
+ default: { ...DEFAULT_PRICING.default, ...(parsed.default ?? {}) }
92
+ }
93
+ return { pricing, source: file, errors: [] }
94
+ } catch (error) {
95
+ return { pricing: DEFAULT_PRICING, source: "default", errors: [`${file}: ${error.message}`] }
96
+ }
97
+ }
98
+
99
+ function findPricingEntry(models, model) {
100
+ if (models[model]) return models[model]
101
+ // Fuzzy: try prefix match (e.g. "claude-opus-4-6-20250601" → "claude-opus-4-6")
102
+ const m = String(model).toLowerCase()
103
+ for (const key of Object.keys(models)) {
104
+ if (m.startsWith(key)) return models[key]
105
+ }
106
+ return null
107
+ }
108
+
109
+ export function calculateCost(pricing, model, usage) {
110
+ const entry = findPricingEntry(pricing.models, model) ?? pricing.default
111
+ const per = pricing.per_tokens || 1000000
112
+ // All providers normalize input to non-cached tokens only (see provider/*.mjs)
113
+ const amount =
114
+ ((usage.input || 0) * (entry.input || 0) +
115
+ (usage.output || 0) * (entry.output || 0) +
116
+ (usage.cacheRead || 0) * (entry.cache_read || 0) +
117
+ (usage.cacheWrite || 0) * (entry.cache_write || 0)) /
118
+ per
119
+ const savings = ((usage.cacheRead || 0) * ((entry.input || 0) - (entry.cache_read || 0))) / per
120
+ const unknown = !findPricingEntry(pricing.models, model)
121
+ return { amount, savings, unknown, currency: pricing.currency }
122
+ }
@@ -80,6 +80,7 @@ export async function resetUsage(sessionId = null) {
80
80
  return
81
81
  }
82
82
  const store = await readUsageStore()
83
+ maybeRotateGlobal(store)
83
84
  delete store.sessions[sessionId]
84
85
  store.global = emptyUsage()
85
86
  for (const session of Object.values(store.sessions)) {