@miphamai/cli 0.2.3 → 0.3.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.
@@ -7,6 +7,15 @@
7
7
  import type { QueryEngine } from '../core/engine'
8
8
  import type { MiphamConfig } from '../shared/index.ts'
9
9
  import type { SkillsLoader } from '../skills/loader'
10
+ import { McpClient } from '../mcp/client'
11
+ import {
12
+ PACKAGE_NAME,
13
+ NPM_INSTALL_COMMAND,
14
+ NPM_UPDATE_COMMAND,
15
+ NPM_URL,
16
+ PRODUCT_URL_INTERNATIONAL,
17
+ PRODUCT_URL_CHINA,
18
+ } from '@mipham/shared'
10
19
 
11
20
  export interface CommandContext {
12
21
  engine: QueryEngine
@@ -1139,7 +1148,7 @@ To upgrade:
1139
1148
  curl -fsSL https://mipham.ai/install.sh | bash
1140
1149
 
1141
1150
  Or if installed via npm:
1142
- npm update -g @mipham/cli
1151
+ ${NPM_UPDATE_COMMAND}
1143
1152
 
1144
1153
  Release channels:
1145
1154
  • stable — recommended for most users
@@ -1819,7 +1828,7 @@ JetBrains (IntelliJ / WebStorm / PyCharm):
1819
1828
  Terminal (any):
1820
1829
  alias mipham='cd your-project && bun run path/to/mipham'
1821
1830
 
1822
- Or install globally: npm install -g @mipham/cli
1831
+ Or install globally: ${NPM_INSTALL_COMMAND}
1823
1832
 
1824
1833
  Coming soon: dedicated VS Code & JetBrains plugin extensions.`,
1825
1834
  })
@@ -1832,7 +1841,7 @@ const terminalSetupCmd: CommandHandler = () => ({
1832
1841
  content: `── Terminal Setup ──
1833
1842
 
1834
1843
  Install globally:
1835
- npm install -g @mipham/cli
1844
+ ${NPM_INSTALL_COMMAND}
1836
1845
  mipham
1837
1846
 
1838
1847
  One-liner install:
@@ -1846,7 +1855,7 @@ Add to shell profile (~/.zshrc or ~/.bashrc):
1846
1855
 
1847
1856
  Upgrade:
1848
1857
  curl -fsSL https://mipham.ai/install.sh | bash
1849
- # or: npm update -g @mipham/cli
1858
+ # or: ${NPM_UPDATE_COMMAND}
1850
1859
 
1851
1860
  Verify installation:
1852
1861
  mipham --version
@@ -1860,18 +1869,40 @@ Works with: Bash, Zsh, Fish, PowerShell, Windows Terminal`,
1860
1869
  // ═══════════════════════════════════════════════════════════════
1861
1870
 
1862
1871
  const mcpCmd: CommandHandler = (ctx) => {
1863
- const mcpServers = ctx.config.skills?.mcpServers ?? []
1872
+ const configuredServers = ctx.config.skills?.mcpServers ?? []
1873
+ const liveConnections = McpClient.getInstance().listConnections()
1864
1874
 
1865
1875
  const lines: string[] = ['── MCP Servers ──', '']
1866
1876
 
1867
- if (mcpServers.length > 0) {
1868
- lines.push(`Configured servers (${mcpServers.length}):`)
1877
+ if (configuredServers.length > 0) {
1878
+ lines.push(`Configured servers (${configuredServers.length}):`)
1869
1879
  lines.push('')
1870
- for (const s of mcpServers) {
1880
+ for (const s of configuredServers) {
1881
+ const live = liveConnections.find((c) => c.config.name === s.name)
1882
+ const statusIcon = live
1883
+ ? live.status === 'connected'
1884
+ ? '🟢'
1885
+ : live.status === 'connecting'
1886
+ ? '🟡'
1887
+ : live.status === 'error'
1888
+ ? '🔴'
1889
+ : '⚪'
1890
+ : '⚪'
1891
+ const statusLabel = live ? live.status : 'not started'
1871
1892
  const envKeys = s.env ? Object.keys(s.env).join(', ') : '(none)'
1872
- lines.push(` 📡 ${s.name}`)
1893
+
1894
+ lines.push(` ${statusIcon} ${s.name} [${statusLabel}]`)
1873
1895
  lines.push(` Command: ${s.command} ${s.args.join(' ')}`)
1874
1896
  lines.push(` Env vars: ${envKeys}`)
1897
+ if (live?.tools && live.tools.length > 0) {
1898
+ lines.push(` Tools: ${live.tools.map((t) => t.name).join(', ')}`)
1899
+ }
1900
+ if (live?.error) {
1901
+ lines.push(` Error: ${live.error}`)
1902
+ }
1903
+ if (live?.serverInfo) {
1904
+ lines.push(` Server: ${live.serverInfo.name} v${live.serverInfo.version}`)
1905
+ }
1875
1906
  lines.push('')
1876
1907
  }
1877
1908
  } else {
@@ -1900,11 +1931,10 @@ const mcpCmd: CommandHandler = (ctx) => {
1900
1931
  }
1901
1932
 
1902
1933
  lines.push('')
1903
- lines.push('── Status ──')
1904
- lines.push('MCP stdio protocol: full implementation in M3 milestone.')
1905
- lines.push('Current: config parsing + server registry ready.')
1934
+ lines.push('── Protocol ──')
1935
+ lines.push('MCP stdio transport (JSON-RPC 2.0) fully implemented.')
1936
+ lines.push('Servers auto-connect on startup when configured.')
1906
1937
  lines.push('')
1907
- lines.push('MCP enables AI to interact with external tools via standardized servers.')
1908
1938
  lines.push('Learn more: https://modelcontextprotocol.io')
1909
1939
 
1910
1940
  return { content: lines.join('\n') }
package/src/ui/input.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react'
1
+ import React, { useState, useEffect, useRef } from 'react'
2
2
  import { Box, Text } from 'ink'
3
3
  import TextInput from 'ink-text-input'
4
4
 
@@ -7,32 +7,37 @@ interface InputBarProps {
7
7
  isLoading: boolean
8
8
  }
9
9
 
10
- // ── Creative status messages (inspired by Claude Code's whimsical verbs) ──
10
+ // ── Status verbs English (Claude Code-aligned) + Chinese (Mipham originals) ──
11
11
 
12
- const STATUS_VERBS = [
13
- '思忖中', // Pondering
14
- '推演中', // Deducting
15
- '凝炼中', // Condensing
16
- '熬煮中', // Simmering
17
- '锻造中', // Forging
18
- '研磨中', // Grinding
19
- '解构中', // Deconstructing
20
- '冥思中', // Contemplating
21
- '编织中', // Weaving
22
- '萃取中', // Extracting
23
- '烹制中', // Cooking
24
- '淬火中', // Quenching
25
- '雕琢中', // Chiseling
26
- '融汇中', // Fusing
27
- '觉照中', // Illuminating
28
- '运转中', // Operating
29
- '参详中', // Studying
30
- '化合中', // Synthesizing
31
- '浸润中', // Infusing
32
- '焙烤中', // Baking
12
+ const STATUS_EN = [
13
+ 'Doodling', 'Forging', 'Germinating', 'Mosmosing', 'Cerebrating',
14
+ 'Boogieing', 'Finagling', 'Misting', 'Recombobulating', 'Slithering',
15
+ 'Effecting', 'Roosting', 'Crystallizing', 'Canoodling', 'Billowing',
16
+ 'Warping', 'Improvising', 'Metamorphing', 'Gusting', 'Whiring',
17
+ 'Topsy-turvying', 'Flibbertigibetting', 'Wibbling', 'Thundering',
18
+ 'Moseying', 'Julienning', 'Evaporating', 'Ruminating', 'Whisking',
19
+ 'Scampering', 'Meandering', 'Concoting', 'Gesticulating', 'Flamebeing',
20
+ 'Quantumizing', 'Waddling', 'Fluttering', 'Sprouting', 'Elucidating',
21
+ 'Embellishing', 'Razzmatizing', 'Pondering', 'Cogitating', 'Garnishing',
22
+ 'Actualizing', 'Zigzagging', 'Mustering', 'Frolicking', 'Hullaballooing',
23
+ 'Doing', 'Fermenting', 'Considering', 'Skedaddling', 'Actioning',
24
+ 'Orbiting', 'Perambulating', 'Drizzling', 'Schlepping', 'Ionizing',
25
+ 'Scurrying',
33
26
  ]
34
27
 
35
- const STATUS_EMOJI = ['🔮', '⚙️', '💎', '🔥', '🧪', '🌊', '⚡', '🌀', '🎯', '💡']
28
+ const STATUS_CN = [
29
+ '思忖中', '推演中', '凝炼中', '熬煮中', '锻造中',
30
+ '研磨中', '解构中', '冥思中', '编织中', '萃取中',
31
+ '烹制中', '淬火中', '雕琢中', '融汇中', '觉照中',
32
+ '运转中', '参详中', '化合中', '浸润中', '焙烤中',
33
+ ]
34
+
35
+ // Merge both — bilingual status verbs
36
+ const STATUS_GERUNDS = [...STATUS_EN, ...STATUS_CN]
37
+
38
+ const STATUS_PAST = [
39
+ 'Brewed', 'Churned', 'Cooked', 'Sautéed', 'Cogitated', 'Crunched',
40
+ ]
36
41
 
37
42
  function pick<T>(arr: T[]): T {
38
43
  return arr[Math.floor(Math.random() * arr.length)]!
@@ -40,25 +45,35 @@ function pick<T>(arr: T[]): T {
40
45
 
41
46
  export function InputBar({ onSubmit, isLoading }: InputBarProps) {
42
47
  const [value, setValue] = useState('')
43
- const [verb, setVerb] = useState(() => pick(STATUS_VERBS))
44
- const [emoji, setEmoji] = useState(() => pick(STATUS_EMOJI))
48
+ const [verb, setVerb] = useState(() => pick(STATUS_GERUNDS))
49
+ const [completionVerb, setCompletionVerb] = useState<string | null>(null)
50
+ const prevLoading = useRef(isLoading)
45
51
 
46
- // Rotate status messages while loading
52
+ // Rotate gerunds while loading
47
53
  useEffect(() => {
48
54
  if (!isLoading) return
49
55
  const interval = setInterval(() => {
50
- setVerb(pick(STATUS_VERBS))
51
- setEmoji(pick(STATUS_EMOJI))
52
- }, 2000)
56
+ setVerb(pick(STATUS_GERUNDS))
57
+ }, 1200)
53
58
  return () => clearInterval(interval)
54
59
  }, [isLoading])
55
60
 
56
- // Reset when loading starts
61
+ // Pick a fresh gerund when loading starts
57
62
  useEffect(() => {
58
63
  if (isLoading) {
59
- setVerb(pick(STATUS_VERBS))
60
- setEmoji(pick(STATUS_EMOJI))
64
+ setVerb(pick(STATUS_GERUNDS))
65
+ setCompletionVerb(null)
66
+ }
67
+ }, [isLoading])
68
+
69
+ // Flash a past participle when loading stops
70
+ useEffect(() => {
71
+ if (prevLoading.current === true && isLoading === false) {
72
+ setCompletionVerb(pick(STATUS_PAST))
73
+ const timer = setTimeout(() => setCompletionVerb(null), 1500)
74
+ return () => clearTimeout(timer)
61
75
  }
76
+ prevLoading.current = isLoading
62
77
  }, [isLoading])
63
78
 
64
79
  const handleSubmit = (val: string) => {
@@ -70,13 +85,19 @@ export function InputBar({ onSubmit, isLoading }: InputBarProps) {
70
85
  return (
71
86
  <Box marginTop={1}>
72
87
  <Box marginRight={1}>
73
- <Text color={isLoading ? 'yellow' : 'cyan'}>{isLoading ? `${emoji}` : ''}</Text>
88
+ <Text color={isLoading ? 'yellow' : 'cyan'}>{'>'}</Text>
74
89
  </Box>
75
90
  <TextInput
76
91
  value={value}
77
92
  onChange={setValue}
78
93
  onSubmit={handleSubmit}
79
- placeholder={isLoading ? `${verb}...` : 'Type a message (Esc to exit)...'}
94
+ placeholder={
95
+ isLoading
96
+ ? `${verb}...`
97
+ : completionVerb
98
+ ? completionVerb
99
+ : 'Type a message (Esc to cancel)...'
100
+ }
80
101
  />
81
102
  </Box>
82
103
  )