mixdog 0.9.25 → 0.9.27

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 (87) hide show
  1. package/package.json +2 -1
  2. package/scripts/arg-guard-test.mjs +68 -0
  3. package/scripts/compacted-placeholder-scrub-test.mjs +77 -0
  4. package/scripts/steering-fold-provenance-test.mjs +71 -0
  5. package/scripts/webhook-smoke.mjs +46 -53
  6. package/src/cli.mjs +40 -4
  7. package/src/defaults/skills/setup/SKILL.md +6 -1
  8. package/src/rules/shared/01-tool.md +11 -4
  9. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  10. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +17 -0
  11. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +2 -2
  12. package/src/runtime/agent/orchestrator/mcp/client.mjs +28 -10
  13. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +8 -1
  14. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  15. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +51 -15
  16. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +5 -1
  17. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +164 -9
  18. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +75 -0
  19. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +5 -0
  20. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +4 -0
  21. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +12 -1
  22. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +14 -1
  23. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
  24. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +2 -2
  25. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  26. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +7 -3
  28. package/src/runtime/channels/lib/config.mjs +13 -11
  29. package/src/runtime/channels/lib/memory-client.mjs +22 -2
  30. package/src/runtime/channels/lib/owned-runtime.mjs +1 -1
  31. package/src/runtime/channels/lib/scheduler.mjs +226 -208
  32. package/src/runtime/channels/lib/status-snapshot.mjs +16 -0
  33. package/src/runtime/channels/lib/webhook/deliveries.mjs +7 -318
  34. package/src/runtime/channels/lib/webhook.mjs +98 -150
  35. package/src/runtime/channels/lib/worker-main.mjs +1 -1
  36. package/src/runtime/memory/index.mjs +50 -25
  37. package/src/runtime/memory/lib/cycle-scheduler.mjs +3 -1
  38. package/src/runtime/memory/lib/memory-config-flags.mjs +13 -1
  39. package/src/runtime/memory/lib/pg/adapter.mjs +6 -1
  40. package/src/runtime/memory/lib/pg/process.mjs +19 -1
  41. package/src/runtime/memory/lib/pg/supervisor.mjs +125 -14
  42. package/src/runtime/memory/lib/query-handlers.mjs +102 -0
  43. package/src/runtime/memory/lib/recall-format.mjs +60 -22
  44. package/src/runtime/memory/lib/session-ingest-runtime.mjs +20 -6
  45. package/src/runtime/memory/tool-defs.mjs +3 -3
  46. package/src/runtime/shared/child-guardian.mjs +2 -2
  47. package/src/runtime/shared/open-url.mjs +2 -1
  48. package/src/runtime/shared/schedules-db.mjs +350 -0
  49. package/src/runtime/shared/service-discovery.mjs +169 -0
  50. package/src/runtime/shared/spawn-flags.mjs +27 -0
  51. package/src/runtime/shared/staged-install-worker.mjs +14 -0
  52. package/src/runtime/shared/staged-update.mjs +530 -0
  53. package/src/runtime/shared/tool-primitives.mjs +3 -1
  54. package/src/runtime/shared/tool-surface.mjs +19 -3
  55. package/src/runtime/shared/update-checker.mjs +54 -10
  56. package/src/runtime/shared/webhooks-db.mjs +405 -0
  57. package/src/session-runtime/channel-config-api.mjs +13 -13
  58. package/src/session-runtime/lifecycle-api.mjs +12 -0
  59. package/src/session-runtime/runtime-core.mjs +41 -23
  60. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  61. package/src/standalone/agent-tool.mjs +42 -11
  62. package/src/standalone/channel-admin.mjs +173 -121
  63. package/src/standalone/channel-worker.mjs +2 -2
  64. package/src/standalone/memory-runtime-proxy.mjs +10 -5
  65. package/src/tui/App.jsx +32 -10
  66. package/src/tui/app/channel-pickers.mjs +9 -9
  67. package/src/tui/app/clipboard.mjs +14 -0
  68. package/src/tui/app/doctor.mjs +1 -1
  69. package/src/tui/app/maintenance-pickers.mjs +17 -7
  70. package/src/tui/app/settings-picker.mjs +2 -2
  71. package/src/tui/app/transcript-window.mjs +63 -7
  72. package/src/tui/app/use-mouse-input.mjs +19 -6
  73. package/src/tui/components/Spinner.jsx +5 -2
  74. package/src/tui/components/StatusLine.jsx +7 -7
  75. package/src/tui/components/ToolExecution.jsx +36 -62
  76. package/src/tui/display-width.mjs +18 -8
  77. package/src/tui/dist/index.mjs +502 -324
  78. package/src/tui/engine/session-api-ext.mjs +12 -12
  79. package/src/tui/hooks/useSharedTick.mjs +103 -0
  80. package/src/tui/index.jsx +12 -2
  81. package/src/tui/markdown/format-token.mjs +46 -8
  82. package/src/tui/markdown/render-ansi.mjs +24 -1
  83. package/src/tui/markdown/stream-fence.mjs +60 -0
  84. package/src/tui/markdown/streaming-markdown.mjs +22 -1
  85. package/src/ui/statusline-segments.mjs +12 -1
  86. package/vendor/ink/build/display-width.js +10 -8
  87. package/src/runtime/shared/schedules-store.mjs +0 -82
@@ -3,7 +3,7 @@ import { join } from "path";
3
3
  import { DiscordBackend } from "../backends/discord.mjs";
4
4
  import { TelegramBackend } from "../backends/telegram.mjs";
5
5
  import { readSection, updateSection, CONFIG_PATH as MIXDOG_CONFIG_PATH, getDiscordToken, getTelegramToken, diagnoseDiscordTokenValue } from "../../shared/config.mjs";
6
- import { listSchedules } from "../../shared/schedules-store.mjs";
6
+ import { listSchedules } from "../../shared/schedules-db.mjs";
7
7
  import { resolvePluginData } from "../../shared/plugin-paths.mjs";
8
8
  const DATA_DIR = resolvePluginData();
9
9
  const CONFIG_FILE = MIXDOG_CONFIG_PATH;
@@ -63,19 +63,21 @@ function resolveChannelId(raw = {}, backend = "discord") {
63
63
  return "";
64
64
  }
65
65
 
66
- function loadConfig() {
66
+ async function loadConfig() {
67
67
  try {
68
68
  let raw = readSection("channels");
69
69
  raw = raw && typeof raw === "object" ? raw : {};
70
- // Schedules live in the Mixdog data dir under `schedules/<name>/` (single
71
- // source of truth). The legacy `raw.schedules.items` / `raw.nonInteractive`
72
- // / `raw.interactive` arrays in mixdog-config.json are no longer read.
73
- const scheduleEntries = listSchedules().filter((s) => s.enabled !== false);
74
- // Channel-presence routing (no `type` field): an entry WITH a channel is
75
- // dispatched directly to that channel; an entry WITHOUT a channel is
76
- // injected into the current (Lead) session. Mirrors the webhook model.
77
- raw.nonInteractive = scheduleEntries.filter((i) => !!i.channel);
78
- raw.interactive = scheduleEntries.filter((i) => !i.channel);
70
+ // Schedules are the PG `scheduler.schedules` table (single source of
71
+ // truth). The legacy SCHEDULE.md store and the `raw.schedules.items` /
72
+ // `raw.nonInteractive` / `raw.interactive` arrays in mixdog-config.json
73
+ // are no longer read. Done one-shots are dropped so they never re-arm.
74
+ const scheduleEntries = (await listSchedules())
75
+ .filter((s) => s.enabled !== false && s.status !== "done");
76
+ // `target` drives routing: 'channel' non-interactive dispatch to the
77
+ // schedule's channel_id; 'session' → inject into the current (Lead)
78
+ // session. Mirrors the webhook model.
79
+ raw.nonInteractive = scheduleEntries.filter((s) => s.target === "channel");
80
+ raw.interactive = scheduleEntries.filter((s) => s.target === "session");
79
81
  const accessChannels = { ...raw.access?.channels ?? {} };
80
82
  // voice config lives at the top level of mixdog-config.json (peer of
81
83
  // channels), so readSection("channels") never sees it. Pull it explicitly.
@@ -4,6 +4,7 @@ import os from 'node:os'
4
4
  import path from 'node:path'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { createStandaloneMemoryRuntime } from '../../../standalone/memory-runtime-proxy.mjs'
7
+ import { readServicePort, markServiceUnreachable, isConnRefuseError } from '../../shared/service-discovery.mjs'
7
8
 
8
9
  const RUNTIME_ROOT = process.env.MIXDOG_RUNTIME_ROOT
9
10
  ? path.resolve(process.env.MIXDOG_RUNTIME_ROOT)
@@ -60,9 +61,28 @@ function isConnRefusedLike(err) {
60
61
  || /ECONNREFUSED|missing memory_port|memory-service timeout/i.test(msg)
61
62
  }
62
63
 
64
+ // A discovery advert validates only the owner pid, which can be a recycled pid
65
+ // living on an unrelated process while its advertised port is dead. This client
66
+ // has no separate /health probe, so on a connect-level failure we distrust the
67
+ // port: mark it unreachable (readServicePort then skips it → legacy fallback)
68
+ // and drop the port cache so the next getMemoryPort re-resolves.
69
+ function _distrustMemoryPort(port, err) {
70
+ // Connection-level failures ONLY. A 'memory-service timeout' means the daemon
71
+ // is slow-but-alive — distrusting it would false-route to legacy/buffer.
72
+ if (port && isConnRefuseError(err)) {
73
+ markServiceUnreachable('memory', port)
74
+ _portCache = null
75
+ }
76
+ }
77
+
63
78
  async function getMemoryPort() {
64
79
  const now = Date.now()
65
80
  if (_portCache && (now - _portCache.ts) < 5_000) return _portCache.port
81
+ // Prefer the single-writer discovery advert (discovery/memory.json), which
82
+ // validates the owner pid is alive. Fall back to the legacy
83
+ // active-instance.json memory_port field for cross-version compat.
84
+ const advertPort = readServicePort('memory', { requirePid: false })
85
+ if (advertPort) { _portCache = { port: advertPort, mtime: 0, ts: now }; return advertPort }
66
86
  try {
67
87
  const stat = await fs.promises.stat(ACTIVE_INSTANCE_FILE)
68
88
  const mtime = stat.mtimeMs
@@ -115,8 +135,8 @@ async function memoryFetch(method, endpoint, body = null, timeoutMs = 10_000, {
115
135
  resolve(parsed)
116
136
  })
117
137
  })
118
- req.on('error', reject)
119
- req.on('timeout', () => { req.destroy(); reject(new Error('memory-service timeout')) })
138
+ req.on('error', err => { _distrustMemoryPort(port, err); reject(err) })
139
+ req.on('timeout', () => { req.destroy(); const err = new Error('memory-service timeout'); _distrustMemoryPort(port, err); reject(err) })
120
140
  if (payload) req.write(payload)
121
141
  req.end()
122
142
  })
@@ -407,7 +407,7 @@ async function refreshBridgeOwnership(options = {}) {
407
407
  async function reloadRuntimeConfig() {
408
408
  const previousBackend = getBackend();
409
409
  const previousBackendName = previousBackend?.name || "";
410
- setConfig(loadConfig());
410
+ setConfig(await loadConfig());
411
411
  scheduler.reloadConfig(
412
412
  getConfig().nonInteractive ?? [],
413
413
  getConfig().interactive ?? [],