mindweave 2.2.1 → 2.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.
- package/README.md +6 -2
- package/dist/cli/App.js +140 -40
- package/dist/cli/App.js.map +1 -1
- package/dist/cli/altScreen.js +17 -1
- package/dist/cli/altScreen.js.map +1 -1
- package/dist/cli/analytics.js +83 -0
- package/dist/cli/analytics.js.map +1 -0
- package/dist/cli/blockSpacing.js +29 -0
- package/dist/cli/blockSpacing.js.map +1 -0
- package/dist/cli/commandLabel.js +85 -0
- package/dist/cli/commandLabel.js.map +1 -0
- package/dist/cli/commands.js +41 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/components/KeyManager.js +3 -3
- package/dist/cli/components/KeyManager.js.map +1 -1
- package/dist/cli/components/Picker.js +10 -6
- package/dist/cli/components/Picker.js.map +1 -1
- package/dist/cli/components/PromptInput.js +8 -1
- package/dist/cli/components/PromptInput.js.map +1 -1
- package/dist/cli/components/ToolGroup.js +5 -1
- package/dist/cli/components/ToolGroup.js.map +1 -1
- package/dist/cli/components/ToolLine.js +61 -6
- package/dist/cli/components/ToolLine.js.map +1 -1
- package/dist/cli/framebuffer/parse.js +10 -4
- package/dist/cli/framebuffer/parse.js.map +1 -1
- package/dist/cli/framebuffer/screen.js +26 -0
- package/dist/cli/framebuffer/screen.js.map +1 -1
- package/dist/cli/framebuffer/writer.js +131 -23
- package/dist/cli/framebuffer/writer.js.map +1 -1
- package/dist/cli/restart.js +99 -0
- package/dist/cli/restart.js.map +1 -0
- package/dist/cli/selfUpdate.js +124 -0
- package/dist/cli/selfUpdate.js.map +1 -0
- package/dist/cli/startupArgs.js +29 -2
- package/dist/cli/startupArgs.js.map +1 -1
- package/dist/cli/terminalRestore.js +9 -1
- package/dist/cli/terminalRestore.js.map +1 -1
- package/dist/cli/toolDisplay.js +15 -6
- package/dist/cli/toolDisplay.js.map +1 -1
- package/dist/cli/transcript.js +1 -1
- package/dist/cli/transcript.js.map +1 -1
- package/dist/cli/updateRunner.js +105 -0
- package/dist/cli/updateRunner.js.map +1 -0
- package/dist/drivers/gemini/manifest.js +16 -11
- package/dist/drivers/gemini/manifest.js.map +1 -1
- package/dist/dynamo/engine.js +30 -4
- package/dist/dynamo/engine.js.map +1 -1
- package/dist/dynamo/prompt.js +7 -4
- package/dist/dynamo/prompt.js.map +1 -1
- package/dist/dynamo/verify.js +8 -5
- package/dist/dynamo/verify.js.map +1 -1
- package/dist/index.js +32 -2
- package/dist/index.js.map +1 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/tools/askUser.js +17 -5
- package/dist/tools/askUser.js.map +1 -1
- package/dist/tools/detail.js +69 -11
- package/dist/tools/detail.js.map +1 -1
- package/dist/tools/exitPlan.js +17 -1
- package/dist/tools/exitPlan.js.map +1 -1
- package/dist/tools/outputShape.js +137 -0
- package/dist/tools/outputShape.js.map +1 -0
- package/dist/tools/registry.js +0 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/runCommand.js +31 -7
- package/dist/tools/runCommand.js.map +1 -1
- package/dist/tools/screenshot.js +33 -5
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/testSummary.js +211 -0
- package/dist/tools/testSummary.js.map +1 -0
- package/package.json +74 -74
- package/dist/alternator/chassis/rank.js +0 -72
- package/dist/alternator/chassis/rank.js.map +0 -1
- package/dist/cli/components/MenuFrame.js +0 -24
- package/dist/cli/components/MenuFrame.js.map +0 -1
- package/dist/cli/reveal.js +0 -32
- package/dist/cli/reveal.js.map +0 -1
- package/dist/cli/smoothScroll.js +0 -74
- package/dist/cli/smoothScroll.js.map +0 -1
- package/dist/cli/viewport.js +0 -179
- package/dist/cli/viewport.js.map +0 -1
- package/dist/dynamo/_probe.tmp.js +0 -20
- package/dist/dynamo/_probe.tmp.js.map +0 -1
- package/dist/tools/captureSweep.js +0 -77
- package/dist/tools/captureSweep.js.map +0 -1
- package/dist/tools/diagnostics.js +0 -174
- package/dist/tools/diagnostics.js.map +0 -1
- package/dist/tools/editFile.js +0 -183
- package/dist/tools/editFile.js.map +0 -1
- package/dist/tools/multiEdit.js +0 -168
- package/dist/tools/multiEdit.js.map +0 -1
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ the agent maintains across sessions, and a long list of things that were quietly
|
|
|
41
41
|
Requires **Windows** and **Node.js 20+**. macOS and Linux are not supported yet, and the
|
|
42
42
|
reason is written down in [KNOWN-ISSUES.md](KNOWN-ISSUES.md) rather than glossed over.
|
|
43
43
|
|
|
44
|
+
Big features coming out soon!
|
|
45
|
+
|
|
44
46
|
```bash
|
|
45
47
|
npm install -g mindweave
|
|
46
48
|
```
|
|
@@ -69,7 +71,7 @@ else is configured inside a session.
|
|
|
69
71
|
|
|
70
72
|
## What it can do
|
|
71
73
|
|
|
72
|
-
**14 providers,
|
|
74
|
+
**14 providers, 53 models, one key.** DeepSeek, Anthropic, OpenAI, Gemini, xAI, Mistral,
|
|
73
75
|
Groq, Cerebras, Qwen, Kimi, GLM, Meta, MiniMax and Tencent. Each family gets its own driver so it
|
|
74
76
|
runs at its best without bloating the shared core, and only the driver you are using is
|
|
75
77
|
ever loaded. Switch with `/provider` and `/model`; the choice is remembered per project.
|
|
@@ -80,7 +82,8 @@ and language servers, costing no tokens, so the agent understands your codebase
|
|
|
80
82
|
than just the file you opened.
|
|
81
83
|
|
|
82
84
|
**Real tools.** File read and edit, multi-file edits, ripgrep search, a shell with
|
|
83
|
-
background jobs, sub-agents
|
|
85
|
+
background jobs, and sub-agents. Every edit comes back with the language server's own
|
|
86
|
+
errors for that file, so a mistake surfaces where it was made. Read-before-edit is enforced, and
|
|
84
87
|
`/undo` is a real net rather than a hope.
|
|
85
88
|
|
|
86
89
|
**Session memory.** Long sessions stay sharp through automatic compaction plus a running
|
|
@@ -118,6 +121,7 @@ paths or commands the agent has to respect.
|
|
|
118
121
|
| `/provider` · `/model` · `/think` | Who answers, which model, how hard it reasons |
|
|
119
122
|
| `/clear` · `/continue` | Start fresh, or resume an earlier session |
|
|
120
123
|
| `/undo` | Reverts what the last turn changed |
|
|
124
|
+
| `/update` | Installs the newest version and reopens on this conversation |
|
|
121
125
|
| `/mcp` | Manages connected MCP servers |
|
|
122
126
|
| `shift-tab` | Cycles interaction modes |
|
|
123
127
|
|
package/dist/cli/App.js
CHANGED
|
@@ -53,11 +53,16 @@ import { formatHelp } from "./help.js";
|
|
|
53
53
|
import { hasApiKey, saveApiKey, removeApiKey, useApiKey, globalEnvPath, reloadConfig } from "./bootstrap.js";
|
|
54
54
|
import { versionLabel, appVersion } from "./version.js";
|
|
55
55
|
import { checkForUpdate } from "./updateCheck.js";
|
|
56
|
+
import { ANALYTICS_EXPLANATION, analyticsEnabled, sendAnalyticsPing, setAnalyticsEnabled, startupStatusLine, } from "./analytics.js";
|
|
56
57
|
import { PromptInput } from "./components/PromptInput.js";
|
|
57
58
|
import { Picker } from "./components/Picker.js";
|
|
58
59
|
import { ApprovalBox } from "./components/ApprovalBox.js";
|
|
59
60
|
import { BlockView } from "./components/BlockView.js";
|
|
60
61
|
import { initialState, reduce, trimNarration } from "./transcript.js";
|
|
62
|
+
import { isTight } from "./blockSpacing.js";
|
|
63
|
+
import { BASE_COMMANDS } from "./commands.js";
|
|
64
|
+
import { manualCommand, refusalReason } from "./selfUpdate.js";
|
|
65
|
+
import { currentInstall, requestRestart, runUpdate } from "./updateRunner.js";
|
|
61
66
|
import { enableMouse, readWheel } from "./mouse.js";
|
|
62
67
|
import { chatLayout, reflowScroll } from "./chatAnchor.js";
|
|
63
68
|
import { virtualWindow } from "./virtualWindow.js";
|
|
@@ -81,6 +86,7 @@ const MINDWEAVE_DOCS_URL = "https://mindweave.dev";
|
|
|
81
86
|
* in full, because only a bare invocation opens anything: given an argument each of these
|
|
82
87
|
* acts directly and there is no surface to hold the frame for. */
|
|
83
88
|
const OVERLAY_COMMANDS = new Set([
|
|
89
|
+
"/analytics",
|
|
84
90
|
"/continue",
|
|
85
91
|
"/key",
|
|
86
92
|
"/mcp",
|
|
@@ -106,7 +112,7 @@ const RESUME_MODES = [
|
|
|
106
112
|
{ label: "Continue as-is", description: "resume the full conversation unchanged" },
|
|
107
113
|
{ label: "Fresh start", description: "leave it and start a new empty session here instead" },
|
|
108
114
|
];
|
|
109
|
-
export function App() {
|
|
115
|
+
export function App({ resumeSessionId }) {
|
|
110
116
|
// The transcript state machine lives in a ref and is advanced by the reducer as
|
|
111
117
|
// the stream arrives; `render` forces a paint. A ref (not useState) so the async
|
|
112
118
|
// streaming loop always reads/writes the latest state without stale closures.
|
|
@@ -321,8 +327,14 @@ export function App() {
|
|
|
321
327
|
// the SAME reducer actions the live stream uses — so a resumed chat shows the
|
|
322
328
|
// exact rows it did before: user/assistant prose, every `● Tool(arg)` with its
|
|
323
329
|
// `⎿` result/diff, the consolidated discovery groups, and a marker where context
|
|
324
|
-
// was summarized. The tool display fields (summary/detail/isError) were
|
|
325
|
-
// each tool entry at run time, so nothing about a row is lost across a resume.
|
|
330
|
+
// was summarized. The tool display fields (summary/detail/detailKind/isError) were
|
|
331
|
+
// stored on each tool entry at run time, so nothing about a row is lost across a resume.
|
|
332
|
+
//
|
|
333
|
+
// `detailKind` used to be missing from that list while this comment already claimed
|
|
334
|
+
// the rows came back identical. They did not: the diff text survived and the fact that
|
|
335
|
+
// it WAS a diff did not, so every resumed edit rendered as dim plain lines. Anything
|
|
336
|
+
// added to a row's appearance has to be stored here too, or the claim above quietly
|
|
337
|
+
// stops being true again.
|
|
326
338
|
function showResumed(transcript) {
|
|
327
339
|
for (const e of transcript) {
|
|
328
340
|
if (e.role === "user") {
|
|
@@ -346,8 +358,22 @@ export function App() {
|
|
|
346
358
|
dispatch({ type: "say", text: intermediate ? trimNarration(e.content) : e.content });
|
|
347
359
|
}
|
|
348
360
|
for (const call of e.toolCalls ?? []) {
|
|
361
|
+
// The spawn itself is drawn by its sub-agent block live, never as a raw row.
|
|
362
|
+
// Replaying it as one puts a `● SpawnSubagent(...)` in a resumed transcript
|
|
363
|
+
// that was not in the live one.
|
|
364
|
+
if (call.name === "spawn_subagent")
|
|
365
|
+
continue;
|
|
349
366
|
const d = toolDisplay(call.name, parseToolArgs(call.arguments));
|
|
350
|
-
dispatch({
|
|
367
|
+
dispatch({
|
|
368
|
+
type: "toolStart",
|
|
369
|
+
toolId: call.id,
|
|
370
|
+
name: d.name,
|
|
371
|
+
arg: d.arg,
|
|
372
|
+
...(d.meta ? { meta: d.meta } : {}),
|
|
373
|
+
action: d.kind,
|
|
374
|
+
group: isGroupable(call.name),
|
|
375
|
+
...(d.covers ? { covers: d.covers } : {}),
|
|
376
|
+
});
|
|
351
377
|
}
|
|
352
378
|
}
|
|
353
379
|
else {
|
|
@@ -358,6 +384,10 @@ export function App() {
|
|
|
358
384
|
ok: e.isError === undefined ? !e.content.startsWith("Error:") : !e.isError,
|
|
359
385
|
summary: e.summary,
|
|
360
386
|
detail: e.detail,
|
|
387
|
+
...(e.detailKind ? { detailKind: e.detailKind } : {}),
|
|
388
|
+
...(e.quiet ? { quiet: true } : {}),
|
|
389
|
+
...(e.displayName ? { name: e.displayName } : {}),
|
|
390
|
+
...(e.displayKind ? { action: e.displayKind } : {}),
|
|
361
391
|
});
|
|
362
392
|
}
|
|
363
393
|
}
|
|
@@ -407,6 +437,9 @@ export function App() {
|
|
|
407
437
|
}
|
|
408
438
|
function attachApproval(s) {
|
|
409
439
|
s.toolContext.requestApproval = (q, o, detail, title) => askApproval.current(q, o, detail, title);
|
|
440
|
+
// Same stop Esc performs. A tool reaches for this when the USER has said, by
|
|
441
|
+
// dismissing a question, that the work should not carry on without them.
|
|
442
|
+
s.toolContext.interrupt = () => abortRef.current?.abort();
|
|
410
443
|
s.toolContext.backgroundShells?.setOnChange(handleBgChange);
|
|
411
444
|
// Servers connect in the background and can die or revive at any time; without this
|
|
412
445
|
// the /mcp view would only ever show what was true when the last key was pressed.
|
|
@@ -480,10 +513,22 @@ export function App() {
|
|
|
480
513
|
// One session for the whole conversation (a ref so it survives re-renders).
|
|
481
514
|
const session = useRef(null);
|
|
482
515
|
useEffect(() => {
|
|
483
|
-
|
|
516
|
+
// A relaunch after `/update` opens on the conversation it left. A resume that does
|
|
517
|
+
// not work out — an id that names nothing, a session file that will not load —
|
|
518
|
+
// falls through to a normal start rather than refusing to open: the point of the
|
|
519
|
+
// whole mechanism is that an update costs you nothing, and failing to come up at
|
|
520
|
+
// all is the one outcome worse than losing the thread. `/continue` still reaches it.
|
|
521
|
+
const open = resumeSessionId
|
|
522
|
+
? resumeSession(process.cwd(), resumeSessionId).then((s) => s ?? createSession())
|
|
523
|
+
: createSession();
|
|
524
|
+
open.then((s) => {
|
|
484
525
|
attachApproval(s);
|
|
485
526
|
session.current = s;
|
|
486
527
|
setReady(true);
|
|
528
|
+
if (resumeSessionId && s.id === resumeSessionId) {
|
|
529
|
+
showResumed(s.transcript);
|
|
530
|
+
note(`— updated to v${appVersion()}, continuing —`);
|
|
531
|
+
}
|
|
487
532
|
// The project may have a model saved from a different provider than the
|
|
488
533
|
// default, so re-check against what we're actually about to run.
|
|
489
534
|
const cur = session.current;
|
|
@@ -505,6 +550,12 @@ export function App() {
|
|
|
505
550
|
setSetupOpen(true);
|
|
506
551
|
});
|
|
507
552
|
}, []);
|
|
553
|
+
// Anonymous usage ping — on by default. The status line shows every launch, not just
|
|
554
|
+
// the first one; the full explanation lives in the /analytics box itself.
|
|
555
|
+
useEffect(() => {
|
|
556
|
+
note(startupStatusLine());
|
|
557
|
+
sendAnalyticsPing(appVersion());
|
|
558
|
+
}, []);
|
|
508
559
|
// A quiet, backgrounded check for a newer release — independent of session startup so a
|
|
509
560
|
// slow or unreachable registry can never delay the first prompt. checkForUpdate() is
|
|
510
561
|
// itself the one that fails silent on every network path; a note only appears when a
|
|
@@ -513,7 +564,7 @@ export function App() {
|
|
|
513
564
|
void checkForUpdate().then((latest) => {
|
|
514
565
|
if (!latest)
|
|
515
566
|
return;
|
|
516
|
-
note(`update available: v${appVersion()} → v${latest} —
|
|
567
|
+
note(`update available: v${appVersion()} → v${latest} — /update to take it`);
|
|
517
568
|
});
|
|
518
569
|
}, []);
|
|
519
570
|
// When a background shell finishes and Mindweave is idle, react to it automatically.
|
|
@@ -1035,7 +1086,7 @@ export function App() {
|
|
|
1035
1086
|
enqueueReveal({ type: "subToolStart", agentId: e.agent, toolId: e.id, name: d.name, arg: d.arg, action: d.kind });
|
|
1036
1087
|
}
|
|
1037
1088
|
else {
|
|
1038
|
-
enqueueReveal({ type: "toolStart", toolId: e.id, name: d.name, arg: d.arg, meta: d.meta, action: d.kind, group: isGroupable(e.name) });
|
|
1089
|
+
enqueueReveal({ type: "toolStart", toolId: e.id, name: d.name, arg: d.arg, meta: d.meta, action: d.kind, group: isGroupable(e.name), ...(d.covers ? { covers: d.covers } : {}) });
|
|
1039
1090
|
}
|
|
1040
1091
|
}
|
|
1041
1092
|
else if (e.type === "tool" && e.phase === "end") {
|
|
@@ -1319,7 +1370,11 @@ export function App() {
|
|
|
1319
1370
|
return;
|
|
1320
1371
|
}
|
|
1321
1372
|
setOverlay(null);
|
|
1322
|
-
if (o.kind === "
|
|
1373
|
+
if (o.kind === "analytics") {
|
|
1374
|
+
setAnalyticsEnabled(index === 0);
|
|
1375
|
+
note(`Analytics turned ${index === 0 ? "on" : "off"}.`);
|
|
1376
|
+
}
|
|
1377
|
+
else if (o.kind === "resumeMode")
|
|
1323
1378
|
void applyResume(o.meta, index);
|
|
1324
1379
|
else if (o.kind === "provider")
|
|
1325
1380
|
void applyProvider(index);
|
|
@@ -1409,6 +1464,75 @@ export function App() {
|
|
|
1409
1464
|
]));
|
|
1410
1465
|
return;
|
|
1411
1466
|
}
|
|
1467
|
+
// /update — take the newer version and come back to this same conversation.
|
|
1468
|
+
//
|
|
1469
|
+
// The restart is the point. A process cannot replace its own code: driver modules
|
|
1470
|
+
// are imported lazily, so a copy that rewrote itself mid-session would be an old
|
|
1471
|
+
// process reading new files, which fails later and somewhere else. Ending and
|
|
1472
|
+
// reopening is what makes the new version actually the version running, and landing
|
|
1473
|
+
// back in this session is what makes that invisible.
|
|
1474
|
+
if (name === "/update") {
|
|
1475
|
+
if (busy) {
|
|
1476
|
+
note("Finish or stop the current turn first — restarting would strand it.", { error: true });
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const install = currentInstall();
|
|
1480
|
+
if (install.kind !== "global") {
|
|
1481
|
+
// Never guessed at. Overwriting a working tree or another project's dependency
|
|
1482
|
+
// is the one thing this command must not do; see selfUpdate.ts.
|
|
1483
|
+
note(`${refusalReason(install)}\n\nTo do it by hand:\n ${manualCommand(install)}`, { error: true });
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
// Past the once-a-day cache deliberately: someone typing this is asking NOW, and
|
|
1487
|
+
// answering from a check made this morning would report "up to date" about a
|
|
1488
|
+
// release that has happened since.
|
|
1489
|
+
const latest = await checkForUpdate({ readCacheImpl: () => null });
|
|
1490
|
+
const current = appVersion();
|
|
1491
|
+
if (!latest) {
|
|
1492
|
+
note(`Already on the latest${current ? ` (v${current})` : ""}.`);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
const choice = await askApproval.current(`Update from v${current} to v${latest}? Mindweave will restart into this same conversation.`, ["Yes, update and restart", "No"], manualCommand(install), "This will run");
|
|
1496
|
+
if (!choice.startsWith("Yes")) {
|
|
1497
|
+
note("Left as it is.");
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
note(`Updating to v${latest}…`);
|
|
1501
|
+
const result = await runUpdate(install.prefix);
|
|
1502
|
+
if (!result.ok) {
|
|
1503
|
+
// A failure here is a no-op rather than a half-state: npm either replaced the
|
|
1504
|
+
// package or it did not, and the copy running is the copy that always was.
|
|
1505
|
+
note(`The update did not run, and nothing was changed.\n${result.message}\n\nTo do it by hand:\n ${manualCommand(install)}`, { error: true });
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
// On disk before the successor goes looking for it.
|
|
1509
|
+
await saveSession(s);
|
|
1510
|
+
// Recorded rather than done here: the terminal can only be handed over once Ink
|
|
1511
|
+
// has unmounted, and unmounting is what ends this render. `index.ts` picks it up.
|
|
1512
|
+
requestRestart({
|
|
1513
|
+
packageRoot: install.packageRoot,
|
|
1514
|
+
sessionId: s.id,
|
|
1515
|
+
previousVersion: current,
|
|
1516
|
+
prefix: install.prefix,
|
|
1517
|
+
});
|
|
1518
|
+
exit();
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
// /analytics — the anonymous usage ping. Bare opens the on/off switch, the same
|
|
1522
|
+
// fixed box every other setting uses; an argument acts directly, same as /model.
|
|
1523
|
+
if (name === "/analytics") {
|
|
1524
|
+
const verb = arg.trim().toLowerCase();
|
|
1525
|
+
if (verb === "on" || verb === "off") {
|
|
1526
|
+
setAnalyticsEnabled(verb === "on");
|
|
1527
|
+
note(`Analytics turned ${verb}.`);
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
if (verb) {
|
|
1531
|
+
return say("/analytics on|off, or bare to open the switch.");
|
|
1532
|
+
}
|
|
1533
|
+
setOverlay({ kind: "analytics" });
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1412
1536
|
// /clear — a fresh conversation without leaving the folder. Until now the only
|
|
1413
1537
|
// way to start over was to quit and relaunch, or to go through /continue and pick
|
|
1414
1538
|
// its third option, which is not somewhere anyone looks for "start over".
|
|
@@ -2016,6 +2140,14 @@ export function App() {
|
|
|
2016
2140
|
if (!overlay)
|
|
2017
2141
|
return null;
|
|
2018
2142
|
const cur = session.current;
|
|
2143
|
+
if (overlay.kind === "analytics") {
|
|
2144
|
+
const enabled = analyticsEnabled();
|
|
2145
|
+
const items = [
|
|
2146
|
+
{ label: "On" + (enabled ? " ✓" : ""), description: "sends the ping" },
|
|
2147
|
+
{ label: "Off" + (!enabled ? " ✓" : ""), description: "sends nothing" },
|
|
2148
|
+
];
|
|
2149
|
+
return (_jsx(Picker, { title: "Anonymous usage analytics", note: ANALYTICS_EXPLANATION, items: items, width: width, maxRows: maxRows, initialIndex: enabled ? 0 : 1, onSelect: onOverlaySelect, onCancel: onOverlayCancel }));
|
|
2150
|
+
}
|
|
2019
2151
|
if (overlay.kind === "sessions") {
|
|
2020
2152
|
const items = overlay.items.map((m) => ({
|
|
2021
2153
|
label: sessionTitle(m),
|
|
@@ -2243,14 +2375,6 @@ const MIN_CHAT_ROWS = 3;
|
|
|
2243
2375
|
const FOOTER_BASE_ROWS = 7;
|
|
2244
2376
|
/** The palette's own chrome: title, the "Tab completes" hint, top+bottom border. */
|
|
2245
2377
|
const MENU_CHROME_ROWS = 4;
|
|
2246
|
-
/** Whether a block hugs the one above it — consecutive tool rows have no blank
|
|
2247
|
-
* line between them. Takes the FULL list, not the rendered slice, so the first
|
|
2248
|
-
* visible block still spaces correctly against the one scrolled off above it. */
|
|
2249
|
-
function isTight(all, i) {
|
|
2250
|
-
const block = all[i];
|
|
2251
|
-
const prev = i > 0 ? all[i - 1] : undefined;
|
|
2252
|
-
return !!block && block.kind === "tool" && !!prev && prev.kind === "tool";
|
|
2253
|
-
}
|
|
2254
2378
|
/** Lines PageUp/PageDown move per press. */
|
|
2255
2379
|
const PAGE_LINES = 10;
|
|
2256
2380
|
/** Lines one wheel notch moves. Three is the usual terminal step, and a flick
|
|
@@ -2383,30 +2507,6 @@ function useTerminalSize() {
|
|
|
2383
2507
|
}, [stdout]);
|
|
2384
2508
|
return size;
|
|
2385
2509
|
}
|
|
2386
|
-
// The built-in slash commands offered by the input's autocomplete. Project skills
|
|
2387
|
-
// are appended at render time from the live session.
|
|
2388
|
-
const BASE_COMMANDS = [
|
|
2389
|
-
{ name: "/help", description: "show this list" },
|
|
2390
|
-
{ name: "/init", description: "write MINDWEAVE.md — what the agent should always know about this project" },
|
|
2391
|
-
{ name: "/provider", description: "choose which provider serves this project" },
|
|
2392
|
-
{ name: "/key", description: "add or replace an API key" },
|
|
2393
|
-
{ name: "/model", description: "choose which model answers, from the current provider" },
|
|
2394
|
-
{ name: "/think", description: "set the reasoning level for the model" },
|
|
2395
|
-
{ name: "/rules", description: "list rules, or add one: /rules <directive>" },
|
|
2396
|
-
{ name: "/skills", description: "list skills, or make one: /skills <description>" },
|
|
2397
|
-
{ name: "/forbidden", description: "list protected paths, or add: /forbidden <path>" },
|
|
2398
|
-
{ name: "/forbid-command", description: "list forbidden commands, or add: /forbid-command <command>" },
|
|
2399
|
-
{ name: "/link", description: "pull in the rest of the project (monorepo / sibling repos)" },
|
|
2400
|
-
{ name: "/include", description: "add a folder to the workspace: /include <path>" },
|
|
2401
|
-
{ name: "/exclude", description: "remove an added folder: /exclude <label>" },
|
|
2402
|
-
{ name: "/shells", description: "view or stop background commands (tests, servers)" },
|
|
2403
|
-
{ name: "/mcp", description: "view MCP servers; /mcp add <name> <command|url> to connect one" },
|
|
2404
|
-
{ name: "/context", description: "show what Mindweave sees about this project" },
|
|
2405
|
-
{ name: "/undo", description: "roll back file changes: /undo, /undo list, /undo <n>" },
|
|
2406
|
-
{ name: "/compact", description: "summarize the conversation to free up context" },
|
|
2407
|
-
{ name: "/clear", description: "start a fresh conversation in this project" },
|
|
2408
|
-
{ name: "/continue", description: "pick a past session to resume" },
|
|
2409
|
-
];
|
|
2410
2510
|
/** Split a /include argument into paths: quoted segments (spaces) or bare tokens. */
|
|
2411
2511
|
function parsePaths(arg) {
|
|
2412
2512
|
const out = [];
|