mindweave 2.3.1 → 2.4.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 (121) hide show
  1. package/README.md +26 -43
  2. package/dist/alternator/chassis/lsp.js +67 -0
  3. package/dist/alternator/chassis/lsp.js.map +1 -1
  4. package/dist/cli/App.js +1175 -99
  5. package/dist/cli/App.js.map +1 -1
  6. package/dist/cli/altScreen.js +80 -10
  7. package/dist/cli/altScreen.js.map +1 -1
  8. package/dist/cli/appIdentity.js +54 -0
  9. package/dist/cli/appIdentity.js.map +1 -0
  10. package/dist/cli/attachments.js +27 -3
  11. package/dist/cli/attachments.js.map +1 -1
  12. package/dist/cli/blockHeights.js +58 -0
  13. package/dist/cli/blockHeights.js.map +1 -0
  14. package/dist/cli/caretPark.js +94 -0
  15. package/dist/cli/caretPark.js.map +1 -0
  16. package/dist/cli/clipboard.js +68 -0
  17. package/dist/cli/clipboard.js.map +1 -0
  18. package/dist/cli/commandLabel.js +19 -2
  19. package/dist/cli/commandLabel.js.map +1 -1
  20. package/dist/cli/commands.js +1 -0
  21. package/dist/cli/commands.js.map +1 -1
  22. package/dist/cli/components/BlockView.js +1 -1
  23. package/dist/cli/components/BlockView.js.map +1 -1
  24. package/dist/cli/components/KeyManager.js +11 -5
  25. package/dist/cli/components/KeyManager.js.map +1 -1
  26. package/dist/cli/components/Picker.js +18 -3
  27. package/dist/cli/components/Picker.js.map +1 -1
  28. package/dist/cli/components/PromptInput.js +300 -74
  29. package/dist/cli/components/PromptInput.js.map +1 -1
  30. package/dist/cli/components/TipLine.js +33 -0
  31. package/dist/cli/components/TipLine.js.map +1 -0
  32. package/dist/cli/components/ToolLine.js +30 -3
  33. package/dist/cli/components/ToolLine.js.map +1 -1
  34. package/dist/cli/dropHandles.js +76 -0
  35. package/dist/cli/dropHandles.js.map +1 -0
  36. package/dist/cli/exitCursor.js +56 -0
  37. package/dist/cli/exitCursor.js.map +1 -0
  38. package/dist/cli/framebuffer/overlay.js +42 -0
  39. package/dist/cli/framebuffer/overlay.js.map +1 -0
  40. package/dist/cli/framebuffer/paint.js +8 -1
  41. package/dist/cli/framebuffer/paint.js.map +1 -1
  42. package/dist/cli/framebuffer/parse.js +54 -4
  43. package/dist/cli/framebuffer/parse.js.map +1 -1
  44. package/dist/cli/framebuffer/writer.js +357 -6
  45. package/dist/cli/framebuffer/writer.js.map +1 -1
  46. package/dist/cli/groupReveal.js +29 -3
  47. package/dist/cli/groupReveal.js.map +1 -1
  48. package/dist/cli/inputView.js +45 -0
  49. package/dist/cli/inputView.js.map +1 -1
  50. package/dist/cli/livePad.js +53 -0
  51. package/dist/cli/livePad.js.map +1 -0
  52. package/dist/cli/memoryTuning.js +31 -0
  53. package/dist/cli/memoryTuning.js.map +1 -0
  54. package/dist/cli/messageQueue.js +76 -7
  55. package/dist/cli/messageQueue.js.map +1 -1
  56. package/dist/cli/mouse.js +40 -7
  57. package/dist/cli/mouse.js.map +1 -1
  58. package/dist/cli/quietConsole.js +50 -0
  59. package/dist/cli/quietConsole.js.map +1 -0
  60. package/dist/cli/screenMode.js +118 -0
  61. package/dist/cli/screenMode.js.map +1 -0
  62. package/dist/cli/screenShell.js +67 -0
  63. package/dist/cli/screenShell.js.map +1 -0
  64. package/dist/cli/screenStore.js +46 -0
  65. package/dist/cli/screenStore.js.map +1 -0
  66. package/dist/cli/scrollPill.js +101 -0
  67. package/dist/cli/scrollPill.js.map +1 -0
  68. package/dist/cli/selection.js +130 -0
  69. package/dist/cli/selection.js.map +1 -0
  70. package/dist/cli/startupFill.js +48 -0
  71. package/dist/cli/startupFill.js.map +1 -0
  72. package/dist/cli/terminalRestore.js +1 -1
  73. package/dist/cli/terminalRestore.js.map +1 -1
  74. package/dist/cli/toolDisplay.js +11 -2
  75. package/dist/cli/toolDisplay.js.map +1 -1
  76. package/dist/cli/toolItems.js +1 -0
  77. package/dist/cli/toolItems.js.map +1 -1
  78. package/dist/cli/transcript.js +54 -3
  79. package/dist/cli/transcript.js.map +1 -1
  80. package/dist/cli/wordEdit.js +95 -0
  81. package/dist/cli/wordEdit.js.map +1 -0
  82. package/dist/drivers/openai/manifest.js +4 -1
  83. package/dist/drivers/openai/manifest.js.map +1 -1
  84. package/dist/dynamo/engine.js +126 -20
  85. package/dist/dynamo/engine.js.map +1 -1
  86. package/dist/index.js +42 -3
  87. package/dist/index.js.map +1 -1
  88. package/dist/memory/pastedText.js +37 -0
  89. package/dist/memory/pastedText.js.map +1 -0
  90. package/dist/memory/presence.js +47 -0
  91. package/dist/memory/presence.js.map +1 -1
  92. package/dist/memory/session.js +78 -4
  93. package/dist/memory/session.js.map +1 -1
  94. package/dist/memory/store.js +22 -1
  95. package/dist/memory/store.js.map +1 -1
  96. package/dist/memory/types.js.map +1 -1
  97. package/dist/tools/backgroundShells.js +105 -18
  98. package/dist/tools/backgroundShells.js.map +1 -1
  99. package/dist/tools/commandOutput.js +207 -0
  100. package/dist/tools/commandOutput.js.map +1 -0
  101. package/dist/tools/detail.js +2 -2
  102. package/dist/tools/detail.js.map +1 -1
  103. package/dist/tools/openDefault.js +150 -0
  104. package/dist/tools/openDefault.js.map +1 -0
  105. package/dist/tools/outputShape.js +31 -6
  106. package/dist/tools/outputShape.js.map +1 -1
  107. package/dist/tools/pathList.js +32 -0
  108. package/dist/tools/pathList.js.map +1 -0
  109. package/dist/tools/readFile.js +3 -15
  110. package/dist/tools/readFile.js.map +1 -1
  111. package/dist/tools/registry.js +3 -1
  112. package/dist/tools/registry.js.map +1 -1
  113. package/dist/tools/runCommand.js +154 -58
  114. package/dist/tools/runCommand.js.map +1 -1
  115. package/dist/tools/screenshot.js +35 -3
  116. package/dist/tools/screenshot.js.map +1 -1
  117. package/dist/tools/viewImage.js +88 -0
  118. package/dist/tools/viewImage.js.map +1 -0
  119. package/dist/tools/writeFile.js +9 -1
  120. package/dist/tools/writeFile.js.map +1 -1
  121. package/package.json +74 -74
@@ -0,0 +1,95 @@
1
+ /**
2
+ * wordEdit.ts — where the cursor lands when you move or delete by the chunk.
3
+ *
4
+ * Backspace one character at a time is fine for a typo and useless for a sentence, and
5
+ * the input had nothing between the two: Ctrl+U cleared the whole line and that was the
6
+ * only bulk operation. These are the missing middle, and they are here as pure functions
7
+ * on (text, cursor) rather than inside the reducer so the boundary rules can be pinned by
8
+ * tests instead of discovered by holding a key down and watching what disappears.
9
+ *
10
+ * A "word" here is a run of non-whitespace, which is coarser than a language-aware
11
+ * boundary and is the right coarseness for this input: `C:\Users\me\Pictures\shot.png`
12
+ * is one thing you want gone in one keystroke, not eight.
13
+ */
14
+ const isSpace = (ch) => ch === " " || ch === "\t" || ch === "\n" || ch === "\r";
15
+ /**
16
+ * Where on a painted terminal row a piece of text begins, or -1 if it is not there.
17
+ *
18
+ * This is how a click in the input box finds its column WITHOUT anyone computing where
19
+ * the box was laid out. The box's border, padding and prompt marker all sit to the left
20
+ * of the text; rather than adding those up (and being wrong the day one of them changes),
21
+ * the row's own text is located in the row that was actually painted, and the difference
22
+ * IS the offset. A row that cannot be found returns -1, and the caller does nothing —
23
+ * which is the whole point: a mistaken guess moves nobody's cursor.
24
+ *
25
+ * One mismatched cell is tolerated because the caret takes the cell it sits on, so the
26
+ * row on screen differs from the row in the buffer by exactly one character whenever the
27
+ * caret is mid-row and lit.
28
+ *
29
+ * `rowAt` reads a cell as a string, so the caller decides where the row comes from.
30
+ */
31
+ export function findTextColumn(rowAt, width, text, tolerance = 1) {
32
+ if (text === "")
33
+ return -1;
34
+ for (let start = 0; start + text.length <= width; start++) {
35
+ let wrong = 0;
36
+ for (let i = 0; i < text.length; i++) {
37
+ if (rowAt(start + i) !== text[i]) {
38
+ wrong++;
39
+ if (wrong > tolerance)
40
+ break;
41
+ }
42
+ }
43
+ if (wrong <= tolerance)
44
+ return start;
45
+ }
46
+ return -1;
47
+ }
48
+ /**
49
+ * Start of the chunk behind the cursor: skip any whitespace immediately behind, then the
50
+ * run of non-whitespace before that. Trailing whitespace goes with the word it follows,
51
+ * so deleting from the end of `foo bar ` lands on `foo ` in one press rather than
52
+ * spending a press on the gap.
53
+ */
54
+ export function wordStart(value, cursor) {
55
+ let i = Math.max(0, Math.min(cursor, value.length));
56
+ while (i > 0 && isSpace(value[i - 1]))
57
+ i--;
58
+ while (i > 0 && !isSpace(value[i - 1]))
59
+ i--;
60
+ return i;
61
+ }
62
+ /**
63
+ * End of the chunk ahead of the cursor: skip whitespace, then the run of non-whitespace.
64
+ * The mirror of wordStart, so pressing forward then back returns you where you were.
65
+ */
66
+ export function wordEnd(value, cursor) {
67
+ let i = Math.max(0, Math.min(cursor, value.length));
68
+ while (i < value.length && isSpace(value[i]))
69
+ i++;
70
+ while (i < value.length && !isSpace(value[i]))
71
+ i++;
72
+ return i;
73
+ }
74
+ /**
75
+ * End of the LINE the cursor is on, not of the whole buffer. The input is multi-line
76
+ * (Shift+Enter), so "delete to the end" has to mean the line or it would eat the rest of
77
+ * a message from the middle of its first line.
78
+ */
79
+ export function lineEnd(value, cursor) {
80
+ const from = Math.max(0, Math.min(cursor, value.length));
81
+ const nl = value.indexOf("\n", from);
82
+ return nl === -1 ? value.length : nl;
83
+ }
84
+ /**
85
+ * What Ctrl+K removes: the rest of the line, or — when the cursor already sits at the end
86
+ * of one — the line break itself, which is what joins this line to the next. Without that
87
+ * second case the key does nothing at a line end and reads as broken.
88
+ */
89
+ export function killToLineEnd(value, cursor) {
90
+ const from = Math.max(0, Math.min(cursor, value.length));
91
+ const end = lineEnd(value, from);
92
+ const to = end === from ? Math.min(from + 1, value.length) : end;
93
+ return { value: value.slice(0, from) + value.slice(to), cursor: from };
94
+ }
95
+ //# sourceMappingURL=wordEdit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wordEdit.js","sourceRoot":"","sources":["../../src/cli/wordEdit.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ export const ASTRA = "gpt-6-astra";
1
2
  export const SOL = "gpt-5.6-sol";
2
3
  export const TERRA = "gpt-5.6-terra";
3
4
  export const LUNA = "gpt-5.6-luna";
@@ -12,7 +13,8 @@ export const DEFAULT_MODEL = TERRA;
12
13
  */
13
14
  export const MODELS = [
14
15
  { id: TERRA, label: "GPT-5.6 Terra", description: "balanced intelligence and cost — the default" },
15
- { id: SOL, label: "GPT-5.6 Sol", description: "the frontier tier, for the hardest problems" },
16
+ { id: ASTRA, label: "GPT-6 Astra", description: "the newest flagship — the most capable, and the priciest" },
17
+ { id: SOL, label: "GPT-5.6 Sol", description: "the GPT-5.6 frontier tier" },
16
18
  { id: LUNA, label: "GPT-5.6 Luna", description: "cheap and quick, for high-volume work" },
17
19
  ];
18
20
  /**
@@ -40,6 +42,7 @@ export function thinkLevels(_model) {
40
42
  * which is what keeps a re-sent conversation cheap.
41
43
  */
42
44
  const PRICES = {
45
+ [ASTRA]: { cacheHit: 1, cacheMiss: 10, output: 50 },
43
46
  [SOL]: { cacheHit: 0.5, cacheMiss: 5, output: 30 },
44
47
  [TERRA]: { cacheHit: 0.2, cacheMiss: 2, output: 12 },
45
48
  [LUNA]: { cacheHit: 0.02, cacheMiss: 0.2, output: 1.2 },
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/drivers/openai/manifest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/drivers/openai/manifest.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,MAAM,KAAK,GAAG,aAAa,CAAC;AACnC,MAAM,CAAC,MAAM,GAAG,GAAG,aAAa,CAAC;AACjC,MAAM,CAAC,MAAM,KAAK,GAAG,eAAe,CAAC;AACrC,MAAM,CAAC,MAAM,IAAI,GAAG,cAAc,CAAC;AAEnC,uEAAuE;AACvE,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAkB;IACnC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,8CAA8C,EAAE;IAClG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,0DAA0D,EAAE;IAC5G,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,2BAA2B,EAAE;IAC3E,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,uCAAuC,EAAE;CAC1F,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,MAAe;IACzC,OAAO;QACL,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,2BAA2B,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE;QAChG,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,0BAA0B,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE;QAChG,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,gCAAgC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;QAChG,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,0BAA0B,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE;KAC7F,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,MAAM,GAA+B;IACzC,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;IACnD,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;IAClD,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;IACpD,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACxD,CAAC;AAEF,+EAA+E;AAC/E,MAAM,UAAU,KAAK,CAAC,KAAc;IAClC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,aAAa,CAAE,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAClD,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,6DAA6D;AAC7D,MAAM,OAAO,GAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAEpE,mEAAmE;AACnE,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,MAAmB;IAC3C,MAAM,KAAK,GAAY,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;IAC3E,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;IAC1C,MAAM,MAAM,GAAW,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAChF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;AACjF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,KAAc,EAAE,QAAiB,EAAE,MAAc;IAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAE5D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC/F,IAAI,GAAG,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,gBAAgB;IAC3B,OAAO,EAAE,sCAAsC;IAC/C,MAAM,EAAE,MAAM;IACd,WAAW;IACX,KAAK;IACL,aAAa;IACb,oBAAoB;IACpB,aAAa;IACb,SAAS;CACV,CAAC"}
@@ -291,13 +291,35 @@ function taskLimits() {
291
291
  maxSeconds: envNum("MINDWEAVE_MAX_TASK_SECONDS", 0),
292
292
  };
293
293
  }
294
- // Max model turns (tool rounds) in one reply. A generous ceiling: real multi-file
295
- // work — a feature across a dozen files, a refactor — should finish in one go, so
296
- // this is a circuit-breaker against a runaway loop, NOT a work limit. When it is
297
- // hit the loop pauses LOSSLESSLY (the transcript, task list, and working set are
298
- // intact) and hands the decision to continue back to the user, so it can never
299
- // silently burn tokens. Env-overridable for power users.
300
- const STEP_BUDGET = envInt("MINDWEAVE_STEP_BUDGET", 50);
294
+ /**
295
+ * How many tool rounds one turn may take, or undefined for no ceiling (pure).
296
+ *
297
+ * A ceiling is for a loop NOBODY IS WATCHING. That is the whole rule, and it is what
298
+ * decides who gets one:
299
+ *
300
+ * - A **sub-agent** always gets one. It runs unattended by definition: there is no
301
+ * prompt to interrupt, no screen showing its steps, and nothing between a worker
302
+ * that has misread its task and an unbounded bill. `subagent.ts` passes its budget
303
+ * explicitly, so a worker is capped whatever this returns.
304
+ * - The **interactive turn** does not, by default. Someone is sitting in front of it
305
+ * watching every tool row appear, and Esc stops the turn at the next boundary. A
306
+ * counter is a worse circuit breaker than the person already holding one.
307
+ *
308
+ * The previous default capped the interactive loop at fifty rounds, and what that
309
+ * actually stopped was work: a task across a dozen files spends fifty rounds without
310
+ * anything going wrong, and it ended mid-flight with a pause the user then had to
311
+ * step over. A guard that fires on ordinary work is not a guard, it is a limit.
312
+ *
313
+ * `MINDWEAVE_STEP_BUDGET` puts a ceiling back for anyone who wants one — an unattended
314
+ * run, a script, a machine that must not be able to spend past a point. Unset, the
315
+ * turn ends when the model is finished or the user stops it.
316
+ */
317
+ export function resolveStepLimit(maxSteps, envValue) {
318
+ if (maxSteps !== undefined)
319
+ return maxSteps;
320
+ const n = Number(envValue);
321
+ return Number.isInteger(n) && n > 0 ? n : undefined;
322
+ }
301
323
  // Verification gate: when the model edits files then tries to finish without
302
324
  // running any check, nudge it once to verify. On by default; MINDWEAVE_VERIFY_GATE=0
303
325
  // disables it. See verify.ts for the (pure, tested) fact detectors.
@@ -311,6 +333,40 @@ const BG_POLL_ALLOWANCE = envInt("MINDWEAVE_BG_POLL_LIMIT", 1);
311
333
  // stop it. 3 is the threshold: repeated identical failures past that are a stuck loop,
312
334
  // not progress. Env-overridable for tuning.
313
335
  const REPEAT_FAIL_LIMIT = envInt("MINDWEAVE_REPEAT_FAIL_LIMIT", 3);
336
+ /**
337
+ * How a mid-turn message is put to the model (pure).
338
+ *
339
+ * The framing is the whole reason this exists. A bare user message appearing after a
340
+ * round of tool results is ambiguous: it reads as if it had always been the request, so
341
+ * the model either restarts on it or, having already been told to do something else,
342
+ * ignores it. Saying when it arrived resolves both, and the second sentence is what
343
+ * makes it a steer rather than an interruption — the work in flight is not thrown away.
344
+ *
345
+ * Applied when the request is BUILT, never stored. The transcript keeps what the person
346
+ * typed; see `steered` in `memory/types.ts`.
347
+ */
348
+ export function steeredMessage(text) {
349
+ return (`The user sent this while you were working:\n\n${text}\n\n` +
350
+ `If it changes what you should be doing, change course now. Otherwise finish the ` +
351
+ `current step, then answer it before you stop.`);
352
+ }
353
+ /**
354
+ * How a message sent straight after an interrupt is put to the model (pure).
355
+ *
356
+ * A different fact from a steer, and it has to read differently. The work was STOPPED —
357
+ * the model is not deciding whether to change course, that decision was made for it by
358
+ * the person who pressed the key. Telling it to "finish the current step" here would be
359
+ * telling it to resume the thing it was just stopped from doing.
360
+ */
361
+ export function interruptedMessage(text) {
362
+ return (`The user stopped you and sent this:\n\n${text}\n\n` +
363
+ `The work you were doing was cut off on purpose. Take it from here rather than ` +
364
+ `picking up where you left off, unless this asks you to.`);
365
+ }
366
+ /** The wire form of a message that did not simply arrive in its turn (pure). */
367
+ export function arrivalNote(arrival, text) {
368
+ return arrival === "steered" ? steeredMessage(text) : interruptedMessage(text);
369
+ }
314
370
  /** True if an error is an AbortError (the model call was cancelled). */
315
371
  function isAbort(error) {
316
372
  return error instanceof Error && error.name === "AbortError";
@@ -423,6 +479,10 @@ directoryNotes = []) {
423
479
  // since it was attached simply isn't in the payload map. Either way the model is
424
480
  // TOLD rather than quietly handed a message that claims an image it cannot see.
425
481
  const refs = e.role === "user" ? e.images : undefined;
482
+ // A message that arrived mid-turn is framed HERE rather than being stored framed,
483
+ // so the transcript keeps what the person typed and only the wire carries the
484
+ // explanation. Deterministic from the entry, so the cached prefix is unaffected.
485
+ const said = e.role === "user" && e.arrival ? arrivalNote(e.arrival, e.content) : e.content;
426
486
  if (refs && refs.length > 0) {
427
487
  const images = [];
428
488
  const missing = [];
@@ -447,13 +507,13 @@ directoryNotes = []) {
447
507
  : []),
448
508
  ...(missing.length > 0 ? [`${missing.join(", ")} could not be read from disk`] : []),
449
509
  ];
450
- const content = notes.length > 0 ? `${e.content}
510
+ const content = notes.length > 0 ? `${said}
451
511
 
452
- [${notes.join("; ")}]` : e.content;
512
+ [${notes.join("; ")}]` : said;
453
513
  messages.push({ role: "user", content, ...(images.length > 0 ? { images } : {}) });
454
514
  continue;
455
515
  }
456
- messages.push({ role: "user", content: e.content });
516
+ messages.push({ role: "user", content: said });
457
517
  }
458
518
  else if (e.role === "assistant") {
459
519
  messages.push({
@@ -715,7 +775,7 @@ async function respondTurn(session, options = {}) {
715
775
  ];
716
776
  };
717
777
  const lookup = (name) => findTool(name) ?? mcpTurn?.asTool(name);
718
- const stepLimit = options.maxSteps ?? STEP_BUDGET;
778
+ const stepLimit = resolveStepLimit(options.maxSteps, process.env["MINDWEAVE_STEP_BUDGET"]);
719
779
  // Sinks the spawn_subagent tool reuses (it only ever gets the ToolContext, not the
720
780
  // Session): fork a scoped child, forward the child's usage to this turn's meter,
721
781
  // and share this turn's abort signal so Esc stops a sub-agent too.
@@ -755,8 +815,8 @@ async function respondTurn(session, options = {}) {
755
815
  await sweepSessionMemory(session, options);
756
816
  // Background shells that finished since last turn — surfaced to the model once.
757
817
  const bgEvents = await backgroundEventNotes(session);
758
- // Per-task guards: cost/time ceilings (opt-in) alongside the step budget. Every
759
- // call's usage is summed so the ceiling reflects the whole task.
818
+ // Per-task guards: cost and time ceilings, both opt-in, like the step ceiling above
819
+ // them. Every call's usage is summed so a ceiling reflects the whole task.
760
820
  const limits = taskLimits();
761
821
  const startedAt = Date.now();
762
822
  const usages = [];
@@ -850,7 +910,10 @@ async function respondTurn(session, options = {}) {
850
910
  // The turn's model↔tool loop. Kept as a closure so the try/finally above owns
851
911
  // every exit path; it reads the flags/usages declared in the enclosing scope.
852
912
  async function runTurn() {
853
- for (let step = 0; step < stepLimit; step++) {
913
+ // No ceiling means no ceiling: the loop's exits are then its own returns — the model
914
+ // finishing, a stop reason, the repeated-failure breaker, a cost or time ceiling if one
915
+ // is set, and the abort check on the line below. See `resolveStepLimit`.
916
+ for (let step = 0; stepLimit === undefined || step < stepLimit; step++) {
854
917
  if (options.signal?.aborted)
855
918
  return interrupted(session);
856
919
  // Stop before another (billable) call if a cost/time ceiling is hit — pause
@@ -1216,7 +1279,13 @@ async function respondTurn(session, options = {}) {
1216
1279
  // rather than fixing an observed bug, and the next tool added inherits it.
1217
1280
  let result;
1218
1281
  try {
1219
- result = await tool.execute(parseArgs(call.arguments), session.toolContext);
1282
+ // A per-call channel, so a tool that runs for minutes can say what it is doing.
1283
+ // Scoped to THIS call rather than hung on the shared context, which every tool in
1284
+ // the turn holds the same instance of — with two commands in flight there would be
1285
+ // no way to tell whose output was whose.
1286
+ result = await tool.execute(parseArgs(call.arguments), session.toolContext, {
1287
+ progress: (text) => options.onEvent?.({ type: "tool", phase: "progress", id: call.id, text }),
1288
+ });
1220
1289
  }
1221
1290
  catch (error) {
1222
1291
  // An abort is the user, not a fault: let it travel so the loop's own handling
@@ -1237,6 +1306,7 @@ async function respondTurn(session, options = {}) {
1237
1306
  images: result.images,
1238
1307
  displayKind: result.displayKind,
1239
1308
  displayName: result.displayName,
1309
+ awaitsModel: result.awaitsModel,
1240
1310
  };
1241
1311
  };
1242
1312
  // Emit each tool's END the instant IT finishes — not batched after the whole
@@ -1532,12 +1602,48 @@ async function respondTurn(session, options = {}) {
1532
1602
  await options.persist?.();
1533
1603
  }
1534
1604
  }
1605
+ // ── The user typed while this was running ────────────────────────────────
1606
+ //
1607
+ // LAST in the round, and that placement is the design. The tool results are all
1608
+ // recorded, so the conversation is well-formed and a user message may follow it —
1609
+ // one arriving between a call and its result is malformed and every provider
1610
+ // rejects it. Being last also puts the person's words closest to the next call,
1611
+ // which is where a change of course has to be read.
1612
+ //
1613
+ // Only reached on a round that ran tools. A round where the model answered instead
1614
+ // returns above, and the turn is over: what is queued then is not a steer, it is the
1615
+ // next request, and the caller sends it as one.
1616
+ if (options.steer) {
1617
+ let arrived = [];
1618
+ try {
1619
+ arrived = await options.steer();
1620
+ }
1621
+ catch {
1622
+ // Resolving an attachment can fail (a dropped file deleted since it was typed).
1623
+ // The turn is not the place to die for it: the message stays queued and the
1624
+ // caller sends it at the end, where it can report the fault to the user.
1625
+ arrived = [];
1626
+ }
1627
+ for (const message of arrived) {
1628
+ session.transcript.push({
1629
+ role: "user",
1630
+ content: message.content,
1631
+ arrival: "steered",
1632
+ ...(message.images && message.images.length > 0 ? { images: message.images } : {}),
1633
+ });
1634
+ }
1635
+ if (arrived.length > 0)
1636
+ await options.persist?.();
1637
+ }
1535
1638
  }
1536
- // Step ceiling reached without the model finishing. Don't spend another call
1537
- // forcing a (misleading) wrap-up the way a tools-off final turn would — that
1538
- // reads as "done" when it isn't. Pause cleanly instead: the transcript, task
1539
- // list, and working set are all intact, so telling Mindweave to continue resumes
1540
- // exactly here with nothing lost, and the user stays in control of the spend.
1639
+ // A ceiling was set and has been reached without the model finishing. Reached only in
1640
+ // that case: with no ceiling the loop condition never ends it.
1641
+ //
1642
+ // Don't spend another call forcing a (misleading) wrap-up the way a tools-off final
1643
+ // turn would — that reads as "done" when it isn't. Pause cleanly instead: the
1644
+ // transcript, task list, and working set are all intact, so telling Mindweave to
1645
+ // continue resumes exactly here with nothing lost, and the user stays in control of
1646
+ // the spend.
1541
1647
  return pauseTask(session, options, `reached the step budget of ${stepLimit} tool steps in one turn`);
1542
1648
  }
1543
1649
  }