@miphamai/cli 0.45.0 → 0.45.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.45.0",
3
+ "version": "0.45.1",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
@@ -9,7 +9,7 @@
9
9
  export const PACKAGE_NAME = '@miphamai/cli' as const
10
10
 
11
11
  /** 当前发布版本 */
12
- export const PACKAGE_VERSION = '0.45.0' as const
12
+ export const PACKAGE_VERSION = '0.45.1' as const
13
13
 
14
14
  /** npm install 全局安装命令 */
15
15
  export const NPM_INSTALL_COMMAND = `npm install -g ${PACKAGE_NAME}` as const
@@ -1,7 +1,28 @@
1
- import { $ } from 'bun'
2
1
  import type { ToolDefinition } from '../../shared/index.ts'
3
2
  import { resolveSafe } from '../../security/path'
4
3
 
4
+ /** Grep stall guard: a search over a huge tree (or a pathological regex) must
5
+ * not hang the session for minutes. Matches the Bash tool's 120s ceiling. */
6
+ const GREP_TIMEOUT_MS = 120_000
7
+
8
+ /** Run a search command with a kill-timer; report whether the timeout fired. */
9
+ export async function runSearch(
10
+ cmd: string[],
11
+ cwd: string,
12
+ timeoutMs: number,
13
+ ): Promise<{ stdout: string; timedOut: boolean; exitCode: number | null }> {
14
+ const proc = Bun.spawn(cmd, { cwd, stdout: 'pipe', stderr: 'pipe' })
15
+ let timedOut = false
16
+ const timer = setTimeout(() => {
17
+ timedOut = true
18
+ proc.kill()
19
+ }, timeoutMs)
20
+ const stdout = await new Response(proc.stdout).text()
21
+ await proc.exited
22
+ clearTimeout(timer)
23
+ return { stdout, timedOut, exitCode: proc.exitCode }
24
+ }
25
+
5
26
  export const grepTool: ToolDefinition = {
6
27
  name: 'Grep',
7
28
  description:
@@ -29,32 +50,52 @@ export const grepTool: ToolDefinition = {
29
50
  const searchPath = resolveSafe(ctx.cwd, (params.path as string) || '.')
30
51
  const include = params.include as string | undefined
31
52
 
53
+ // 1. ripgrep (fast path)
54
+ const rgArgs = ['rg', '-n', '--heading', '--color=never', '-M', '500', pattern]
55
+ if (include) rgArgs.push('--glob', include)
56
+ rgArgs.push(searchPath)
32
57
  try {
33
- const args = ['-n', '--heading', '--color=never', '-M', '500', pattern]
34
- if (include) args.push('--glob', include)
35
- args.push(searchPath)
36
-
37
- const result = await $`rg ${args}`.cwd(ctx.cwd).quiet().text()
38
- return { success: true, content: result || '(no matches)' }
39
- } catch (err: unknown) {
40
- const exitErr = err as { exitCode?: number }
41
- if (exitErr.exitCode === 1) {
42
- return { success: true, content: '(no matches)' }
43
- }
44
- // Fallback to grep
45
- try {
46
- const content = await $`grep -rn ${pattern} ${searchPath}`.cwd(ctx.cwd).quiet().text()
58
+ const { stdout, timedOut, exitCode } = await runSearch(rgArgs, ctx.cwd, GREP_TIMEOUT_MS)
59
+ if (timedOut) {
47
60
  return {
48
- success: true,
49
- content: content.slice(0, 50000) || '(no matches)',
61
+ success: false,
62
+ content: '',
63
+ error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
50
64
  }
51
- } catch {
65
+ }
66
+ if (exitCode === 1) return { success: true, content: '(no matches)' }
67
+ if (exitCode === 0) return { success: true, content: stdout || '(no matches)' }
68
+ // rg exit 2 (error) or null (killed) → fall through to grep
69
+ } catch {
70
+ // rg not installed → fall through to grep
71
+ }
72
+
73
+ // 2. fallback to plain grep
74
+ const grepArgs = ['grep', '-rn', pattern, searchPath]
75
+ try {
76
+ const { stdout, timedOut, exitCode } = await runSearch(grepArgs, ctx.cwd, GREP_TIMEOUT_MS)
77
+ if (timedOut) {
52
78
  return {
53
79
  success: false,
54
80
  content: '',
55
- error: 'grep failed. Install ripgrep: brew install ripgrep',
81
+ error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
56
82
  }
57
83
  }
84
+ if (exitCode === 1) return { success: true, content: '(no matches)' }
85
+ if (exitCode === 0) {
86
+ return { success: true, content: stdout.slice(0, 50000) || '(no matches)' }
87
+ }
88
+ return {
89
+ success: false,
90
+ content: '',
91
+ error: 'grep failed. Install ripgrep: brew install ripgrep',
92
+ }
93
+ } catch {
94
+ return {
95
+ success: false,
96
+ content: '',
97
+ error: 'grep failed. Install ripgrep: brew install ripgrep',
98
+ }
58
99
  }
59
100
  },
60
101
  }
package/src/ui/chat.tsx CHANGED
@@ -83,6 +83,10 @@ const MessageRow = React.memo(
83
83
  <Text bold color="green">
84
84
  ▸ {displayCwd()}:
85
85
  </Text>
86
+ ) : msg.role === 'assistant' ? (
87
+ <Text bold color="magenta">
88
+ ◆ {t('ui.assistant.role_label')}:
89
+ </Text>
86
90
  ) : msg.role === 'system' ? (
87
91
  <Text bold color="yellow">
88
92
  ⚠ {t('ui.system.role_label')}: