mixdog 1.2.6 → 1.3.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 (294) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +71 -9
  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 +10 -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 +14 -4
  13. package/src/defaults/skills/setup-guide/SKILL.md +178 -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/output-styles/common.md +13 -8
  17. package/src/rules/agent/AGENT.md +4 -0
  18. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  19. package/src/rules/agent-mode/MIXY.md +28 -0
  20. package/src/rules/agent-mode/ROUTINE.md +6 -0
  21. package/src/rules/lead/LEAD.md +7 -3
  22. package/src/rules/shared/70-delivery.md +3 -0
  23. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  24. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  25. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +241 -14
  26. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +4 -2
  27. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +216 -0
  28. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -4
  29. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  30. package/src/runtime/agent/orchestrator/mcp/client.mjs +115 -11
  31. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  34. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  35. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  36. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  37. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +1 -0
  40. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +10 -3
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  43. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +7 -8
  44. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  45. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +3 -1
  46. package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +9 -2
  49. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  50. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  51. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
  52. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
  53. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +96 -1
  55. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  56. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  57. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +14 -0
  58. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  59. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  60. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  61. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +21 -5
  62. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +40 -7
  63. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +52 -20
  64. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  66. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  67. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  68. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  69. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  70. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +166 -0
  71. package/src/runtime/agent/orchestrator/session/agent-room.mjs +650 -0
  72. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  73. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  74. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  75. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +192 -0
  76. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  77. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  78. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  79. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  80. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  81. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
  82. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  83. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +108 -6
  84. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -1
  85. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +74 -15
  86. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +9 -1
  87. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  88. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  89. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +49 -0
  90. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
  91. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  92. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -1
  93. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  94. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  95. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  96. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  97. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
  98. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  99. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  100. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +33 -24
  101. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +58 -8
  102. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  103. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  104. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
  105. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  106. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  107. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +27 -0
  108. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  109. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +86 -0
  110. package/src/runtime/agent/orchestrator/session/routine-result.mjs +329 -0
  111. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  112. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +28 -9
  113. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  114. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  115. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  116. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  117. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +58 -10
  118. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +92 -15
  119. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  120. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  121. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +4 -0
  122. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +25 -1
  123. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +8 -0
  124. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +6 -0
  125. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -0
  126. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +75 -57
  127. package/src/runtime/attachments/store.mjs +6 -0
  128. package/src/runtime/browser-bridge/client.mjs +24 -0
  129. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  130. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  131. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  132. package/src/runtime/channels/lib/webhook.mjs +0 -1
  133. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  134. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  135. package/src/runtime/computer-bridge/client.mjs +28 -1
  136. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  137. package/src/runtime/connectors/google-mcp.mjs +446 -0
  138. package/src/runtime/effort-judge/judge-client.mjs +1 -1
  139. package/src/runtime/effort-judge/model-manifest.json +7 -7
  140. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  141. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  142. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  143. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  144. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  145. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  146. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  147. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  148. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  149. package/src/runtime/memory/lib/memory.mjs +7 -1
  150. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  151. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  152. package/src/runtime/memory/lib/tool-call-handler.mjs +2 -0
  153. package/src/runtime/memory/tool-defs.mjs +5 -0
  154. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  155. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  156. package/src/runtime/shared/agent-avatar.mjs +320 -0
  157. package/src/runtime/shared/agent-kind.mjs +152 -0
  158. package/src/runtime/shared/agent-route-config.d.mts +4 -0
  159. package/src/runtime/shared/agent-route-config.mjs +30 -0
  160. package/src/runtime/shared/agent-store.mjs +132 -0
  161. package/src/runtime/shared/atomic-file.mjs +14 -1
  162. package/src/runtime/shared/bot-split-migration.mjs +457 -0
  163. package/src/runtime/shared/config-patch.mjs +20 -1
  164. package/src/runtime/shared/config.mjs +8 -1
  165. package/src/runtime/shared/connector-accounts.mjs +15 -0
  166. package/src/runtime/shared/connector-catalog.d.mts +51 -0
  167. package/src/runtime/shared/connector-catalog.mjs +228 -0
  168. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  169. package/src/runtime/shared/connector-triggers.mjs +45 -0
  170. package/src/runtime/shared/err-text.mjs +3 -1
  171. package/src/runtime/shared/error-presentation.mjs +91 -6
  172. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  173. package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
  174. package/src/runtime/shared/handoff-artifacts.mjs +61 -0
  175. package/src/runtime/shared/held-request-host.d.mts +12 -0
  176. package/src/runtime/shared/held-request-host.mjs +71 -0
  177. package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
  178. package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
  179. package/src/runtime/shared/model-route-fallback.mjs +79 -7
  180. package/src/runtime/shared/plain-preview.d.mts +1 -0
  181. package/src/runtime/shared/plain-preview.mjs +33 -0
  182. package/src/runtime/shared/routine-limits.d.mts +11 -0
  183. package/src/runtime/shared/routine-limits.mjs +21 -0
  184. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  185. package/src/runtime/shared/routine-trigger.mjs +44 -0
  186. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  187. package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
  188. package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
  189. package/src/runtime/shared/slow-span.mjs +4 -12
  190. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  191. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  192. package/src/runtime/shared/turn-changes.mjs +0 -8
  193. package/src/runtime/shared/usage-readout-totals.mjs +58 -0
  194. package/src/runtime/shared/user-data-guard.mjs +119 -38
  195. package/src/session-runtime/agent-home-delivery.mjs +826 -0
  196. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  197. package/src/session-runtime/agent-room-delivery.mjs +133 -0
  198. package/src/session-runtime/agent-task-sessions.mjs +460 -0
  199. package/src/session-runtime/boot/apis.mjs +63 -18
  200. package/src/session-runtime/boot/facade.mjs +5 -8
  201. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  202. package/src/session-runtime/boot/providers.mjs +14 -4
  203. package/src/session-runtime/boot/tools.mjs +3 -0
  204. package/src/session-runtime/channel-config-api.mjs +53 -5
  205. package/src/session-runtime/config-lifecycle.mjs +43 -2
  206. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  207. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  208. package/src/session-runtime/handoff-attachments.mjs +593 -0
  209. package/src/session-runtime/held-requests.mjs +228 -0
  210. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  211. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  212. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  213. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +56 -3
  214. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  215. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  216. package/src/session-runtime/lifecycle/session-switch/resume.mjs +4 -0
  217. package/src/session-runtime/lifecycle/shared.mjs +6 -0
  218. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  219. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  220. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  221. package/src/session-runtime/model-route/route-persist.mjs +2 -2
  222. package/src/session-runtime/model-route/route-tuning.mjs +7 -1
  223. package/src/session-runtime/model-route/set-route.mjs +35 -4
  224. package/src/session-runtime/native-web-search.mjs +2 -2
  225. package/src/session-runtime/new-session-config.mjs +6 -1
  226. package/src/session-runtime/owned-automation-run.mjs +229 -0
  227. package/src/session-runtime/resource-api.mjs +5 -0
  228. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  229. package/src/session-runtime/resource-skills-api.mjs +12 -0
  230. package/src/session-runtime/room-member-gate.mjs +48 -0
  231. package/src/session-runtime/route-resolution.mjs +5 -11
  232. package/src/session-runtime/routine-home-turn.mjs +156 -0
  233. package/src/session-runtime/routine-owner.mjs +48 -0
  234. package/src/session-runtime/schedule-session-run.mjs +30 -64
  235. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -1
  236. package/src/session-runtime/services/agent-tool/send-flow.mjs +11 -3
  237. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  238. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  239. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  240. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
  241. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  242. package/src/session-runtime/services/channel-admin.mjs +93 -24
  243. package/src/session-runtime/services/memory-access.mjs +37 -0
  244. package/src/session-runtime/services/provider-admin.mjs +74 -39
  245. package/src/session-runtime/services/schedule-access.mjs +91 -0
  246. package/src/session-runtime/session-create/session-options.mjs +34 -7
  247. package/src/session-runtime/session-hooks.mjs +16 -8
  248. package/src/session-runtime/setup-tool/executor.mjs +79 -6
  249. package/src/session-runtime/setup-tool/extended-actions.mjs +90 -20
  250. package/src/session-runtime/setup-tool/settings-contract.mjs +14 -6
  251. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  252. package/src/session-runtime/skills-api.mjs +16 -1
  253. package/src/session-runtime/tool-policy-refresh.mjs +249 -29
  254. package/src/session-runtime/turn/session-ops.mjs +8 -1
  255. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +10 -2
  256. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +14 -0
  257. package/src/session-runtime/webhook-session-run.mjs +49 -67
  258. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  259. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +650 -25
  260. package/src/session-runtime/workflow-agents-api/agent-route.mjs +67 -7
  261. package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
  262. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  263. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  264. package/src/standalone/daemon-agent-control.mjs +1 -8
  265. package/src/standalone/daemon-session-control.mjs +21 -4
  266. package/src/standalone/daemon.mjs +31 -5
  267. package/src/standalone/session-protocol.mjs +27 -0
  268. package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
  269. package/src/standalone/session-service/agent-tree.mjs +4 -3
  270. package/src/standalone/session-service/session-calls/session-turns.mjs +28 -0
  271. package/src/standalone/session-service.mjs +19 -0
  272. package/src/tui/app/slash-commands.mjs +20 -0
  273. package/src/tui/dist/index.mjs +234 -95
  274. package/src/tui/session/context-state.mjs +6 -1
  275. package/src/tui/session/notice-surface.mjs +34 -4
  276. package/src/tui/session/queue-helpers.mjs +2 -1
  277. package/src/tui/session/session-api/extensions.mjs +4 -0
  278. package/src/tui/session/session-api/intake/submission.mjs +5 -0
  279. package/src/tui/session/session-api/integrations.mjs +8 -0
  280. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  281. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  282. package/src/tui/session/session-api/routes.mjs +61 -5
  283. package/src/tui/session/session-flow/drain.mjs +12 -3
  284. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  285. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  286. package/src/tui/session/session-flow/steering.mjs +58 -24
  287. package/src/tui/session/tool-approval.mjs +26 -5
  288. package/src/tui/session/transcript-intake.mjs +8 -2
  289. package/src/tui/session/transcript-spill.mjs +5 -1
  290. package/src/tui/session/tui-steering-persist.mjs +65 -42
  291. package/src/tui/session/turn-live-call.mjs +64 -0
  292. package/src/tui/session/turn.mjs +34 -8
  293. package/src/session-runtime/automation-agents.mjs +0 -94
  294. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -29,15 +29,22 @@ export function createSessionOps(deps) {
29
29
  } catch {}
30
30
  }
31
31
 
32
+ // `rebuildPrompt` (an agent chat's "대화 초기화"): refused while a turn
33
+ // runs, and the emptied session's prompt and tool surface are then rebuilt
34
+ // from the current rules, as a new session's are (refreshEmptySessionToolPolicy).
32
35
  async function clear(options = {}) {
33
36
  const session = getSession();
34
37
  if (!session?.id) return false;
38
+ const rebuild = options.rebuildPrompt === true;
39
+ if (rebuild && getActiveTurnCount() > 0) throw new Error('The session is running a turn; wait for it to finish.');
35
40
  const cleared = await mgr.clearSessionMessages(session.id, options);
36
41
  if (!cleared) return false;
37
42
  setSession(typeof cleared === 'object' ? cleared : mgr.getSession(session.id) || session);
38
43
  if (options.recoverAgent === true) recoverAgentWorkers();
44
+ let promptRebuilt = false;
45
+ if (rebuild) promptRebuilt = (await refreshEmptySessionToolPolicy?.())?.appliedToCurrentSession === true;
39
46
  invalidateContextStatusCache();
40
- return true;
47
+ return rebuild ? { promptRebuilt } : true;
41
48
  }
42
49
 
43
50
  // Message-selector rewind: drop the chosen user prompt and everything
@@ -61,11 +61,17 @@ export function createAskCallbacks({ transcript, notifyFnForSession, scheduleSea
61
61
 
62
62
  // The turn's change-record key rides the caller's transcript metadata (in
63
63
  // place: the stream stamps assistantAt on this same object), so the
64
- // persisted user row and completion carry it across restore.
64
+ // persisted user row and completion carry it across restore. A merged
65
+ // batch also names every submission it delivers, so a queued-input restore
66
+ // can tell each one delivered.
65
67
  function stampCheckpoint(options) {
66
68
  const meta = options.transcriptMeta;
69
+ if (!meta || typeof meta !== 'object') return meta;
67
70
  const checkpointId = String(options.id || '').trim();
68
- if (checkpointId && meta && typeof meta === 'object') meta.checkpointId = checkpointId;
71
+ if (checkpointId) meta.checkpointId = checkpointId;
72
+ if (Array.isArray(options.submissionIds) && options.submissionIds.length > 1) {
73
+ meta.submissionIds = options.submissionIds.map(String);
74
+ }
69
75
  return meta;
70
76
  }
71
77
 
@@ -74,6 +80,8 @@ export function createAskCallbacks({ transcript, notifyFnForSession, scheduleSea
74
80
  beforeToolExecution: () => turn.snapshot.promise || Promise.resolve(),
75
81
  transcriptMeta: stampCheckpoint(options),
76
82
  promptSource: options.promptSource,
83
+ // A routine turn's trusted selection text (its instructions only).
84
+ ...(typeof options.skillSelection === 'string' ? { skillSelection: options.skillSelection } : {}),
77
85
  retryFailedTurn: options.retryFailedTurn === true,
78
86
  retryTurnId: options.retryTurnId,
79
87
  retryAttemptId: options.retryAttemptId,
@@ -10,6 +10,8 @@ import { throwIfAborted } from '../../../runtime/shared/abort-race.mjs';
10
10
  // UserPromptSubmit hook.
11
11
  export function createTurnPreparation({
12
12
  getSession,
13
+ setSession,
14
+ mgr,
13
15
  getCurrentCwd,
14
16
  awaitRoutePreparation,
15
17
  createCurrentSession,
@@ -24,6 +26,7 @@ export function createTurnPreparation({
24
26
  prepareTurnWorkspace,
25
27
  admitTurnWorkspace,
26
28
  applyPendingRoute,
29
+ applyPendingAgentProfile,
27
30
  }) {
28
31
  const scopedMcpTools = (session) => scopedMcpToolsFor(session, getConfig());
29
32
 
@@ -104,6 +107,15 @@ export function createTurnPreparation({
104
107
  }
105
108
  throwIfAborted(turn.signal);
106
109
  assertSessionAdmission?.();
110
+ // askSession runs the turn on the session the store serves for this id.
111
+ // While this runtime idled, the store's idle sweep may have released the
112
+ // snapshot it holds, and the store then serves a fresh parse of the file:
113
+ // preparing the turn on the held copy would leave its one-shot work (the
114
+ // first-turn MCP fold, its flag) undone on the turn's session, which then
115
+ // rewrites the prompt it already sent on the next turn. Prepare the turn
116
+ // on the session it runs on (as completeTurn adopts it afterwards).
117
+ const stored = mgr.getSession(getSession().id);
118
+ if (stored && stored !== getSession()) setSession(stored);
107
119
  // Turn admission: waits while this session's workspace transitions or
108
120
  // another session changes the checkout this session works in, then holds
109
121
  // the turn registered (released by settleTurn) so no checkout changes
@@ -131,6 +143,8 @@ export function createTurnPreparation({
131
143
  assertSessionAdmission?.();
132
144
  }
133
145
  const modelSwitch = applyPendingRoute?.();
146
+ // An agent profile saved while the previous turn ran applies from this one.
147
+ await applyPendingAgentProfile?.();
134
148
  options.onRouteApplied?.(getSession());
135
149
  if (modelSwitch) options.onModelSwitch?.(modelSwitch);
136
150
  ensureSessionTranscriptWriter?.();
@@ -1,83 +1,65 @@
1
1
  /**
2
- * Run an inbound webhook as a VISIBLE Mixdog session (schedules parity, user
3
- * decision): no Lead-context injection, no channel forward — every fire is a
4
- * fresh New task with the endpoint's prompt/model/workflow/project, owned by
5
- * 'user' + sourceType 'webhook' (sidebar Automations section, newest per
6
- * name). Invoked from the channels worker's webhook dispatch.
2
+ * Run an inbound webhook: the endpoint's instructions and the fenced event
3
+ * payload become one turn in its owner bot's home thread
4
+ * (routine-home-turn.mjs). Invoked from the channels worker's webhook
5
+ * dispatch and the app's "Run now".
7
6
  */
8
- import { loadConfig } from '../runtime/agent/orchestrator/config.mjs';
9
- import { createSession } from '../runtime/agent/orchestrator/session/manager/session-lifecycle.mjs';
10
- import { askSession } from '../runtime/agent/orchestrator/session/manager/ask-session.mjs';
11
- import { modelRouteFields, parseScheduleModelRef } from '../runtime/shared/schedule-model-ref.mjs';
12
- import { migrateCodexRoute } from '../runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs';
13
- import { automationWorkflowOpts } from './automation-workflow.mjs';
14
- import { runAutomationTurns } from './automation-agents.mjs';
15
- import { automationPromptContent } from '../runtime/shared/automation-attachments.mjs';
7
+ import { markEndpointRun } from '../runtime/channels/lib/webhooks-db.mjs';
8
+ import { runOwnedAutomation } from './owned-automation-run.mjs';
9
+ import { runRoutineTurn } from './routine-home-turn.mjs';
16
10
 
17
- /** Endpoint model ref wins; the maintenance.webhook route is the fallback. */
18
- function webhookRoute(modelRef) {
19
- if (modelRef) {
20
- const ref = parseScheduleModelRef(modelRef);
21
- // A model the provider catalog superseded runs on its successor.
22
- if (ref && typeof ref === 'object') return migrateCodexRoute(ref);
11
+ /**
12
+ * One run of the endpoint in its owner's thread (Mixy when absent): a run
13
+ * while the previous one of the same endpoint is still going is skipped (and
14
+ * stamped), and every outcome is stamped on the endpoint. `prompt` carries the
15
+ * fenced payload; `skillSelection` only the endpoint's instructions.
16
+ */
17
+ export async function runWebhookSession({ ownerAgentId = null, ...options }, deps = {}) {
18
+ const name = String(options.name || '').trim();
19
+ const { markRun = markEndpointRun, run = runWebhookTurn, ...ownedDeps } = deps;
20
+ const stamp = (outcome) =>
21
+ markRun(name, outcome, new Date()).catch((error) =>
22
+ process.stderr.write(`mixdog webhook: ${name} ${outcome} stamp failed: ${error?.message || error}\n`)
23
+ );
24
+ let outcome;
25
+ try {
26
+ // The dispatch's cancellation reaches the run as `signal`.
27
+ outcome = await runOwnedAutomation(
28
+ 'webhook',
29
+ { name, ownerAgentId },
30
+ ({ signal }) => run({ ...options, ownerAgentId, signal }),
31
+ { recordSkip: () => stamp('skipped'), signal: options.signal || null, ...ownedDeps }
32
+ );
33
+ } catch (error) {
34
+ await stamp('failed');
35
+ throw error;
23
36
  }
24
- const cfg = loadConfig({ secrets: false });
25
- const maintenance = cfg?.maintenance?.webhook;
26
- if (maintenance?.provider && maintenance?.model) return modelRouteFields(maintenance);
27
- throw new Error('webhook run has no model: set one on the endpoint or configure maintenance.webhook');
37
+ if (!outcome.skipped) await stamp('success');
38
+ return outcome;
28
39
  }
29
40
 
30
- export async function runWebhookSession({
41
+ /** One turn in the owner's thread; `skillSelection` absent selects nothing. */
42
+ function runWebhookTurn({
31
43
  name,
32
- model = null,
33
44
  prompt,
45
+ ownerAgentId = null,
34
46
  cwd = null,
35
- workflow = null,
36
47
  attachments = null,
37
- signal = null,
38
- // Endpoint-authored instructions: the run's ONLY skill-selection input.
39
- // `prompt` also carries the fenced external payload, which must never
40
- // select a skill; absent means nothing selects.
48
+ event = '',
41
49
  skillSelection = '',
50
+ signal = null,
42
51
  }) {
43
52
  const endpoint = String(name || '').trim();
44
- const body = String(prompt || '').trim();
45
53
  if (!endpoint) throw new Error('runWebhookSession: endpoint name required');
46
- if (!body) throw new Error(`webhook "${endpoint}" has no prompt body`);
47
- // The dispatcher's cancellation (delivery timeout) has to reach the run
48
- // itself: an already-cancelled dispatch must not even create a session.
49
- if (signal?.aborted) throw signal.reason ?? new Error('webhook dispatch aborted');
50
- const route = webhookRoute(model);
51
- const projectCwd = cwd ? String(cwd) : null;
52
- const session = createSession({
53
- ...modelRouteFields(route),
54
- owner: 'user',
55
- sourceType: 'webhook',
56
- sourceName: endpoint,
57
- ...(projectCwd ? { cwd: projectCwd } : {}),
58
- desktopSession: projectCwd
59
- ? { classification: 'project', projectPath: projectCwd }
60
- : { classification: 'task', projectPath: null },
61
- ...automationWorkflowOpts(workflow),
54
+ return runRoutineTurn({
55
+ kind: 'webhook',
56
+ name: endpoint,
57
+ ownerAgentId,
58
+ prompt,
59
+ skillSelection: String(skillSelection ?? ''),
60
+ attachments,
61
+ cwd,
62
+ event,
63
+ signal,
62
64
  });
63
- // The user message leads with the endpoint's instructions, so Recent titles
64
- // read as the user-authored intent rather than payload noise.
65
- // Stored attachments ride along as composer-style content parts.
66
- const content = automationPromptContent(body, attachments);
67
- // askOpts.signal is the parent-abort link: it is cascaded onto the turn
68
- // controller, so aborting it stops the in-flight provider/tool work instead
69
- // of leaving a timed-out delivery's session running with live side effects.
70
- const ask = (turnContent, askOpts) =>
71
- askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, {
72
- ...askOpts,
73
- ...(signal ? { signal } : {}),
74
- });
75
- // Agents the run delegates to report back; each result is the next turn
76
- // (runAutomationTurns marks those turns as task notifications).
77
- const result = await runAutomationTurns(
78
- session.id,
79
- () => ask(content, { skillSelection: String(skillSelection ?? '') }),
80
- ask
81
- );
82
- return { sessionId: session.id, result: String(result?.content || '') };
83
65
  }
@@ -0,0 +1,239 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import {
4
+ CONNECTOR_PERMISSIONS,
5
+ connectorEnabled,
6
+ DENY_ALL_CONNECTORS,
7
+ migrateLegacyConnectorPolicy,
8
+ PROJECT_CONNECTORS_FILE,
9
+ parseConnectorPolicy,
10
+ readProjectConnectorsFile,
11
+ storedConnectorPolicy,
12
+ } from '../../runtime/agent/orchestrator/mcp/agent-connectors.mjs';
13
+ import {
14
+ cwdWithinProjects,
15
+ extensionScopesFromConfig,
16
+ withExtensionScope,
17
+ } from '../../runtime/shared/extension-scopes.mjs';
18
+ import { withFileLockSync, writeJsonAtomicSync } from '../../runtime/shared/atomic-file.mjs';
19
+ import { listProjectsStrict } from '../../runtime/shared/projects.mjs';
20
+ import { isSelfMcpToolName, parseMcpToolName } from '../../runtime/shared/tool-primitives.mjs';
21
+ import { resolveDataDir } from './shared.mjs';
22
+
23
+ const samePath = (left, right) => cwdWithinProjects(left, [right]) && cwdWithinProjects(right, [left]);
24
+ const PLUGIN_REGISTRY_WARNING = /^plugin MCP servers unavailable/;
25
+
26
+ // Host-only surface for the connector switches ("사용할 커넥터"): the global
27
+ // MCP servers (with their sign-in state), and per agent and per project which
28
+ // of them are on. Every installed connector is on unless switched off there.
29
+ // Agent policies go through the agent editor, which keeps every other
30
+ // agent.json key; project policies live in <data>/project-connectors.json,
31
+ // keyed by the registered Project path.
32
+ export function createAgentConnectorsApi(deps, editor) {
33
+ const {
34
+ mcpStatus,
35
+ getMcpTools,
36
+ getConfig,
37
+ saveConfigAndAdopt,
38
+ resolveConfiguredMcpCatalog,
39
+ listProjects = listProjectsStrict,
40
+ } = deps;
41
+ const dataDir = () => resolveDataDir(deps);
42
+ const projectFile = () => join(dataDir(), PROJECT_CONNECTORS_FILE);
43
+ const installedIds = () => listConnectors().map(({ id }) => id);
44
+ const switches = (policy) => installedIds().map((id) => ({ id, enabled: connectorEnabled(policy, id) }));
45
+ // A legacy list or an unreadable policy becomes its deny-list equivalent
46
+ // over today's connectors before any edit, so an edit never widens it.
47
+ const editablePolicy = (agentId) =>
48
+ migrateLegacyConnectorPolicy(editor.getAgentConnectorPolicy(agentId), installedIds()) || { off: [], tools: {} };
49
+
50
+ function listConnectors() {
51
+ return (mcpStatus()?.servers || []).map((row) => ({
52
+ id: row.name,
53
+ enabled: row.enabled !== false,
54
+ status: row.status,
55
+ connected: row.connected === true,
56
+ authRequired: row.authRequired === true,
57
+ signedIn: row.oauth ? row.oauth.signedIn === true : null,
58
+ transport: row.transport,
59
+ toolCount: row.toolCount || 0,
60
+ source: row.source,
61
+ ...(row.error ? { error: row.error } : {}),
62
+ }));
63
+ }
64
+
65
+ // `readOnly` is the server's own `readOnlyHint` (null when it gives none).
66
+ function listConnectorTools(connectorId) {
67
+ return (getMcpTools() || [])
68
+ .filter((tool) => !isSelfMcpToolName(tool) && parseMcpToolName(tool)?.server === connectorId)
69
+ .map((tool) => {
70
+ const annotations = tool.annotations && typeof tool.annotations === 'object' ? tool.annotations : {};
71
+ return {
72
+ name: parseMcpToolName(tool).tool,
73
+ description: tool.description || '',
74
+ annotations,
75
+ readOnly: typeof annotations.readOnlyHint === 'boolean' ? annotations.readOnlyHint : null,
76
+ };
77
+ });
78
+ }
79
+
80
+ const requireId = (value, label) => {
81
+ const id = typeof value === 'string' ? value.trim() : '';
82
+ if (!id) throw new Error(`${label} is required`);
83
+ return id;
84
+ };
85
+
86
+ /** `[{ id, enabled }]`: each installed connector and whether the agent may use it. */
87
+ function getAgentConnectors(agentId) {
88
+ return switches(editor.getAgentConnectorPolicy(agentId));
89
+ }
90
+
91
+ /** Switch one connector on or off for the agent; returns its switches. */
92
+ async function setAgentConnectorEnabled(agentId, connectorId, enabled) {
93
+ const id = requireId(connectorId, 'connector id');
94
+ if (typeof enabled !== 'boolean') throw new TypeError('enabled must be a boolean');
95
+ const policy = editablePolicy(agentId);
96
+ const off = enabled ? policy.off.filter((entry) => entry !== id) : [...policy.off, id];
97
+ await editor.setAgentConnectorPolicy(agentId, storedConnectorPolicy({ off, tools: policy.tools }));
98
+ return getAgentConnectors(agentId);
99
+ }
100
+
101
+ // Older per-tool overrides keep working (the profile no longer shows them):
102
+ // `permission` null drops the tool's entry, so the tool is auto again.
103
+ async function setAgentConnectorToolPermission(agentId, connectorId, toolName, permission) {
104
+ if (permission != null && !CONNECTOR_PERMISSIONS.includes(permission)) {
105
+ throw new Error(`permission must be one of ${CONNECTOR_PERMISSIONS.join(', ')}`);
106
+ }
107
+ const server = requireId(connectorId, 'connector id');
108
+ const tool = requireId(toolName, 'tool name');
109
+ const policy = editablePolicy(agentId);
110
+ const own = { ...policy.tools[server] };
111
+ if (permission == null) delete own[tool];
112
+ else own[tool] = permission;
113
+ return editor.setAgentConnectorPolicy(
114
+ agentId,
115
+ storedConnectorPolicy({ off: policy.off, tools: { ...policy.tools, [server]: own } })
116
+ );
117
+ }
118
+
119
+ /** The registered Project at `projectPath` (its path is the policy key). */
120
+ function registeredProject(projectPath) {
121
+ const path = requireId(projectPath, 'project path');
122
+ const project = listProjects().find((entry) => samePath(entry.path, path));
123
+ if (!project) throw new Error(`project not registered: ${path}`);
124
+ return project.path;
125
+ }
126
+
127
+ function projectPolicies() {
128
+ const policies = readProjectConnectorsFile(projectFile());
129
+ if (policies === DENY_ALL_CONNECTORS) return policies;
130
+ return policies || [];
131
+ }
132
+
133
+ /** `[{ id, enabled }]`: each installed connector and whether the project allows it. */
134
+ function getProjectConnectors(projectPath) {
135
+ const root = registeredProject(projectPath);
136
+ const policies = projectPolicies();
137
+ if (policies === DENY_ALL_CONNECTORS) return switches(DENY_ALL_CONNECTORS);
138
+ const off = policies.filter((entry) => samePath(entry.root, root)).flatMap((entry) => entry.off);
139
+ return switches({ off, tools: {} });
140
+ }
141
+
142
+ /** Rewrite the project policy file under its lock; `edit` maps root → off list. */
143
+ function updateProjectPolicies(edit) {
144
+ const path = projectFile();
145
+ withFileLockSync(`${path}.lock`, () => {
146
+ const policies = projectPolicies();
147
+ // A file that cannot be read is never overwritten: it may hold switches.
148
+ if (policies === DENY_ALL_CONNECTORS) {
149
+ throw new Error(`${PROJECT_CONNECTORS_FILE} cannot be read; fix or remove it first`);
150
+ }
151
+ const byRoot = new Map(policies.map(({ root, off }) => [root, off]));
152
+ edit(byRoot);
153
+ const projects = {};
154
+ for (const [root, off] of byRoot) if (off.length) projects[root] = { off: [...new Set(off)].sort() };
155
+ writeJsonAtomicSync(path, { projects }, { lock: false });
156
+ });
157
+ }
158
+
159
+ /** Switch one connector on or off for the project; returns its switches. */
160
+ function setProjectConnectorEnabled(projectPath, connectorId, enabled) {
161
+ const id = requireId(connectorId, 'connector id');
162
+ if (typeof enabled !== 'boolean') throw new TypeError('enabled must be a boolean');
163
+ const root = registeredProject(projectPath);
164
+ updateProjectPolicies((byRoot) => {
165
+ const key = [...byRoot.keys()].find((entry) => samePath(entry, root)) ?? root;
166
+ const off = (byRoot.get(key) || []).filter((entry) => entry !== id);
167
+ byRoot.set(key, enabled ? off : [...off, id]);
168
+ });
169
+ return getProjectConnectors(root);
170
+ }
171
+
172
+ /** One-time, idempotent: legacy allow lists become deny lists. Agent lists
173
+ * (agent.json arrays) switch off each configured connector they did not
174
+ * enable; MCP project scopes (`extensionScopes.mcp`, "only in these
175
+ * projects") switch the server off in every other registered Project.
176
+ * Skipped while the configured connector set is not fully known. */
177
+ function migrateConnectorPolicies() {
178
+ const catalog = resolveConfiguredMcpCatalog?.();
179
+ if (!catalog || (catalog.warnings || []).some((warning) => PLUGIN_REGISTRY_WARNING.test(warning?.message || ''))) {
180
+ return { skipped: true, agents: [], scopes: [] };
181
+ }
182
+ const installed = Object.keys(catalog.servers || {});
183
+ const agents = [];
184
+ const agentsDir = join(dataDir(), 'agents');
185
+ let entries = [];
186
+ try {
187
+ entries = readdirSync(agentsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory());
188
+ } catch {
189
+ entries = [];
190
+ }
191
+ for (const entry of entries) {
192
+ const file = join(agentsDir, entry.name, 'agent.json');
193
+ let manifest;
194
+ try {
195
+ manifest = JSON.parse(readFileSync(file, 'utf8'));
196
+ } catch {
197
+ continue; // missing or unreadable: the runtime already denies or allows as before
198
+ }
199
+ if (!Array.isArray(manifest?.connectors)) continue;
200
+ const next = storedConnectorPolicy(
201
+ migrateLegacyConnectorPolicy(parseConnectorPolicy(manifest.connectors), installed)
202
+ );
203
+ if (next) manifest.connectors = next;
204
+ else delete manifest.connectors;
205
+ writeJsonAtomicSync(file, manifest);
206
+ agents.push(entry.name);
207
+ }
208
+ const config = getConfig?.();
209
+ const scoped = Object.entries(extensionScopesFromConfig(config).mcp);
210
+ if (scoped.length) {
211
+ const projects = listProjects();
212
+ updateProjectPolicies((byRoot) => {
213
+ for (const [server, roots] of scoped) {
214
+ for (const { path } of projects) {
215
+ if (cwdWithinProjects(path, roots)) continue;
216
+ const key = [...byRoot.keys()].find((root) => samePath(root, path)) ?? path;
217
+ byRoot.set(key, [...(byRoot.get(key) || []), server]);
218
+ }
219
+ }
220
+ });
221
+ let next = config;
222
+ for (const [server] of scoped) next = withExtensionScope(next, 'mcp', server, null);
223
+ saveConfigAndAdopt(next);
224
+ }
225
+ return { skipped: false, agents, scopes: scoped.map(([server]) => server) };
226
+ }
227
+
228
+ return {
229
+ listConnectors,
230
+ listConnectorTools,
231
+ getAgentConnectors,
232
+ setAgentConnectors: editor.setAgentConnectorPolicy,
233
+ setAgentConnectorEnabled,
234
+ setAgentConnectorToolPermission,
235
+ getProjectConnectors,
236
+ setProjectConnectorEnabled,
237
+ migrateConnectorPolicies,
238
+ };
239
+ }