@code4bug/jarvis-agent 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agents/jarvis.md +1 -1
- package/dist/components/AnimatedStatusText.d.ts +10 -0
- package/dist/components/AnimatedStatusText.js +17 -0
- package/dist/components/ComposerPane.d.ts +25 -0
- package/dist/components/ComposerPane.js +10 -0
- package/dist/components/FooterPane.d.ts +9 -0
- package/dist/components/FooterPane.js +22 -0
- package/dist/components/InputTextView.d.ts +11 -0
- package/dist/components/InputTextView.js +44 -0
- package/dist/components/MessageList.d.ts +9 -0
- package/dist/components/MessageList.js +8 -0
- package/dist/components/MessageViewport.d.ts +21 -0
- package/dist/components/MessageViewport.js +11 -0
- package/dist/components/MultilineInput.js +62 -344
- package/dist/components/StreamingDraft.d.ts +11 -0
- package/dist/components/StreamingDraft.js +14 -0
- package/dist/components/inputEditing.d.ts +20 -0
- package/dist/components/inputEditing.js +48 -0
- package/dist/hooks/useMultilineInputStream.d.ts +17 -0
- package/dist/hooks/useMultilineInputStream.js +141 -0
- package/dist/hooks/useTerminalCursorSync.d.ts +8 -0
- package/dist/hooks/useTerminalCursorSync.js +44 -0
- package/dist/hooks/useTerminalSize.d.ts +7 -0
- package/dist/hooks/useTerminalSize.js +21 -0
- package/dist/screens/repl.js +39 -28
- package/dist/services/api/llm.js +3 -1
- package/dist/skills/index.js +10 -3
- package/dist/terminal/cursor.d.ts +6 -0
- package/dist/terminal/cursor.js +21 -0
- package/dist/tools/writeFile.js +63 -2
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/agents/jarvis.md
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface AnimatedStatusTextProps {
|
|
3
|
+
label: string;
|
|
4
|
+
color?: string;
|
|
5
|
+
dotColor?: string;
|
|
6
|
+
intervalMs?: number;
|
|
7
|
+
}
|
|
8
|
+
declare function AnimatedStatusText({ label, color, dotColor, intervalMs, }: AnimatedStatusTextProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
declare const _default: React.MemoExoticComponent<typeof AnimatedStatusText>;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { Text } from 'ink';
|
|
4
|
+
const FRAMES = [' ', '. ', '.. ', '...'];
|
|
5
|
+
function AnimatedStatusText({ label, color = 'gray', dotColor = 'yellow', intervalMs = 600, }) {
|
|
6
|
+
const [frameIndex, setFrameIndex] = useState(0);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const timer = setInterval(() => {
|
|
9
|
+
setFrameIndex((prev) => (prev + 1) % FRAMES.length);
|
|
10
|
+
}, intervalMs);
|
|
11
|
+
return () => {
|
|
12
|
+
clearInterval(timer);
|
|
13
|
+
};
|
|
14
|
+
}, [intervalMs]);
|
|
15
|
+
return (_jsxs(Text, { color: color, children: [_jsx(Text, { color: dotColor, children: "\u25CF" }), ' ', label, FRAMES[frameIndex]] }));
|
|
16
|
+
}
|
|
17
|
+
export default React.memo(AnimatedStatusText);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SlashCommand } from '../commands/index.js';
|
|
3
|
+
interface ComposerPaneProps {
|
|
4
|
+
width: number;
|
|
5
|
+
countdown: number | null;
|
|
6
|
+
isProcessing: boolean;
|
|
7
|
+
input: string;
|
|
8
|
+
placeholder: string;
|
|
9
|
+
windowFocused: boolean;
|
|
10
|
+
slashMenuVisible: boolean;
|
|
11
|
+
slashMenuItems: SlashCommand[];
|
|
12
|
+
slashMenuIndex: number;
|
|
13
|
+
onInputChange: (value: string) => void;
|
|
14
|
+
onSubmit: (value: string) => Promise<void>;
|
|
15
|
+
onUpArrow: () => void;
|
|
16
|
+
onDownArrow: () => void;
|
|
17
|
+
onSlashMenuUp: () => void;
|
|
18
|
+
onSlashMenuDown: () => void;
|
|
19
|
+
onSlashMenuSelect: () => void;
|
|
20
|
+
onSlashMenuClose: () => void;
|
|
21
|
+
onTabFillPlaceholder: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare function ComposerPane({ width, countdown, isProcessing, input, placeholder, windowFocused, slashMenuVisible, slashMenuItems, slashMenuIndex, onInputChange, onSubmit, onUpArrow, onDownArrow, onSlashMenuUp, onSlashMenuDown, onSlashMenuSelect, onSlashMenuClose, onTabFillPlaceholder, }: ComposerPaneProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
declare const _default: React.MemoExoticComponent<typeof ComposerPane>;
|
|
25
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import Spinner from 'ink-spinner';
|
|
5
|
+
import MultilineInput from './MultilineInput.js';
|
|
6
|
+
import SlashCommandMenu from './SlashCommandMenu.js';
|
|
7
|
+
function ComposerPane({ width, countdown, isProcessing, input, placeholder, windowFocused, slashMenuVisible, slashMenuItems, slashMenuIndex, onInputChange, onSubmit, onUpArrow, onDownArrow, onSlashMenuUp, onSlashMenuDown, onSlashMenuSelect, onSlashMenuClose, onTabFillPlaceholder, }) {
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "gray", children: '─'.repeat(Math.max(width - 2, 1)) }), slashMenuVisible && !isProcessing && (_jsx(SlashCommandMenu, { commands: slashMenuItems, selectedIndex: slashMenuIndex })), _jsx(Box, { children: countdown !== null ? (_jsxs(Box, { children: [_jsx(Text, { color: "gray", dimColor: true, children: "\u276F " }), _jsx(Text, { color: "yellow", children: "Press " }), _jsx(Text, { color: "yellow", bold: true, children: "Ctrl+C" }), _jsx(Text, { color: "yellow", children: " again to exit " }), _jsxs(Text, { color: "gray", dimColor: true, children: ["(", countdown, "s)"] })] })) : isProcessing ? (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", bold: true, children: "\u276F " }), _jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "gray", italic: true, children: " processing..." })] })) : (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", bold: true, children: "\u276F " }), _jsx(MultilineInput, { value: input, onChange: onInputChange, onSubmit: onSubmit, onUpArrow: onUpArrow, onDownArrow: onDownArrow, placeholder: placeholder, isActive: !isProcessing, showCursor: windowFocused && !isProcessing, slashMenuActive: slashMenuVisible, onSlashMenuUp: onSlashMenuUp, onSlashMenuDown: onSlashMenuDown, onSlashMenuSelect: onSlashMenuSelect, onSlashMenuClose: onSlashMenuClose, onTabFillPlaceholder: onTabFillPlaceholder })] })) })] }));
|
|
9
|
+
}
|
|
10
|
+
export default React.memo(ComposerPane);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface FooterPaneProps {
|
|
3
|
+
width: number;
|
|
4
|
+
tokenCountRef: React.MutableRefObject<number>;
|
|
5
|
+
activeAgents: number;
|
|
6
|
+
}
|
|
7
|
+
declare function FooterPane({ width, tokenCountRef, activeAgents }: FooterPaneProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare const _default: React.MemoExoticComponent<typeof FooterPane>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import StatusBar from './StatusBar.js';
|
|
5
|
+
const TOKEN_REFRESH_INTERVAL = 100;
|
|
6
|
+
function FooterPane({ width, tokenCountRef, activeAgents }) {
|
|
7
|
+
const [displayTokens, setDisplayTokens] = useState(() => tokenCountRef.current);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setDisplayTokens(tokenCountRef.current);
|
|
10
|
+
const timer = setInterval(() => {
|
|
11
|
+
setDisplayTokens((prev) => {
|
|
12
|
+
const next = tokenCountRef.current;
|
|
13
|
+
return prev === next ? prev : next;
|
|
14
|
+
});
|
|
15
|
+
}, TOKEN_REFRESH_INTERVAL);
|
|
16
|
+
return () => {
|
|
17
|
+
clearInterval(timer);
|
|
18
|
+
};
|
|
19
|
+
}, [tokenCountRef]);
|
|
20
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "gray", children: '─'.repeat(Math.max(width - 2, 1)) }), _jsx(StatusBar, { width: width - 2, totalTokens: displayTokens, activeAgents: activeAgents })] }));
|
|
21
|
+
}
|
|
22
|
+
export default React.memo(FooterPane);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface InputTextViewProps {
|
|
3
|
+
value: string;
|
|
4
|
+
cursor: number;
|
|
5
|
+
placeholder: string;
|
|
6
|
+
showCursor: boolean;
|
|
7
|
+
onResetPastedChunks?: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare function InputTextView({ value, cursor, placeholder, showCursor, onResetPastedChunks, }: InputTextViewProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare const _default: React.MemoExoticComponent<typeof InputTextView>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { getCursorRowCol, PASTE_PLACEHOLDER_RE } from './inputEditing.js';
|
|
5
|
+
function renderWithPlaceholders(text, keyPrefix) {
|
|
6
|
+
const parts = [];
|
|
7
|
+
let lastIndex = 0;
|
|
8
|
+
const re = new RegExp(PASTE_PLACEHOLDER_RE.source, 'g');
|
|
9
|
+
let m;
|
|
10
|
+
while ((m = re.exec(text)) !== null) {
|
|
11
|
+
if (m.index > lastIndex) {
|
|
12
|
+
parts.push(_jsx(Text, { children: text.slice(lastIndex, m.index) }, `${keyPrefix}-t-${lastIndex}`));
|
|
13
|
+
}
|
|
14
|
+
parts.push(_jsx(Text, { color: "cyan", dimColor: true, children: m[0] }, `${keyPrefix}-p-${m.index}`));
|
|
15
|
+
lastIndex = m.index + m[0].length;
|
|
16
|
+
}
|
|
17
|
+
if (lastIndex < text.length) {
|
|
18
|
+
parts.push(_jsx(Text, { children: text.slice(lastIndex) }, `${keyPrefix}-t-${lastIndex}`));
|
|
19
|
+
}
|
|
20
|
+
return parts;
|
|
21
|
+
}
|
|
22
|
+
function InputTextView({ value, cursor, placeholder, showCursor, onResetPastedChunks, }) {
|
|
23
|
+
const isEmpty = value.length === 0;
|
|
24
|
+
if (isEmpty) {
|
|
25
|
+
onResetPastedChunks?.();
|
|
26
|
+
if (showCursor && placeholder.length > 0) {
|
|
27
|
+
return (_jsxs(Box, { children: [_jsx(Text, { inverse: true, color: "white", children: placeholder[0] }), _jsx(Text, { color: "gray", children: placeholder.slice(1) }), _jsx(Text, { color: "gray", dimColor: true, children: " [Tab]" })] }));
|
|
28
|
+
}
|
|
29
|
+
return (_jsxs(Box, { children: [showCursor && _jsx(Text, { inverse: true, children: " " }), _jsx(Text, { color: "gray", children: placeholder })] }));
|
|
30
|
+
}
|
|
31
|
+
const lines = value.split('\n');
|
|
32
|
+
const { row: cursorRow, col: cursorCol } = getCursorRowCol(value, cursor);
|
|
33
|
+
return (_jsx(Box, { flexDirection: "column", children: lines.map((line, i) => {
|
|
34
|
+
if (!showCursor || i !== cursorRow) {
|
|
35
|
+
const parts = renderWithPlaceholders(line, `l${i}`);
|
|
36
|
+
return _jsx(Box, { children: parts.length > 0 ? parts : _jsx(Text, { children: " " }) }, i);
|
|
37
|
+
}
|
|
38
|
+
const before = line.slice(0, cursorCol);
|
|
39
|
+
const cursorChar = line[cursorCol] ?? ' ';
|
|
40
|
+
const after = line.slice(cursorCol + 1);
|
|
41
|
+
return (_jsxs(Box, { children: [renderWithPlaceholders(before, `b${i}`), _jsx(Text, { inverse: true, children: cursorChar }), renderWithPlaceholders(after, `a${i}`)] }, i));
|
|
42
|
+
}) }));
|
|
43
|
+
}
|
|
44
|
+
export default React.memo(InputTextView);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Message } from '../types/index.js';
|
|
3
|
+
interface MessageListProps {
|
|
4
|
+
messages: Message[];
|
|
5
|
+
showDetails: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare function MessageList({ messages, showDetails }: MessageListProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare const _default: React.MemoExoticComponent<typeof MessageList>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box } from 'ink';
|
|
4
|
+
import MessageItem from './MessageItem.js';
|
|
5
|
+
function MessageList({ messages, showDetails }) {
|
|
6
|
+
return (_jsx(Box, { flexDirection: "column", children: messages.map((msg) => (_jsx(MessageItem, { msg: msg, showDetails: showDetails }, msg.id))) }));
|
|
7
|
+
}
|
|
8
|
+
export default React.memo(MessageList);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ConfirmChoice } from './DangerConfirm.js';
|
|
3
|
+
import { LoopState, Message } from '../types/index.js';
|
|
4
|
+
import { DangerConfirmResult } from '../core/query.js';
|
|
5
|
+
interface DangerConfirmState {
|
|
6
|
+
command: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
ruleName: string;
|
|
9
|
+
resolve: (choice: DangerConfirmResult) => void;
|
|
10
|
+
}
|
|
11
|
+
interface MessageViewportProps {
|
|
12
|
+
messages: Message[];
|
|
13
|
+
streamText: string;
|
|
14
|
+
showDetails: boolean;
|
|
15
|
+
dangerConfirm: DangerConfirmState | null;
|
|
16
|
+
loopState: LoopState | null;
|
|
17
|
+
onResolveDangerConfirm: (choice: ConfirmChoice) => void;
|
|
18
|
+
}
|
|
19
|
+
declare function MessageViewport({ messages, streamText, showDetails, dangerConfirm, loopState, onResolveDangerConfirm, }: MessageViewportProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
declare const _default: React.MemoExoticComponent<typeof MessageViewport>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import Spinner from 'ink-spinner';
|
|
5
|
+
import DangerConfirm from './DangerConfirm.js';
|
|
6
|
+
import MessageList from './MessageList.js';
|
|
7
|
+
import StreamingDraft from './StreamingDraft.js';
|
|
8
|
+
function MessageViewport({ messages, streamText, showDetails, dangerConfirm, loopState, onResolveDangerConfirm, }) {
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(MessageList, { messages: messages, showDetails: showDetails }), streamText && _jsx(StreamingDraft, { text: streamText }), dangerConfirm && (_jsx(DangerConfirm, { command: dangerConfirm.command, reason: dangerConfirm.reason, ruleName: dangerConfirm.ruleName, onSelect: onResolveDangerConfirm })), loopState?.isRunning && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "gray", children: [" iteration ", loopState.iteration, "/", loopState.maxIterations] })] }))] }));
|
|
10
|
+
}
|
|
11
|
+
export default React.memo(MessageViewport);
|