@miphamai/cli 0.50.0 → 0.51.0

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 (46) hide show
  1. package/bin/mipham.ts +1 -9
  2. package/package.json +1 -1
  3. package/skills/standard/web-access/references/cdp-api.md +2 -1
  4. package/skills/standard/web-access/scripts/cdp-proxy.mjs +75 -1
  5. package/skills/standard/web-access/scripts/check-deps.mjs +17 -2
  6. package/skills/standard/web-access/scripts/find-url.mjs +0 -0
  7. package/skills/standard/web-access/scripts/match-site.mjs +0 -0
  8. package/skills/standard/web-access.SKILL.md +10 -3
  9. package/src/commands/project.ts +1 -1
  10. package/src/config/defaults.ts +5 -0
  11. package/src/core/auto-memory.ts +3 -3
  12. package/src/core/constitution-loader.ts +0 -2
  13. package/src/core/context.ts +0 -1
  14. package/src/core/credential-masker/index.ts +1 -0
  15. package/src/core/credential-masker/matcher.ts +18 -7
  16. package/src/core/credential-masker/search.ts +73 -0
  17. package/src/core/credential-masker.ts +1 -0
  18. package/src/core/crsi-sandbox.ts +0 -1
  19. package/src/core/dream-engine.ts +0 -2
  20. package/src/core/memory/memory-loader.ts +3 -1
  21. package/src/core/permission-rules.ts +23 -12
  22. package/src/core/rules-loader.ts +8 -10
  23. package/src/daemon/database.ts +0 -1
  24. package/src/daemon/feishu/adapter.ts +2 -1
  25. package/src/daemon/index.ts +18 -8
  26. package/src/daemon/server.ts +53 -10
  27. package/src/daemon/session-manager.ts +5 -4
  28. package/src/daemon/telegram/adapter.ts +70 -0
  29. package/src/daemon/telegram/api.ts +45 -0
  30. package/src/daemon/telegram/env.ts +14 -0
  31. package/src/daemon/telegram/poller.ts +64 -0
  32. package/src/daemon/telegram/types.ts +10 -0
  33. package/src/i18n-core/locales/en-US.json +123 -0
  34. package/src/i18n-core/locales/zh-CN.json +123 -0
  35. package/src/index.tsx +6 -0
  36. package/src/shared/package-info.ts +1 -1
  37. package/src/shared/types.ts +2 -0
  38. package/src/skills/bundled-skill-assets.ts +5 -5
  39. package/src/skills/bundled-skills.ts +1 -1
  40. package/src/tools/agent/exit-plan.ts +1 -3
  41. package/src/tools/agent/memory.ts +2 -1
  42. package/src/tools/file/glob.ts +38 -23
  43. package/src/tools/file/grep.ts +86 -64
  44. package/src/tools/index.ts +5 -5
  45. package/src/ui/commands.ts +188 -119
  46. package/src/ui/config-wizard.tsx +1 -1
@@ -1,29 +1,44 @@
1
1
  import { Glob } from 'bun'
2
- import type { ToolDefinition } from '../../shared/index.ts'
2
+ import type { ToolDefinition, CredentialMaskingConfig } from '../../shared/index.ts'
3
3
  import { resolveSafe } from '../../security/path'
4
+ import type { Service } from '../../vajra'
5
+ import { toolKey } from '../seam'
6
+ import { withValidation } from '../validation'
7
+ import { maskGlobOutput } from '../../core/credential-masker'
4
8
 
5
- export const globTool: ToolDefinition = {
6
- name: 'Glob',
7
- description: 'Find files matching a glob pattern.',
8
- category: 'file',
9
- permission: 'auto',
10
- parameters: {
11
- type: 'object',
12
- properties: {
13
- pattern: { type: 'string', description: 'Glob pattern (e.g., "src/**/*.ts")' },
14
- path: { type: 'string', description: 'Base directory' },
9
+ export function createGlobTool(credentialConfig?: CredentialMaskingConfig): ToolDefinition {
10
+ return {
11
+ name: 'Glob',
12
+ description: 'Find files matching a glob pattern.',
13
+ category: 'file',
14
+ permission: 'auto',
15
+ parameters: {
16
+ type: 'object',
17
+ properties: {
18
+ pattern: { type: 'string', description: 'Glob pattern (e.g., "src/**/*.ts")' },
19
+ path: { type: 'string', description: 'Base directory' },
20
+ },
21
+ required: ['pattern'],
15
22
  },
16
- required: ['pattern'],
17
- },
18
- async execute(params, ctx) {
19
- const pattern = params.pattern as string
20
- const basePath = resolveSafe(ctx.cwd, (params.path as string) || '.')
21
- const glob = new Glob(pattern)
22
- const results: string[] = []
23
- for await (const file of glob.scan({ cwd: basePath, absolute: true })) {
24
- results.push(file)
25
- if (results.length >= 500) break
26
- }
27
- return { success: true, content: results.join('\n') || '(no matches)' }
23
+ async execute(params, ctx) {
24
+ const pattern = params.pattern as string
25
+ const basePath = resolveSafe(ctx.cwd, (params.path as string) || '.')
26
+ const glob = new Glob(pattern)
27
+ const results: string[] = []
28
+ for await (const file of glob.scan({ cwd: basePath, absolute: true })) {
29
+ results.push(file)
30
+ if (results.length >= 500) break
31
+ }
32
+ const content = results.join('\n') || '(no matches)'
33
+ return { success: true, content: maskGlobOutput(content, credentialConfig) }
34
+ },
35
+ }
36
+ }
37
+
38
+ export const globToolService: Service = {
39
+ inject: ['credentials'],
40
+ apply(ctx) {
41
+ const credentialConfig = ctx.get<CredentialMaskingConfig>('credentials')
42
+ ctx.provide(toolKey('Glob'), withValidation(createGlobTool(credentialConfig)))
28
43
  },
29
44
  }
@@ -1,5 +1,9 @@
1
- import type { ToolDefinition } from '../../shared/index.ts'
1
+ import type { ToolDefinition, CredentialMaskingConfig } from '../../shared/index.ts'
2
2
  import { resolveSafe } from '../../security/path'
3
+ import type { Service } from '../../vajra'
4
+ import { toolKey } from '../seam'
5
+ import { withValidation } from '../validation'
6
+ import { maskSearchOutput } from '../../core/credential-masker'
3
7
 
4
8
  /** Grep stall guard: a search over a huge tree (or a pathological regex) must
5
9
  * not hang the session for minutes. Matches the Bash tool's 120s ceiling. */
@@ -33,79 +37,97 @@ export function truncateGrepOutput(stdout: string): string {
33
37
  return `${out.slice(0, GREP_MAX_OUTPUT_CHARS)}\n\n... (truncated)`
34
38
  }
35
39
 
36
- export const grepTool: ToolDefinition = {
37
- name: 'Grep',
38
- description:
39
- 'Search file contents using ripgrep (rg) — the recommended code search tool. ' +
40
- '~10× faster than grep, with automatic fallback to grep if rg is unavailable. ' +
41
- 'Use this for single-shot regex searches across files. ' +
42
- 'Prefer Grep over Bash grep/rg for code search; use Bash only for complex ' +
43
- 'multi-step pipelines (e.g., pipe to sort/uniq/wc, or chained find+xargs). ' +
44
- 'Best practice: narrow scope with `path` (directory/file) and `include` ' +
45
- '(glob pattern, e.g. "*.ts") before searching. ' +
46
- 'The `pattern` parameter accepts full regex syntax (e.g., "log.*Error", "\\bclass\\s+\\w+").',
47
- category: 'file',
48
- permission: 'auto',
49
- parameters: {
50
- type: 'object',
51
- properties: {
52
- pattern: { type: 'string', description: 'Regex pattern to search for' },
53
- path: { type: 'string', description: 'Directory or file to search in' },
54
- include: { type: 'string', description: 'File pattern to include (e.g., "*.ts")' },
40
+ export function createGrepTool(credentialConfig?: CredentialMaskingConfig): ToolDefinition {
41
+ return {
42
+ name: 'Grep',
43
+ description:
44
+ 'Search file contents using ripgrep (rg) — the recommended code search tool. ' +
45
+ '~10× faster than grep, with automatic fallback to grep if rg is unavailable. ' +
46
+ 'Use this for single-shot regex searches across files. ' +
47
+ 'Prefer Grep over Bash grep/rg for code search; use Bash only for complex ' +
48
+ 'multi-step pipelines (e.g., pipe to sort/uniq/wc, or chained find+xargs). ' +
49
+ 'Best practice: narrow scope with `path` (directory/file) and `include` ' +
50
+ '(glob pattern, e.g. "*.ts") before searching. ' +
51
+ 'The `pattern` parameter accepts full regex syntax (e.g., "log.*Error", "\\bclass\\s+\\w+").',
52
+ category: 'file',
53
+ permission: 'auto',
54
+ parameters: {
55
+ type: 'object',
56
+ properties: {
57
+ pattern: { type: 'string', description: 'Regex pattern to search for' },
58
+ path: { type: 'string', description: 'Directory or file to search in' },
59
+ include: { type: 'string', description: 'File pattern to include (e.g., "*.ts")' },
60
+ },
61
+ required: ['pattern'],
55
62
  },
56
- required: ['pattern'],
57
- },
58
- async execute(params, ctx) {
59
- const pattern = params.pattern as string
60
- const searchPath = resolveSafe(ctx.cwd, (params.path as string) || '.')
61
- const include = params.include as string | undefined
63
+ async execute(params, ctx) {
64
+ const pattern = params.pattern as string
65
+ const searchPath = resolveSafe(ctx.cwd, (params.path as string) || '.')
66
+ const include = params.include as string | undefined
67
+
68
+ // 1. ripgrep (fast path)
69
+ const rgArgs = ['rg', '-n', '--heading', '--color=never', '-M', '500', pattern]
70
+ if (include) rgArgs.push('--glob', include)
71
+ rgArgs.push(searchPath)
72
+ try {
73
+ const { stdout, timedOut, exitCode } = await runSearch(rgArgs, ctx.cwd, GREP_TIMEOUT_MS)
74
+ if (timedOut) {
75
+ return {
76
+ success: false,
77
+ content: '',
78
+ error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
79
+ }
80
+ }
81
+ if (exitCode === 1) return { success: true, content: '(no matches)' }
82
+ if (exitCode === 0) {
83
+ return {
84
+ success: true,
85
+ content: maskSearchOutput(stdout || '(no matches)', credentialConfig, 'heading'),
86
+ }
87
+ }
88
+ // rg exit 2 (error) or null (killed) → fall through to grep
89
+ } catch {
90
+ // rg not installed → fall through to grep
91
+ }
62
92
 
63
- // 1. ripgrep (fast path)
64
- const rgArgs = ['rg', '-n', '--heading', '--color=never', '-M', '500', pattern]
65
- if (include) rgArgs.push('--glob', include)
66
- rgArgs.push(searchPath)
67
- try {
68
- const { stdout, timedOut, exitCode } = await runSearch(rgArgs, ctx.cwd, GREP_TIMEOUT_MS)
69
- if (timedOut) {
93
+ // 2. fallback to plain grep
94
+ const grepArgs = ['grep', '-rn', pattern, searchPath]
95
+ try {
96
+ const { stdout, timedOut, exitCode } = await runSearch(grepArgs, ctx.cwd, GREP_TIMEOUT_MS)
97
+ if (timedOut) {
98
+ return {
99
+ success: false,
100
+ content: '',
101
+ error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
102
+ }
103
+ }
104
+ if (exitCode === 1) return { success: true, content: '(no matches)' }
105
+ if (exitCode === 0) {
106
+ return {
107
+ success: true,
108
+ content: truncateGrepOutput(maskSearchOutput(stdout, credentialConfig, 'filename')),
109
+ }
110
+ }
70
111
  return {
71
112
  success: false,
72
113
  content: '',
73
- error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
114
+ error: 'grep failed. Install ripgrep: brew install ripgrep',
74
115
  }
75
- }
76
- if (exitCode === 1) return { success: true, content: '(no matches)' }
77
- if (exitCode === 0) return { success: true, content: stdout || '(no matches)' }
78
- // rg exit 2 (error) or null (killed) → fall through to grep
79
- } catch {
80
- // rg not installed → fall through to grep
81
- }
82
-
83
- // 2. fallback to plain grep
84
- const grepArgs = ['grep', '-rn', pattern, searchPath]
85
- try {
86
- const { stdout, timedOut, exitCode } = await runSearch(grepArgs, ctx.cwd, GREP_TIMEOUT_MS)
87
- if (timedOut) {
116
+ } catch {
88
117
  return {
89
118
  success: false,
90
119
  content: '',
91
- error: `Grep timed out after ${GREP_TIMEOUT_MS / 1000}s — narrow scope with "path" and "include".`,
120
+ error: 'grep failed. Install ripgrep: brew install ripgrep',
92
121
  }
93
122
  }
94
- if (exitCode === 1) return { success: true, content: '(no matches)' }
95
- if (exitCode === 0) {
96
- return { success: true, content: truncateGrepOutput(stdout) }
97
- }
98
- return {
99
- success: false,
100
- content: '',
101
- error: 'grep failed. Install ripgrep: brew install ripgrep',
102
- }
103
- } catch {
104
- return {
105
- success: false,
106
- content: '',
107
- error: 'grep failed. Install ripgrep: brew install ripgrep',
108
- }
109
- }
123
+ },
124
+ }
125
+ }
126
+
127
+ export const grepToolService: Service = {
128
+ inject: ['credentials'],
129
+ apply(ctx) {
130
+ const credentialConfig = ctx.get<CredentialMaskingConfig>('credentials')
131
+ ctx.provide(toolKey('Grep'), withValidation(createGrepTool(credentialConfig)))
110
132
  },
111
133
  }
@@ -5,8 +5,8 @@ import { toolService, collectTools } from './seam'
5
5
  import { readToolService } from './file/read'
6
6
  import { writeTool } from './file/write'
7
7
  import { editTool } from './file/edit'
8
- import { globTool } from './file/glob'
9
- import { grepTool } from './file/grep'
8
+ import { globToolService } from './file/glob'
9
+ import { grepToolService } from './file/grep'
10
10
  import { bashToolService } from './exec/bash'
11
11
  import { gitTool } from './exec/git'
12
12
  import { taskTool } from './exec/task'
@@ -49,8 +49,6 @@ export function createToolRegistry(
49
49
  // File tools
50
50
  writeTool,
51
51
  editTool,
52
- globTool,
53
- grepTool,
54
52
  // Exec tools
55
53
  gitTool,
56
54
  taskTool,
@@ -87,9 +85,11 @@ export function createToolRegistry(
87
85
  for (const tool of plainTools) {
88
86
  ctx.mount(toolService(withValidation(tool)))
89
87
  }
90
- // 注入工具(credentials 依赖):read + bash
88
+ // 注入工具(credentials 依赖):read + bash + grep + glob
91
89
  ctx.mount(readToolService)
92
90
  ctx.mount(bashToolService)
91
+ ctx.mount(grepToolService)
92
+ ctx.mount(globToolService)
93
93
 
94
94
  return collectTools(ctx)
95
95
  }