@code4bug/jarvis-agent 1.2.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/jarvis.md +1 -1
  3. package/dist/components/AnimatedStatusText.d.ts +10 -0
  4. package/dist/components/AnimatedStatusText.js +17 -0
  5. package/dist/components/ComposerPane.d.ts +25 -0
  6. package/dist/components/ComposerPane.js +10 -0
  7. package/dist/components/FooterPane.d.ts +9 -0
  8. package/dist/components/FooterPane.js +22 -0
  9. package/dist/components/InputTextView.d.ts +11 -0
  10. package/dist/components/InputTextView.js +44 -0
  11. package/dist/components/MessageList.d.ts +9 -0
  12. package/dist/components/MessageList.js +8 -0
  13. package/dist/components/MessageViewport.d.ts +21 -0
  14. package/dist/components/MessageViewport.js +11 -0
  15. package/dist/components/MultilineInput.js +75 -343
  16. package/dist/components/StreamingDraft.d.ts +11 -0
  17. package/dist/components/StreamingDraft.js +14 -0
  18. package/dist/components/inputEditing.d.ts +20 -0
  19. package/dist/components/inputEditing.js +48 -0
  20. package/dist/core/WorkerBridge.d.ts +3 -0
  21. package/dist/core/WorkerBridge.js +75 -16
  22. package/dist/core/query.js +68 -10
  23. package/dist/hooks/useMultilineInputStream.d.ts +17 -0
  24. package/dist/hooks/useMultilineInputStream.js +141 -0
  25. package/dist/hooks/useTerminalCursorSync.d.ts +11 -0
  26. package/dist/hooks/useTerminalCursorSync.js +46 -0
  27. package/dist/hooks/useTerminalSize.d.ts +7 -0
  28. package/dist/hooks/useTerminalSize.js +21 -0
  29. package/dist/screens/repl.js +74 -33
  30. package/dist/services/api/llm.js +3 -1
  31. package/dist/skills/index.js +10 -3
  32. package/dist/terminal/cursor.d.ts +6 -0
  33. package/dist/terminal/cursor.js +22 -0
  34. package/dist/tools/writeFile.js +63 -2
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -139,7 +139,7 @@ jarvis --version
139
139
  | 工具名 | 说明 |
140
140
  | --- | --- |
141
141
  | `read_file` | 读取文件 |
142
- | `write_file` | 写入文件 |
142
+ | `write_file` | 写入文件,支持整文件覆盖或局部修改 |
143
143
  | `run_command` | 执行命令 |
144
144
  | `list_directory` | 列出目录内容 |
145
145
  | `search_files` | 搜索文件内容 |
@@ -58,7 +58,7 @@ vibe: 你的全能助手,有问必答,随时待命。
58
58
  - 自动化脚本编写
59
59
 
60
60
  ### 信息检索与知识问答
61
- - 利用联网搜索工具(tavily_search)获取实时信息,包括新闻、天气、热点事件等
61
+ - 利用联网搜索工具(web_search)获取实时信息,包括新闻、天气、热点事件等
62
62
  - 回答各领域知识问题:科技、历史、地理、文化、商业等
63
63
  - 信息汇总、对比分析、趋势解读
64
64
 
@@ -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);