mixdog 0.8.0 → 0.9.0

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 (285) hide show
  1. package/README.md +47 -23
  2. package/package.json +33 -27
  3. package/scripts/_test-folder-dialog.mjs +30 -0
  4. package/scripts/agent-parallel-smoke.mjs +388 -0
  5. package/scripts/agent-tag-reuse-smoke.mjs +183 -0
  6. package/scripts/background-task-meta-smoke.mjs +38 -0
  7. package/scripts/boot-smoke.mjs +52 -9
  8. package/scripts/build-runtime-linux.sh +348 -0
  9. package/scripts/build-runtime-macos.sh +217 -0
  10. package/scripts/build-runtime-windows.ps1 +242 -0
  11. package/scripts/compact-active-turn-test.mjs +68 -0
  12. package/scripts/compact-smoke.mjs +859 -129
  13. package/scripts/compact-trigger-migration-smoke.mjs +187 -0
  14. package/scripts/fix-brief-fn.mjs +35 -0
  15. package/scripts/fix-format-tool-surface.mjs +24 -0
  16. package/scripts/fix-tool-exec-visible.mjs +42 -0
  17. package/scripts/generate-runtime-manifest.mjs +166 -0
  18. package/scripts/hook-bus-test.mjs +330 -0
  19. package/scripts/lead-workflow-smoke.mjs +33 -39
  20. package/scripts/live-worker-smoke.mjs +43 -37
  21. package/scripts/llm-trace-summary.mjs +315 -0
  22. package/scripts/memory-meta-concurrency-test.mjs +20 -0
  23. package/scripts/output-style-smoke.mjs +56 -15
  24. package/scripts/parent-abort-link-test.mjs +44 -0
  25. package/scripts/patch-agent-brief.mjs +48 -0
  26. package/scripts/patch-app.mjs +21 -0
  27. package/scripts/patch-app2.mjs +18 -0
  28. package/scripts/patch-dist-brief.mjs +96 -0
  29. package/scripts/patch-tool-exec.mjs +70 -0
  30. package/scripts/pretool-ask-runtime-test.mjs +54 -0
  31. package/scripts/provider-toolcall-test.mjs +376 -0
  32. package/scripts/reactive-compact-persist-smoke.mjs +124 -0
  33. package/scripts/sanitize-tool-pairs-test.mjs +260 -0
  34. package/scripts/session-context-bench.mjs +344 -0
  35. package/scripts/session-ingest-smoke.mjs +177 -0
  36. package/scripts/set-effort-config-test.mjs +41 -0
  37. package/scripts/smoke-runtime-negative.ps1 +106 -0
  38. package/scripts/smoke-runtime-negative.sh +97 -0
  39. package/scripts/smoke.mjs +25 -0
  40. package/scripts/tool-result-hook-test.mjs +48 -0
  41. package/scripts/tool-smoke.mjs +1223 -95
  42. package/scripts/toolcall-args-test.mjs +150 -0
  43. package/scripts/tui-background-failure-smoke.mjs +73 -0
  44. package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
  45. package/src/agents/debugger/AGENT.md +8 -0
  46. package/src/agents/explore/AGENT.md +4 -0
  47. package/src/agents/heavy-worker/AGENT.md +9 -3
  48. package/src/agents/maintainer/AGENT.md +4 -0
  49. package/src/agents/reviewer/AGENT.md +8 -0
  50. package/src/agents/scheduler-task/AGENT.md +12 -0
  51. package/src/agents/scheduler-task/agent.json +6 -0
  52. package/src/agents/webhook-handler/AGENT.md +12 -0
  53. package/src/agents/webhook-handler/agent.json +6 -0
  54. package/src/agents/worker/AGENT.md +9 -3
  55. package/src/app.mjs +77 -3
  56. package/src/defaults/hidden-roles.json +17 -12
  57. package/src/headless-role.mjs +117 -0
  58. package/src/help.mjs +30 -0
  59. package/src/hooks/lib/permission-evaluator.cjs +11 -475
  60. package/src/lib/keychain-cjs.cjs +9 -1
  61. package/src/lib/mixdog-debug.cjs +0 -7
  62. package/src/lib/rules-builder.cjs +240 -96
  63. package/src/lib/text-utils.cjs +1 -1
  64. package/src/mixdog-session-runtime.mjs +2325 -450
  65. package/src/output-styles/default.md +12 -28
  66. package/src/output-styles/extreme-simple.md +9 -6
  67. package/src/output-styles/simple.md +22 -9
  68. package/src/repl.mjs +118 -59
  69. package/src/rules/agent/00-common.md +15 -0
  70. package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
  71. package/src/rules/agent/30-explorer.md +22 -0
  72. package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
  73. package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
  74. package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
  75. package/src/rules/lead/01-general.md +9 -5
  76. package/src/rules/lead/04-workflow.md +51 -12
  77. package/src/rules/lead/lead-tool.md +6 -0
  78. package/src/rules/shared/01-tool.md +12 -1
  79. package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
  80. package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
  81. package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
  82. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
  83. package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
  84. package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
  85. package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
  86. package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
  87. package/src/runtime/agent/orchestrator/config.mjs +174 -55
  88. package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
  89. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
  90. package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
  91. package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
  92. package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
  93. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
  94. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
  95. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
  96. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
  97. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
  99. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
  100. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
  101. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
  102. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
  103. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
  106. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
  107. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
  109. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
  110. package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
  111. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
  112. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
  113. package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +4 -4
  114. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +1 -1
  115. package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
  116. package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
  117. package/src/runtime/agent/orchestrator/session/loop.mjs +851 -674
  118. package/src/runtime/agent/orchestrator/session/manager.mjs +1593 -466
  119. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
  120. package/src/runtime/agent/orchestrator/session/store.mjs +291 -46
  121. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
  123. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
  124. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
  125. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
  126. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
  127. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
  128. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
  129. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
  130. package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
  131. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
  132. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
  133. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
  134. package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
  136. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
  137. package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
  138. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
  139. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
  140. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
  141. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
  142. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
  143. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
  144. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +1 -1
  145. package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
  146. package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
  147. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
  148. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
  149. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
  150. package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
  151. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
  152. package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
  153. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
  154. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
  155. package/src/runtime/channels/index.mjs +152 -24
  156. package/src/runtime/channels/lib/scheduler.mjs +18 -14
  157. package/src/runtime/channels/lib/session-discovery.mjs +3 -2
  158. package/src/runtime/channels/lib/tool-format.mjs +0 -2
  159. package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
  160. package/src/runtime/channels/lib/webhook.mjs +1 -1
  161. package/src/runtime/channels/tool-defs.mjs +29 -29
  162. package/src/runtime/memory/index.mjs +635 -107
  163. package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
  164. package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
  165. package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
  166. package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
  167. package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
  168. package/src/runtime/memory/lib/memory-cycle1.mjs +38 -17
  169. package/src/runtime/memory/lib/memory-cycle2.mjs +6 -7
  170. package/src/runtime/memory/lib/memory-cycle3.mjs +4 -4
  171. package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
  172. package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
  173. package/src/runtime/memory/lib/memory.mjs +88 -9
  174. package/src/runtime/memory/lib/model-profile.mjs +1 -1
  175. package/src/runtime/memory/lib/pg/adapter.mjs +15 -1
  176. package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
  177. package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
  178. package/src/runtime/memory/lib/session-ingest.mjs +194 -0
  179. package/src/runtime/memory/lib/trace-store.mjs +96 -51
  180. package/src/runtime/memory/tool-defs.mjs +46 -37
  181. package/src/runtime/search/index.mjs +102 -466
  182. package/src/runtime/search/lib/web-tools.mjs +45 -25
  183. package/src/runtime/search/tool-defs.mjs +16 -23
  184. package/src/runtime/shared/abort-controller.mjs +1 -1
  185. package/src/runtime/shared/atomic-file.mjs +4 -3
  186. package/src/runtime/shared/background-tasks.mjs +122 -11
  187. package/src/runtime/shared/child-spawn-gate.mjs +145 -0
  188. package/src/runtime/shared/config.mjs +7 -4
  189. package/src/runtime/shared/err-text.mjs +131 -4
  190. package/src/runtime/shared/llm/cost.mjs +2 -2
  191. package/src/runtime/shared/llm/http-agent.mjs +23 -7
  192. package/src/runtime/shared/llm/index.mjs +34 -11
  193. package/src/runtime/shared/llm/usage-log.mjs +4 -4
  194. package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
  195. package/src/runtime/shared/singleton-owner.mjs +104 -0
  196. package/src/runtime/shared/tool-execution-contract.mjs +199 -20
  197. package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
  198. package/src/runtime/shared/tool-surface.mjs +624 -98
  199. package/src/runtime/shared/user-data-guard.mjs +0 -2
  200. package/src/standalone/agent-task-status.mjs +203 -0
  201. package/src/standalone/agent-task-status.test.mjs +76 -0
  202. package/src/standalone/agent-tool.mjs +1913 -0
  203. package/src/standalone/channel-worker.mjs +370 -14
  204. package/src/standalone/explore-tool.mjs +165 -70
  205. package/src/standalone/folder-dialog.mjs +314 -0
  206. package/src/standalone/hook-bus.mjs +898 -22
  207. package/src/standalone/memory-runtime-proxy.mjs +320 -0
  208. package/src/standalone/projects.mjs +226 -0
  209. package/src/standalone/provider-admin.mjs +41 -24
  210. package/src/standalone/seeds.mjs +2 -69
  211. package/src/standalone/usage-dashboard.mjs +96 -8
  212. package/src/tui/App.jsx +4798 -2153
  213. package/src/tui/components/AnsiText.jsx +39 -28
  214. package/src/tui/components/ContextPanel.jsx +87 -29
  215. package/src/tui/components/Markdown.jsx +43 -77
  216. package/src/tui/components/MarkdownTable.jsx +9 -184
  217. package/src/tui/components/Message.jsx +28 -11
  218. package/src/tui/components/Picker.jsx +95 -56
  219. package/src/tui/components/PromptInput.jsx +367 -239
  220. package/src/tui/components/QueuedCommands.jsx +1 -1
  221. package/src/tui/components/SlashCommandPalette.jsx +27 -21
  222. package/src/tui/components/Spinner.jsx +67 -38
  223. package/src/tui/components/StatusLine.jsx +606 -38
  224. package/src/tui/components/TextEntryPanel.jsx +128 -9
  225. package/src/tui/components/ToolExecution.jsx +617 -368
  226. package/src/tui/components/TurnDone.jsx +3 -3
  227. package/src/tui/components/UsagePanel.jsx +3 -5
  228. package/src/tui/components/tool-output-format.mjs +365 -0
  229. package/src/tui/components/tool-output-format.test.mjs +220 -0
  230. package/src/tui/dist/index.mjs +8915 -2418
  231. package/src/tui/engine-runtime-notification.test.mjs +115 -0
  232. package/src/tui/engine-tool-result-text.test.mjs +75 -0
  233. package/src/tui/engine.mjs +1455 -279
  234. package/src/tui/figures.mjs +21 -40
  235. package/src/tui/index.jsx +75 -31
  236. package/src/tui/input-editing.mjs +25 -0
  237. package/src/tui/markdown/format-token.mjs +511 -68
  238. package/src/tui/markdown/format-token.test.mjs +216 -0
  239. package/src/tui/markdown/render-ansi.mjs +94 -0
  240. package/src/tui/markdown/render-ansi.test.mjs +108 -0
  241. package/src/tui/markdown/stream-fence.mjs +34 -0
  242. package/src/tui/markdown/stream-fence.test.mjs +26 -0
  243. package/src/tui/markdown/table-layout.mjs +250 -0
  244. package/src/tui/paste-attachments.mjs +0 -7
  245. package/src/tui/spinner-verbs.mjs +1 -2
  246. package/src/tui/statusline-ansi-bridge.mjs +172 -0
  247. package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
  248. package/src/tui/theme.mjs +746 -24
  249. package/src/tui/time-format.mjs +1 -1
  250. package/src/tui/transcript-tool-failures.mjs +67 -0
  251. package/src/tui/transcript-tool-failures.test.mjs +111 -0
  252. package/src/ui/ansi.mjs +1 -2
  253. package/src/ui/markdown.mjs +85 -26
  254. package/src/ui/markdown.test.mjs +70 -0
  255. package/src/ui/model-display.mjs +121 -0
  256. package/src/ui/session-stats.mjs +44 -0
  257. package/src/ui/statusline-context-label.test.mjs +15 -0
  258. package/src/ui/statusline.mjs +386 -178
  259. package/src/ui/tool-card.mjs +3 -16
  260. package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
  261. package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
  262. package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
  263. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
  264. package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
  265. package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
  266. package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
  267. package/src/workflows/default/WORKFLOW.md +12 -5
  268. package/src/workflows/default/workflow.json +0 -1
  269. package/src/workflows/solo/WORKFLOW.md +15 -0
  270. package/src/workflows/solo/workflow.json +7 -0
  271. package/vendor/ink/build/output.js +6 -1
  272. package/src/agents/scheduler-task.md +0 -3
  273. package/src/agents/web-researcher/AGENT.md +0 -3
  274. package/src/agents/web-researcher/agent.json +0 -6
  275. package/src/agents/webhook-handler.md +0 -3
  276. package/src/rules/bridge/00-common.md +0 -5
  277. package/src/rules/bridge/30-explorer.md +0 -4
  278. package/src/rules/lead/00-tool-lead.md +0 -5
  279. package/src/rules/shared/00-language.md +0 -3
  280. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  281. package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
  282. package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
  283. package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
  284. package/src/standalone/bridge-tool.mjs +0 -1414
  285. package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
@@ -1,60 +1,7 @@
1
- import { copyFileSync, existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs';
2
- import { dirname, join, resolve } from 'node:path';
1
+ import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
3
 
4
4
  const DEFAULT_DATA_FILES = [];
5
- const DEFAULT_MIXDOG_MD = `# Mixdog Instructions
6
-
7
- Use this file for Mixdog-specific user and project context.
8
-
9
- - Keep stable preferences, workflow notes, and project conventions here.
10
- - Mixdog loads this file as context for new sessions.
11
- - Edit or replace this content at any time.
12
- `;
13
-
14
- const DEFAULT_PROJECT_MIXDOG_MD = `# Mixdog Instructions
15
-
16
- Use this file for project-specific Mixdog context.
17
-
18
- - Add stable project conventions, commands, and workflow notes here.
19
- - Mixdog loads this file from the project root for new sessions.
20
- - Edit or replace this content at any time.
21
- `;
22
-
23
- function isDirectory(path) {
24
- try {
25
- return statSync(path).isDirectory();
26
- } catch {
27
- return false;
28
- }
29
- }
30
-
31
- function hasProjectSentinel(dir) {
32
- return existsSync(join(dir, '.git'))
33
- || existsSync(join(dir, 'package.json'))
34
- || existsSync(join(dir, 'pyproject.toml'))
35
- || existsSync(join(dir, 'Cargo.toml'))
36
- || existsSync(join(dir, 'go.mod'))
37
- || existsSync(join(dir, 'mixdog.md'))
38
- || existsSync(join(dir, 'Mixdog.md'))
39
- || existsSync(join(dir, 'AGENTS.md'));
40
- }
41
-
42
- function resolveProjectRoot(cwd) {
43
- if (!cwd || typeof cwd !== 'string') return null;
44
- let cur;
45
- try {
46
- cur = resolve(cwd);
47
- } catch {
48
- return null;
49
- }
50
- if (!isDirectory(cur)) return null;
51
- while (true) {
52
- if (hasProjectSentinel(cur)) return cur;
53
- const parent = dirname(cur);
54
- if (parent === cur) return null;
55
- cur = parent;
56
- }
57
- }
58
5
 
59
6
  export function ensureStandaloneEnvironment({ rootDir, dataDir }) {
60
7
  if (!rootDir) throw new Error('standalone rootDir is required');
@@ -70,10 +17,6 @@ export function ensureStandaloneEnvironment({ rootDir, dataDir }) {
70
17
  process.env.MIXDOG_PATCH_NATIVE_PREWARM ??= '0';
71
18
 
72
19
  mkdirSync(dataDir, { recursive: true });
73
- const mixdogMdPath = join(dataDir, 'mixdog.md');
74
- if (!existsSync(mixdogMdPath)) {
75
- writeFileSync(mixdogMdPath, DEFAULT_MIXDOG_MD, { encoding: 'utf8', mode: 0o600 });
76
- }
77
20
  for (const file of DEFAULT_DATA_FILES) {
78
21
  const from = join(rootDir, 'defaults', file);
79
22
  const to = join(dataDir, file);
@@ -82,13 +25,3 @@ export function ensureStandaloneEnvironment({ rootDir, dataDir }) {
82
25
  copyFileSync(from, to);
83
26
  }
84
27
  }
85
-
86
- export function ensureProjectMixdogMd({ cwd } = {}) {
87
- const projectRoot = resolveProjectRoot(cwd);
88
- if (!projectRoot) return null;
89
- const target = join(projectRoot, 'Mixdog.md');
90
- if (!existsSync(target)) {
91
- writeFileSync(target, DEFAULT_PROJECT_MIXDOG_MD, { encoding: 'utf8', mode: 0o600 });
92
- }
93
- return target;
94
- }
@@ -122,6 +122,23 @@ function snapshotUsage(snapshot) {
122
122
  };
123
123
  }
124
124
 
125
+ function snapshotTokenUsage(snapshot) {
126
+ const value = snapshot?.tokenUsage;
127
+ if (!value || typeof value !== 'object') return null;
128
+ const inputTokens = num(value.inputTokens ?? value.input_tokens, 0);
129
+ const outputTokens = num(value.outputTokens ?? value.output_tokens, 0);
130
+ const cachedInputTokens = num(value.cachedInputTokens ?? value.cached_input_tokens, 0);
131
+ const requests = num(value.requests ?? value.numModelRequests ?? value.num_model_requests, 0);
132
+ if (!inputTokens && !outputTokens && !cachedInputTokens && !requests) return null;
133
+ return {
134
+ inputTokens,
135
+ outputTokens,
136
+ cachedInputTokens,
137
+ requests,
138
+ source: clean(value.source) || clean(snapshot?.source) || 'provider-api',
139
+ };
140
+ }
141
+
125
142
  function displayWindow(w) {
126
143
  const label = String(w?.label || 'USE').toUpperCase();
127
144
  if (num(w?.remainingUsd, null) !== null) return `${label} ${money(w.remainingUsd)}`;
@@ -135,8 +152,8 @@ function displayWindow(w) {
135
152
 
136
153
  function providerDescription(id, group) {
137
154
  switch (String(id || '').toLowerCase()) {
138
- case 'openai-oauth': return 'ChatGPT/Codex subscription quota';
139
- case 'anthropic-oauth': return 'Claude Code subscription quota';
155
+ case 'openai-oauth': return 'OpenAI OAuth subscription quota';
156
+ case 'anthropic-oauth': return 'Anthropic OAuth subscription quota';
140
157
  case 'grok-oauth': return 'Grok Build subscription quota';
141
158
  case 'opencode-go': return 'OpenCode Go subscription quota';
142
159
  case 'openai': return 'OpenAI API billing';
@@ -150,6 +167,42 @@ function providerDescription(id, group) {
150
167
  }
151
168
  }
152
169
 
170
+ function snapshotUnavailable(snapshot) {
171
+ const value = snapshot?.unavailable;
172
+ return value && typeof value === 'object' ? value : null;
173
+ }
174
+
175
+ function apiUnavailableDetail(id, snapshot) {
176
+ const providerId = String(id || '').toLowerCase();
177
+ const unavailable = snapshotUnavailable(snapshot);
178
+ const message = clean(unavailable?.message);
179
+ if (providerId === 'openai') {
180
+ if (/invalid|incorrect api key|unauthorized/i.test(message)) return `OpenAI usage probe failed: ${message}`;
181
+ if (/api\.usage\.read|insufficient permissions/i.test(message)) {
182
+ return 'OpenAI spend needs api.usage.read; remaining credit is web UI only';
183
+ }
184
+ if (message) return `OpenAI usage probe failed: ${message}; remaining credit is web UI only`;
185
+ return 'OpenAI API does not expose remaining credit; org spend needs api.usage.read';
186
+ }
187
+ if (providerId === 'anthropic') {
188
+ if (message) return `Anthropic cost probe: ${message}`;
189
+ return 'Anthropic balance is Console-only; usage needs ANTHROPIC_ADMIN_API_KEY';
190
+ }
191
+ if (providerId === 'gemini') return 'Gemini balance is AI Studio/Cloud Billing only; no key-scope probe';
192
+ if (providerId === 'xai') return message || 'xAI balance needs XAI_MANAGEMENT_API_KEY and XAI_TEAM_ID';
193
+ if (providerId === 'deepseek') return message ? `DeepSeek balance unavailable: ${message}` : 'DeepSeek balance unavailable';
194
+ return message || 'Usage not exposed';
195
+ }
196
+
197
+ function applyApiUnavailable(row, id, snapshot) {
198
+ row.status = 'hidden';
199
+ row.source = snapshotUnavailable(snapshot) ? 'provider-api-unavailable' : 'provider-hidden';
200
+ row.sourceLabel = 'unavailable';
201
+ row.primary = '';
202
+ row.detail = apiUnavailableDetail(id, snapshot);
203
+ return row;
204
+ }
205
+
153
206
  function rowTone(row) {
154
207
  if (row.status === 'error') return 'error';
155
208
  if (row.status === 'missing') return 'missing';
@@ -263,6 +316,19 @@ function applyKnownUsage(row, known) {
263
316
  return row;
264
317
  }
265
318
 
319
+ function applyTokenUsage(row, usage) {
320
+ if (!usage) return row;
321
+ const totalTokens = num(usage.inputTokens, 0) + num(usage.outputTokens, 0);
322
+ row.status = 'partial';
323
+ row.source = usage.source || 'provider-api';
324
+ row.sourceLabel = 'usage';
325
+ row.primary = `${compactNumber(totalTokens)} tokens`;
326
+ row.detail = `${compactNumber(usage.inputTokens)} in · ${compactNumber(usage.outputTokens)} out${usage.requests ? ` · ${compactNumber(usage.requests)} req` : ''}`;
327
+ row.includeInTotal = false;
328
+ row.totalBucket = null;
329
+ return row;
330
+ }
331
+
266
332
  function applyWindowQuota(row, windows, { source = 'quota', detail = 'quota windows' } = {}) {
267
333
  const normalized = normaliseWindows(windows, source);
268
334
  if (!normalized.length) return false;
@@ -341,6 +407,7 @@ export async function createUsageDashboard(config = {}, options = {}) {
341
407
  const rows = [];
342
408
  const checkedAt = Date.now();
343
409
  const refresh = options.refresh === true;
410
+ const preview = options.preview === true;
344
411
  const emit = (checking = true) => emitUsageDashboard(
345
412
  options,
346
413
  usageDashboardSnapshot(rows, { checkedAt, refresh, checking }),
@@ -358,6 +425,10 @@ export async function createUsageDashboard(config = {}, options = {}) {
358
425
  rows.push(row);
359
426
  emit(true);
360
427
 
428
+ if (preview) {
429
+ return row;
430
+ }
431
+
361
432
  if (!row.authenticated) {
362
433
  row.status = 'missing';
363
434
  row.source = 'not-configured';
@@ -366,6 +437,7 @@ export async function createUsageDashboard(config = {}, options = {}) {
366
437
  row.detail = 'Configure auth';
367
438
  } else {
368
439
  let hasQuota = false;
440
+ let apiUsageSnapshot = null;
369
441
  if (item.id === 'opencode-go') {
370
442
  const usageStatus = openCodeGoUsageConfigStatus(config);
371
443
  try {
@@ -400,9 +472,12 @@ export async function createUsageDashboard(config = {}, options = {}) {
400
472
  }
401
473
  } else {
402
474
  const snapshot = await apiSnapshot(item.id, options);
475
+ apiUsageSnapshot = snapshot;
403
476
  const known = snapshotRemaining(snapshot);
404
477
  const usage = snapshotUsage(snapshot);
478
+ const tokenUsage = snapshotTokenUsage(snapshot);
405
479
  const windows = normaliseWindows(snapshot?.quotaWindows, clean(snapshot?.source) || 'provider-api');
480
+ const estimated = localBudget(providerCfg);
406
481
  row.updatedAt = num(snapshot?.cachedAt, null);
407
482
  if (known) {
408
483
  applyKnownRemaining(row, known, { estimated: false });
@@ -413,17 +488,26 @@ export async function createUsageDashboard(config = {}, options = {}) {
413
488
  source: clean(snapshot?.source) || 'provider-api',
414
489
  detail: 'provider quota',
415
490
  });
491
+ } else if (estimated) {
492
+ applyKnownRemaining(row, estimated, { estimated: true });
493
+ hasQuota = true;
416
494
  } else if (usage) {
417
495
  applyKnownUsage(row, usage);
418
496
  hasQuota = true;
497
+ } else if (tokenUsage) {
498
+ applyTokenUsage(row, tokenUsage);
499
+ hasQuota = true;
500
+ }
501
+ }
502
+ if (!row.includeInTotal && !hasQuota) {
503
+ const estimated = localBudget(providerCfg);
504
+ if (estimated) {
505
+ applyKnownRemaining(row, estimated, { estimated: true });
506
+ hasQuota = true;
419
507
  }
420
508
  }
421
509
  if (item.id !== 'opencode-go' && !row.includeInTotal && !hasQuota) {
422
- row.status = 'hidden';
423
- row.source = 'provider-hidden';
424
- row.sourceLabel = 'hidden';
425
- row.primary = '';
426
- row.detail = 'Usage not exposed';
510
+ applyApiUnavailable(row, item.id, apiUsageSnapshot);
427
511
  }
428
512
  }
429
513
  row.tone = rowTone(row);
@@ -443,6 +527,10 @@ export async function createUsageDashboard(config = {}, options = {}) {
443
527
  rows.push(row);
444
528
  emit(true);
445
529
 
530
+ if (preview) {
531
+ return row;
532
+ }
533
+
446
534
  if (!row.authenticated) {
447
535
  row.status = 'missing';
448
536
  row.source = 'not-configured';
@@ -504,7 +592,7 @@ export async function createUsageDashboard(config = {}, options = {}) {
504
592
 
505
593
  await Promise.all([...apiTasks, ...oauthTasks]);
506
594
 
507
- const dashboard = usageDashboardSnapshot(rows, { checkedAt, refresh, checking: false });
595
+ const dashboard = usageDashboardSnapshot(rows, { checkedAt, refresh, checking: preview });
508
596
  emitUsageDashboard(options, dashboard);
509
597
  return dashboard;
510
598
  }