@code4bug/jarvis-agent 1.3.3 → 1.3.5

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.
@@ -91,6 +91,7 @@ vibe: 你的全能助手,有问必答,随时待命。
91
91
  - 涉及代码时,代码必须可直接运行,无语法错误
92
92
  - 多方案时先推荐最优解,再列备选
93
93
  - 根据问题类型灵活调整输出格式:代码用代码块、信息用结构化列表、分析用表格等
94
+ - 用户消息里的文件名、路径、命令、参数、扩展名必须逐字保留,不得擅自纠错或改写;若目标不存在,先检查目录或搜索再判断
94
95
 
95
96
  ### 沟通风格
96
97
  - 默认中文回答,代码注释优先中文
@@ -8,6 +8,9 @@
8
8
  const builtinCommands = [
9
9
  { name: 'init', description: '初始化项目信息,生成 JARVIS.md', category: 'builtin', submitMode: 'action' },
10
10
  { name: 'new', description: '开启新会话,重新初始化上下文', category: 'builtin', submitMode: 'action' },
11
+ { name: 'exit', description: '退出应用程序', category: 'builtin', submitMode: 'action' },
12
+ { name: 'quit', description: '退出应用程序', category: 'builtin', submitMode: 'action' },
13
+ { name: 'bye', description: '退出应用程序', category: 'builtin', submitMode: 'action' },
11
14
  { name: 'resume', description: '恢复历史会话上下文', category: 'builtin', submitMode: 'list' },
12
15
  { name: 'help', description: '显示帮助信息', category: 'builtin', submitMode: 'action' },
13
16
  { name: 'agent', description: '切换智能体', category: 'builtin', submitMode: 'list' },
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useMemo } from 'react';
3
- import { Box, Text } from 'ink';
3
+ import { Box, Text, useStdout } from 'ink';
4
4
  import { Marked } from 'marked';
5
5
  // @ts-ignore — marked-terminal 无内置类型声明
6
6
  import { markedTerminal } from 'marked-terminal';
7
7
  // @ts-ignore
8
8
  import Table from 'cli-table3';
9
+ // @ts-ignore — wrap-ansi 无显式类型声明
10
+ import wrapAnsi from 'wrap-ansi';
9
11
  // ===== ANSI 颜色常量 =====
10
12
  const RESET = '\x1b[0m';
11
13
  const BG_CODE = '\x1b[48;5;236m'; // 深灰背景
@@ -154,6 +156,29 @@ function renderMarkdown(text) {
154
156
  return text;
155
157
  }
156
158
  }
159
+ function wrapRenderedLine(line, width) {
160
+ if (!line)
161
+ return [''];
162
+ const safeWidth = Math.max(width, 12);
163
+ const plainLine = stripAnsi(line);
164
+ const listPrefixMatch = plainLine.match(/^(\s*(?:[*+-]|\d+\.)\s+)/);
165
+ if (!listPrefixMatch) {
166
+ return wrapAnsi(line, safeWidth, {
167
+ hard: true,
168
+ trim: false,
169
+ wordWrap: false,
170
+ }).split('\n');
171
+ }
172
+ const prefix = listPrefixMatch[1];
173
+ const content = line.slice(prefix.length);
174
+ const contentWidth = Math.max(safeWidth - prefix.length, 8);
175
+ const wrappedContent = wrapAnsi(content, contentWidth, {
176
+ hard: true,
177
+ trim: false,
178
+ wordWrap: false,
179
+ }).split('\n');
180
+ return wrappedContent.map((segment, index) => (`${index === 0 ? prefix : ' '.repeat(prefix.length)}${segment}`));
181
+ }
157
182
  /**
158
183
  * Markdown 终端渲染组件
159
184
  * 支持表格(动态列宽+自动换行)、代码块(深色背景+边框)、加粗、列表等
@@ -164,10 +189,14 @@ function renderMarkdown(text) {
164
189
  * 与 ANSI 转义序列冲突,出现光标错位和输出错乱。
165
190
  */
166
191
  function MarkdownText({ text, color }) {
192
+ const { stdout } = useStdout();
167
193
  const lines = useMemo(() => {
168
194
  const rendered = renderMarkdown(text);
169
- return rendered.split('\n');
170
- }, [text]);
171
- return (_jsx(Box, { flexDirection: "column", children: lines.map((line, i) => (_jsx(Text, { wrap: "wrap", color: color, children: line }, i))) }));
195
+ const availableWidth = Math.max(Math.min(stdout?.columns ?? 80, 100) - 6, 20);
196
+ return rendered
197
+ .split('\n')
198
+ .flatMap((line) => wrapRenderedLine(line, availableWidth));
199
+ }, [text, stdout]);
200
+ return (_jsx(Box, { flexDirection: "column", children: lines.map((line, i) => (_jsx(Text, { color: color, children: line || ' ' }, i))) }));
172
201
  }
173
202
  export default React.memo(MarkdownText);
@@ -208,6 +208,12 @@ export default function REPL() {
208
208
  const parts = trimmed.slice(1).split(/\s+/);
209
209
  const cmdName = parts[0].toLowerCase();
210
210
  const hasArgs = parts.length > 1 && parts.slice(1).join('').length > 0;
211
+ if (['exit', 'quit', 'bye'].includes(cmdName)) {
212
+ setInput('');
213
+ slashMenu.setSlashMenuVisible(false);
214
+ handleExit();
215
+ return;
216
+ }
211
217
  // 内置命令
212
218
  if (['new', 'help', 'init', 'session_clear', 'permissions', 'skills', 'version'].includes(cmdName)) {
213
219
  setInput('');
@@ -319,7 +325,7 @@ export default function REPL() {
319
325
  clearStream();
320
326
  abortRequestedRef.current = false;
321
327
  await engineRef.current.handleQuery(trimmed, callbacks);
322
- }, [isProcessing, pushHistory, clearStream, slashMenu, handleNewSession]);
328
+ }, [isProcessing, pushHistory, clearStream, slashMenu, handleNewSession, handleExit]);
323
329
  // ===== 输入处理 =====
324
330
  const handleUpArrow = useCallback(() => {
325
331
  const result = navigateUp(input);
@@ -26,6 +26,9 @@ export async function executeSlashCommand(cmdName) {
26
26
  '可用命令:',
27
27
  ' /init 初始化项目信息,生成 JARVIS.md',
28
28
  ' /new 开启新会话,重新初始化上下文',
29
+ ' /exit 退出应用程序',
30
+ ' /quit 退出应用程序',
31
+ ' /bye 退出应用程序',
29
32
  ' /resume 恢复历史会话(支持二级菜单选择)',
30
33
  ' /resume <ID> 直接恢复指定会话',
31
34
  ' /help 显示此帮助信息',
@@ -186,6 +186,9 @@ export class LLMServiceImpl {
186
186
  '\n\n[安全围栏] 系统已内置安全围栏(Safeguard),会自动拦截危险命令并弹出交互式确认菜单。' +
187
187
  '当你需要执行任何命令时,直接调用 Bash 工具即可,不要自行判断命令是否危险,不要用文字询问用户"是否确认执行"。' +
188
188
  '安全围栏会自动处理拦截和用户确认流程。' +
189
+ '\n\n[文件与命令保真] 用户消息中出现的文件名、目录名、路径、命令、参数、扩展名,必须按原文逐字使用,不得自行纠错、改写、补全或翻译。' +
190
+ '即使你怀疑用户有拼写错误,也必须先按原文检查;若原文目标不存在,再基于目录扫描结果给出候选项。' +
191
+ '尤其不要把相似文件名擅自改成你认为“更正确”的拼写。' +
189
192
  '\n\n[文件修改约束] 修改已有文件时,先读取目标文件,再优先使用局部修改方式。' +
190
193
  '如果只改少量内容,优先使用 write_file 的 replace 模式;需要结构化补丁时使用 diff 模式;只有新建文件或确实需要大范围重写时才使用 overwrite。';
191
194
  // 追加系统环境信息,帮助 LLM 感知用户运行环境
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code4bug/jarvis-agent",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "基于 React + TypeScript + Ink 构建的命令行智能体交互界面",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",