wave-code 0.8.0 → 0.8.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/dist/components/CommandSelector.d.ts.map +1 -1
- package/dist/components/CommandSelector.js +1 -38
- package/dist/components/ConfirmationSelector.d.ts.map +1 -1
- package/dist/components/ConfirmationSelector.js +11 -3
- package/dist/components/HelpView.d.ts +2 -0
- package/dist/components/HelpView.d.ts.map +1 -1
- package/dist/components/HelpView.js +49 -5
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +1 -1
- package/dist/constants/commands.d.ts +3 -0
- package/dist/constants/commands.d.ts.map +1 -0
- package/dist/constants/commands.js +38 -0
- package/dist/utils/highlightUtils.d.ts.map +1 -1
- package/dist/utils/highlightUtils.js +66 -42
- package/package.json +2 -2
- package/src/components/CommandSelector.tsx +1 -40
- package/src/components/ConfirmationSelector.tsx +13 -3
- package/src/components/HelpView.tsx +129 -16
- package/src/components/InputBox.tsx +3 -1
- package/src/constants/commands.ts +41 -0
- package/src/utils/highlightUtils.ts +66 -42
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandSelector.d.ts","sourceRoot":"","sources":["../../src/components/CommandSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"CommandSelector.d.ts","sourceRoot":"","sources":["../../src/components/CommandSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+I1D,CAAC"}
|
|
@@ -1,44 +1,7 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React, { useState } from "react";
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
|
-
|
|
5
|
-
{
|
|
6
|
-
id: "clear",
|
|
7
|
-
name: "clear",
|
|
8
|
-
description: "Clear the chat session and terminal",
|
|
9
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
id: "tasks",
|
|
13
|
-
name: "tasks",
|
|
14
|
-
description: "View and manage background tasks (shells and subagents)",
|
|
15
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
id: "mcp",
|
|
19
|
-
name: "mcp",
|
|
20
|
-
description: "View and manage MCP servers",
|
|
21
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: "rewind",
|
|
25
|
-
name: "rewind",
|
|
26
|
-
description: "Revert conversation and file changes to a previous checkpoint",
|
|
27
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
id: "help",
|
|
31
|
-
name: "help",
|
|
32
|
-
description: "Show help and key bindings",
|
|
33
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: "status",
|
|
37
|
-
name: "status",
|
|
38
|
-
description: "Show agent status and configuration",
|
|
39
|
-
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
40
|
-
},
|
|
41
|
-
];
|
|
4
|
+
import { AVAILABLE_COMMANDS } from "../constants/commands.js";
|
|
42
5
|
export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, commands = [], // Default to empty array
|
|
43
6
|
}) => {
|
|
44
7
|
const MAX_VISIBLE_ITEMS = 3;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AAgB/E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AASD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA6mBpE,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import { Box, Text, useInput, useStdout, measureElement } from "ink";
|
|
4
4
|
import { BASH_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "wave-agent-sdk";
|
|
5
5
|
const getHeaderColor = (header) => {
|
|
@@ -34,6 +34,14 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
|
|
|
34
34
|
otherCursorPosition: 0,
|
|
35
35
|
savedStates: {},
|
|
36
36
|
});
|
|
37
|
+
const pendingDecisionRef = useRef(null);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (pendingDecisionRef.current) {
|
|
40
|
+
const decision = pendingDecisionRef.current;
|
|
41
|
+
pendingDecisionRef.current = null;
|
|
42
|
+
onDecision(decision);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
37
45
|
const questions = toolInput?.questions || [];
|
|
38
46
|
const currentQuestion = questions[questionState.currentQuestionIndex];
|
|
39
47
|
const getAutoOptionText = () => {
|
|
@@ -147,10 +155,10 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
|
|
|
147
155
|
const allAnswered = questions.every((q) => finalAnswers[q.question]);
|
|
148
156
|
if (!allAnswered)
|
|
149
157
|
return prev;
|
|
150
|
-
|
|
158
|
+
pendingDecisionRef.current = {
|
|
151
159
|
behavior: "allow",
|
|
152
160
|
message: JSON.stringify(finalAnswers),
|
|
153
|
-
}
|
|
161
|
+
};
|
|
154
162
|
return {
|
|
155
163
|
...prev,
|
|
156
164
|
userAnswers: finalAnswers,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { SlashCommand } from "wave-agent-sdk";
|
|
2
3
|
export interface HelpViewProps {
|
|
3
4
|
onCancel: () => void;
|
|
5
|
+
commands?: SlashCommand[];
|
|
4
6
|
}
|
|
5
7
|
export declare const HelpView: React.FC<HelpViewProps>;
|
|
6
8
|
//# sourceMappingURL=HelpView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmK5C,CAAC"}
|
|
@@ -1,9 +1,40 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
import { Box, Text, useInput } from "ink";
|
|
3
|
-
|
|
4
|
+
import { AVAILABLE_COMMANDS } from "../constants/commands.js";
|
|
5
|
+
export const HelpView = ({ onCancel, commands = [], }) => {
|
|
6
|
+
const [activeTab, setActiveTab] = useState("general");
|
|
7
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
8
|
+
const MAX_VISIBLE_ITEMS = 10;
|
|
9
|
+
const tabs = [
|
|
10
|
+
"general",
|
|
11
|
+
"commands",
|
|
12
|
+
];
|
|
13
|
+
if (commands.length > 0) {
|
|
14
|
+
tabs.push("custom-commands");
|
|
15
|
+
}
|
|
4
16
|
useInput((_, key) => {
|
|
5
|
-
if (key.escape
|
|
17
|
+
if (key.escape) {
|
|
6
18
|
onCancel();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (key.tab) {
|
|
22
|
+
setActiveTab((prev) => {
|
|
23
|
+
const currentIndex = tabs.indexOf(prev);
|
|
24
|
+
const nextIndex = (currentIndex + 1) % tabs.length;
|
|
25
|
+
return tabs[nextIndex];
|
|
26
|
+
});
|
|
27
|
+
setSelectedIndex(0);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (activeTab === "commands" || activeTab === "custom-commands") {
|
|
31
|
+
const currentCommands = activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
32
|
+
if (key.upArrow) {
|
|
33
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
34
|
+
}
|
|
35
|
+
else if (key.downArrow) {
|
|
36
|
+
setSelectedIndex((prev) => Math.min(currentCommands.length - 1, prev + 1));
|
|
37
|
+
}
|
|
7
38
|
}
|
|
8
39
|
});
|
|
9
40
|
const helpItems = [
|
|
@@ -15,12 +46,25 @@ export const HelpView = ({ onCancel }) => {
|
|
|
15
46
|
{ key: "Ctrl+B", description: "Background current task" },
|
|
16
47
|
{ key: "Ctrl+V", description: "Paste image" },
|
|
17
48
|
{ key: "Shift+Tab", description: "Cycle permission mode" },
|
|
18
|
-
{ key: "/status", description: "Show agent status and configuration" },
|
|
19
|
-
{ key: "/clear", description: "Clear the chat session and terminal" },
|
|
20
49
|
{
|
|
21
50
|
key: "Esc",
|
|
22
51
|
description: "Interrupt AI or command / Cancel selector / Close help",
|
|
23
52
|
},
|
|
24
53
|
];
|
|
25
|
-
|
|
54
|
+
// Calculate visible window for commands
|
|
55
|
+
const currentCommands = activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
56
|
+
const startIndex = Math.max(0, Math.min(selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2), Math.max(0, currentCommands.length - MAX_VISIBLE_ITEMS)));
|
|
57
|
+
const visibleCommands = currentCommands.slice(startIndex, startIndex + MAX_VISIBLE_ITEMS);
|
|
58
|
+
const footerText = [
|
|
59
|
+
"Tab switch",
|
|
60
|
+
activeTab !== "general" && "↑↓ navigate",
|
|
61
|
+
"Esc close",
|
|
62
|
+
]
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
.join(" • ");
|
|
65
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderLeft: false, borderRight: false, paddingX: 1, width: "100%", children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsx(Text, { color: activeTab === "general" ? "cyan" : "gray", bold: true, underline: activeTab === "general", children: "General" }), _jsx(Text, { color: activeTab === "commands" ? "cyan" : "gray", bold: true, underline: activeTab === "commands", children: "Commands" }), commands.length > 0 && (_jsx(Text, { color: activeTab === "custom-commands" ? "cyan" : "gray", bold: true, underline: activeTab === "custom-commands", children: "Custom Commands" }))] }), activeTab === "general" ? (_jsx(Box, { flexDirection: "column", children: helpItems.map((item, index) => (_jsxs(Box, { children: [_jsx(Box, { width: 20, children: _jsx(Text, { color: "yellow", children: item.key }) }), _jsx(Text, { color: "white", children: item.description })] }, index))) })) : (_jsx(Box, { flexDirection: "column", children: visibleCommands.map((command, index) => {
|
|
66
|
+
const actualIndex = startIndex + index;
|
|
67
|
+
const isSelected = actualIndex === selectedIndex;
|
|
68
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: isSelected ? "black" : "white", backgroundColor: isSelected ? "cyan" : undefined, children: [isSelected ? "▶ " : " ", "/", command.id] }), isSelected && (_jsx(Box, { marginLeft: 4, children: _jsx(Text, { color: "gray", dimColor: true, children: command.description }) }))] }, command.id));
|
|
69
|
+
}) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: footerText }) })] }));
|
|
26
70
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAczC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAczC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAkO5C,CAAC"}
|
|
@@ -78,7 +78,7 @@ export const InputBox = ({ isLoading = false, isCommandRunning = false, sendMess
|
|
|
78
78
|
return (_jsx(RewindCommand, { messages: messages, onSelect: handleRewindSelectWithClose, onCancel: handleRewindCancel, getFullMessageThread: getFullMessageThread }));
|
|
79
79
|
}
|
|
80
80
|
if (showHelp) {
|
|
81
|
-
return _jsx(HelpView, { onCancel: () => setShowHelp(false) });
|
|
81
|
+
return (_jsx(HelpView, { onCancel: () => setShowHelp(false), commands: slashCommands }));
|
|
82
82
|
}
|
|
83
83
|
if (showStatusCommand) {
|
|
84
84
|
return _jsx(StatusCommand, { onCancel: () => setShowStatusCommand(false) });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/constants/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,kBAAkB,EAAE,YAAY,EAsC5C,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const AVAILABLE_COMMANDS = [
|
|
2
|
+
{
|
|
3
|
+
id: "clear",
|
|
4
|
+
name: "clear",
|
|
5
|
+
description: "Clear the chat session and terminal",
|
|
6
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: "tasks",
|
|
10
|
+
name: "tasks",
|
|
11
|
+
description: "View and manage background tasks (shells and subagents)",
|
|
12
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "mcp",
|
|
16
|
+
name: "mcp",
|
|
17
|
+
description: "View and manage MCP servers",
|
|
18
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "rewind",
|
|
22
|
+
name: "rewind",
|
|
23
|
+
description: "Revert conversation and file changes to a previous checkpoint",
|
|
24
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "help",
|
|
28
|
+
name: "help",
|
|
29
|
+
description: "Show help and key bindings",
|
|
30
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "status",
|
|
34
|
+
name: "status",
|
|
35
|
+
description: "Show agent status and configuration",
|
|
36
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
37
|
+
},
|
|
38
|
+
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"highlightUtils.d.ts","sourceRoot":"","sources":["../../src/utils/highlightUtils.ts"],"names":[],"mappings":"AA6DA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"highlightUtils.d.ts","sourceRoot":"","sources":["../../src/utils/highlightUtils.ts"],"names":[],"mappings":"AA6DA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAsCvE"}
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import hljs from
|
|
2
|
-
import { parse, HTMLElement, TextNode } from
|
|
3
|
-
import chalk from
|
|
1
|
+
import hljs from "highlight.js";
|
|
2
|
+
import { parse, HTMLElement, TextNode } from "node-html-parser";
|
|
3
|
+
import chalk from "chalk";
|
|
4
4
|
const theme = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
5
|
+
"hljs-keyword": chalk.blue,
|
|
6
|
+
"hljs-built_in": chalk.cyan,
|
|
7
|
+
"hljs-type": chalk.cyan,
|
|
8
|
+
"hljs-literal": chalk.magenta,
|
|
9
|
+
"hljs-number": chalk.magenta,
|
|
10
|
+
"hljs-operator": chalk.white,
|
|
11
|
+
"hljs-punctuation": chalk.white,
|
|
12
|
+
"hljs-property": chalk.yellow,
|
|
13
|
+
"hljs-attr": chalk.yellow,
|
|
14
|
+
"hljs-variable": chalk.white,
|
|
15
|
+
"hljs-template-variable": chalk.white,
|
|
16
|
+
"hljs-string": chalk.green,
|
|
17
|
+
"hljs-char": chalk.green,
|
|
18
|
+
"hljs-comment": chalk.gray,
|
|
19
|
+
"hljs-doctag": chalk.gray,
|
|
20
|
+
"hljs-function": chalk.yellow,
|
|
21
|
+
"hljs-title": chalk.yellow,
|
|
22
|
+
"hljs-params": chalk.white,
|
|
23
|
+
"hljs-tag": chalk.blue,
|
|
24
|
+
"hljs-name": chalk.blue,
|
|
25
|
+
"hljs-selector-tag": chalk.blue,
|
|
26
|
+
"hljs-selector-id": chalk.blue,
|
|
27
|
+
"hljs-selector-class": chalk.blue,
|
|
28
|
+
"hljs-selector-attr": chalk.blue,
|
|
29
|
+
"hljs-selector-pseudo": chalk.blue,
|
|
30
|
+
"hljs-subst": chalk.white,
|
|
31
|
+
"hljs-section": chalk.blue.bold,
|
|
32
|
+
"hljs-bullet": chalk.magenta,
|
|
33
|
+
"hljs-emphasis": chalk.italic,
|
|
34
|
+
"hljs-strong": chalk.bold,
|
|
35
|
+
"hljs-addition": chalk.green,
|
|
36
|
+
"hljs-deletion": chalk.red,
|
|
37
|
+
"hljs-link": chalk.blue.underline,
|
|
38
38
|
};
|
|
39
39
|
function nodeToAnsi(node) {
|
|
40
40
|
if (node instanceof TextNode) {
|
|
41
41
|
return node.text;
|
|
42
42
|
}
|
|
43
43
|
if (node instanceof HTMLElement) {
|
|
44
|
-
const content = node.childNodes.map(nodeToAnsi).join(
|
|
45
|
-
const classes = node.getAttribute(
|
|
44
|
+
const content = node.childNodes.map(nodeToAnsi).join("");
|
|
45
|
+
const classes = node.getAttribute("class")?.split(/\s+/) || [];
|
|
46
46
|
for (const className of classes) {
|
|
47
47
|
if (theme[className]) {
|
|
48
48
|
return theme[className](content);
|
|
@@ -50,18 +50,42 @@ function nodeToAnsi(node) {
|
|
|
50
50
|
}
|
|
51
51
|
return content;
|
|
52
52
|
}
|
|
53
|
-
return
|
|
53
|
+
return "";
|
|
54
54
|
}
|
|
55
55
|
export function highlightToAnsi(code, language) {
|
|
56
56
|
if (!code) {
|
|
57
|
-
return
|
|
57
|
+
return "";
|
|
58
58
|
}
|
|
59
59
|
try {
|
|
60
60
|
const highlighted = language
|
|
61
61
|
? hljs.highlight(code, { language }).value
|
|
62
|
-
: hljs.highlightAuto(code
|
|
62
|
+
: hljs.highlightAuto(code, [
|
|
63
|
+
"javascript",
|
|
64
|
+
"typescript",
|
|
65
|
+
"bash",
|
|
66
|
+
"json",
|
|
67
|
+
"markdown",
|
|
68
|
+
"python",
|
|
69
|
+
"yaml",
|
|
70
|
+
"html",
|
|
71
|
+
"css",
|
|
72
|
+
"sql",
|
|
73
|
+
"xml",
|
|
74
|
+
"rust",
|
|
75
|
+
"go",
|
|
76
|
+
"java",
|
|
77
|
+
"cpp",
|
|
78
|
+
"c",
|
|
79
|
+
"csharp",
|
|
80
|
+
"php",
|
|
81
|
+
"ruby",
|
|
82
|
+
"swift",
|
|
83
|
+
"kotlin",
|
|
84
|
+
"toml",
|
|
85
|
+
"ini",
|
|
86
|
+
]).value;
|
|
63
87
|
const root = parse(highlighted);
|
|
64
|
-
return root.childNodes.map(nodeToAnsi).join(
|
|
88
|
+
return root.childNodes.map(nodeToAnsi).join("");
|
|
65
89
|
}
|
|
66
90
|
catch {
|
|
67
91
|
return code;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-code",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "CLI-based code assistant powered by AI, built with React and Ink",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"react": "^19.2.4",
|
|
40
40
|
"react-dom": "19.2.4",
|
|
41
41
|
"yargs": "^17.7.2",
|
|
42
|
-
"wave-agent-sdk": "0.8.
|
|
42
|
+
"wave-agent-sdk": "0.8.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/react": "^19.1.8",
|
|
@@ -1,46 +1,7 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
3
|
import type { SlashCommand } from "wave-agent-sdk";
|
|
4
|
-
|
|
5
|
-
const AVAILABLE_COMMANDS: SlashCommand[] = [
|
|
6
|
-
{
|
|
7
|
-
id: "clear",
|
|
8
|
-
name: "clear",
|
|
9
|
-
description: "Clear the chat session and terminal",
|
|
10
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: "tasks",
|
|
14
|
-
name: "tasks",
|
|
15
|
-
description: "View and manage background tasks (shells and subagents)",
|
|
16
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
id: "mcp",
|
|
20
|
-
name: "mcp",
|
|
21
|
-
description: "View and manage MCP servers",
|
|
22
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: "rewind",
|
|
26
|
-
name: "rewind",
|
|
27
|
-
description:
|
|
28
|
-
"Revert conversation and file changes to a previous checkpoint",
|
|
29
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: "help",
|
|
33
|
-
name: "help",
|
|
34
|
-
description: "Show help and key bindings",
|
|
35
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: "status",
|
|
39
|
-
name: "status",
|
|
40
|
-
description: "Show agent status and configuration",
|
|
41
|
-
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
42
|
-
},
|
|
43
|
-
];
|
|
4
|
+
import { AVAILABLE_COMMANDS } from "../constants/commands.js";
|
|
44
5
|
|
|
45
6
|
export interface CommandSelectorProps {
|
|
46
7
|
searchQuery: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useLayoutEffect, useRef, useState } from "react";
|
|
1
|
+
import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
import { Box, Text, useInput, useStdout, measureElement } from "ink";
|
|
3
3
|
import type { PermissionDecision, AskUserQuestionInput } from "wave-agent-sdk";
|
|
4
4
|
import {
|
|
@@ -81,6 +81,16 @@ export const ConfirmationSelector: React.FC<ConfirmationSelectorProps> = ({
|
|
|
81
81
|
>,
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
const pendingDecisionRef = useRef<PermissionDecision | null>(null);
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (pendingDecisionRef.current) {
|
|
88
|
+
const decision = pendingDecisionRef.current;
|
|
89
|
+
pendingDecisionRef.current = null;
|
|
90
|
+
onDecision(decision);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
84
94
|
const questions =
|
|
85
95
|
(toolInput as unknown as AskUserQuestionInput)?.questions || [];
|
|
86
96
|
const currentQuestion = questions[questionState.currentQuestionIndex];
|
|
@@ -204,10 +214,10 @@ export const ConfirmationSelector: React.FC<ConfirmationSelectorProps> = ({
|
|
|
204
214
|
);
|
|
205
215
|
if (!allAnswered) return prev;
|
|
206
216
|
|
|
207
|
-
|
|
217
|
+
pendingDecisionRef.current = {
|
|
208
218
|
behavior: "allow",
|
|
209
219
|
message: JSON.stringify(finalAnswers),
|
|
210
|
-
}
|
|
220
|
+
};
|
|
211
221
|
return {
|
|
212
222
|
...prev,
|
|
213
223
|
userAnswers: finalAnswers,
|
|
@@ -1,14 +1,57 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import type { SlashCommand } from "wave-agent-sdk";
|
|
4
|
+
import { AVAILABLE_COMMANDS } from "../constants/commands.js";
|
|
3
5
|
|
|
4
6
|
export interface HelpViewProps {
|
|
5
7
|
onCancel: () => void;
|
|
8
|
+
commands?: SlashCommand[];
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
export const HelpView: React.FC<HelpViewProps> = ({
|
|
11
|
+
export const HelpView: React.FC<HelpViewProps> = ({
|
|
12
|
+
onCancel,
|
|
13
|
+
commands = [],
|
|
14
|
+
}) => {
|
|
15
|
+
const [activeTab, setActiveTab] = useState<
|
|
16
|
+
"general" | "commands" | "custom-commands"
|
|
17
|
+
>("general");
|
|
18
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
19
|
+
const MAX_VISIBLE_ITEMS = 10;
|
|
20
|
+
|
|
21
|
+
const tabs: ("general" | "commands" | "custom-commands")[] = [
|
|
22
|
+
"general",
|
|
23
|
+
"commands",
|
|
24
|
+
];
|
|
25
|
+
if (commands.length > 0) {
|
|
26
|
+
tabs.push("custom-commands");
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
useInput((_, key) => {
|
|
10
|
-
if (key.escape
|
|
30
|
+
if (key.escape) {
|
|
11
31
|
onCancel();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (key.tab) {
|
|
36
|
+
setActiveTab((prev) => {
|
|
37
|
+
const currentIndex = tabs.indexOf(prev);
|
|
38
|
+
const nextIndex = (currentIndex + 1) % tabs.length;
|
|
39
|
+
return tabs[nextIndex];
|
|
40
|
+
});
|
|
41
|
+
setSelectedIndex(0);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (activeTab === "commands" || activeTab === "custom-commands") {
|
|
46
|
+
const currentCommands =
|
|
47
|
+
activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
48
|
+
if (key.upArrow) {
|
|
49
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
50
|
+
} else if (key.downArrow) {
|
|
51
|
+
setSelectedIndex((prev) =>
|
|
52
|
+
Math.min(currentCommands.length - 1, prev + 1),
|
|
53
|
+
);
|
|
54
|
+
}
|
|
12
55
|
}
|
|
13
56
|
});
|
|
14
57
|
|
|
@@ -21,14 +64,35 @@ export const HelpView: React.FC<HelpViewProps> = ({ onCancel }) => {
|
|
|
21
64
|
{ key: "Ctrl+B", description: "Background current task" },
|
|
22
65
|
{ key: "Ctrl+V", description: "Paste image" },
|
|
23
66
|
{ key: "Shift+Tab", description: "Cycle permission mode" },
|
|
24
|
-
{ key: "/status", description: "Show agent status and configuration" },
|
|
25
|
-
{ key: "/clear", description: "Clear the chat session and terminal" },
|
|
26
67
|
{
|
|
27
68
|
key: "Esc",
|
|
28
69
|
description: "Interrupt AI or command / Cancel selector / Close help",
|
|
29
70
|
},
|
|
30
71
|
];
|
|
31
72
|
|
|
73
|
+
// Calculate visible window for commands
|
|
74
|
+
const currentCommands =
|
|
75
|
+
activeTab === "commands" ? AVAILABLE_COMMANDS : commands;
|
|
76
|
+
const startIndex = Math.max(
|
|
77
|
+
0,
|
|
78
|
+
Math.min(
|
|
79
|
+
selectedIndex - Math.floor(MAX_VISIBLE_ITEMS / 2),
|
|
80
|
+
Math.max(0, currentCommands.length - MAX_VISIBLE_ITEMS),
|
|
81
|
+
),
|
|
82
|
+
);
|
|
83
|
+
const visibleCommands = currentCommands.slice(
|
|
84
|
+
startIndex,
|
|
85
|
+
startIndex + MAX_VISIBLE_ITEMS,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const footerText = [
|
|
89
|
+
"Tab switch",
|
|
90
|
+
activeTab !== "general" && "↑↓ navigate",
|
|
91
|
+
"Esc close",
|
|
92
|
+
]
|
|
93
|
+
.filter(Boolean)
|
|
94
|
+
.join(" • ");
|
|
95
|
+
|
|
32
96
|
return (
|
|
33
97
|
<Box
|
|
34
98
|
flexDirection="column"
|
|
@@ -37,24 +101,73 @@ export const HelpView: React.FC<HelpViewProps> = ({ onCancel }) => {
|
|
|
37
101
|
borderLeft={false}
|
|
38
102
|
borderRight={false}
|
|
39
103
|
paddingX={1}
|
|
104
|
+
width="100%"
|
|
40
105
|
>
|
|
41
|
-
<Box marginBottom={1}>
|
|
42
|
-
<Text
|
|
43
|
-
|
|
106
|
+
<Box marginBottom={1} gap={2}>
|
|
107
|
+
<Text
|
|
108
|
+
color={activeTab === "general" ? "cyan" : "gray"}
|
|
109
|
+
bold
|
|
110
|
+
underline={activeTab === "general"}
|
|
111
|
+
>
|
|
112
|
+
General
|
|
113
|
+
</Text>
|
|
114
|
+
<Text
|
|
115
|
+
color={activeTab === "commands" ? "cyan" : "gray"}
|
|
116
|
+
bold
|
|
117
|
+
underline={activeTab === "commands"}
|
|
118
|
+
>
|
|
119
|
+
Commands
|
|
44
120
|
</Text>
|
|
121
|
+
{commands.length > 0 && (
|
|
122
|
+
<Text
|
|
123
|
+
color={activeTab === "custom-commands" ? "cyan" : "gray"}
|
|
124
|
+
bold
|
|
125
|
+
underline={activeTab === "custom-commands"}
|
|
126
|
+
>
|
|
127
|
+
Custom Commands
|
|
128
|
+
</Text>
|
|
129
|
+
)}
|
|
45
130
|
</Box>
|
|
46
131
|
|
|
47
|
-
{
|
|
48
|
-
<Box
|
|
49
|
-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
132
|
+
{activeTab === "general" ? (
|
|
133
|
+
<Box flexDirection="column">
|
|
134
|
+
{helpItems.map((item, index) => (
|
|
135
|
+
<Box key={index}>
|
|
136
|
+
<Box width={20}>
|
|
137
|
+
<Text color="yellow">{item.key}</Text>
|
|
138
|
+
</Box>
|
|
139
|
+
<Text color="white">{item.description}</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
))}
|
|
142
|
+
</Box>
|
|
143
|
+
) : (
|
|
144
|
+
<Box flexDirection="column">
|
|
145
|
+
{visibleCommands.map((command, index) => {
|
|
146
|
+
const actualIndex = startIndex + index;
|
|
147
|
+
const isSelected = actualIndex === selectedIndex;
|
|
148
|
+
return (
|
|
149
|
+
<Box key={command.id} flexDirection="column">
|
|
150
|
+
<Text
|
|
151
|
+
color={isSelected ? "black" : "white"}
|
|
152
|
+
backgroundColor={isSelected ? "cyan" : undefined}
|
|
153
|
+
>
|
|
154
|
+
{isSelected ? "▶ " : " "}/{command.id}
|
|
155
|
+
</Text>
|
|
156
|
+
{isSelected && (
|
|
157
|
+
<Box marginLeft={4}>
|
|
158
|
+
<Text color="gray" dimColor>
|
|
159
|
+
{command.description}
|
|
160
|
+
</Text>
|
|
161
|
+
</Box>
|
|
162
|
+
)}
|
|
163
|
+
</Box>
|
|
164
|
+
);
|
|
165
|
+
})}
|
|
53
166
|
</Box>
|
|
54
|
-
)
|
|
167
|
+
)}
|
|
55
168
|
|
|
56
169
|
<Box marginTop={1}>
|
|
57
|
-
<Text dimColor>
|
|
170
|
+
<Text dimColor>{footerText}</Text>
|
|
58
171
|
</Box>
|
|
59
172
|
</Box>
|
|
60
173
|
);
|
|
@@ -174,7 +174,9 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
if (showHelp) {
|
|
177
|
-
return
|
|
177
|
+
return (
|
|
178
|
+
<HelpView onCancel={() => setShowHelp(false)} commands={slashCommands} />
|
|
179
|
+
);
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
if (showStatusCommand) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SlashCommand } from "wave-agent-sdk";
|
|
2
|
+
|
|
3
|
+
export const AVAILABLE_COMMANDS: SlashCommand[] = [
|
|
4
|
+
{
|
|
5
|
+
id: "clear",
|
|
6
|
+
name: "clear",
|
|
7
|
+
description: "Clear the chat session and terminal",
|
|
8
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "tasks",
|
|
12
|
+
name: "tasks",
|
|
13
|
+
description: "View and manage background tasks (shells and subagents)",
|
|
14
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "mcp",
|
|
18
|
+
name: "mcp",
|
|
19
|
+
description: "View and manage MCP servers",
|
|
20
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "rewind",
|
|
24
|
+
name: "rewind",
|
|
25
|
+
description:
|
|
26
|
+
"Revert conversation and file changes to a previous checkpoint",
|
|
27
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "help",
|
|
31
|
+
name: "help",
|
|
32
|
+
description: "Show help and key bindings",
|
|
33
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "status",
|
|
37
|
+
name: "status",
|
|
38
|
+
description: "Show agent status and configuration",
|
|
39
|
+
handler: () => {}, // Handler here won't be used, actual processing is in the hook
|
|
40
|
+
},
|
|
41
|
+
];
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import hljs from
|
|
2
|
-
import { parse, Node, HTMLElement, TextNode } from
|
|
3
|
-
import chalk from
|
|
1
|
+
import hljs from "highlight.js";
|
|
2
|
+
import { parse, Node, HTMLElement, TextNode } from "node-html-parser";
|
|
3
|
+
import chalk from "chalk";
|
|
4
4
|
|
|
5
5
|
const theme: Record<string, (text: string) => string> = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
6
|
+
"hljs-keyword": chalk.blue,
|
|
7
|
+
"hljs-built_in": chalk.cyan,
|
|
8
|
+
"hljs-type": chalk.cyan,
|
|
9
|
+
"hljs-literal": chalk.magenta,
|
|
10
|
+
"hljs-number": chalk.magenta,
|
|
11
|
+
"hljs-operator": chalk.white,
|
|
12
|
+
"hljs-punctuation": chalk.white,
|
|
13
|
+
"hljs-property": chalk.yellow,
|
|
14
|
+
"hljs-attr": chalk.yellow,
|
|
15
|
+
"hljs-variable": chalk.white,
|
|
16
|
+
"hljs-template-variable": chalk.white,
|
|
17
|
+
"hljs-string": chalk.green,
|
|
18
|
+
"hljs-char": chalk.green,
|
|
19
|
+
"hljs-comment": chalk.gray,
|
|
20
|
+
"hljs-doctag": chalk.gray,
|
|
21
|
+
"hljs-function": chalk.yellow,
|
|
22
|
+
"hljs-title": chalk.yellow,
|
|
23
|
+
"hljs-params": chalk.white,
|
|
24
|
+
"hljs-tag": chalk.blue,
|
|
25
|
+
"hljs-name": chalk.blue,
|
|
26
|
+
"hljs-selector-tag": chalk.blue,
|
|
27
|
+
"hljs-selector-id": chalk.blue,
|
|
28
|
+
"hljs-selector-class": chalk.blue,
|
|
29
|
+
"hljs-selector-attr": chalk.blue,
|
|
30
|
+
"hljs-selector-pseudo": chalk.blue,
|
|
31
|
+
"hljs-subst": chalk.white,
|
|
32
|
+
"hljs-section": chalk.blue.bold,
|
|
33
|
+
"hljs-bullet": chalk.magenta,
|
|
34
|
+
"hljs-emphasis": chalk.italic,
|
|
35
|
+
"hljs-strong": chalk.bold,
|
|
36
|
+
"hljs-addition": chalk.green,
|
|
37
|
+
"hljs-deletion": chalk.red,
|
|
38
|
+
"hljs-link": chalk.blue.underline,
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
function nodeToAnsi(node: Node): string {
|
|
@@ -44,8 +44,8 @@ function nodeToAnsi(node: Node): string {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (node instanceof HTMLElement) {
|
|
47
|
-
const content = node.childNodes.map(nodeToAnsi).join(
|
|
48
|
-
const classes = node.getAttribute(
|
|
47
|
+
const content = node.childNodes.map(nodeToAnsi).join("");
|
|
48
|
+
const classes = node.getAttribute("class")?.split(/\s+/) || [];
|
|
49
49
|
|
|
50
50
|
for (const className of classes) {
|
|
51
51
|
if (theme[className]) {
|
|
@@ -56,20 +56,44 @@ function nodeToAnsi(node: Node): string {
|
|
|
56
56
|
return content;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
return
|
|
59
|
+
return "";
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export function highlightToAnsi(code: string, language?: string): string {
|
|
63
63
|
if (!code) {
|
|
64
|
-
return
|
|
64
|
+
return "";
|
|
65
65
|
}
|
|
66
66
|
try {
|
|
67
67
|
const highlighted = language
|
|
68
68
|
? hljs.highlight(code, { language }).value
|
|
69
|
-
: hljs.highlightAuto(code
|
|
69
|
+
: hljs.highlightAuto(code, [
|
|
70
|
+
"javascript",
|
|
71
|
+
"typescript",
|
|
72
|
+
"bash",
|
|
73
|
+
"json",
|
|
74
|
+
"markdown",
|
|
75
|
+
"python",
|
|
76
|
+
"yaml",
|
|
77
|
+
"html",
|
|
78
|
+
"css",
|
|
79
|
+
"sql",
|
|
80
|
+
"xml",
|
|
81
|
+
"rust",
|
|
82
|
+
"go",
|
|
83
|
+
"java",
|
|
84
|
+
"cpp",
|
|
85
|
+
"c",
|
|
86
|
+
"csharp",
|
|
87
|
+
"php",
|
|
88
|
+
"ruby",
|
|
89
|
+
"swift",
|
|
90
|
+
"kotlin",
|
|
91
|
+
"toml",
|
|
92
|
+
"ini",
|
|
93
|
+
]).value;
|
|
70
94
|
|
|
71
95
|
const root = parse(highlighted);
|
|
72
|
-
return root.childNodes.map(nodeToAnsi).join(
|
|
96
|
+
return root.childNodes.map(nodeToAnsi).join("");
|
|
73
97
|
} catch {
|
|
74
98
|
return code;
|
|
75
99
|
}
|