mixdog 1.2.6 → 1.3.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 (246) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/isolated-test-env.mjs +16 -0
  7. package/src/agents/reviewer/AGENT.md +4 -2
  8. package/src/agents/reviewer/agent.json +1 -1
  9. package/src/defaults/shipped-history.json +7 -0
  10. package/src/defaults/skills/browser-use/SKILL.md +5 -0
  11. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  12. package/src/defaults/skills/setup/references/actions.md +11 -4
  13. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  14. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  15. package/src/lib/rules-builder.cjs +55 -6
  16. package/src/rules/agent/AGENT.md +4 -0
  17. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  18. package/src/rules/agent-mode/MIXY.md +21 -0
  19. package/src/rules/agent-mode/ROUTINE.md +6 -0
  20. package/src/rules/lead/LEAD.md +7 -3
  21. package/src/rules/shared/70-delivery.md +3 -0
  22. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  23. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  24. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  25. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +4 -2
  26. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  27. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -4
  28. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  29. package/src/runtime/agent/orchestrator/mcp/client.mjs +115 -11
  30. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  33. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  34. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  36. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +1 -0
  39. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +10 -3
  40. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  41. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  42. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  43. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  44. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +96 -1
  45. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  46. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  47. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +12 -0
  48. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  49. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  50. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  51. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  52. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  53. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  54. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  55. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  56. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  57. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  58. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  59. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  60. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  61. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  62. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  63. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  64. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  66. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  67. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  68. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  69. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  70. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  72. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  73. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +74 -15
  74. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +9 -1
  75. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  76. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  77. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  78. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  79. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -1
  80. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  81. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  83. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  84. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  85. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  86. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  87. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  88. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  89. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  90. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  91. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  92. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  93. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  94. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  95. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  96. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  97. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +28 -9
  98. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  99. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  100. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  101. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  102. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  103. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  105. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +4 -0
  106. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +25 -1
  107. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +8 -0
  108. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +6 -0
  109. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -0
  110. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +75 -57
  111. package/src/runtime/browser-bridge/client.mjs +24 -0
  112. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  113. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  114. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  115. package/src/runtime/channels/lib/webhook.mjs +0 -1
  116. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  117. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  118. package/src/runtime/computer-bridge/client.mjs +28 -1
  119. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  120. package/src/runtime/connectors/google-mcp.mjs +446 -0
  121. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  122. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  123. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  124. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  125. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  126. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  127. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  128. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  129. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  130. package/src/runtime/memory/lib/memory.mjs +7 -1
  131. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  132. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  133. package/src/runtime/memory/lib/tool-call-handler.mjs +2 -0
  134. package/src/runtime/memory/tool-defs.mjs +5 -0
  135. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  136. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  137. package/src/runtime/shared/agent-avatar.mjs +320 -0
  138. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  139. package/src/runtime/shared/agent-route-config.mjs +16 -0
  140. package/src/runtime/shared/atomic-file.mjs +14 -1
  141. package/src/runtime/shared/config.mjs +8 -1
  142. package/src/runtime/shared/connector-accounts.mjs +15 -0
  143. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  144. package/src/runtime/shared/connector-catalog.mjs +230 -0
  145. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  146. package/src/runtime/shared/connector-triggers.mjs +43 -0
  147. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  148. package/src/runtime/shared/held-request-host.d.mts +12 -0
  149. package/src/runtime/shared/held-request-host.mjs +71 -0
  150. package/src/runtime/shared/plain-preview.d.mts +1 -0
  151. package/src/runtime/shared/plain-preview.mjs +28 -0
  152. package/src/runtime/shared/routine-limits.d.mts +11 -0
  153. package/src/runtime/shared/routine-limits.mjs +21 -0
  154. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  155. package/src/runtime/shared/routine-trigger.mjs +44 -0
  156. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  157. package/src/runtime/shared/slow-span.mjs +4 -12
  158. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  159. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  160. package/src/runtime/shared/turn-changes.mjs +0 -8
  161. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  162. package/src/runtime/shared/user-data-guard.mjs +114 -36
  163. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  164. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  165. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  166. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  167. package/src/session-runtime/boot/apis.mjs +50 -18
  168. package/src/session-runtime/boot/facade.mjs +5 -8
  169. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  170. package/src/session-runtime/boot/tools.mjs +3 -0
  171. package/src/session-runtime/channel-config-api.mjs +53 -5
  172. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  173. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  174. package/src/session-runtime/held-requests.mjs +228 -0
  175. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  176. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  177. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  178. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  179. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  180. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  181. package/src/session-runtime/lifecycle/session-switch/resume.mjs +4 -0
  182. package/src/session-runtime/lifecycle/shared.mjs +6 -0
  183. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  184. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  185. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  186. package/src/session-runtime/model-route/set-route.mjs +14 -3
  187. package/src/session-runtime/owned-automation-run.mjs +229 -0
  188. package/src/session-runtime/resource-api.mjs +5 -0
  189. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  190. package/src/session-runtime/resource-skills-api.mjs +12 -0
  191. package/src/session-runtime/room-member-gate.mjs +48 -0
  192. package/src/session-runtime/routine-home-turn.mjs +156 -0
  193. package/src/session-runtime/routine-owner.mjs +48 -0
  194. package/src/session-runtime/schedule-session-run.mjs +30 -64
  195. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  196. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  197. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  198. package/src/session-runtime/services/channel-admin.mjs +93 -24
  199. package/src/session-runtime/services/memory-access.mjs +37 -0
  200. package/src/session-runtime/services/provider-admin.mjs +74 -39
  201. package/src/session-runtime/services/schedule-access.mjs +91 -0
  202. package/src/session-runtime/session-create/session-options.mjs +34 -7
  203. package/src/session-runtime/session-hooks.mjs +16 -8
  204. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  205. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  206. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  207. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  208. package/src/session-runtime/skills-api.mjs +16 -1
  209. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  210. package/src/session-runtime/turn/session-ops.mjs +8 -1
  211. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +10 -2
  212. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  213. package/src/session-runtime/webhook-session-run.mjs +49 -67
  214. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  215. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  216. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  217. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  218. package/src/standalone/daemon-agent-control.mjs +1 -8
  219. package/src/standalone/daemon-session-control.mjs +11 -2
  220. package/src/standalone/daemon.mjs +18 -4
  221. package/src/standalone/session-protocol.mjs +27 -0
  222. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  223. package/src/standalone/session-service.mjs +19 -0
  224. package/src/tui/app/slash-commands.mjs +20 -0
  225. package/src/tui/dist/index.mjs +164 -86
  226. package/src/tui/session/context-state.mjs +6 -1
  227. package/src/tui/session/notice-surface.mjs +35 -4
  228. package/src/tui/session/queue-helpers.mjs +2 -1
  229. package/src/tui/session/session-api/extensions.mjs +4 -0
  230. package/src/tui/session/session-api/intake/submission.mjs +5 -0
  231. package/src/tui/session/session-api/integrations.mjs +8 -0
  232. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  233. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  234. package/src/tui/session/session-api/routes.mjs +48 -3
  235. package/src/tui/session/session-flow/drain.mjs +12 -3
  236. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  237. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  238. package/src/tui/session/session-flow/steering.mjs +58 -24
  239. package/src/tui/session/tool-approval.mjs +26 -5
  240. package/src/tui/session/transcript-intake.mjs +6 -2
  241. package/src/tui/session/transcript-spill.mjs +5 -1
  242. package/src/tui/session/tui-steering-persist.mjs +65 -42
  243. package/src/tui/session/turn-live-call.mjs +56 -0
  244. package/src/tui/session/turn.mjs +22 -6
  245. package/src/session-runtime/automation-agents.mjs +0 -94
  246. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -1825,8 +1825,8 @@ var require_react_reconciler_production = __commonJS({
1825
1825
  currentEntangledActionThenable = {
1826
1826
  status: "pending",
1827
1827
  value: void 0,
1828
- then: function(resolve7) {
1829
- entangledListeners.push(resolve7);
1828
+ then: function(resolve8) {
1829
+ entangledListeners.push(resolve8);
1830
1830
  }
1831
1831
  };
1832
1832
  }
@@ -1849,8 +1849,8 @@ var require_react_reconciler_production = __commonJS({
1849
1849
  status: "pending",
1850
1850
  value: null,
1851
1851
  reason: null,
1852
- then: function(resolve7) {
1853
- listeners.push(resolve7);
1852
+ then: function(resolve8) {
1853
+ listeners.push(resolve8);
1854
1854
  }
1855
1855
  };
1856
1856
  thenable.then(
@@ -11449,8 +11449,8 @@ var require_react_reconciler_development = __commonJS({
11449
11449
  currentEntangledActionThenable = {
11450
11450
  status: "pending",
11451
11451
  value: void 0,
11452
- then: function(resolve7) {
11453
- entangledListeners.push(resolve7);
11452
+ then: function(resolve8) {
11453
+ entangledListeners.push(resolve8);
11454
11454
  }
11455
11455
  };
11456
11456
  }
@@ -11473,8 +11473,8 @@ var require_react_reconciler_development = __commonJS({
11473
11473
  status: "pending",
11474
11474
  value: null,
11475
11475
  reason: null,
11476
- then: function(resolve7) {
11477
- listeners.push(resolve7);
11476
+ then: function(resolve8) {
11477
+ listeners.push(resolve8);
11478
11478
  }
11479
11479
  };
11480
11480
  thenable.then(
@@ -23486,7 +23486,7 @@ var init_keyed_serial_queue = __esm({
23486
23486
 
23487
23487
  // src/runtime/shared/sleep.mjs
23488
23488
  function sleep(ms) {
23489
- return new Promise((resolve7) => setTimeout(resolve7, ms));
23489
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
23490
23490
  }
23491
23491
  function sleepSync(ms) {
23492
23492
  const buffer = new SharedArrayBuffer(4);
@@ -23951,7 +23951,8 @@ import {
23951
23951
  unlink as unlinkAsync2,
23952
23952
  writeFile as writeFileAsync2
23953
23953
  } from "node:fs/promises";
23954
- import { dirname as dirname5, basename as basename3, join as join5 } from "node:path";
23954
+ import { tmpdir as tmpdir2 } from "node:os";
23955
+ import { dirname as dirname5, basename as basename3, join as join5, relative, isAbsolute as isAbsolute2, resolve as resolve4 } from "node:path";
23955
23956
  import { randomBytes as randomBytes3 } from "node:crypto";
23956
23957
  function _drainAdaptiveFileIo() {
23957
23958
  while (_ioActive < _ioLimit && _ioQueue.length > 0) {
@@ -23978,8 +23979,8 @@ function _drainAdaptiveFileIo() {
23978
23979
  }
23979
23980
  }
23980
23981
  function _runAdaptiveFileIo(run) {
23981
- return new Promise((resolve7, reject) => {
23982
- _ioQueue.push({ run, resolve: resolve7, reject });
23982
+ return new Promise((resolve8, reject) => {
23983
+ _ioQueue.push({ run, resolve: resolve8, reject });
23983
23984
  _drainAdaptiveFileIo();
23984
23985
  });
23985
23986
  }
@@ -24051,7 +24052,14 @@ async function fsyncPathAsync(path2, tolerated) {
24051
24052
  }
24052
24053
  }
24053
24054
  }
24055
+ function assertTestSecretWriteSafe(filePath, opts) {
24056
+ if (opts.secret !== true || !process.env.NODE_TEST_CONTEXT) return;
24057
+ const rel = relative(resolve4(tmpdir2()).toLowerCase(), resolve4(filePath).toLowerCase());
24058
+ if (rel === "" || !rel.startsWith("..") && !isAbsolute2(rel)) return;
24059
+ throw new Error(`refusing to write a secret outside the temp dir under node --test: ${filePath}`);
24060
+ }
24054
24061
  function writeFileAtomicSync(filePath, data, opts = {}) {
24062
+ assertTestSecretWriteSafe(filePath, opts);
24055
24063
  const run = () => {
24056
24064
  const dir = dirname5(filePath);
24057
24065
  mkdirSync3(dir, { recursive: true });
@@ -24116,6 +24124,7 @@ function writeJsonAtomicSync(filePath, value, opts = {}) {
24116
24124
  `, opts);
24117
24125
  }
24118
24126
  async function writeFileAtomicAsync(filePath, data, opts = {}) {
24127
+ assertTestSecretWriteSafe(filePath, opts);
24119
24128
  const run = async () => {
24120
24129
  const dir = dirname5(filePath);
24121
24130
  await mkdirAsync2(dir, { recursive: true });
@@ -34090,8 +34099,8 @@ var App_default = App;
34090
34099
  var noop = () => {
34091
34100
  };
34092
34101
  var textEncoder = new TextEncoder();
34093
- var yieldImmediate = async () => new Promise((resolve7) => {
34094
- setImmediate(resolve7);
34102
+ var yieldImmediate = async () => new Promise((resolve8) => {
34103
+ setImmediate(resolve8);
34095
34104
  });
34096
34105
  var kittyQueryEscapeByte = 27;
34097
34106
  var kittyQueryOpenBracketByte = 91;
@@ -34346,8 +34355,8 @@ var Ink = class {
34346
34355
  };
34347
34356
  }
34348
34357
  this.initKittyKeyboard();
34349
- this.exitPromise = new Promise((resolve7, reject) => {
34350
- this.resolveExitPromise = resolve7;
34358
+ this.exitPromise = new Promise((resolve8, reject) => {
34359
+ this.resolveExitPromise = resolve8;
34351
34360
  this.rejectExitPromise = reject;
34352
34361
  });
34353
34362
  void this.exitPromise.catch(noop);
@@ -34787,9 +34796,9 @@ var Ink = class {
34787
34796
  settleThrottle(this.throttledOnRender, canWriteToStdout);
34788
34797
  settleThrottle(this.throttledLog, canWriteToStdout);
34789
34798
  if (canWriteToStdout && hasWritableState) {
34790
- await new Promise((resolve7) => {
34799
+ await new Promise((resolve8) => {
34791
34800
  this.options.stdout.write("", () => {
34792
- resolve7();
34801
+ resolve8();
34793
34802
  });
34794
34803
  });
34795
34804
  return;
@@ -34875,8 +34884,8 @@ var Ink = class {
34875
34884
  async awaitNextRender() {
34876
34885
  if (!this.nextRenderCommit) {
34877
34886
  let resolveRender;
34878
- const promise = new Promise((resolve7) => {
34879
- resolveRender = resolve7;
34887
+ const promise = new Promise((resolve8) => {
34888
+ resolveRender = resolve8;
34880
34889
  });
34881
34890
  this.nextRenderCommit = { promise, resolve: resolveRender };
34882
34891
  }
@@ -35328,7 +35337,7 @@ import { useState as useState5, useEffect as useEffect6, useCallback as useCallb
35328
35337
 
35329
35338
  // src/tui/index.jsx
35330
35339
  import { closeSync as closeSync3, constants as fsConstants, createWriteStream as createWriteStream3, mkdirSync as mkdirSync8, openSync as openSync3, readSync } from "node:fs";
35331
- import { tmpdir as tmpdir3 } from "node:os";
35340
+ import { tmpdir as tmpdir4 } from "node:os";
35332
35341
  import { dirname as dirname12, join as join17 } from "node:path";
35333
35342
  import { performance as performance2 } from "node:perf_hooks";
35334
35343
  import { format } from "node:util";
@@ -35347,12 +35356,12 @@ import { spawn } from "node:child_process";
35347
35356
  import path from "node:path";
35348
35357
  var DIALOG_TIMEOUT_MS = 5 * 60 * 1e3;
35349
35358
  function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35350
- return new Promise((resolve7) => {
35359
+ return new Promise((resolve8) => {
35351
35360
  let child;
35352
35361
  try {
35353
35362
  child = spawn(cmd, args, { stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
35354
35363
  } catch (error) {
35355
- resolve7({ ok: false, code: -1, stdout: "", error });
35364
+ resolve8({ ok: false, code: -1, stdout: "", error });
35356
35365
  return;
35357
35366
  }
35358
35367
  let stdout2 = "";
@@ -35364,7 +35373,7 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35364
35373
  child.kill();
35365
35374
  } catch {
35366
35375
  }
35367
- resolve7({ ok: false, code: -1, stdout: "", error: new Error("dialog timed out") });
35376
+ resolve8({ ok: false, code: -1, stdout: "", error: new Error("dialog timed out") });
35368
35377
  }, timeoutMs);
35369
35378
  timer2.unref?.();
35370
35379
  child.stdout.on("data", (chunk) => {
@@ -35374,13 +35383,13 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35374
35383
  if (settled) return;
35375
35384
  settled = true;
35376
35385
  clearTimeout(timer2);
35377
- resolve7({ ok: false, code: -1, stdout: "", error });
35386
+ resolve8({ ok: false, code: -1, stdout: "", error });
35378
35387
  });
35379
35388
  child.on("close", (code) => {
35380
35389
  if (settled) return;
35381
35390
  settled = true;
35382
35391
  clearTimeout(timer2);
35383
- resolve7({ ok: code === 0, code, stdout: stdout2 });
35392
+ resolve8({ ok: code === 0, code, stdout: stdout2 });
35384
35393
  });
35385
35394
  });
35386
35395
  }
@@ -35388,10 +35397,10 @@ function spawnFailed(result) {
35388
35397
  return !!result && result.code === -1;
35389
35398
  }
35390
35399
  function commandExists(cmd) {
35391
- return new Promise((resolve7) => {
35400
+ return new Promise((resolve8) => {
35392
35401
  const probe = process.platform === "win32" ? spawn("where", [cmd], { stdio: "ignore", windowsHide: true }) : spawn("which", [cmd], { stdio: "ignore" });
35393
- probe.on("error", () => resolve7(false));
35394
- probe.on("close", (code) => resolve7(code === 0));
35402
+ probe.on("error", () => resolve8(false));
35403
+ probe.on("close", (code) => resolve8(code === 0));
35395
35404
  });
35396
35405
  }
35397
35406
  function psSingleQuoted(value) {
@@ -46197,8 +46206,8 @@ var notifyRenderFrame = (seq) => {
46197
46206
  for (const ack of acks) ack(seq);
46198
46207
  };
46199
46208
  var yieldToRenderer = ({ frames = 1 } = {}) => {
46200
- if (!hasRenderFrameSource()) return new Promise((resolve7) => setImmediate(resolve7));
46201
- return new Promise((resolve7) => {
46209
+ if (!hasRenderFrameSource()) return new Promise((resolve8) => setImmediate(resolve8));
46210
+ return new Promise((resolve8) => {
46202
46211
  const minSeq = renderAckSeq;
46203
46212
  let remainingFrames = Math.max(1, Math.floor(Number(frames) || 1));
46204
46213
  let settled = false;
@@ -46213,7 +46222,7 @@ var yieldToRenderer = ({ frames = 1 } = {}) => {
46213
46222
  releaseClosedListener();
46214
46223
  const idx = pendingRenderAcks.indexOf(onFrame);
46215
46224
  if (idx !== -1) pendingRenderAcks.splice(idx, 1);
46216
- resolve7();
46225
+ resolve8();
46217
46226
  };
46218
46227
  releaseClosedListener = onRenderFrameSourcesClosed(finish);
46219
46228
  const onTimeout = () => {
@@ -47013,13 +47022,13 @@ function nativeClipboardCommand(text) {
47013
47022
  function copyToClipboard(text) {
47014
47023
  const value = String(text ?? "");
47015
47024
  const wroteOsc52 = writeOsc52Clipboard(value);
47016
- return new Promise((resolve7, reject) => {
47025
+ return new Promise((resolve8, reject) => {
47017
47026
  const { cmd, args, input } = nativeClipboardCommand(value);
47018
47027
  let child;
47019
47028
  try {
47020
47029
  child = spawn2(cmd, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
47021
47030
  } catch (e) {
47022
- if (wroteOsc52) resolve7();
47031
+ if (wroteOsc52) resolve8();
47023
47032
  else reject(clipboardHelperError(cmd, e));
47024
47033
  return;
47025
47034
  }
@@ -47028,7 +47037,7 @@ function copyToClipboard(text) {
47028
47037
  });
47029
47038
  if (!wroteOsc52) {
47030
47039
  child.on("close", (code) => {
47031
- if (code === 0) resolve7();
47040
+ if (code === 0) resolve8();
47032
47041
  else reject(new Error(`${cmd} exited with code ${code}`));
47033
47042
  });
47034
47043
  }
@@ -47037,7 +47046,7 @@ function copyToClipboard(text) {
47037
47046
  child.stdin.end(input);
47038
47047
  if (wroteOsc52) {
47039
47048
  child.unref?.();
47040
- resolve7();
47049
+ resolve8();
47041
47050
  }
47042
47051
  });
47043
47052
  }
@@ -47341,7 +47350,7 @@ function mimeForPath(path2) {
47341
47350
  return IMAGE_MIME[extname(String(path2 || "")).toLowerCase()] || null;
47342
47351
  }
47343
47352
  function execFileBuffer(cmd, args, options = {}) {
47344
- return new Promise((resolve7) => {
47353
+ return new Promise((resolve8) => {
47345
47354
  execFile(
47346
47355
  cmd,
47347
47356
  args,
@@ -47353,7 +47362,7 @@ function execFileBuffer(cmd, args, options = {}) {
47353
47362
  ...options
47354
47363
  },
47355
47364
  (error, stdout2, stderr) => {
47356
- resolve7({ ok: !error, code: error?.code ?? 0, stdout: stdout2, stderr, error });
47365
+ resolve8({ ok: !error, code: error?.code ?? 0, stdout: stdout2, stderr, error });
47357
47366
  }
47358
47367
  );
47359
47368
  });
@@ -48749,7 +48758,7 @@ function completeOAuthCode(ctx, target, commandText) {
48749
48758
  }
48750
48759
  oauthSubmitRef.current = true;
48751
48760
  setProviderPrompt((prompt) => prompt === target ? { ...prompt, submitting: true } : prompt);
48752
- const completion = typeof target.login?.completeCode === "function" ? new Promise((resolve7) => resolve7(target.login.completeCode(commandText))) : Promise.reject(new Error("OAuth login is no longer active"));
48761
+ const completion = typeof target.login?.completeCode === "function" ? new Promise((resolve8) => resolve8(target.login.completeCode(commandText))) : Promise.reject(new Error("OAuth login is no longer active"));
48753
48762
  void completion.then(() => {
48754
48763
  const successReturn = target.successReturn;
48755
48764
  const afterSave = target.afterSave;
@@ -51323,11 +51332,11 @@ function isPidAlive(value) {
51323
51332
 
51324
51333
  // src/runtime/shared/worktrees/git-head.mjs
51325
51334
  import { readFileSync as readFileSync9, statSync as statSync2, watch } from "node:fs";
51326
- import { dirname as dirname8, resolve as resolve5 } from "node:path";
51335
+ import { dirname as dirname8, resolve as resolve6 } from "node:path";
51327
51336
 
51328
51337
  // src/runtime/shared/worktrees/paths.mjs
51329
51338
  import { existsSync as existsSync9, realpathSync as realpathSync2 } from "node:fs";
51330
- import { dirname as dirname7, isAbsolute as isAbsolute2, join as join9, relative, resolve as resolve4, sep } from "node:path";
51339
+ import { dirname as dirname7, isAbsolute as isAbsolute3, join as join9, relative as relative2, resolve as resolve5, sep } from "node:path";
51331
51340
 
51332
51341
  // src/runtime/shared/statusline/statusline-segments.mjs
51333
51342
  var DEFAULT_MIXDOG_HOME = process.env.MIXDOG_HOME || join10(homedir2(), ".mixdog");
@@ -51415,7 +51424,8 @@ async function refreshShellJobsStatus(ownerPid) {
51415
51424
  continue;
51416
51425
  }
51417
51426
  const unconfirmed = detail?.terminationUnconfirmed === true;
51418
- if (unconfirmed ? !isPidAlive(ownerByJob.get(id) || 0) : !await isShellJobAlive(detail, p, dir, id)) continue;
51427
+ if (unconfirmed ? !isHeldShellJobAlive(detail, ownerByJob.get(id)) : !await isShellJobAlive(detail, p, dir, id))
51428
+ continue;
51419
51429
  if (detail?.foreground === true && !unconfirmed) continue;
51420
51430
  const ownedByThisHost = ownerByJob.get(id) === ownerPid;
51421
51431
  if (ownedByThisHost) count++;
@@ -51504,6 +51514,12 @@ function summarizeShellJobs({ count, oldestMs, jobs, bySession }) {
51504
51514
  }
51505
51515
  return { count, elapsedLabel, jobs, sessions };
51506
51516
  }
51517
+ function isHeldShellJobAlive(detail, ownerPid) {
51518
+ if (!isPidAlive(ownerPid || 0)) return false;
51519
+ if (detail?.ownerSessionClosed !== true) return true;
51520
+ const survivors = Array.isArray(detail?.survivorPids) ? detail.survivorPids : [];
51521
+ return [detail?.pid, ...survivors].some((pid) => isPidAlive(positiveInt(pid)));
51522
+ }
51507
51523
  async function isShellJobAlive(detail, detailPath, dir, id) {
51508
51524
  const pid = positiveInt(detail?.pid);
51509
51525
  if (!pid) return false;
@@ -55872,7 +55888,7 @@ function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionP
55872
55888
  toolApproval.id
55873
55889
  );
55874
55890
  }
55875
- const resolve7 = (approved) => {
55891
+ const resolve8 = (approved) => {
55876
55892
  store.resolveToolApproval?.(toolApproval.id, {
55877
55893
  approved,
55878
55894
  reason: approved ? "approved by user" : "denied by user"
@@ -55897,12 +55913,12 @@ function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionP
55897
55913
  description: "run this tool call"
55898
55914
  }
55899
55915
  ],
55900
- onSelect: (value) => resolve7(value === "approve"),
55901
- onCancel: () => resolve7(false),
55916
+ onSelect: (value) => resolve8(value === "approve"),
55917
+ onCancel: () => resolve8(false),
55902
55918
  onKey: (input) => {
55903
55919
  const value = String(input || "").trim().toLowerCase();
55904
- if (value === "a" || value === "y") resolve7(true);
55905
- else if (value === "d" || value === "n") resolve7(false);
55920
+ if (value === "a" || value === "y") resolve8(true);
55921
+ else if (value === "d" || value === "n") resolve8(false);
55906
55922
  },
55907
55923
  title: "Tool approval",
55908
55924
  description: toolApprovalDescription(toolApproval),
@@ -60273,7 +60289,7 @@ function createProviderSetupPicker({
60273
60289
  }
60274
60290
  });
60275
60291
  try {
60276
- await new Promise((resolve7) => setTimeout(resolve7, 0));
60292
+ await new Promise((resolve8) => setTimeout(resolve8, 0));
60277
60293
  return await store.getProviderSetup(options.forceRefresh ? { force: true } : void 0);
60278
60294
  } catch (e) {
60279
60295
  store.pushNotice(`providers failed: ${e?.message || e}`, "error");
@@ -60395,7 +60411,7 @@ function createModelCatalog({ store, providerModelsCacheRef, webSearchModelsCach
60395
60411
  let renderedQuickModels = false;
60396
60412
  if (!providerModels.length || options.refreshModels === true) {
60397
60413
  paintLoading();
60398
- await new Promise((resolve7) => setTimeout(resolve7, 0));
60414
+ await new Promise((resolve8) => setTimeout(resolve8, 0));
60399
60415
  try {
60400
60416
  if (options.refreshModels !== true && options.cacheRef !== "webSearch") {
60401
60417
  refreshModelsPromise = Promise.resolve(loadModels({ force: false }));
@@ -61437,7 +61453,7 @@ import {
61437
61453
  rm as rmP,
61438
61454
  stat as statP
61439
61455
  } from "node:fs/promises";
61440
- import { basename as basename5, dirname as dirname9, join as join11, resolve as resolve6 } from "node:path";
61456
+ import { basename as basename5, dirname as dirname9, join as join11, resolve as resolve7 } from "node:path";
61441
61457
  import { homedir as homedir3 } from "node:os";
61442
61458
  import { createHash as createHash4, randomUUID } from "node:crypto";
61443
61459
  function getBackupRoot() {
@@ -61449,7 +61465,7 @@ var BACKUP_MANIFEST = "backup.json";
61449
61465
  var INIT_MARKER = ".mixdog-user-data.json";
61450
61466
  var SCOPE_PREFIX = "scope-";
61451
61467
  function normalizeDataDir(dataDir2) {
61452
- const full = resolve6(String(dataDir2));
61468
+ const full = resolve7(String(dataDir2));
61453
61469
  return process.platform === "win32" ? full.toLowerCase() : full;
61454
61470
  }
61455
61471
  function scopeDirFor(dataDir2) {
@@ -61458,20 +61474,67 @@ function scopeDirFor(dataDir2) {
61458
61474
  }
61459
61475
  var lastBackupMs = 0;
61460
61476
  var backupSeq = 0;
61477
+ var BACKUP_NAME_RE = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z-(?:(\d{10})-)?/;
61478
+ function newestBackupOrder(names) {
61479
+ let ms = 0;
61480
+ let seq = -1;
61481
+ for (const name of names) {
61482
+ const match = BACKUP_NAME_RE.exec(name);
61483
+ if (!match) continue;
61484
+ const time = Date.parse(`${match[1]}T${match[2]}:${match[3]}:${match[4]}.${match[5]}Z`);
61485
+ if (!Number.isFinite(time)) continue;
61486
+ const order = match[6] === void 0 ? Number.POSITIVE_INFINITY : Number(match[6]);
61487
+ if (time > ms || time === ms && order > seq) {
61488
+ ms = time;
61489
+ seq = order;
61490
+ }
61491
+ }
61492
+ return { ms, seq };
61493
+ }
61494
+ function nextBackupName(names, reason) {
61495
+ const newest = newestBackupOrder(names);
61496
+ lastBackupMs = Math.max(Date.now(), lastBackupMs, newest.ms);
61497
+ if (lastBackupMs === newest.ms) {
61498
+ if (newest.seq === Number.POSITIVE_INFINITY) lastBackupMs += 1;
61499
+ else backupSeq = Math.max(backupSeq, newest.seq + 1);
61500
+ }
61501
+ const time = new Date(lastBackupMs).toISOString().replace(/[:.]/g, "-");
61502
+ return `${time}-${String(backupSeq++).padStart(10, "0")}-${safeReason(reason)}`;
61503
+ }
61504
+ function scopeBackupNames(entries) {
61505
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
61506
+ }
61461
61507
  function reserveBackupDir(scopeDir, reason) {
61462
61508
  mkdirSync4(scopeDir, { recursive: true });
61509
+ const names = scopeBackupNames(readdirSync2(scopeDir, { withFileTypes: true }));
61463
61510
  for (; ; ) {
61464
- lastBackupMs = Math.max(Date.now(), lastBackupMs);
61465
- const time = new Date(lastBackupMs).toISOString().replace(/[:.]/g, "-");
61466
- const backupDir = join11(scopeDir, `${time}-${String(backupSeq++).padStart(10, "0")}-${safeReason(reason)}`);
61511
+ const name = nextBackupName(names, reason);
61512
+ names.push(name);
61467
61513
  try {
61468
- mkdirSync4(backupDir);
61469
- return backupDir;
61514
+ mkdirSync4(join11(scopeDir, name));
61515
+ return { backupDir: join11(scopeDir, name), names };
61470
61516
  } catch (error) {
61471
61517
  if (error?.code !== "EEXIST") throw error;
61472
61518
  }
61473
61519
  }
61474
61520
  }
61521
+ async function reserveBackupDirAsync(scopeDir, reason) {
61522
+ await mkdirP(scopeDir, { recursive: true });
61523
+ const names = scopeBackupNames(await readdirP(scopeDir, { withFileTypes: true }));
61524
+ for (; ; ) {
61525
+ const name = nextBackupName(names, reason);
61526
+ names.push(name);
61527
+ try {
61528
+ await mkdirP(join11(scopeDir, name));
61529
+ return { backupDir: join11(scopeDir, name), names };
61530
+ } catch (error) {
61531
+ if (error?.code !== "EEXIST") throw error;
61532
+ }
61533
+ }
61534
+ }
61535
+ function backupsToPrune(names, own, keep = 40) {
61536
+ return [...names].sort().reverse().slice(keep).filter((name) => name !== own);
61537
+ }
61475
61538
  function safeReason(reason) {
61476
61539
  return String(reason || "snapshot").replace(/[^a-z0-9_.-]+/gi, "-").slice(0, 48) || "snapshot";
61477
61540
  }
@@ -61502,7 +61565,7 @@ function manifestDataDirMatches(backupDir, dataDirKey) {
61502
61565
  }
61503
61566
  function legacyMarkersFor(root, dataDir2, dataDirKey) {
61504
61567
  const hashed = new Set(
61505
- [String(dataDir2), resolve6(String(dataDir2))].map(
61568
+ [String(dataDir2), resolve7(String(dataDir2))].map(
61506
61569
  (value) => `.initialized-${createHash4("sha256").update(value).digest("hex").slice(0, 16)}.json`
61507
61570
  )
61508
61571
  );
@@ -61556,9 +61619,20 @@ function isStructurallyCompleteMixdogConfigBackup(parsed) {
61556
61619
  if (!parsed.agent && !parsed.channels) return false;
61557
61620
  return true;
61558
61621
  }
61559
- function backupDirsNewestFirst(dir) {
61622
+ function isAbsentBackupError(error) {
61623
+ return error instanceof SyntaxError || error?.code === "ENOENT" || error?.code === "ENOTDIR";
61624
+ }
61625
+ function listBackupDirsNewestFirst(dir) {
61560
61626
  try {
61561
61627
  return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
61628
+ } catch (error) {
61629
+ if (isAbsentBackupError(error)) return [];
61630
+ throw error;
61631
+ }
61632
+ }
61633
+ function backupDirsNewestFirst(dir) {
61634
+ try {
61635
+ return listBackupDirsNewestFirst(dir);
61562
61636
  } catch {
61563
61637
  return [];
61564
61638
  }
@@ -61570,19 +61644,20 @@ function readRestorableConfig(backupDir, dataDirKey, instanceId) {
61570
61644
  if (manifest.instanceId !== instanceId) return null;
61571
61645
  const parsed = JSON.parse(readFileSync11(join11(backupDir, "mixdog-config.json"), "utf8"));
61572
61646
  return isStructurallyCompleteMixdogConfigBackup(parsed) ? parsed : null;
61573
- } catch {
61574
- return null;
61647
+ } catch (error) {
61648
+ if (isAbsentBackupError(error)) return null;
61649
+ throw error;
61575
61650
  }
61576
61651
  }
61577
61652
  function findRestorableConfig(dataDir2, instanceId) {
61578
61653
  const key = normalizeDataDir(dataDir2);
61579
61654
  const scopeDir = scopeDirFor(dataDir2);
61580
- for (const name of backupDirsNewestFirst(scopeDir)) {
61655
+ for (const name of listBackupDirsNewestFirst(scopeDir)) {
61581
61656
  const parsed = readRestorableConfig(join11(scopeDir, name), key, instanceId);
61582
61657
  if (parsed) return parsed;
61583
61658
  }
61584
61659
  const root = getBackupRoot();
61585
- for (const name of backupDirsNewestFirst(root)) {
61660
+ for (const name of listBackupDirsNewestFirst(root)) {
61586
61661
  if (name.startsWith(SCOPE_PREFIX)) continue;
61587
61662
  const parsed = readRestorableConfig(join11(root, name), key, instanceId);
61588
61663
  if (parsed) return parsed;
@@ -61596,7 +61671,8 @@ function loadLatestMixdogConfigFromBackup(dataDir2, options) {
61596
61671
  const key = normalizeDataDir(dataDir2);
61597
61672
  const root = getBackupRoot();
61598
61673
  let hit = restoreLookupCache.get(key);
61599
- if (!hit || hit.root !== root || hit.instanceId !== instanceId) {
61674
+ if (options?.fresh || !hit || hit.root !== root || hit.instanceId !== instanceId) {
61675
+ restoreLookupCache.delete(key);
61600
61676
  hit = { root, instanceId, config: findRestorableConfig(dataDir2, instanceId) };
61601
61677
  restoreLookupCache.set(key, hit);
61602
61678
  }
@@ -61626,8 +61702,8 @@ function copyTree(src, dst, copied) {
61626
61702
  copyFileSync(src, dst);
61627
61703
  copied.push(dst);
61628
61704
  }
61629
- function pruneBackups(scopeDir, keep = 40) {
61630
- for (const name of backupDirsNewestFirst(scopeDir).slice(keep)) {
61705
+ function pruneBackups(scopeDir, names, own) {
61706
+ for (const name of backupsToPrune(names, own)) {
61631
61707
  try {
61632
61708
  rmSync(join11(scopeDir, name), { recursive: true, force: true });
61633
61709
  } catch {
@@ -61641,7 +61717,7 @@ function markUserDataInitialized(dataDir2) {
61641
61717
  writeFileSync4(
61642
61718
  join11(dataDir2, INIT_MARKER),
61643
61719
  `${JSON.stringify(
61644
- { instanceId: randomUUID(), dataDir: resolve6(dataDir2), createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61720
+ { instanceId: randomUUID(), dataDir: resolve7(dataDir2), createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61645
61721
  null,
61646
61722
  2
61647
61723
  )}
@@ -61669,7 +61745,7 @@ function finishBackup(dataDir2, backupDir, reason) {
61669
61745
  writeFileSync4(
61670
61746
  join11(backupDir, BACKUP_MANIFEST),
61671
61747
  `${JSON.stringify(
61672
- { dataDir: resolve6(dataDir2), instanceId, reason, createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61748
+ { dataDir: resolve7(dataDir2), instanceId, reason, createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61673
61749
  null,
61674
61750
  2
61675
61751
  )}
@@ -61683,7 +61759,7 @@ function backupUserData(dataDir2, reason = "snapshot") {
61683
61759
  if (skipBackups()) return { dir: null, copied: [] };
61684
61760
  if (!dataDir2 || !existsSync10(dataDir2)) return { dir: null, copied: [] };
61685
61761
  const scopeDir = scopeDirFor(dataDir2);
61686
- const backupDir = reserveBackupDir(scopeDir, reason);
61762
+ const { backupDir, names } = reserveBackupDir(scopeDir, reason);
61687
61763
  const copied = [];
61688
61764
  for (const rel of USER_DATA_FILES) {
61689
61765
  const src = join11(dataDir2, rel);
@@ -61695,7 +61771,7 @@ function backupUserData(dataDir2, reason = "snapshot") {
61695
61771
  }
61696
61772
  if (copied.length > 0) {
61697
61773
  finishBackup(dataDir2, backupDir, reason);
61698
- pruneBackups(scopeDir);
61774
+ pruneBackups(scopeDir, names, basename5(backupDir));
61699
61775
  if (process.env.MIXDOG_SETUP_QUIET !== "1") {
61700
61776
  process.stderr.write(`[user-data-backup] ${reason}: copied ${copied.length} file(s) to ${backupDir}
61701
61777
  `);
@@ -61718,14 +61794,8 @@ async function copyTreeAsync(src, dst, copied) {
61718
61794
  await copyFileP(src, dst);
61719
61795
  copied.push(dst);
61720
61796
  }
61721
- async function pruneBackupsAsync(scopeDir, keep = 40) {
61722
- let entries = [];
61723
- try {
61724
- entries = (await readdirP(scopeDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
61725
- } catch {
61726
- return;
61727
- }
61728
- for (const name of entries.slice(keep)) {
61797
+ async function pruneBackupsAsync(scopeDir, names, own) {
61798
+ for (const name of backupsToPrune(names, own)) {
61729
61799
  try {
61730
61800
  await rmP(join11(scopeDir, name), { recursive: true, force: true });
61731
61801
  } catch {
@@ -61736,7 +61806,7 @@ async function backupUserDataAsync(dataDir2, reason = "snapshot") {
61736
61806
  if (skipBackups()) return { dir: null, copied: [] };
61737
61807
  if (!dataDir2 || !existsSync10(dataDir2)) return { dir: null, copied: [] };
61738
61808
  const scopeDir = scopeDirFor(dataDir2);
61739
- const backupDir = reserveBackupDir(scopeDir, reason);
61809
+ const { backupDir, names } = await reserveBackupDirAsync(scopeDir, reason);
61740
61810
  const copied = [];
61741
61811
  for (const rel of USER_DATA_FILES) {
61742
61812
  const src = join11(dataDir2, rel);
@@ -61748,7 +61818,7 @@ async function backupUserDataAsync(dataDir2, reason = "snapshot") {
61748
61818
  }
61749
61819
  if (copied.length > 0) {
61750
61820
  finishBackup(dataDir2, backupDir, reason);
61751
- await pruneBackupsAsync(scopeDir);
61821
+ await pruneBackupsAsync(scopeDir, names, basename5(backupDir));
61752
61822
  if (process.env.MIXDOG_SETUP_QUIET !== "1") {
61753
61823
  process.stderr.write(`[user-data-backup] ${reason}: copied ${copied.length} file(s) to ${backupDir}
61754
61824
  `);
@@ -61970,7 +62040,13 @@ function readAll() {
61970
62040
  return canonicalizeUnifiedConfig(parsed);
61971
62041
  }
61972
62042
  if (isUserDataRecoveryExpected(resolvePluginData())) {
61973
- const restored = loadLatestMixdogConfigFromBackup(resolvePluginData());
62043
+ let restored = null;
62044
+ try {
62045
+ restored = loadLatestMixdogConfigFromBackup(resolvePluginData());
62046
+ } catch (err) {
62047
+ process.stderr.write(`[config] backup restore lookup failed: ${err.message}
62048
+ `);
62049
+ }
61974
62050
  if (restored && isPlainObject(restored)) {
61975
62051
  const config = canonicalizeUnifiedConfig(restored);
61976
62052
  persistRestoredConfig(config);
@@ -63563,8 +63639,8 @@ function usePromptQueueHistory({
63563
63639
  let timer2 = null;
63564
63640
  Promise.race([
63565
63641
  Promise.resolve(store.dispose?.("cli-react-exit", { detach: true })),
63566
- new Promise((resolve7) => {
63567
- timer2 = setTimeout(resolve7, 350);
63642
+ new Promise((resolve8) => {
63643
+ timer2 = setTimeout(resolve8, 350);
63568
63644
  })
63569
63645
  ]).finally(() => {
63570
63646
  if (timer2) clearTimeout(timer2);
@@ -63769,6 +63845,7 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
63769
63845
  import { useCallback as useCallback21, useEffect as useEffect27, useLayoutEffect as useLayoutEffect8 } from "react";
63770
63846
 
63771
63847
  // src/tui/session/transcript-spill.mjs
63848
+ import { randomBytes as randomBytes4 } from "node:crypto";
63772
63849
  import { readFileSync as readFileSync16 } from "node:fs";
63773
63850
  import { join as join16 } from "node:path";
63774
63851
  import { Worker as Worker2 } from "node:worker_threads";
@@ -63776,7 +63853,7 @@ import { Worker as Worker2 } from "node:worker_threads";
63776
63853
  // src/tui/session/transcript-spill/spill-dir.mjs
63777
63854
  import { randomUUID as randomUUID2 } from "node:crypto";
63778
63855
  import { mkdtempSync, readdirSync as readdirSync5, readFileSync as readFileSync15, rmSync as rmSync5, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
63779
- import { tmpdir as tmpdir2 } from "node:os";
63856
+ import { tmpdir as tmpdir3 } from "node:os";
63780
63857
  import { join as join15 } from "node:path";
63781
63858
  var STALE_MS = 24 * 60 * 60 * 1e3;
63782
63859
  var PROCESS_NONCE = randomUUID2();
@@ -63786,6 +63863,7 @@ import { randomUUID as randomUUID3 } from "node:crypto";
63786
63863
 
63787
63864
  // src/tui/session/transcript-spill.mjs
63788
63865
  var TUI_DEBUG = /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_TUI_DEBUG || ""));
63866
+ var ID_PREFIX = `it_${randomBytes4(4).toString("hex")}_`;
63789
63867
 
63790
63868
  // src/tui/app/transcript-measure.mjs
63791
63869
  var HARVEST_BUMP_STREAK_LIMIT = 10;
@@ -66151,8 +66229,8 @@ function waitWithTimeout(promise, ms) {
66151
66229
  let timer2 = null;
66152
66230
  return Promise.race([
66153
66231
  Promise.resolve(promise).then(() => true),
66154
- new Promise((resolve7) => {
66155
- timer2 = setTimeout(() => resolve7(false), ms);
66232
+ new Promise((resolve8) => {
66233
+ timer2 = setTimeout(() => resolve8(false), ms);
66156
66234
  })
66157
66235
  ]).finally(() => {
66158
66236
  if (timer2) clearTimeout(timer2);
@@ -66171,7 +66249,7 @@ function scheduleHardExit(code = 0) {
66171
66249
  timer2.unref?.();
66172
66250
  }
66173
66251
  function resolveTuiStderrLogPath() {
66174
- return process.env.MIXDOG_TUI_STDERR_LOG || join17(process.env.MIXDOG_RUNTIME_ROOT || join17(tmpdir3(), "mixdog"), "mixdog-tui.stderr.log");
66252
+ return process.env.MIXDOG_TUI_STDERR_LOG || join17(process.env.MIXDOG_RUNTIME_ROOT || join17(tmpdir4(), "mixdog"), "mixdog-tui.stderr.log");
66175
66253
  }
66176
66254
  function ansiFg(rgb2) {
66177
66255
  const m = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/.exec(String(rgb2 || ""));
@@ -135,7 +135,12 @@ export function createContextState({
135
135
  const ctx = runtime.contextStatus?.() || null;
136
136
  if (!ctx) return null;
137
137
  syncContextDisplayFields(ctx);
138
- const stats = { ...getState().stats, ...contextMeasurementStats(ctx) };
138
+ const stats = {
139
+ ...getState().stats,
140
+ ...contextMeasurementStats(ctx),
141
+ // The persisted session totals behind the composer's usage readout.
142
+ usageReadout: ctx.usage?.usageReadout ?? null,
143
+ };
139
144
  updateState({ stats });
140
145
  return ctx;
141
146
  };