@bike4mind/cli 0.2.31-feat-ui-side-effect-protocol.19584 → 0.2.31-feat-ask-user-question.19587
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/dist/{chunk-BYXFQJYT.js → chunk-G2LYCVZJ.js} +16 -0
- package/dist/{chunk-J7BHBDO4.js → chunk-VWUG4OK6.js} +6 -6
- package/dist/commands/doctorCommand.js +1 -1
- package/dist/commands/updateCommand.js +1 -1
- package/dist/index.js +398 -128
- package/dist/{store-K5MB3SE7.js → store-X5LEOSGZ.js} +1 -1
- package/package.json +6 -6
|
@@ -75,6 +75,22 @@ var useCliStore = create((set) => ({
|
|
|
75
75
|
permissionQueue: rest
|
|
76
76
|
};
|
|
77
77
|
}),
|
|
78
|
+
// User question prompt queue
|
|
79
|
+
userQuestionPrompt: null,
|
|
80
|
+
userQuestionQueue: [],
|
|
81
|
+
enqueueUserQuestionPrompt: (prompt) => set((state) => {
|
|
82
|
+
if (!state.userQuestionPrompt) {
|
|
83
|
+
return { userQuestionPrompt: prompt };
|
|
84
|
+
}
|
|
85
|
+
return { userQuestionQueue: [...state.userQuestionQueue, prompt] };
|
|
86
|
+
}),
|
|
87
|
+
dequeueUserQuestionPrompt: () => set((state) => {
|
|
88
|
+
const [next, ...rest] = state.userQuestionQueue;
|
|
89
|
+
return {
|
|
90
|
+
userQuestionPrompt: next ?? null,
|
|
91
|
+
userQuestionQueue: rest
|
|
92
|
+
};
|
|
93
|
+
}),
|
|
78
94
|
// Config editor
|
|
79
95
|
showConfigEditor: false,
|
|
80
96
|
setShowConfigEditor: (show) => set({ showConfigEditor: show }),
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@bike4mind/cli",
|
|
6
|
-
version: "0.2.31-feat-
|
|
6
|
+
version: "0.2.31-feat-ask-user-question.19587+cad088dc1",
|
|
7
7
|
type: "module",
|
|
8
8
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
9
9
|
license: "UNLICENSED",
|
|
@@ -114,10 +114,10 @@ var package_default = {
|
|
|
114
114
|
},
|
|
115
115
|
devDependencies: {
|
|
116
116
|
"@bike4mind/agents": "0.1.0",
|
|
117
|
-
"@bike4mind/common": "2.52.1-feat-
|
|
118
|
-
"@bike4mind/mcp": "1.31.1-feat-
|
|
119
|
-
"@bike4mind/services": "2.50.1-feat-
|
|
120
|
-
"@bike4mind/utils": "2.7.1-feat-
|
|
117
|
+
"@bike4mind/common": "2.52.1-feat-ask-user-question.19587+cad088dc1",
|
|
118
|
+
"@bike4mind/mcp": "1.31.1-feat-ask-user-question.19587+cad088dc1",
|
|
119
|
+
"@bike4mind/services": "2.50.1-feat-ask-user-question.19587+cad088dc1",
|
|
120
|
+
"@bike4mind/utils": "2.7.1-feat-ask-user-question.19587+cad088dc1",
|
|
121
121
|
"@types/better-sqlite3": "^7.6.13",
|
|
122
122
|
"@types/diff": "^5.0.9",
|
|
123
123
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -138,7 +138,7 @@ var package_default = {
|
|
|
138
138
|
optionalDependencies: {
|
|
139
139
|
"@vscode/ripgrep": "^1.17.0"
|
|
140
140
|
},
|
|
141
|
-
gitHead: "
|
|
141
|
+
gitHead: "cad088dc1ad77d3c716da4e6fc78489039d71678"
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
// src/utils/updateChecker.ts
|
package/dist/index.js
CHANGED
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
checkForUpdate,
|
|
18
18
|
package_default
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-VWUG4OK6.js";
|
|
20
20
|
import {
|
|
21
21
|
selectActiveBackgroundAgents,
|
|
22
22
|
useCliStore
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-G2LYCVZJ.js";
|
|
24
24
|
import {
|
|
25
25
|
BFLImageService,
|
|
26
26
|
BaseStorage,
|
|
@@ -96,15 +96,15 @@ import {
|
|
|
96
96
|
} from "./chunk-PFBYGCOW.js";
|
|
97
97
|
|
|
98
98
|
// src/index.tsx
|
|
99
|
-
import
|
|
100
|
-
import { render, Box as
|
|
99
|
+
import React22, { useState as useState11, useEffect as useEffect7, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
100
|
+
import { render, Box as Box21, Text as Text21, useApp, useInput as useInput10 } from "ink";
|
|
101
101
|
import { execSync } from "child_process";
|
|
102
102
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
103
103
|
import { v4 as uuidv413 } from "uuid";
|
|
104
104
|
|
|
105
105
|
// src/components/App.tsx
|
|
106
|
-
import
|
|
107
|
-
import { Box as
|
|
106
|
+
import React16, { useState as useState7, useEffect as useEffect5 } from "react";
|
|
107
|
+
import { Box as Box15, Text as Text15, Static, useInput as useInput7 } from "ink";
|
|
108
108
|
|
|
109
109
|
// src/components/StatusBar.tsx
|
|
110
110
|
import React from "react";
|
|
@@ -1506,9 +1506,152 @@ function PermissionPrompt({
|
|
|
1506
1506
|
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Tool: "), /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Action: "), /* @__PURE__ */ React10.createElement(Text9, null, toolDescription)), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Arguments:"), /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { bold: true }, "Preview:"), /* @__PURE__ */ React10.createElement(Box9, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1, flexDirection: "column" }, items.map((item, index) => /* @__PURE__ */ React10.createElement(Box9, { key: item.value }, /* @__PURE__ */ React10.createElement(Text9, { color: "cyan" }, index + 1, "."), /* @__PURE__ */ React10.createElement(Text9, { color: index === selectedIndex ? "cyan" : void 0, bold: index === selectedIndex }, index === selectedIndex ? " \u276F " : " ", item.label)))), /* @__PURE__ */ React10.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Press 1-", items.length, ", y/n, or \u2191\u2193 + Enter")));
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
|
-
// src/components/
|
|
1510
|
-
import React11, { useState as useState5,
|
|
1509
|
+
// src/components/UserQuestionPrompt.tsx
|
|
1510
|
+
import React11, { useState as useState5, useCallback as useCallback2 } from "react";
|
|
1511
1511
|
import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
|
|
1512
|
+
import TextInput from "ink-text-input";
|
|
1513
|
+
function UserQuestionPrompt({ payload, onResponse }) {
|
|
1514
|
+
const [questionIndex, setQuestionIndex] = useState5(0);
|
|
1515
|
+
const [answers, setAnswers] = useState5([]);
|
|
1516
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
1517
|
+
const [multiSelected, setMultiSelected] = useState5(/* @__PURE__ */ new Set());
|
|
1518
|
+
const [otherText, setOtherText] = useState5("");
|
|
1519
|
+
const [done, setDone] = useState5(false);
|
|
1520
|
+
const currentQuestion = payload.questions[questionIndex];
|
|
1521
|
+
const options = [...currentQuestion.options, { label: "Other...", description: "Provide your own answer" }];
|
|
1522
|
+
const otherIndex = options.length - 1;
|
|
1523
|
+
const isMulti = currentQuestion.multiSelect;
|
|
1524
|
+
const isOnOther = selectedIndex === otherIndex;
|
|
1525
|
+
const advanceToNextQuestion = useCallback2(
|
|
1526
|
+
(answer) => {
|
|
1527
|
+
const updatedAnswers = [...answers, answer];
|
|
1528
|
+
if (questionIndex + 1 >= payload.questions.length) {
|
|
1529
|
+
setDone(true);
|
|
1530
|
+
onResponse({ answers: updatedAnswers });
|
|
1531
|
+
} else {
|
|
1532
|
+
setAnswers(updatedAnswers);
|
|
1533
|
+
setQuestionIndex(questionIndex + 1);
|
|
1534
|
+
setSelectedIndex(0);
|
|
1535
|
+
setMultiSelected(/* @__PURE__ */ new Set());
|
|
1536
|
+
setOtherText("");
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
[answers, questionIndex, payload.questions.length, onResponse]
|
|
1540
|
+
);
|
|
1541
|
+
const submitOther = useCallback2(() => {
|
|
1542
|
+
if (done) return;
|
|
1543
|
+
const text = otherText.trim();
|
|
1544
|
+
if (!text) return;
|
|
1545
|
+
if (isMulti) {
|
|
1546
|
+
const selected = Array.from(multiSelected).filter((i) => i !== otherIndex).map((i) => options[i].label);
|
|
1547
|
+
selected.push(text);
|
|
1548
|
+
advanceToNextQuestion({ question: currentQuestion.question, selected });
|
|
1549
|
+
} else {
|
|
1550
|
+
advanceToNextQuestion({ question: currentQuestion.question, selected: [text] });
|
|
1551
|
+
}
|
|
1552
|
+
}, [done, otherText, isMulti, multiSelected, otherIndex, options, currentQuestion, advanceToNextQuestion]);
|
|
1553
|
+
const confirmSelection = useCallback2(() => {
|
|
1554
|
+
if (done) return;
|
|
1555
|
+
if (isMulti) {
|
|
1556
|
+
const selected = Array.from(multiSelected).filter((i) => i !== otherIndex).map((i) => options[i].label);
|
|
1557
|
+
if (multiSelected.has(otherIndex) && otherText.trim()) {
|
|
1558
|
+
selected.push(otherText.trim());
|
|
1559
|
+
}
|
|
1560
|
+
if (selected.length === 0) return;
|
|
1561
|
+
advanceToNextQuestion({ question: currentQuestion.question, selected });
|
|
1562
|
+
} else if (isOnOther) {
|
|
1563
|
+
submitOther();
|
|
1564
|
+
} else {
|
|
1565
|
+
advanceToNextQuestion({
|
|
1566
|
+
question: currentQuestion.question,
|
|
1567
|
+
selected: [options[selectedIndex].label]
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
}, [
|
|
1571
|
+
done,
|
|
1572
|
+
isMulti,
|
|
1573
|
+
multiSelected,
|
|
1574
|
+
selectedIndex,
|
|
1575
|
+
otherIndex,
|
|
1576
|
+
isOnOther,
|
|
1577
|
+
options,
|
|
1578
|
+
otherText,
|
|
1579
|
+
currentQuestion,
|
|
1580
|
+
advanceToNextQuestion,
|
|
1581
|
+
submitOther
|
|
1582
|
+
]);
|
|
1583
|
+
useInput4(
|
|
1584
|
+
(input, key) => {
|
|
1585
|
+
if (done) return;
|
|
1586
|
+
if (key.upArrow) {
|
|
1587
|
+
setSelectedIndex((i) => i > 0 ? i - 1 : options.length - 1);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
if (key.downArrow) {
|
|
1591
|
+
setSelectedIndex((i) => i < options.length - 1 ? i + 1 : 0);
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
if (isOnOther) {
|
|
1595
|
+
if (key.return) {
|
|
1596
|
+
confirmSelection();
|
|
1597
|
+
}
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
const num = parseInt(input, 10);
|
|
1601
|
+
if (num >= 1 && num <= options.length) {
|
|
1602
|
+
const idx = num - 1;
|
|
1603
|
+
if (isMulti) {
|
|
1604
|
+
setMultiSelected((prev) => {
|
|
1605
|
+
const next = new Set(prev);
|
|
1606
|
+
if (next.has(idx)) next.delete(idx);
|
|
1607
|
+
else next.add(idx);
|
|
1608
|
+
return next;
|
|
1609
|
+
});
|
|
1610
|
+
setSelectedIndex(idx);
|
|
1611
|
+
} else if (idx === otherIndex) {
|
|
1612
|
+
setSelectedIndex(idx);
|
|
1613
|
+
} else {
|
|
1614
|
+
advanceToNextQuestion({
|
|
1615
|
+
question: currentQuestion.question,
|
|
1616
|
+
selected: [options[idx].label]
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (input === " " && isMulti) {
|
|
1622
|
+
setMultiSelected((prev) => {
|
|
1623
|
+
const next = new Set(prev);
|
|
1624
|
+
if (next.has(selectedIndex)) next.delete(selectedIndex);
|
|
1625
|
+
else next.add(selectedIndex);
|
|
1626
|
+
return next;
|
|
1627
|
+
});
|
|
1628
|
+
} else if (key.return) {
|
|
1629
|
+
confirmSelection();
|
|
1630
|
+
}
|
|
1631
|
+
},
|
|
1632
|
+
{ isActive: !done }
|
|
1633
|
+
);
|
|
1634
|
+
if (done) return null;
|
|
1635
|
+
const totalQuestions = payload.questions.length;
|
|
1636
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", borderStyle: "bold", borderColor: "cyan", padding: 1, marginY: 1 }, /* @__PURE__ */ React11.createElement(Box10, null, /* @__PURE__ */ React11.createElement(Text10, { bold: true, color: "cyan" }, "? Question", totalQuestions > 1 ? ` ${questionIndex + 1}/${totalQuestions}` : "")), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { bold: true }, currentQuestion.question)), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1, flexDirection: "column" }, options.map((opt, idx) => {
|
|
1637
|
+
const isHighlighted = idx === selectedIndex;
|
|
1638
|
+
const isToggled = isMulti && multiSelected.has(idx);
|
|
1639
|
+
const prefix = isMulti ? isToggled ? "[x]" : "[ ]" : isHighlighted ? " > " : " ";
|
|
1640
|
+
return /* @__PURE__ */ React11.createElement(Box10, { key: idx }, /* @__PURE__ */ React11.createElement(Text10, { color: "cyan" }, idx + 1, "."), /* @__PURE__ */ React11.createElement(Text10, { color: isHighlighted ? "cyan" : void 0, bold: isHighlighted }, " ", prefix, " ", opt.label), idx === otherIndex && isHighlighted ? /* @__PURE__ */ React11.createElement(Box10, { marginLeft: 1 }, /* @__PURE__ */ React11.createElement(
|
|
1641
|
+
TextInput,
|
|
1642
|
+
{
|
|
1643
|
+
value: otherText,
|
|
1644
|
+
onChange: setOtherText,
|
|
1645
|
+
onSubmit: submitOther,
|
|
1646
|
+
placeholder: "Type your answer..."
|
|
1647
|
+
}
|
|
1648
|
+
)) : opt.description && idx !== otherIndex && /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, " - ", opt.description));
|
|
1649
|
+
})), /* @__PURE__ */ React11.createElement(Box10, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text10, { dimColor: true }, isOnOther ? "Type your answer, Enter to submit, or arrow keys to go back" : isMulti ? "Press 1-" + options.length + ", Space to toggle, Enter to confirm" : "Press 1-" + options.length + ", or arrow keys + Enter")));
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// src/components/ConfigEditor.tsx
|
|
1653
|
+
import React12, { useState as useState6, useMemo as useMemo3 } from "react";
|
|
1654
|
+
import { Box as Box11, Text as Text11, useInput as useInput5 } from "ink";
|
|
1512
1655
|
var MAX_ITERATIONS_OPTIONS = [
|
|
1513
1656
|
{ label: "10", value: 10 },
|
|
1514
1657
|
{ label: "20", value: 20 },
|
|
@@ -1652,10 +1795,10 @@ function buildConfigItems(availableModels) {
|
|
|
1652
1795
|
return items;
|
|
1653
1796
|
}
|
|
1654
1797
|
function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
1655
|
-
const [selectedIndex, setSelectedIndex] =
|
|
1656
|
-
const [editedConfig, setEditedConfig] =
|
|
1657
|
-
const [saveError, setSaveError] =
|
|
1658
|
-
const [isSaving, setIsSaving] =
|
|
1798
|
+
const [selectedIndex, setSelectedIndex] = useState6(0);
|
|
1799
|
+
const [editedConfig, setEditedConfig] = useState6(config);
|
|
1800
|
+
const [saveError, setSaveError] = useState6(null);
|
|
1801
|
+
const [isSaving, setIsSaving] = useState6(false);
|
|
1659
1802
|
const configItems = useMemo3(() => buildConfigItems(availableModels), [availableModels]);
|
|
1660
1803
|
const hasChanges = useMemo3(() => {
|
|
1661
1804
|
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
@@ -1675,7 +1818,7 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1675
1818
|
}
|
|
1676
1819
|
onClose();
|
|
1677
1820
|
};
|
|
1678
|
-
|
|
1821
|
+
useInput5((input, key) => {
|
|
1679
1822
|
const currentItem = configItems[selectedIndex];
|
|
1680
1823
|
if (key.upArrow) {
|
|
1681
1824
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : configItems.length - 1);
|
|
@@ -1740,33 +1883,33 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1740
1883
|
}
|
|
1741
1884
|
return String(value);
|
|
1742
1885
|
};
|
|
1743
|
-
return /* @__PURE__ */
|
|
1886
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, marginY: 1 }, /* @__PURE__ */ React12.createElement(Box11, { justifyContent: "space-between", marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { bold: true, color: "cyan" }, "Settings"), isSaving ? /* @__PURE__ */ React12.createElement(Text11, { color: "yellow" }, "Saving...") : hasChanges ? /* @__PURE__ */ React12.createElement(Text11, { dimColor: true, color: "yellow" }, "(unsaved changes)") : null), saveError && /* @__PURE__ */ React12.createElement(Box11, { marginBottom: 1 }, /* @__PURE__ */ React12.createElement(Text11, { color: "red" }, "Error: ", saveError)), /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", marginBottom: 1 }, configItems.map((item, index) => {
|
|
1744
1887
|
const isSelected = index === selectedIndex;
|
|
1745
1888
|
const value = item.getValue(editedConfig);
|
|
1746
1889
|
const displayValue = formatValue(item, value);
|
|
1747
1890
|
const hasOptions = item.type === "select" || item.type === "boolean" || item.type === "number";
|
|
1748
|
-
return /* @__PURE__ */
|
|
1749
|
-
})), /* @__PURE__ */
|
|
1891
|
+
return /* @__PURE__ */ React12.createElement(Box11, { key: item.key }, /* @__PURE__ */ React12.createElement(Text11, { color: isSelected ? "cyan" : void 0 }, isSelected ? "> " : " "), /* @__PURE__ */ React12.createElement(Box11, { width: 18 }, /* @__PURE__ */ React12.createElement(Text11, { bold: isSelected, color: isSelected ? "white" : "gray" }, item.label, ":")), /* @__PURE__ */ React12.createElement(Box11, null, hasOptions && isSelected && /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "< "), /* @__PURE__ */ React12.createElement(Text11, { bold: isSelected, color: isSelected ? "green" : void 0 }, displayValue), hasOptions && isSelected && /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, " >")));
|
|
1892
|
+
})), /* @__PURE__ */ React12.createElement(Box11, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text11, { dimColor: true }, "\u2191/\u2193: Navigate | Space/\u2190/\u2192: Change | q/Esc: Save & Exit")));
|
|
1750
1893
|
}
|
|
1751
1894
|
|
|
1752
1895
|
// src/components/McpViewer.tsx
|
|
1753
|
-
import
|
|
1754
|
-
import { Box as
|
|
1896
|
+
import React13 from "react";
|
|
1897
|
+
import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
|
|
1755
1898
|
function McpViewer({ config, mcpManager, onClose }) {
|
|
1756
|
-
|
|
1899
|
+
useInput6((input, key) => {
|
|
1757
1900
|
if (key.escape || input === "q") {
|
|
1758
1901
|
onClose();
|
|
1759
1902
|
}
|
|
1760
1903
|
});
|
|
1761
1904
|
if (config.mcpServers.length === 0) {
|
|
1762
|
-
return /* @__PURE__ */
|
|
1905
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true, color: "cyan" }, "\u{1F4E1} MCP Server Status")), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "No MCP servers configured."), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "To add MCP servers, edit your config file:")), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " Global: ~/.bike4mind/config.json"), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " Project: .bike4mind/config.json"), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 2 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true, italic: true }, "Press Esc or q to close")));
|
|
1763
1906
|
}
|
|
1764
1907
|
const enabledServers = config.mcpServers.filter((s) => s.enabled);
|
|
1765
|
-
return /* @__PURE__ */
|
|
1908
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true, color: "cyan" }, "\u{1F4E1} MCP Server Status")), /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginBottom: 2 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true, dimColor: true }, "Configured Servers:"), config.mcpServers.map((server) => {
|
|
1766
1909
|
const status = server.enabled ? "\u2705 Enabled" : "\u23F8\uFE0F Disabled";
|
|
1767
1910
|
const commandInfo = server.command ? `${server.command} ${(server.args || []).join(" ")}` : "(internal)";
|
|
1768
|
-
return /* @__PURE__ */
|
|
1769
|
-
})), enabledServers.length > 0 && mcpManager && /* @__PURE__ */
|
|
1911
|
+
return /* @__PURE__ */ React13.createElement(Box12, { key: server.name, flexDirection: "column", marginTop: 1, marginLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, null, "\u2022 ", /* @__PURE__ */ React13.createElement(Text12, { bold: true }, server.name), " - ", /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, status)), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " Command: ", commandInfo), Object.keys(server.env).length > 0 && /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " Env vars: ", Object.keys(server.env).join(", ")));
|
|
1912
|
+
})), enabledServers.length > 0 && mcpManager && /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", marginBottom: 2 }, /* @__PURE__ */ React13.createElement(Text12, { bold: true, dimColor: true }, "Connection Status:"), enabledServers.map((server) => {
|
|
1770
1913
|
const state = mcpManager.getConnectionState(server.name);
|
|
1771
1914
|
let icon;
|
|
1772
1915
|
let statusText;
|
|
@@ -1796,30 +1939,30 @@ function McpViewer({ config, mcpManager, onClose }) {
|
|
|
1796
1939
|
const serverTools = toolCounts.find((t) => t.serverName === server.name);
|
|
1797
1940
|
const toolCount = serverTools?.count || 0;
|
|
1798
1941
|
const toolInfo = state === "connected" && toolCount > 0 ? ` (${toolCount} tool${toolCount === 1 ? "" : "s"})` : "";
|
|
1799
|
-
return /* @__PURE__ */
|
|
1800
|
-
}), /* @__PURE__ */
|
|
1942
|
+
return /* @__PURE__ */ React13.createElement(Box12, { key: server.name, marginTop: 1, marginLeft: 2 }, /* @__PURE__ */ React13.createElement(Text12, null, "\u2022 ", /* @__PURE__ */ React13.createElement(Text12, { bold: true }, server.name), " \xB7 ", /* @__PURE__ */ React13.createElement(Text12, { color }, icon), " ", /* @__PURE__ */ React13.createElement(Text12, { color }, statusText), toolInfo && /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, toolInfo)));
|
|
1943
|
+
}), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1, marginLeft: 2 }, (() => {
|
|
1801
1944
|
const toolCounts = mcpManager.getToolCount();
|
|
1802
1945
|
const totalTools = toolCounts.reduce((sum2, s) => sum2 + s.count, 0);
|
|
1803
1946
|
if (totalTools > 0) {
|
|
1804
|
-
return /* @__PURE__ */
|
|
1947
|
+
return /* @__PURE__ */ React13.createElement(Text12, { bold: true, color: "green" }, "Total: ", totalTools, " MCP tool", totalTools === 1 ? "" : "s", " available");
|
|
1805
1948
|
} else {
|
|
1806
|
-
return /* @__PURE__ */
|
|
1949
|
+
return /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, "No MCP tools available yet (servers still connecting)");
|
|
1807
1950
|
}
|
|
1808
|
-
})())), enabledServers.length === 0 && /* @__PURE__ */
|
|
1951
|
+
})())), enabledServers.length === 0 && /* @__PURE__ */ React13.createElement(Box12, { marginBottom: 2 }, /* @__PURE__ */ React13.createElement(Text12, { color: "yellow" }, "\u26A0\uFE0F No MCP servers enabled"), /* @__PURE__ */ React13.createElement(Text12, { dimColor: true }, " Use `b4m mcp enable ", "<name>", "` to enable a server")), /* @__PURE__ */ React13.createElement(Box12, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text12, { dimColor: true, italic: true }, "Press Esc or q to close")));
|
|
1809
1952
|
}
|
|
1810
1953
|
|
|
1811
1954
|
// src/components/MessageItem.tsx
|
|
1812
|
-
import
|
|
1813
|
-
import { Box as
|
|
1955
|
+
import React15 from "react";
|
|
1956
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1814
1957
|
|
|
1815
1958
|
// src/components/MarkdownRenderer.tsx
|
|
1816
|
-
import
|
|
1817
|
-
import { Box as
|
|
1959
|
+
import React14 from "react";
|
|
1960
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1818
1961
|
import { marked } from "marked";
|
|
1819
1962
|
import { highlight } from "cli-highlight";
|
|
1820
1963
|
function MarkdownRenderer({ content }) {
|
|
1821
1964
|
const tokens = marked.lexer(content);
|
|
1822
|
-
return /* @__PURE__ */
|
|
1965
|
+
return /* @__PURE__ */ React14.createElement(Box13, { flexDirection: "column" }, tokens.map((token, idx) => renderToken(token, idx)));
|
|
1823
1966
|
}
|
|
1824
1967
|
function renderToken(token, idx) {
|
|
1825
1968
|
switch (token.type) {
|
|
@@ -1834,12 +1977,12 @@ function renderToken(token, idx) {
|
|
|
1834
1977
|
case "blockquote":
|
|
1835
1978
|
return renderBlockquote(token, idx);
|
|
1836
1979
|
case "hr":
|
|
1837
|
-
return /* @__PURE__ */
|
|
1980
|
+
return /* @__PURE__ */ React14.createElement(Text13, { key: idx, dimColor: true }, "\u2500".repeat(50));
|
|
1838
1981
|
case "space":
|
|
1839
1982
|
return null;
|
|
1840
1983
|
default:
|
|
1841
1984
|
if ("text" in token) {
|
|
1842
|
-
return /* @__PURE__ */
|
|
1985
|
+
return /* @__PURE__ */ React14.createElement(Text13, { key: idx }, token.text);
|
|
1843
1986
|
}
|
|
1844
1987
|
return null;
|
|
1845
1988
|
}
|
|
@@ -1854,7 +1997,7 @@ function renderHeading(token, idx) {
|
|
|
1854
1997
|
6: "white"
|
|
1855
1998
|
};
|
|
1856
1999
|
const color = colors[token.depth] || "white";
|
|
1857
|
-
return /* @__PURE__ */
|
|
2000
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, marginTop: idx > 0 ? 1 : 0 }, /* @__PURE__ */ React14.createElement(Text13, { bold: true, color }, parseInlineText(token.text)));
|
|
1858
2001
|
}
|
|
1859
2002
|
function renderCodeBlock(token, idx) {
|
|
1860
2003
|
let highlightedCode;
|
|
@@ -1866,20 +2009,20 @@ function renderCodeBlock(token, idx) {
|
|
|
1866
2009
|
} catch (error) {
|
|
1867
2010
|
highlightedCode = token.text;
|
|
1868
2011
|
}
|
|
1869
|
-
return /* @__PURE__ */
|
|
2012
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, flexDirection: "column", paddingLeft: 2 }, token.lang && /* @__PURE__ */ React14.createElement(Text13, { dimColor: true, color: "gray" }, token.lang), /* @__PURE__ */ React14.createElement(Text13, null, highlightedCode));
|
|
1870
2013
|
}
|
|
1871
2014
|
function renderParagraph(token, idx) {
|
|
1872
|
-
return /* @__PURE__ */
|
|
2015
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx }, /* @__PURE__ */ React14.createElement(Text13, null, parseInlineText(token.text)));
|
|
1873
2016
|
}
|
|
1874
2017
|
function renderList(token, idx) {
|
|
1875
|
-
return /* @__PURE__ */
|
|
2018
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, flexDirection: "column" }, token.items.map((item, itemIdx) => renderListItem(item, itemIdx, token.ordered, itemIdx + 1)));
|
|
1876
2019
|
}
|
|
1877
2020
|
function renderListItem(item, idx, ordered, number) {
|
|
1878
2021
|
const bullet = ordered ? `${number}.` : "\u2022";
|
|
1879
|
-
return /* @__PURE__ */
|
|
2022
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, paddingLeft: 2 }, /* @__PURE__ */ React14.createElement(Text13, null, bullet, " ", parseInlineText(item.text)));
|
|
1880
2023
|
}
|
|
1881
2024
|
function renderBlockquote(token, idx) {
|
|
1882
|
-
return /* @__PURE__ */
|
|
2025
|
+
return /* @__PURE__ */ React14.createElement(Box13, { key: idx, paddingLeft: 2, borderStyle: "single", borderLeft: true, borderColor: "gray" }, token.tokens.map((t, i) => renderToken(t, i)));
|
|
1883
2026
|
}
|
|
1884
2027
|
function parseInlineText(text) {
|
|
1885
2028
|
const parts = [];
|
|
@@ -1892,15 +2035,15 @@ function parseInlineText(text) {
|
|
|
1892
2035
|
}
|
|
1893
2036
|
if (match[1]) {
|
|
1894
2037
|
parts.push(
|
|
1895
|
-
/* @__PURE__ */
|
|
2038
|
+
/* @__PURE__ */ React14.createElement(Text13, { key: match.index, bold: true }, match[2])
|
|
1896
2039
|
);
|
|
1897
2040
|
} else if (match[3]) {
|
|
1898
2041
|
parts.push(
|
|
1899
|
-
/* @__PURE__ */
|
|
2042
|
+
/* @__PURE__ */ React14.createElement(Text13, { key: match.index, italic: true }, match[4])
|
|
1900
2043
|
);
|
|
1901
2044
|
} else if (match[5]) {
|
|
1902
2045
|
parts.push(
|
|
1903
|
-
/* @__PURE__ */
|
|
2046
|
+
/* @__PURE__ */ React14.createElement(Text13, { key: match.index, color: "cyan" }, match[6])
|
|
1904
2047
|
);
|
|
1905
2048
|
}
|
|
1906
2049
|
lastIndex = regex.lastIndex;
|
|
@@ -1911,7 +2054,7 @@ function parseInlineText(text) {
|
|
|
1911
2054
|
if (parts.length === 0) {
|
|
1912
2055
|
return text;
|
|
1913
2056
|
}
|
|
1914
|
-
return /* @__PURE__ */
|
|
2057
|
+
return /* @__PURE__ */ React14.createElement(React14.Fragment, null, parts);
|
|
1915
2058
|
}
|
|
1916
2059
|
|
|
1917
2060
|
// src/components/MessageItem.tsx
|
|
@@ -1922,21 +2065,21 @@ function truncateValue(value, maxLength) {
|
|
|
1922
2065
|
}
|
|
1923
2066
|
return str.slice(0, maxLength) + "...";
|
|
1924
2067
|
}
|
|
1925
|
-
var MessageItem =
|
|
2068
|
+
var MessageItem = React15.memo(function MessageItem2({ message }) {
|
|
1926
2069
|
const isUser = message.role === "user";
|
|
1927
|
-
return /* @__PURE__ */
|
|
2070
|
+
return /* @__PURE__ */ React15.createElement(Box14, { flexDirection: "column" }, isUser && message.content && /* @__PURE__ */ React15.createElement(Box14, { marginBottom: 1 }, /* @__PURE__ */ React15.createElement(Text14, { backgroundColor: "whiteBright", color: "black" }, "\u276F ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.filter((s) => ["thought", "action"].includes(s.type)).length > 0 && /* @__PURE__ */ React15.createElement(Box14, { paddingLeft: 2, flexDirection: "column", marginBottom: 1 }, message.metadata.steps.map((step, idx) => {
|
|
1928
2071
|
if (step.type === "thought") {
|
|
1929
|
-
return /* @__PURE__ */
|
|
2072
|
+
return /* @__PURE__ */ React15.createElement(Box14, { key: idx, flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Text14, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, ` ${step.content}`));
|
|
1930
2073
|
}
|
|
1931
2074
|
if (step.type === "action") {
|
|
1932
2075
|
const toolName = step.metadata?.toolName || "unknown";
|
|
1933
2076
|
const toolInput = step.metadata?.toolInput;
|
|
1934
2077
|
const observationStep = message.metadata?.steps?.[idx + 1];
|
|
1935
2078
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
1936
|
-
return /* @__PURE__ */
|
|
2079
|
+
return /* @__PURE__ */ React15.createElement(Box14, { key: idx, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React15.createElement(Text14, { color: "yellow" }, "\u{1F527} ", toolName), toolInput && /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, ` Input: ${truncateValue(toolInput, 100)}`), result && /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, ` Result: ${truncateValue(result, 200)}`));
|
|
1937
2080
|
}
|
|
1938
2081
|
return null;
|
|
1939
|
-
}).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */
|
|
2082
|
+
}).filter(Boolean)), !isUser && message.content !== "..." && /* @__PURE__ */ React15.createElement(Box14, { paddingLeft: 2, marginBottom: 1 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React15.createElement(Text14, { color: "yellow" }, "\u26A0\uFE0F ", message.content) : /* @__PURE__ */ React15.createElement(MarkdownRenderer, { content: message.content })), !isUser && message.content !== "..." && message.metadata && /* @__PURE__ */ React15.createElement(Box14, { paddingLeft: 2, marginBottom: 1 }, (message.metadata.tokenUsage?.total || message.metadata.creditsUsed) && /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, "(", message.metadata.tokenUsage?.total ? `${message.metadata.tokenUsage.total.toLocaleString()} tokens` : "", message.metadata.creditsUsed && message.metadata.creditsUsed > 0 ? (message.metadata.tokenUsage?.total ? " \u2022 " : "") + `used ${message.metadata.creditsUsed.toLocaleString()} ${message.metadata.creditsUsed === 1 ? "credit" : "credits"}` : "", ")")));
|
|
1940
2083
|
});
|
|
1941
2084
|
|
|
1942
2085
|
// src/utils/processFileReferences.ts
|
|
@@ -2064,6 +2207,7 @@ function App({
|
|
|
2064
2207
|
onCommand,
|
|
2065
2208
|
onBashCommand,
|
|
2066
2209
|
onPermissionResponse,
|
|
2210
|
+
onUserQuestionResponse,
|
|
2067
2211
|
onImageDetected,
|
|
2068
2212
|
commandHistory = [],
|
|
2069
2213
|
commands = [],
|
|
@@ -2082,6 +2226,7 @@ function App({
|
|
|
2082
2226
|
const totalCredits = useCliStore((state) => state.session?.metadata.totalCredits);
|
|
2083
2227
|
const isThinking = useCliStore((state) => state.isThinking);
|
|
2084
2228
|
const permissionPrompt = useCliStore((state) => state.permissionPrompt);
|
|
2229
|
+
const userQuestionPrompt = useCliStore((state) => state.userQuestionPrompt);
|
|
2085
2230
|
const showConfigEditor = useCliStore((state) => state.showConfigEditor);
|
|
2086
2231
|
const setShowConfigEditor = useCliStore((state) => state.setShowConfigEditor);
|
|
2087
2232
|
const showMcpViewer = useCliStore((state) => state.showMcpViewer);
|
|
@@ -2097,13 +2242,13 @@ function App({
|
|
|
2097
2242
|
}
|
|
2098
2243
|
}, [pendingBackgroundTrigger, isThinking, setPendingBackgroundTrigger, onBackgroundCompletion]);
|
|
2099
2244
|
const toggleAutoAcceptEdits = useCliStore((state) => state.toggleAutoAcceptEdits);
|
|
2100
|
-
|
|
2245
|
+
useInput7((_input, key) => {
|
|
2101
2246
|
if (key.tab && key.shift) {
|
|
2102
2247
|
toggleAutoAcceptEdits();
|
|
2103
2248
|
}
|
|
2104
2249
|
});
|
|
2105
|
-
const [isBashMode, setIsBashMode] =
|
|
2106
|
-
const handleSubmit =
|
|
2250
|
+
const [isBashMode, setIsBashMode] = useState7(false);
|
|
2251
|
+
const handleSubmit = React16.useCallback(
|
|
2107
2252
|
async (input) => {
|
|
2108
2253
|
const trimmed = input.trim();
|
|
2109
2254
|
if (!trimmed) return;
|
|
@@ -2132,7 +2277,7 @@ ${errorBlock}`;
|
|
|
2132
2277
|
},
|
|
2133
2278
|
[onMessage, onCommand, setIsThinking]
|
|
2134
2279
|
);
|
|
2135
|
-
return /* @__PURE__ */
|
|
2280
|
+
return /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column" }, showConfigEditor && config && onSaveConfig ? /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(
|
|
2136
2281
|
ConfigEditor,
|
|
2137
2282
|
{
|
|
2138
2283
|
config,
|
|
@@ -2142,8 +2287,8 @@ ${errorBlock}`;
|
|
|
2142
2287
|
}
|
|
2143
2288
|
)) : showMcpViewer && config ? (
|
|
2144
2289
|
/* MCP Viewer - full screen takeover */
|
|
2145
|
-
/* @__PURE__ */
|
|
2146
|
-
) : /* @__PURE__ */
|
|
2290
|
+
/* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(McpViewer, { config, mcpManager, onClose: () => setShowMcpViewer(false) }))
|
|
2291
|
+
) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Static, { items: messages }, (message) => /* @__PURE__ */ React16.createElement(Box15, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(MessageItem, { message }))), /* @__PURE__ */ React16.createElement(Box15, { flexDirection: "column" }, pendingMessages.map((message) => /* @__PURE__ */ React16.createElement(Box15, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(MessageItem, { message })))), permissionPrompt && /* @__PURE__ */ React16.createElement(Box15, { key: permissionPrompt.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(
|
|
2147
2292
|
PermissionPrompt,
|
|
2148
2293
|
{
|
|
2149
2294
|
toolName: permissionPrompt.toolName,
|
|
@@ -2152,20 +2297,20 @@ ${errorBlock}`;
|
|
|
2152
2297
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
2153
2298
|
onResponse: onPermissionResponse
|
|
2154
2299
|
}
|
|
2155
|
-
)), !permissionPrompt && /* @__PURE__ */
|
|
2300
|
+
)), userQuestionPrompt && /* @__PURE__ */ React16.createElement(Box15, { key: userQuestionPrompt.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React16.createElement(UserQuestionPrompt, { payload: userQuestionPrompt.payload, onResponse: onUserQuestionResponse })), !permissionPrompt && !userQuestionPrompt && /* @__PURE__ */ React16.createElement(AgentThinking, null), /* @__PURE__ */ React16.createElement(BackgroundAgentStatus, null), /* @__PURE__ */ React16.createElement(CompletedGroupNotification, null), exitRequested && /* @__PURE__ */ React16.createElement(Box15, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text15, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React16.createElement(Box15, { borderStyle: "single", borderColor: isBashMode ? "yellow" : "cyan", paddingX: 1 }, /* @__PURE__ */ React16.createElement(
|
|
2156
2301
|
InputPrompt,
|
|
2157
2302
|
{
|
|
2158
2303
|
onSubmit: handleSubmit,
|
|
2159
2304
|
onBashCommand,
|
|
2160
2305
|
onImageDetected,
|
|
2161
|
-
disabled: isThinking || !!permissionPrompt,
|
|
2306
|
+
disabled: isThinking || !!permissionPrompt || !!userQuestionPrompt,
|
|
2162
2307
|
history: commandHistory,
|
|
2163
2308
|
commands,
|
|
2164
2309
|
prefillInput,
|
|
2165
2310
|
onPrefillConsumed,
|
|
2166
2311
|
onBashModeChange: setIsBashMode
|
|
2167
2312
|
}
|
|
2168
|
-
)), /* @__PURE__ */
|
|
2313
|
+
)), /* @__PURE__ */ React16.createElement(
|
|
2169
2314
|
StatusBar,
|
|
2170
2315
|
{
|
|
2171
2316
|
sessionName,
|
|
@@ -2177,20 +2322,20 @@ ${errorBlock}`;
|
|
|
2177
2322
|
}
|
|
2178
2323
|
|
|
2179
2324
|
// src/components/MessageList.tsx
|
|
2180
|
-
import
|
|
2181
|
-
import { Box as
|
|
2325
|
+
import React17 from "react";
|
|
2326
|
+
import { Box as Box16, Text as Text16 } from "ink";
|
|
2182
2327
|
function stripThinkingTags(content) {
|
|
2183
2328
|
return content.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
2184
2329
|
}
|
|
2185
|
-
var MessageList =
|
|
2330
|
+
var MessageList = React17.memo(
|
|
2186
2331
|
function MessageList2({ messages }) {
|
|
2187
2332
|
if (messages.length === 0) {
|
|
2188
|
-
return /* @__PURE__ */
|
|
2333
|
+
return /* @__PURE__ */ React17.createElement(Box16, { paddingY: 1 }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, "No messages yet. Type a message to start!"));
|
|
2189
2334
|
}
|
|
2190
|
-
return /* @__PURE__ */
|
|
2335
|
+
return /* @__PURE__ */ React17.createElement(Box16, { flexDirection: "column", gap: 1, paddingY: 1 }, messages.map((message, index) => /* @__PURE__ */ React17.createElement(Box16, { key: index, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React17.createElement(Box16, null, /* @__PURE__ */ React17.createElement(Text16, { bold: true, color: message.role === "user" ? "cyan" : "green" }, message.role === "user" ? "\u{1F464} You" : "\u{1F916} Assistant"), /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), /* @__PURE__ */ React17.createElement(Box16, { paddingLeft: 2 }, message.metadata?.permissionDenied ? /* @__PURE__ */ React17.createElement(Text16, { color: "yellow" }, "\u26A0\uFE0F ", stripThinkingTags(message.content)) : /* @__PURE__ */ React17.createElement(Text16, null, stripThinkingTags(message.content))), message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React17.createElement(Box16, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " tools used,", " ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
2191
2336
|
if (step.type === "thought") {
|
|
2192
|
-
return /* @__PURE__ */
|
|
2193
|
-
|
|
2337
|
+
return /* @__PURE__ */ React17.createElement(Box16, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React17.createElement(Text16, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React17.createElement(
|
|
2338
|
+
Text16,
|
|
2194
2339
|
{
|
|
2195
2340
|
dimColor: true
|
|
2196
2341
|
},
|
|
@@ -2202,10 +2347,10 @@ var MessageList = React16.memo(
|
|
|
2202
2347
|
const toolInput = step.metadata?.toolInput;
|
|
2203
2348
|
const observationStep = message.metadata.steps[idx + 1];
|
|
2204
2349
|
const result = observationStep?.type === "observation" ? observationStep.content : null;
|
|
2205
|
-
return /* @__PURE__ */
|
|
2350
|
+
return /* @__PURE__ */ React17.createElement(Box16, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React17.createElement(Text16, { color: "yellow" }, "\u{1F527} Action: ", toolName), toolInput && /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, ` Input: ${typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput).slice(0, 100)}`), result && /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, ` Result: ${typeof result === "string" ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200)}${(typeof result === "string" ? result.length : JSON.stringify(result).length) > 200 ? "..." : ""}`));
|
|
2206
2351
|
}
|
|
2207
2352
|
return null;
|
|
2208
|
-
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */
|
|
2353
|
+
}).filter(Boolean)), message.metadata?.tokenUsage && (!message.metadata.steps || message.metadata.steps.length === 0) && /* @__PURE__ */ React17.createElement(Box16, { paddingLeft: 2 }, /* @__PURE__ */ React17.createElement(Text16, { dimColor: true }, `${message.metadata.tokenUsage.total} tokens`)))));
|
|
2209
2354
|
},
|
|
2210
2355
|
(prevProps, nextProps) => {
|
|
2211
2356
|
if (prevProps.messages.length !== nextProps.messages.length) {
|
|
@@ -2216,8 +2361,8 @@ var MessageList = React16.memo(
|
|
|
2216
2361
|
);
|
|
2217
2362
|
|
|
2218
2363
|
// src/components/TrustLocationSelector.tsx
|
|
2219
|
-
import
|
|
2220
|
-
import { Box as
|
|
2364
|
+
import React18 from "react";
|
|
2365
|
+
import { Box as Box17, Text as Text17 } from "ink";
|
|
2221
2366
|
import SelectInput from "ink-select-input";
|
|
2222
2367
|
function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
2223
2368
|
const items = [];
|
|
@@ -2238,24 +2383,24 @@ function TrustLocationSelector({ inProject, onSelect, onCancel }) {
|
|
|
2238
2383
|
const handleSelect = (item) => {
|
|
2239
2384
|
onSelect(item.value);
|
|
2240
2385
|
};
|
|
2241
|
-
return /* @__PURE__ */
|
|
2386
|
+
return /* @__PURE__ */ React18.createElement(Box17, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React18.createElement(Box17, { marginBottom: 1 }, /* @__PURE__ */ React18.createElement(Text17, { bold: true }, "Where should this rule be saved?")), /* @__PURE__ */ React18.createElement(
|
|
2242
2387
|
SelectInput,
|
|
2243
2388
|
{
|
|
2244
2389
|
items,
|
|
2245
2390
|
onSelect: handleSelect,
|
|
2246
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
2391
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React18.createElement(Box17, null, /* @__PURE__ */ React18.createElement(Text17, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
2247
2392
|
}
|
|
2248
|
-
), /* @__PURE__ */
|
|
2393
|
+
), /* @__PURE__ */ React18.createElement(Box17, { marginTop: 1 }, /* @__PURE__ */ React18.createElement(Text17, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Ctrl+C to cancel")));
|
|
2249
2394
|
}
|
|
2250
2395
|
|
|
2251
2396
|
// src/components/RewindSelector.tsx
|
|
2252
|
-
import
|
|
2253
|
-
import { Box as
|
|
2397
|
+
import React19, { useState as useState8 } from "react";
|
|
2398
|
+
import { Box as Box18, Text as Text18, useInput as useInput8 } from "ink";
|
|
2254
2399
|
import SelectInput2 from "ink-select-input";
|
|
2255
2400
|
function RewindSelector({ messages, onSelect, onCancel }) {
|
|
2256
|
-
const [step, setStep] =
|
|
2257
|
-
const [selectedMessageIndex, setSelectedMessageIndex] =
|
|
2258
|
-
|
|
2401
|
+
const [step, setStep] = useState8("selection");
|
|
2402
|
+
const [selectedMessageIndex, setSelectedMessageIndex] = useState8(null);
|
|
2403
|
+
useInput8((input, key) => {
|
|
2259
2404
|
if (key.escape) {
|
|
2260
2405
|
if (step === "confirmation") {
|
|
2261
2406
|
setStep("selection");
|
|
@@ -2292,14 +2437,14 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
2292
2437
|
return sum2 + (msg.metadata?.tokenUsage?.total || 0);
|
|
2293
2438
|
}, 0);
|
|
2294
2439
|
if (step === "selection") {
|
|
2295
|
-
return /* @__PURE__ */
|
|
2440
|
+
return /* @__PURE__ */ React19.createElement(Box18, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React19.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React19.createElement(Text18, { bold: true }, "Select a point to rewind to:")), /* @__PURE__ */ React19.createElement(
|
|
2296
2441
|
SelectInput2,
|
|
2297
2442
|
{
|
|
2298
2443
|
items,
|
|
2299
2444
|
onSelect: handleSelectionSelect,
|
|
2300
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
2445
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
2301
2446
|
}
|
|
2302
|
-
), /* @__PURE__ */
|
|
2447
|
+
), /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
2303
2448
|
}
|
|
2304
2449
|
const confirmationItems = [
|
|
2305
2450
|
{ label: "Yes, rewind to this point", value: "confirm" },
|
|
@@ -2307,24 +2452,24 @@ function RewindSelector({ messages, onSelect, onCancel }) {
|
|
|
2307
2452
|
];
|
|
2308
2453
|
const selectedMessage = selectedMessageIndex !== null && selectedMessageIndex >= 0 && selectedMessageIndex < messages.length ? messages[selectedMessageIndex] : null;
|
|
2309
2454
|
const selectedPreview = selectedMessage ? selectedMessage.content.length > 50 ? selectedMessage.content.substring(0, 50) + "..." : selectedMessage.content : "";
|
|
2310
|
-
return /* @__PURE__ */
|
|
2455
|
+
return /* @__PURE__ */ React19.createElement(Box18, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React19.createElement(Box18, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React19.createElement(Text18, { bold: true }, "Confirm rewind operation:"), /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "Message: ", selectedPreview), /* @__PURE__ */ React19.createElement(Text18, { color: "yellow" }, "This will remove ", messagesToRemove.length, " message(s) (", tokensToRemove.toLocaleString(), " tokens)"), /* @__PURE__ */ React19.createElement(Text18, { color: "cyan" }, "The selected message will be placed in your input for editing.")), /* @__PURE__ */ React19.createElement(
|
|
2311
2456
|
SelectInput2,
|
|
2312
2457
|
{
|
|
2313
2458
|
items: confirmationItems,
|
|
2314
2459
|
onSelect: handleConfirmationSelect,
|
|
2315
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
2460
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React19.createElement(Box18, null, /* @__PURE__ */ React19.createElement(Text18, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u276F " : " ", label))
|
|
2316
2461
|
}
|
|
2317
|
-
), /* @__PURE__ */
|
|
2462
|
+
), /* @__PURE__ */ React19.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React19.createElement(Text18, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
|
|
2318
2463
|
}
|
|
2319
2464
|
|
|
2320
2465
|
// src/components/SessionSelector.tsx
|
|
2321
|
-
import
|
|
2322
|
-
import { Box as
|
|
2466
|
+
import React20, { useState as useState9 } from "react";
|
|
2467
|
+
import { Box as Box19, Text as Text19, useInput as useInput9 } from "ink";
|
|
2323
2468
|
import SelectInput3 from "ink-select-input";
|
|
2324
2469
|
function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
2325
|
-
const [step, setStep] =
|
|
2326
|
-
const [selectedSession, setSelectedSession] =
|
|
2327
|
-
|
|
2470
|
+
const [step, setStep] = useState9("selection");
|
|
2471
|
+
const [selectedSession, setSelectedSession] = useState9(null);
|
|
2472
|
+
useInput9((_input, key) => {
|
|
2328
2473
|
if (key.escape) {
|
|
2329
2474
|
if (step === "confirmation") {
|
|
2330
2475
|
setStep("selection");
|
|
@@ -2374,32 +2519,32 @@ function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
|
|
|
2374
2519
|
}
|
|
2375
2520
|
};
|
|
2376
2521
|
if (step === "selection") {
|
|
2377
|
-
return /* @__PURE__ */
|
|
2522
|
+
return /* @__PURE__ */ React20.createElement(Box19, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React20.createElement(Box19, { marginBottom: 1 }, /* @__PURE__ */ React20.createElement(Text19, { bold: true }, "Select a session to resume:")), /* @__PURE__ */ React20.createElement(
|
|
2378
2523
|
SelectInput3,
|
|
2379
2524
|
{
|
|
2380
2525
|
items,
|
|
2381
2526
|
onSelect: handleSelectionSelect,
|
|
2382
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
2527
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React20.createElement(Box19, null, /* @__PURE__ */ React20.createElement(Text19, { color: isSelected ? "cyan" : void 0 }, label))
|
|
2383
2528
|
}
|
|
2384
|
-
), /* @__PURE__ */
|
|
2529
|
+
), /* @__PURE__ */ React20.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text19, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to cancel")));
|
|
2385
2530
|
}
|
|
2386
2531
|
const confirmationItems = [
|
|
2387
2532
|
{ label: "Yes, resume this session", value: "confirm" },
|
|
2388
2533
|
{ label: "No, go back to selection", value: "cancel" }
|
|
2389
2534
|
];
|
|
2390
|
-
return /* @__PURE__ */
|
|
2535
|
+
return /* @__PURE__ */ React20.createElement(Box19, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React20.createElement(Box19, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React20.createElement(Text19, { bold: true }, 'Resume session: "', selectedSession?.name, '"'), /* @__PURE__ */ React20.createElement(Text19, { dimColor: true }, selectedSession?.messages.length, " messages | ", selectedSession?.model, " |", " ", selectedSession?.metadata?.totalTokens?.toLocaleString() ?? 0, " tokens"), hasUnsavedWork && /* @__PURE__ */ React20.createElement(Text19, { color: "yellow" }, "Warning: Your current session has unsaved messages. Use /save first if needed.")), /* @__PURE__ */ React20.createElement(
|
|
2391
2536
|
SelectInput3,
|
|
2392
2537
|
{
|
|
2393
2538
|
items: confirmationItems,
|
|
2394
2539
|
onSelect: handleConfirmationSelect,
|
|
2395
|
-
itemComponent: ({ isSelected, label }) => /* @__PURE__ */
|
|
2540
|
+
itemComponent: ({ isSelected, label }) => /* @__PURE__ */ React20.createElement(Box19, null, /* @__PURE__ */ React20.createElement(Text19, { color: isSelected ? "cyan" : void 0 }, label))
|
|
2396
2541
|
}
|
|
2397
|
-
), /* @__PURE__ */
|
|
2542
|
+
), /* @__PURE__ */ React20.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React20.createElement(Text19, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select, Esc to go back")));
|
|
2398
2543
|
}
|
|
2399
2544
|
|
|
2400
2545
|
// src/components/LoginFlow.tsx
|
|
2401
|
-
import
|
|
2402
|
-
import { Box as
|
|
2546
|
+
import React21, { useState as useState10, useEffect as useEffect6 } from "react";
|
|
2547
|
+
import { Box as Box20, Text as Text20 } from "ink";
|
|
2403
2548
|
import Spinner3 from "ink-spinner";
|
|
2404
2549
|
import jwt from "jsonwebtoken";
|
|
2405
2550
|
import open from "open";
|
|
@@ -2515,10 +2660,10 @@ var OAuthClient = class {
|
|
|
2515
2660
|
|
|
2516
2661
|
// src/components/LoginFlow.tsx
|
|
2517
2662
|
function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, onError }) {
|
|
2518
|
-
const [status, setStatus] =
|
|
2519
|
-
const [deviceFlow, setDeviceFlow] =
|
|
2520
|
-
const [statusMessage, setStatusMessage] =
|
|
2521
|
-
const [error, setError] =
|
|
2663
|
+
const [status, setStatus] = useState10("initiating");
|
|
2664
|
+
const [deviceFlow, setDeviceFlow] = useState10(null);
|
|
2665
|
+
const [statusMessage, setStatusMessage] = useState10("Initiating device authorization...");
|
|
2666
|
+
const [error, setError] = useState10(null);
|
|
2522
2667
|
useEffect6(() => {
|
|
2523
2668
|
const runLoginFlow = async () => {
|
|
2524
2669
|
const oauth = new OAuthClient(apiUrl);
|
|
@@ -2562,15 +2707,15 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
2562
2707
|
}
|
|
2563
2708
|
}, [deviceFlow, status]);
|
|
2564
2709
|
if (status === "initiating") {
|
|
2565
|
-
return /* @__PURE__ */
|
|
2710
|
+
return /* @__PURE__ */ React21.createElement(Box20, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Box20, null, /* @__PURE__ */ React21.createElement(Text20, { color: "cyan" }, /* @__PURE__ */ React21.createElement(Spinner3, { type: "dots" }), " Initiating device authorization...")));
|
|
2566
2711
|
}
|
|
2567
2712
|
if (status === "error") {
|
|
2568
|
-
return /* @__PURE__ */
|
|
2713
|
+
return /* @__PURE__ */ React21.createElement(Box20, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text20, { color: "red", bold: true }, "\u2716 Authentication Failed")), /* @__PURE__ */ React21.createElement(Box20, null, /* @__PURE__ */ React21.createElement(Text20, { color: "red" }, error)));
|
|
2569
2714
|
}
|
|
2570
2715
|
if (status === "success") {
|
|
2571
|
-
return /* @__PURE__ */
|
|
2716
|
+
return /* @__PURE__ */ React21.createElement(Box20, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text20, { color: "green", bold: true }, "\u2714 Successfully authenticated!")), /* @__PURE__ */ React21.createElement(Box20, null, /* @__PURE__ */ React21.createElement(Text20, { dimColor: true }, "You can now use B4M CLI with your account.")));
|
|
2572
2717
|
}
|
|
2573
|
-
return /* @__PURE__ */
|
|
2718
|
+
return /* @__PURE__ */ React21.createElement(Box20, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan" }, /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text20, { color: "cyan", bold: true }, "\u{1F510} Device Authorization")), /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text20, null, "Opening browser automatically... If it doesn't open, please visit:")), /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React21.createElement(Text20, { color: "blue", bold: true }, deviceFlow?.verification_uri)), /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text20, null, "And enter this code when prompted:")), /* @__PURE__ */ React21.createElement(Box20, { marginBottom: 1, paddingLeft: 2 }, /* @__PURE__ */ React21.createElement(Text20, { color: "yellow", bold: true }, deviceFlow?.user_code)), /* @__PURE__ */ React21.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text20, { color: "cyan" }, /* @__PURE__ */ React21.createElement(Spinner3, { type: "dots" }), " ", statusMessage)), /* @__PURE__ */ React21.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text20, { dimColor: true }, "Expires in ", deviceFlow ? Math.floor(deviceFlow.expires_in / 60) : 0, " minutes")));
|
|
2574
2719
|
}
|
|
2575
2720
|
|
|
2576
2721
|
// src/storage/SessionStore.ts
|
|
@@ -3757,6 +3902,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
3757
3902
|
dice_roll: "auto_approve",
|
|
3758
3903
|
prompt_enhancement: "auto_approve",
|
|
3759
3904
|
find_definition: "auto_approve",
|
|
3905
|
+
ask_user_question: "auto_approve",
|
|
3760
3906
|
weather_info: "prompt_default",
|
|
3761
3907
|
// ===== PROMPT ALWAYS (Dangerous tools) =====
|
|
3762
3908
|
// These tools can modify files, execute code, or have other dangerous side effects
|
|
@@ -14217,6 +14363,101 @@ The tool combines git status (working tree) with git log (commit history) to giv
|
|
|
14217
14363
|
})
|
|
14218
14364
|
};
|
|
14219
14365
|
|
|
14366
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/askUserQuestion/index.js
|
|
14367
|
+
var _showUserQuestion = null;
|
|
14368
|
+
function setShowUserQuestionFn(fn) {
|
|
14369
|
+
_showUserQuestion = fn;
|
|
14370
|
+
}
|
|
14371
|
+
var askUserQuestionTool = {
|
|
14372
|
+
name: "ask_user_question",
|
|
14373
|
+
implementation: () => ({
|
|
14374
|
+
toolFn: async (args) => {
|
|
14375
|
+
if (!_showUserQuestion) {
|
|
14376
|
+
return JSON.stringify({
|
|
14377
|
+
error: "ask_user_question is only available in the CLI environment."
|
|
14378
|
+
});
|
|
14379
|
+
}
|
|
14380
|
+
const params = args;
|
|
14381
|
+
if (!params.questions || !Array.isArray(params.questions) || params.questions.length === 0) {
|
|
14382
|
+
return JSON.stringify({ error: "At least one question is required." });
|
|
14383
|
+
}
|
|
14384
|
+
if (params.questions.length > 4) {
|
|
14385
|
+
return JSON.stringify({ error: "Maximum 4 questions allowed." });
|
|
14386
|
+
}
|
|
14387
|
+
const payload = {
|
|
14388
|
+
questions: params.questions.map((q) => ({
|
|
14389
|
+
question: q.question,
|
|
14390
|
+
options: (q.options || []).slice(0, 4).map((o) => ({
|
|
14391
|
+
label: o.label,
|
|
14392
|
+
description: o.description
|
|
14393
|
+
})),
|
|
14394
|
+
multiSelect: q.multiSelect === true
|
|
14395
|
+
}))
|
|
14396
|
+
};
|
|
14397
|
+
for (const q of payload.questions) {
|
|
14398
|
+
if (q.options.length < 2) {
|
|
14399
|
+
return JSON.stringify({
|
|
14400
|
+
error: `Question "${q.question}" must have at least 2 options.`
|
|
14401
|
+
});
|
|
14402
|
+
}
|
|
14403
|
+
}
|
|
14404
|
+
const response = await _showUserQuestion(payload);
|
|
14405
|
+
return JSON.stringify(response);
|
|
14406
|
+
},
|
|
14407
|
+
toolSchema: {
|
|
14408
|
+
name: "ask_user_question",
|
|
14409
|
+
description: 'Ask the user one or more structured questions with selectable options. Use this when you need clarification, user preferences, or decisions. Each question has 2-4 options. The user can also provide free-text via "Other". For multiSelect questions, the user can pick multiple options.',
|
|
14410
|
+
parameters: {
|
|
14411
|
+
type: "object",
|
|
14412
|
+
properties: {
|
|
14413
|
+
questions: {
|
|
14414
|
+
type: "array",
|
|
14415
|
+
description: "Array of questions to ask (1-4 questions)",
|
|
14416
|
+
minItems: 1,
|
|
14417
|
+
maxItems: 4,
|
|
14418
|
+
items: {
|
|
14419
|
+
type: "object",
|
|
14420
|
+
properties: {
|
|
14421
|
+
question: {
|
|
14422
|
+
type: "string",
|
|
14423
|
+
description: "The question to ask. Should be clear and end with a question mark."
|
|
14424
|
+
},
|
|
14425
|
+
options: {
|
|
14426
|
+
type: "array",
|
|
14427
|
+
description: 'Available choices (2-4 options). An "Other" free-text option is always appended automatically.',
|
|
14428
|
+
minItems: 2,
|
|
14429
|
+
maxItems: 4,
|
|
14430
|
+
items: {
|
|
14431
|
+
type: "object",
|
|
14432
|
+
properties: {
|
|
14433
|
+
label: {
|
|
14434
|
+
type: "string",
|
|
14435
|
+
description: "Short display text for this option (1-5 words)"
|
|
14436
|
+
},
|
|
14437
|
+
description: {
|
|
14438
|
+
type: "string",
|
|
14439
|
+
description: "Explanation of what this option means"
|
|
14440
|
+
}
|
|
14441
|
+
},
|
|
14442
|
+
required: ["label", "description"]
|
|
14443
|
+
}
|
|
14444
|
+
},
|
|
14445
|
+
multiSelect: {
|
|
14446
|
+
type: "boolean",
|
|
14447
|
+
description: "If true, the user can select multiple options. Default: false.",
|
|
14448
|
+
default: false
|
|
14449
|
+
}
|
|
14450
|
+
},
|
|
14451
|
+
required: ["question", "options"]
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
},
|
|
14455
|
+
required: ["questions"]
|
|
14456
|
+
}
|
|
14457
|
+
}
|
|
14458
|
+
})
|
|
14459
|
+
};
|
|
14460
|
+
|
|
14220
14461
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
14221
14462
|
var b4mTools = {
|
|
14222
14463
|
dice_roll: diceRollTool,
|
|
@@ -14268,7 +14509,9 @@ var cliOnlyTools = {
|
|
|
14268
14509
|
lattice_set_value: latticeSetValueTool,
|
|
14269
14510
|
lattice_create_rule: latticeCreateRuleTool,
|
|
14270
14511
|
lattice_query: latticeQueryTool,
|
|
14271
|
-
lattice_explain: latticeExplainTool
|
|
14512
|
+
lattice_explain: latticeExplainTool,
|
|
14513
|
+
// Interactive tools
|
|
14514
|
+
ask_user_question: askUserQuestionTool
|
|
14272
14515
|
};
|
|
14273
14516
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model, imageProcessorLambdaName, tools = b4mTools) => {
|
|
14274
14517
|
const context = {
|
|
@@ -15333,7 +15576,8 @@ var LOCAL_TOOLS = [
|
|
|
15333
15576
|
"math_evaluate",
|
|
15334
15577
|
"current_datetime",
|
|
15335
15578
|
"bash_execute",
|
|
15336
|
-
"recent_changes"
|
|
15579
|
+
"recent_changes",
|
|
15580
|
+
"ask_user_question"
|
|
15337
15581
|
];
|
|
15338
15582
|
function isServerTool(toolName) {
|
|
15339
15583
|
return SERVER_TOOLS.includes(toolName);
|
|
@@ -15612,7 +15856,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
15612
15856
|
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
15613
15857
|
return result2;
|
|
15614
15858
|
}
|
|
15615
|
-
const { useCliStore: useCliStore2 } = await import("./store-
|
|
15859
|
+
const { useCliStore: useCliStore2 } = await import("./store-X5LEOSGZ.js");
|
|
15616
15860
|
if (useCliStore2.getState().autoAcceptEdits) {
|
|
15617
15861
|
const result2 = await executeTool(toolName, args, apiClient, originalFn);
|
|
15618
15862
|
agentContext.observationQueue.push({ toolName, result: result2 });
|
|
@@ -15778,7 +16022,10 @@ function normalizeToolName(toolName) {
|
|
|
15778
16022
|
}
|
|
15779
16023
|
return TOOL_NAME_MAPPING[toolName] || toolName;
|
|
15780
16024
|
}
|
|
15781
|
-
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter) {
|
|
16025
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter, showUserQuestion) {
|
|
16026
|
+
if (showUserQuestion) {
|
|
16027
|
+
setShowUserQuestionFn(showUserQuestion);
|
|
16028
|
+
}
|
|
15782
16029
|
const logger2 = new CliLogger();
|
|
15783
16030
|
const storage = new NoOpStorage();
|
|
15784
16031
|
const user = {
|
|
@@ -18188,7 +18435,10 @@ var SubagentOrchestrator = class {
|
|
|
18188
18435
|
this.deps.showPermissionPrompt,
|
|
18189
18436
|
agentContext,
|
|
18190
18437
|
this.deps.configStore,
|
|
18191
|
-
this.deps.apiClient
|
|
18438
|
+
this.deps.apiClient,
|
|
18439
|
+
void 0,
|
|
18440
|
+
// toolFilter (applied below via filterToolsByPatterns)
|
|
18441
|
+
this.deps.showUserQuestion
|
|
18192
18442
|
);
|
|
18193
18443
|
const filteredTools = filterToolsByPatterns2(allTools, toolFilter.allowedTools, toolFilter.deniedTools);
|
|
18194
18444
|
if (this.deps.customCommandStore) {
|
|
@@ -19651,7 +19901,7 @@ var usageCache = null;
|
|
|
19651
19901
|
function CliApp() {
|
|
19652
19902
|
const { exit } = useApp();
|
|
19653
19903
|
const imageRenderer = new ImageRenderer();
|
|
19654
|
-
const [state, setState] =
|
|
19904
|
+
const [state, setState] = useState11({
|
|
19655
19905
|
session: null,
|
|
19656
19906
|
sessionStore: new SessionStore(),
|
|
19657
19907
|
configStore: new ConfigStore(),
|
|
@@ -19675,17 +19925,19 @@ function CliApp() {
|
|
|
19675
19925
|
backgroundManager: null,
|
|
19676
19926
|
wsManager: null
|
|
19677
19927
|
});
|
|
19678
|
-
const [isInitialized, setIsInitialized] =
|
|
19679
|
-
const [initError, setInitError] =
|
|
19680
|
-
const [commandHistory, setCommandHistory] =
|
|
19928
|
+
const [isInitialized, setIsInitialized] = useState11(false);
|
|
19929
|
+
const [initError, setInitError] = useState11(null);
|
|
19930
|
+
const [commandHistory, setCommandHistory] = useState11([]);
|
|
19681
19931
|
const imageStoreInitPromise = useRef3(null);
|
|
19682
19932
|
const setStoreSession = useCliStore((state2) => state2.setSession);
|
|
19683
19933
|
const enqueuePermissionPrompt = useCliStore((state2) => state2.enqueuePermissionPrompt);
|
|
19684
19934
|
const dequeuePermissionPrompt = useCliStore((state2) => state2.dequeuePermissionPrompt);
|
|
19935
|
+
const enqueueUserQuestionPrompt = useCliStore((state2) => state2.enqueueUserQuestionPrompt);
|
|
19936
|
+
const dequeueUserQuestionPrompt = useCliStore((state2) => state2.dequeueUserQuestionPrompt);
|
|
19685
19937
|
const setShowConfigEditor = useCliStore((state2) => state2.setShowConfigEditor);
|
|
19686
19938
|
const setShowMcpViewer = useCliStore((state2) => state2.setShowMcpViewer);
|
|
19687
19939
|
const setExitRequested = useCliStore((state2) => state2.setExitRequested);
|
|
19688
|
-
const performCleanup =
|
|
19940
|
+
const performCleanup = useCallback3(async () => {
|
|
19689
19941
|
const cleanupTasks = [];
|
|
19690
19942
|
if (state.session) {
|
|
19691
19943
|
cleanupTasks.push(
|
|
@@ -19724,7 +19976,7 @@ function CliApp() {
|
|
|
19724
19976
|
process.exit(0);
|
|
19725
19977
|
}, 100);
|
|
19726
19978
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
|
|
19727
|
-
|
|
19979
|
+
useInput10((input, key) => {
|
|
19728
19980
|
if (key.escape) {
|
|
19729
19981
|
const store = useCliStore.getState();
|
|
19730
19982
|
if (store.pastedContent) {
|
|
@@ -19761,7 +20013,7 @@ function CliApp() {
|
|
|
19761
20013
|
}
|
|
19762
20014
|
}
|
|
19763
20015
|
});
|
|
19764
|
-
const init =
|
|
20016
|
+
const init = useCallback3(async () => {
|
|
19765
20017
|
try {
|
|
19766
20018
|
const startupLog = [];
|
|
19767
20019
|
const config = await state.configStore.load();
|
|
@@ -19927,6 +20179,13 @@ function CliApp() {
|
|
|
19927
20179
|
enqueuePermissionPrompt(prompt);
|
|
19928
20180
|
});
|
|
19929
20181
|
};
|
|
20182
|
+
let userQuestionCounter = 0;
|
|
20183
|
+
const userQuestionFn = (payload) => {
|
|
20184
|
+
return new Promise((resolve3) => {
|
|
20185
|
+
const id = `uq-${++userQuestionCounter}`;
|
|
20186
|
+
enqueueUserQuestionPrompt({ id, payload, resolve: resolve3 });
|
|
20187
|
+
});
|
|
20188
|
+
};
|
|
19930
20189
|
const agentContext = {
|
|
19931
20190
|
currentAgent: null,
|
|
19932
20191
|
observationQueue: []
|
|
@@ -19939,7 +20198,10 @@ function CliApp() {
|
|
|
19939
20198
|
promptFn,
|
|
19940
20199
|
agentContext,
|
|
19941
20200
|
state.configStore,
|
|
19942
|
-
apiClient
|
|
20201
|
+
apiClient,
|
|
20202
|
+
void 0,
|
|
20203
|
+
// toolFilter
|
|
20204
|
+
userQuestionFn
|
|
19943
20205
|
);
|
|
19944
20206
|
startupLog.push(`\u{1F6E0}\uFE0F Loaded ${b4mTools2.length} B4M tool(s)`);
|
|
19945
20207
|
const mcpManager = new McpManager(config);
|
|
@@ -19970,7 +20232,8 @@ function CliApp() {
|
|
|
19970
20232
|
apiClient,
|
|
19971
20233
|
agentStore,
|
|
19972
20234
|
customCommandStore: state.customCommandStore,
|
|
19973
|
-
enableParallelToolExecution: config.preferences.enableParallelToolExecution === true
|
|
20235
|
+
enableParallelToolExecution: config.preferences.enableParallelToolExecution === true,
|
|
20236
|
+
showUserQuestion: userQuestionFn
|
|
19974
20237
|
});
|
|
19975
20238
|
const backgroundManager = new BackgroundAgentManager(orchestrator);
|
|
19976
20239
|
backgroundManager.setOnStatusChange((job) => {
|
|
@@ -20609,7 +20872,7 @@ function CliApp() {
|
|
|
20609
20872
|
useCliStore.getState().setIsThinking(false);
|
|
20610
20873
|
}
|
|
20611
20874
|
};
|
|
20612
|
-
const handleBashCommand =
|
|
20875
|
+
const handleBashCommand = useCallback3(
|
|
20613
20876
|
(command) => {
|
|
20614
20877
|
if (!state.session) return;
|
|
20615
20878
|
let output;
|
|
@@ -21615,12 +21878,12 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21615
21878
|
}
|
|
21616
21879
|
};
|
|
21617
21880
|
if (initError) {
|
|
21618
|
-
return /* @__PURE__ */
|
|
21881
|
+
return /* @__PURE__ */ React22.createElement(Box21, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text21, { color: "red", bold: true }, "\u274C Initialization Error"), /* @__PURE__ */ React22.createElement(Text21, null, initError), /* @__PURE__ */ React22.createElement(Text21, { dimColor: true }, "\n", "Tip: Run /config to set up your API keys"));
|
|
21619
21882
|
}
|
|
21620
21883
|
if (state.trustLocationSelector) {
|
|
21621
21884
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
21622
21885
|
const inProject = projectDir !== null;
|
|
21623
|
-
return /* @__PURE__ */
|
|
21886
|
+
return /* @__PURE__ */ React22.createElement(
|
|
21624
21887
|
TrustLocationSelector,
|
|
21625
21888
|
{
|
|
21626
21889
|
inProject,
|
|
@@ -21638,7 +21901,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21638
21901
|
);
|
|
21639
21902
|
}
|
|
21640
21903
|
if (state.rewindSelector && state.session) {
|
|
21641
|
-
return /* @__PURE__ */
|
|
21904
|
+
return /* @__PURE__ */ React22.createElement(
|
|
21642
21905
|
RewindSelector,
|
|
21643
21906
|
{
|
|
21644
21907
|
messages: state.session.messages,
|
|
@@ -21656,7 +21919,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21656
21919
|
);
|
|
21657
21920
|
}
|
|
21658
21921
|
if (state.sessionSelector) {
|
|
21659
|
-
return /* @__PURE__ */
|
|
21922
|
+
return /* @__PURE__ */ React22.createElement(
|
|
21660
21923
|
SessionSelector,
|
|
21661
21924
|
{
|
|
21662
21925
|
sessions: state.sessionSelector.sessions,
|
|
@@ -21676,7 +21939,7 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21676
21939
|
}
|
|
21677
21940
|
if (state.showLoginFlow) {
|
|
21678
21941
|
const loginApiUrl = getApiUrl(state.config?.apiConfig);
|
|
21679
|
-
return /* @__PURE__ */
|
|
21942
|
+
return /* @__PURE__ */ React22.createElement(
|
|
21680
21943
|
LoginFlow,
|
|
21681
21944
|
{
|
|
21682
21945
|
apiUrl: loginApiUrl,
|
|
@@ -21699,10 +21962,10 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21699
21962
|
);
|
|
21700
21963
|
}
|
|
21701
21964
|
if (!isInitialized) {
|
|
21702
|
-
return /* @__PURE__ */
|
|
21965
|
+
return /* @__PURE__ */ React22.createElement(Box21, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text21, null, "\u{1F680} Initializing..."));
|
|
21703
21966
|
}
|
|
21704
21967
|
const allCommands = mergeCommands(state.customCommandStore.getAllCommands());
|
|
21705
|
-
return /* @__PURE__ */
|
|
21968
|
+
return /* @__PURE__ */ React22.createElement(
|
|
21706
21969
|
App,
|
|
21707
21970
|
{
|
|
21708
21971
|
onMessage: handleMessage,
|
|
@@ -21726,6 +21989,13 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
21726
21989
|
currentPrompt.resolve({ action: response });
|
|
21727
21990
|
dequeuePermissionPrompt();
|
|
21728
21991
|
}
|
|
21992
|
+
},
|
|
21993
|
+
onUserQuestionResponse: (response) => {
|
|
21994
|
+
const currentPrompt = useCliStore.getState().userQuestionPrompt;
|
|
21995
|
+
if (currentPrompt) {
|
|
21996
|
+
currentPrompt.resolve(response);
|
|
21997
|
+
dequeueUserQuestionPrompt();
|
|
21998
|
+
}
|
|
21729
21999
|
}
|
|
21730
22000
|
}
|
|
21731
22001
|
);
|
|
@@ -21748,6 +22018,6 @@ if (isDevMode) {
|
|
|
21748
22018
|
logger.debug("\u{1F527} Running in development mode (using TypeScript source)\n");
|
|
21749
22019
|
}
|
|
21750
22020
|
warmFileCache();
|
|
21751
|
-
render(/* @__PURE__ */
|
|
22021
|
+
render(/* @__PURE__ */ React22.createElement(CliApp, null), {
|
|
21752
22022
|
exitOnCtrlC: false
|
|
21753
22023
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.31-feat-
|
|
3
|
+
"version": "0.2.31-feat-ask-user-question.19587+cad088dc1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -111,10 +111,10 @@
|
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@bike4mind/agents": "0.1.0",
|
|
114
|
-
"@bike4mind/common": "2.52.1-feat-
|
|
115
|
-
"@bike4mind/mcp": "1.31.1-feat-
|
|
116
|
-
"@bike4mind/services": "2.50.1-feat-
|
|
117
|
-
"@bike4mind/utils": "2.7.1-feat-
|
|
114
|
+
"@bike4mind/common": "2.52.1-feat-ask-user-question.19587+cad088dc1",
|
|
115
|
+
"@bike4mind/mcp": "1.31.1-feat-ask-user-question.19587+cad088dc1",
|
|
116
|
+
"@bike4mind/services": "2.50.1-feat-ask-user-question.19587+cad088dc1",
|
|
117
|
+
"@bike4mind/utils": "2.7.1-feat-ask-user-question.19587+cad088dc1",
|
|
118
118
|
"@types/better-sqlite3": "^7.6.13",
|
|
119
119
|
"@types/diff": "^5.0.9",
|
|
120
120
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -135,5 +135,5 @@
|
|
|
135
135
|
"optionalDependencies": {
|
|
136
136
|
"@vscode/ripgrep": "^1.17.0"
|
|
137
137
|
},
|
|
138
|
-
"gitHead": "
|
|
138
|
+
"gitHead": "cad088dc1ad77d3c716da4e6fc78489039d71678"
|
|
139
139
|
}
|