mixdog 0.9.19 → 0.9.21

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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +100 -34
  3. package/package.json +3 -2
  4. package/scripts/build-tui.mjs +6 -0
  5. package/scripts/hook-bus-test.mjs +8 -0
  6. package/scripts/log-writer-guard-smoke.mjs +131 -0
  7. package/scripts/reactive-compact-persist-smoke.mjs +22 -6
  8. package/scripts/recall-bench-cases.json +0 -1
  9. package/scripts/recall-quality-cases.json +1 -2
  10. package/scripts/session-ingest-compaction-smoke.mjs +241 -0
  11. package/scripts/tool-smoke.mjs +150 -45
  12. package/src/defaults/skills/setup/SKILL.md +327 -0
  13. package/src/help.mjs +2 -5
  14. package/src/lib/mixdog-debug.cjs +13 -0
  15. package/src/mixdog-session-runtime.mjs +7 -3328
  16. package/src/runtime/agent/orchestrator/context/collect.mjs +33 -9
  17. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +34 -2
  18. package/src/runtime/agent/orchestrator/providers/gemini.mjs +3 -0
  19. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -10
  20. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +3 -0
  21. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +40 -3
  22. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +73 -3
  23. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +663 -0
  24. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +6 -0
  25. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +153 -0
  26. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +49 -0
  27. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -1
  28. package/src/runtime/agent/orchestrator/session/loop.mjs +8 -1860
  29. package/src/runtime/agent/orchestrator/session/manager/agent-runtime-singleton.mjs +29 -0
  30. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +686 -0
  31. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +60 -12
  32. package/src/runtime/agent/orchestrator/session/manager/env-utils.mjs +8 -0
  33. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +159 -0
  34. package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +143 -0
  35. package/src/runtime/agent/orchestrator/session/manager/prefetch-bridge.mjs +268 -0
  36. package/src/runtime/agent/orchestrator/session/manager/provider-cache-key.mjs +22 -0
  37. package/src/runtime/agent/orchestrator/session/manager/runtime-loaders.mjs +26 -0
  38. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +124 -0
  39. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +258 -0
  40. package/src/runtime/agent/orchestrator/session/manager/session-errors.mjs +20 -0
  41. package/src/runtime/agent/orchestrator/session/manager/session-id.mjs +9 -0
  42. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +475 -0
  43. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +23 -0
  44. package/src/runtime/agent/orchestrator/session/manager.mjs +88 -2285
  45. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +440 -0
  46. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +153 -0
  47. package/src/runtime/agent/orchestrator/session/store.mjs +4 -1
  48. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +642 -0
  49. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +23 -3
  50. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +108 -2
  51. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +15 -3
  52. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +7 -0
  53. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +24 -2
  54. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
  55. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +72 -8
  56. package/src/runtime/agent/orchestrator/tools/shell-policy-danger-target.mjs +5 -1
  57. package/src/runtime/channels/index.mjs +6 -2183
  58. package/src/runtime/channels/lib/inbound-handler.mjs +328 -0
  59. package/src/runtime/channels/lib/interaction-handlers.mjs +260 -0
  60. package/src/runtime/channels/lib/network-retry.mjs +23 -0
  61. package/src/runtime/channels/lib/owned-runtime.mjs +627 -0
  62. package/src/runtime/channels/lib/runtime-paths.mjs +20 -9
  63. package/src/runtime/channels/lib/transcript-binding.mjs +336 -0
  64. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +39 -2
  65. package/src/runtime/channels/lib/worker-bootstrap.mjs +97 -0
  66. package/src/runtime/channels/lib/worker-ipc.mjs +201 -0
  67. package/src/runtime/channels/lib/worker-main.mjs +777 -0
  68. package/src/runtime/memory/index.mjs +163 -1725
  69. package/src/runtime/memory/lib/embedding-provider.mjs +4 -2
  70. package/src/runtime/memory/lib/embedding-worker.mjs +47 -6
  71. package/src/runtime/memory/lib/http-router.mjs +811 -0
  72. package/src/runtime/memory/lib/memory-action-handlers.mjs +901 -0
  73. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +6 -0
  74. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +46 -9
  75. package/src/runtime/memory/lib/memory-cycle2.mjs +87 -11
  76. package/src/runtime/memory/lib/memory-embed.mjs +28 -7
  77. package/src/runtime/memory/lib/memory-recall-store.mjs +4 -4
  78. package/src/runtime/memory/lib/memory.mjs +39 -0
  79. package/src/runtime/memory/lib/query-handlers.mjs +2 -2
  80. package/src/runtime/memory/lib/session-ingest-runtime.mjs +401 -0
  81. package/src/runtime/shared/atomic-file.mjs +138 -80
  82. package/src/runtime/shared/child-guardian.mjs +61 -3
  83. package/src/session-runtime/boot-profile.mjs +36 -0
  84. package/src/session-runtime/channel-config-api.mjs +70 -0
  85. package/src/session-runtime/context-status.mjs +181 -0
  86. package/src/session-runtime/env.mjs +17 -0
  87. package/src/session-runtime/lifecycle-api.mjs +242 -0
  88. package/src/session-runtime/model-route-api.mjs +198 -0
  89. package/src/session-runtime/provider-auth-api.mjs +135 -0
  90. package/src/session-runtime/resource-api.mjs +282 -0
  91. package/src/session-runtime/runtime-core.mjs +2104 -0
  92. package/src/session-runtime/session-turn-api.mjs +274 -0
  93. package/src/session-runtime/tool-catalog.mjs +18 -264
  94. package/src/session-runtime/tool-defs.mjs +2 -2
  95. package/src/session-runtime/workflow-agents-api.mjs +238 -0
  96. package/src/standalone/agent-tool.mjs +2 -2
  97. package/src/standalone/channel-worker.mjs +67 -7
  98. package/src/standalone/folder-dialog.mjs +4 -1
  99. package/src/standalone/memory-runtime-proxy.mjs +154 -17
  100. package/src/standalone/seeds.mjs +28 -1
  101. package/src/tui/App.jsx +40 -28
  102. package/src/tui/app/core-memory-picker.mjs +1 -1
  103. package/src/tui/app/doctor.mjs +175 -0
  104. package/src/tui/app/slash-commands.mjs +1 -0
  105. package/src/tui/app/slash-dispatch.mjs +9 -0
  106. package/src/tui/app/use-mouse-input.mjs +6 -0
  107. package/src/tui/app/use-transcript-scroll.mjs +77 -3
  108. package/src/tui/dist/index.mjs +2851 -2162
  109. package/src/tui/engine/context-state.mjs +145 -0
  110. package/src/tui/engine/prompt-history.mjs +27 -0
  111. package/src/tui/engine/session-api-ext.mjs +478 -0
  112. package/src/tui/engine/session-api.mjs +564 -0
  113. package/src/tui/engine/session-flow.mjs +485 -0
  114. package/src/tui/engine/turn.mjs +1078 -0
  115. package/src/tui/engine.mjs +68 -2620
  116. package/src/tui/index.jsx +7 -0
  117. package/vendor/ink/build/ink.js +16 -1
  118. package/vendor/ink/build/output.js +30 -4
  119. package/vendor/ink/build/render.js +5 -0
  120. package/src/workflows/sequential/WORKFLOW.md +0 -51
package/src/tui/index.jsx CHANGED
@@ -17,6 +17,7 @@ import { touchUiHeartbeat } from '../runtime/channels/lib/runtime-paths.mjs';
17
17
  import { emitTerminalBackground, loadThemeSettingFromConfig, theme } from './theme.mjs';
18
18
  import { POP_KITTY, DISABLE_MODIFY_OTHER_KEYS } from './keyboard-protocol.mjs';
19
19
  import { displayWidth } from './display-width.mjs';
20
+ import { rotateBoundedLog, PLUGIN_LOG_MAX_BYTES, PLUGIN_LOG_KEEP_BYTES } from '../lib/mixdog-debug.cjs';
20
21
 
21
22
  const TERMINAL_MODE_RESET = '\x1b[?1006l\x1b[?1005l\x1b[?1015l\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?2004l\x1b[?25h';
22
23
  const TERMINAL_OSC_RESET_BG = '\x1b]111\x07';
@@ -326,6 +327,9 @@ function installTuiStderrGuard() {
326
327
  const originalWrite = process.stderr.write.bind(process.stderr);
327
328
  const logPath = resolveTuiStderrLogPath();
328
329
  try { mkdirSync(dirname(logPath), { recursive: true }); } catch { /* ignore */ }
330
+ // One-shot bound before the append stream opens: this TUI process never
331
+ // passes through the channels-worker rotation path, so cap it writer-side.
332
+ rotateBoundedLog(logPath, PLUGIN_LOG_MAX_BYTES, PLUGIN_LOG_KEEP_BYTES);
329
333
  let logStream = null;
330
334
  try {
331
335
  logStream = createWriteStream(logPath, { flags: 'a' });
@@ -543,6 +547,9 @@ export async function runTui({ provider, model, toolMode, remote, forceOnboardin
543
547
  if (mouseTracking && typeof instance.getLineRectAt === 'function') {
544
548
  store.getLineRectAt = instance.getLineRectAt;
545
549
  }
550
+ if (mouseTracking && typeof instance.getSelectionRows === 'function') {
551
+ store.getRenderSelectionRows = instance.getSelectionRows;
552
+ }
546
553
  await waitUntilExit();
547
554
  } finally {
548
555
  stopPerfProbe();
@@ -221,6 +221,10 @@ export default class Ink {
221
221
  // [mixdog fork] column-indexed cell values per grid row from the last frame,
222
222
  // used by getWordRectAt() to compute word boundaries for double-click select.
223
223
  lastPlainRows = null;
224
+ // [mixdog fork] per-row {y, text} selection harvest from the last frame,
225
+ // refreshed every render; read back via getSelectionRows() so the app can
226
+ // stitch selections taller than the viewport. null when no selection.
227
+ lastSelectionRows = null;
224
228
  constructor(options) {
225
229
  autoBind(this);
226
230
  this.options = options;
@@ -558,6 +562,13 @@ export default class Ink {
558
562
  return null;
559
563
  return { x1: 0, y1: y, x2, y2: y };
560
564
  };
565
+ // [mixdog fork] Return the per-row {y, text} selection harvest cached from the
566
+ // last frame, or null when there is no selection. y is the absolute screen row
567
+ // of the last frame; text is trailing-space-trimmed (partial first/last rows
568
+ // respect x1/x2). Lets the app stitch selections taller than the viewport.
569
+ getSelectionRows = () => {
570
+ return this.lastSelectionRows;
571
+ };
561
572
  restoreLastOutput = () => {
562
573
  if (!this.interactive) {
563
574
  return;
@@ -604,7 +615,7 @@ export default class Ink {
604
615
  this.isRendering = true;
605
616
  try {
606
617
  const startTime = performance.now();
607
- const { output, outputHeight, staticOutput, cursor, selectedText, plainRows } = render(this.rootNode, this.isScreenReaderEnabled, this.selectionRect);
618
+ const { output, outputHeight, staticOutput, cursor, selectedText, plainRows, selectionRows } = render(this.rootNode, this.isScreenReaderEnabled, this.selectionRect);
608
619
  // [mixdog fork] Cache the text under the current selection rect so the App
609
620
  // can read it back on drag-release to copy it to the OS clipboard.
610
621
  if (selectedText !== undefined) {
@@ -614,6 +625,10 @@ export default class Ink {
614
625
  if (plainRows !== undefined) {
615
626
  this.lastPlainRows = plainRows ?? null;
616
627
  }
628
+ // [mixdog fork] Cache per-row selection harvest for getSelectionRows().
629
+ if (selectionRows !== undefined) {
630
+ this.lastSelectionRows = selectionRows ?? null;
631
+ }
617
632
  this.options.onRender?.({ renderTime: performance.now() - startTime });
618
633
  // [mixdog fork] Drive the hardware cursor from the anchored input node's
619
634
  // real render-time position, computed fresh every frame. This replaces
@@ -262,6 +262,12 @@ export default class Output {
262
262
  // dim text, and status colors do not bleed through.
263
263
  const sel = this.selection;
264
264
  let selectedText = null;
265
+ // [mixdog fork] Per-row selection harvest ({y, text}) exposed via the
266
+ // instance getSelectionRows() so the app can stitch selections taller
267
+ // than the viewport. y is the absolute screen row of the last frame;
268
+ // text is trailing-space-trimmed and partial first/last rows respect
269
+ // x1/x2. Null when there is no selection (mirrors selectedText).
270
+ let selectionRows = null;
265
271
  // [mixdog fork] noSelect exclusion (claude-code skips gutter / line-number
266
272
  // / diff-sigil cells from both highlight and copy via screen.noSelect):
267
273
  // mixdog's cell model has NO noSelect marker — the Output grid stores only
@@ -303,9 +309,16 @@ export default class Output {
303
309
  const y2 = Math.min(this.height - 1, clipY2, linear ? end.y : Math.max(sel.y1, sel.y2));
304
310
  const lineMode = linear && y1 !== y2;
305
311
  const selRows = captureSelectedText ? [] : null;
312
+ // [mixdog fork] selRowObjs is built UNCONDITIONALLY whenever a
313
+ // selection rect exists, independent of captureSelectedText: a
314
+ // capture-disabled drag (rect.captureText === false) still needs a
315
+ // per-row harvest so getSelectionRows() can stitch tall selections.
316
+ // Only selectedText/selRows honor the captureSelectedText gate.
317
+ const selRowObjs = [];
306
318
  for (let y = y1; y <= y2; y++) {
307
319
  const row = output[y];
308
320
  if (!row) {
321
+ selRowObjs.push({ y, text: '' });
309
322
  if (captureSelectedText) {
310
323
  selRows.push('');
311
324
  }
@@ -338,9 +351,9 @@ export default class Output {
338
351
  }
339
352
  // Collect the visible glyph. Wide-char trailing placeholders
340
353
  // carry value '' and contribute nothing, which is correct.
341
- if (captureSelectedText) {
342
- rowText += cell.value ?? '';
343
- }
354
+ // Always accumulated so the unconditional selRowObjs harvest
355
+ // has row text even when captureSelectedText is false.
356
+ rowText += cell.value ?? '';
344
357
  if (contentStart === -1 || x < contentStart || x > contentEnd) {
345
358
  continue;
346
359
  }
@@ -357,10 +370,22 @@ export default class Output {
357
370
  };
358
371
  }
359
372
  // Trailing spaces in a selected row are padding, not content.
373
+ const trimmedRowText = rowText.replace(/\s+$/u, '');
374
+ selRowObjs.push({ y, text: trimmedRowText });
360
375
  if (captureSelectedText) {
361
- selRows.push(rowText.replace(/\s+$/u, ''));
376
+ selRows.push(trimmedRowText);
362
377
  }
363
378
  }
379
+ // [mixdog fork] Outer-trim the per-row harvest (same rule as
380
+ // selectedText below) but UNCONDITIONALLY, keeping the absolute row
381
+ // index per entry so the app can stitch rows across the viewport.
382
+ while (selRowObjs.length > 0 && selRowObjs[0].text.trim() === '') {
383
+ selRowObjs.shift();
384
+ }
385
+ while (selRowObjs.length > 0 && selRowObjs[selRowObjs.length - 1].text.trim() === '') {
386
+ selRowObjs.pop();
387
+ }
388
+ selectionRows = selRowObjs;
364
389
  if (captureSelectedText) {
365
390
  // Blank edge rows come from selecting through padded alt-screen
366
391
  // space around rendered content. Native terminal selection does
@@ -433,6 +458,7 @@ export default class Output {
433
458
  cursor: this.cursor, // [mixdog fork] absolute cursor cell or null
434
459
  selectedText, // [mixdog fork] text inside the selection rect, or null
435
460
  plainRows, // [mixdog fork] column-indexed cell values per row for word lookup
461
+ selectionRows, // [mixdog fork] per-row {y, text} selection harvest, or null
436
462
  };
437
463
  }
438
464
  }
@@ -45,6 +45,11 @@ const render = (node, options) => {
45
45
  // line select. Symmetric to getWordRectAt; index.jsx wires it into the
46
46
  // store as store.getLineRectAt.
47
47
  getLineRectAt: (y) => instance.getLineRectAt(y),
48
+ // [mixdog fork] read the per-row {y, text} selection harvest from the last
49
+ // frame (or null when no selection); index.jsx wires it into the store as
50
+ // store.getRenderSelectionRows so the app can stitch selections taller
51
+ // than the viewport.
52
+ getSelectionRows: () => instance.getSelectionRows(),
48
53
  };
49
54
  };
50
55
  export default render;
@@ -1,51 +0,0 @@
1
- ---
2
- id: sequential
3
- name: Sequential
4
- description: "Sequential workflow — delegates 1:1 with no fan-out; one agent at a time."
5
- agents: worker, heavy-worker, reviewer, debugger, maintainer
6
- ---
7
-
8
- # Sequential Workflow
9
-
10
- Unlike Default, which fans out independent scopes in parallel, this mode runs
11
- with no fan-out: it delegates one scope at a time, 1:1, and only moves to the
12
- next after the current one completes.
13
-
14
- Lead supervises: delegates, coordinates, judges, decides. Route by complexity:
15
- - Lead handles directly: simple 1–2 step work, plus coordination, pre-planning,
16
- config changes, and final git deployment.
17
- - Worker: implementation that takes several steps.
18
- - Heavy Worker: high-complexity, multi-step implementation.
19
- - Reviewer: verify implementation scopes (diff, regressions, missing checks).
20
- - Debugger: deploy for very high complexity, or when root-causing has already
21
- failed at least once.
22
-
23
- 1. Plan — discuss the request with the user, form a plan, wait for approval.
24
- Only an explicit go-ahead is approval; diagnosis agreement is not. When
25
- ambiguous, restate the plan and ask before executing.
26
- 2. Delegate — split into ordered scopes and hand off ONE AT A TIME.
27
- - NO PARALLEL, NO FAN-OUT. Even when scopes are independent, spawn exactly
28
- one agent per turn; never multiple in the same turn. Wait for the current
29
- scope's completion notification before spawning the next (1:1 sequential).
30
- - SEQUENTIAL within a single complex scope — split into ordered steps rather
31
- than one shot, with a build/test-green gate between steps.
32
- - Write briefs per the Lead brief contract (token-optimized labeled
33
- fragments).
34
- - After spawning an async agent, END THE TURN — do not poll, guess, or start
35
- dependent or subsequent work until the completion notification resumes
36
- you. Then wait and continue automatically.
37
- 3. Review — after each implementation scope completes, pair one reviewer 1:1
38
- with that scope (spawned on its own turn, not batched); never defer the
39
- reviewer call — wait for its result. Fact-check the agent response and
40
- cross-check implementation and review results yourself before acting. Send
41
- fixes back to the original scope and loop verify -> fix -> re-verify until
42
- clean. Skip review only for simple, low-risk tasks. If the user asks for
43
- debugging, or a bug survives 2+ fix cycles, have the debugger investigate
44
- first instead of another fix round.
45
- 4. Report — synthesize results (outcome + key evidence; never forward raw agent
46
- output), state the final state, and ask whether to ship/deploy when
47
- relevant. Only after user feedback with no issues prepare
48
- deploy/build/commit.
49
-
50
- On any major change or direction shift mid-work, pause and re-consult the user
51
- before continuing.