@miphamai/cli 0.5.12 → 0.6.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.
@@ -150,30 +150,100 @@ export class OpenAICompatProvider implements ProviderInstance {
150
150
  }
151
151
  }
152
152
 
153
- private convertMessages(
154
- messages: Message[],
155
- systemPrompt?: string,
156
- ): { role: string; content: string | unknown[] }[] {
157
- const result: { role: string; content: string | unknown[] }[] = []
153
+ private convertMessages(messages: Message[], systemPrompt?: string): Record<string, unknown>[] {
154
+ const result: Record<string, unknown>[] = []
158
155
 
159
156
  if (systemPrompt) {
160
157
  result.push({ role: 'system', content: systemPrompt })
161
158
  }
162
159
 
163
- for (const msg of messages) {
160
+ for (let i = 0; i < messages.length; i++) {
161
+ const msg = messages[i]!
162
+ if (!msg) continue
163
+
164
+ // ── String content ──
164
165
  if (typeof msg.content === 'string') {
166
+ // Combine: assistant text + next assistant message with tool_use blocks
167
+ const next: Message | undefined = messages[i + 1]
168
+ if (
169
+ msg.role === 'assistant' &&
170
+ msg.content.length > 0 &&
171
+ next &&
172
+ next.role === 'assistant' &&
173
+ typeof next.content !== 'string' &&
174
+ next.content.some((b) => b.type === 'tool_use')
175
+ ) {
176
+ const toolUses = next.content.filter((b) => b.type === 'tool_use')
177
+ result.push({
178
+ role: 'assistant',
179
+ content: msg.content,
180
+ tool_calls: toolUses.map((tu) => ({
181
+ id: tu.id,
182
+ type: 'function',
183
+ function: {
184
+ name: tu.name,
185
+ arguments: JSON.stringify(tu.input),
186
+ },
187
+ })),
188
+ })
189
+ i++ // skip the next message (consumed)
190
+ continue
191
+ }
192
+
165
193
  result.push({ role: msg.role, content: msg.content })
166
- } else {
167
- const parts: unknown[] = []
168
- for (const block of msg.content) {
169
- if (block.type === 'text') {
170
- parts.push({ type: 'text', text: block.text })
171
- } else if (block.type === 'image_url') {
172
- parts.push({ type: 'image_url', image_url: block.image_url })
173
- }
194
+ continue
195
+ }
196
+
197
+ // ── ContentBlock[] ──
198
+ const blocks = msg.content
199
+ const toolUses = blocks.filter((b) => b.type === 'tool_use')
200
+ const toolResults = blocks.filter((b) => b.type === 'tool_result')
201
+
202
+ // ── Assistant tool_use → OpenAI tool_calls ──
203
+ if (toolUses.length > 0 && msg.role === 'assistant') {
204
+ const textContent =
205
+ blocks
206
+ .filter((b) => b.type === 'text')
207
+ .map((b) => (b.type === 'text' ? b.text : ''))
208
+ .join('') || null
209
+
210
+ result.push({
211
+ role: 'assistant',
212
+ content: textContent,
213
+ tool_calls: toolUses.map((tu) => ({
214
+ id: tu.id,
215
+ type: 'function',
216
+ function: {
217
+ name: tu.name,
218
+ arguments: JSON.stringify(tu.input),
219
+ },
220
+ })),
221
+ })
222
+ continue
223
+ }
224
+
225
+ // ── Tool result → OpenAI tool role ──
226
+ if (toolResults.length > 0) {
227
+ for (const tr of toolResults) {
228
+ result.push({
229
+ role: 'tool',
230
+ tool_call_id: tr.tool_use_id,
231
+ content: tr.content,
232
+ })
233
+ }
234
+ continue
235
+ }
236
+
237
+ // ── Regular content blocks (text, image) ──
238
+ const parts: unknown[] = []
239
+ for (const block of blocks) {
240
+ if (block.type === 'text') {
241
+ parts.push({ type: 'text', text: block.text })
242
+ } else if (block.type === 'image_url') {
243
+ parts.push({ type: 'image_url', image_url: block.image_url })
174
244
  }
175
- result.push({ role: msg.role, content: parts })
176
245
  }
246
+ result.push({ role: msg.role, content: parts })
177
247
  }
178
248
 
179
249
  return result
@@ -260,6 +260,15 @@ export const DEFAULT_PROVIDERS: ProviderConfig[] = [
260
260
  vision: true,
261
261
  status: 'active',
262
262
  },
263
+ {
264
+ id: 'kimi-k3',
265
+ name: 'Kimi K3',
266
+ providerId: 'kimi',
267
+ contextWindow: 1_000_000,
268
+ maxOutput: 128_000,
269
+ vision: true,
270
+ status: 'active',
271
+ },
263
272
  {
264
273
  id: 'moonshot-v1-8k',
265
274
  name: 'Moonshot v1 8K',
@@ -30,6 +30,8 @@ export interface SkillEntry {
30
30
  category: string
31
31
  /** Author */
32
32
  author: string
33
+ /** If true, skill is already built-in — no download needed */
34
+ builtin?: boolean
33
35
  }
34
36
 
35
37
  /**
@@ -39,11 +41,13 @@ export interface SkillEntry {
39
41
  const COMMUNITY_SKILLS: SkillEntry[] = [
40
42
  {
41
43
  name: 'code-review',
42
- description: 'Automated code review with multiple dimensions',
44
+ description:
45
+ 'Automated code review with multiple dimensions — complexity, security, performance, quality',
43
46
  url: 'https://github.com/One-Mipham/skill-code-review',
44
47
  file: 'code-review.SKILL.md',
45
48
  category: 'Development',
46
49
  author: 'MiphamAI',
50
+ builtin: true,
47
51
  },
48
52
  {
49
53
  name: 'systematic-debugging',
@@ -60,42 +64,49 @@ const COMMUNITY_SKILLS: SkillEntry[] = [
60
64
  file: 'test-driven-development.SKILL.md',
61
65
  category: 'Development',
62
66
  author: 'Anthropic',
67
+ builtin: true,
63
68
  },
64
69
  {
65
70
  name: 'web-access',
66
- description: 'Web search, scraping, and browser automation',
71
+ description:
72
+ 'Web search, scraping, and browser automation — search engines, page fetching, authenticated sites',
67
73
  url: 'https://github.com/One-Mipham/skill-web-access',
68
74
  file: 'web-access.SKILL.md',
69
75
  category: 'Network',
70
76
  author: 'MiphamAI',
77
+ builtin: true,
71
78
  },
72
79
  {
73
80
  name: 'doc-generator',
74
- description: 'Generate API docs, READMEs, and changelogs',
81
+ description: 'Generate API docs, READMEs, and changelogs from code analysis',
75
82
  url: 'https://github.com/One-Mipham/skill-doc-generator',
76
83
  file: 'doc-generator.SKILL.md',
77
84
  category: 'Documentation',
78
85
  author: 'MiphamAI',
86
+ builtin: true,
79
87
  },
80
88
  {
81
89
  name: 'github-ops',
82
- description: 'GitHub PR/issue management and automation',
90
+ description: 'GitHub PR/issue management and automation — labels, milestones, reviews',
83
91
  url: 'https://github.com/One-Mipham/skill-github-ops',
84
92
  file: 'github-ops.SKILL.md',
85
93
  category: 'DevOps',
86
94
  author: 'MiphamAI',
95
+ builtin: true,
87
96
  },
88
97
  {
89
98
  name: 'security-review',
90
- description: 'Security audit and vulnerability scanning for code changes',
99
+ description:
100
+ 'Security audit and vulnerability scanning for code changes — OWASP, secrets, supply chain',
91
101
  url: 'https://github.com/One-Mipham/skill-security-review',
92
102
  file: 'security-review.SKILL.md',
93
103
  category: 'Security',
94
104
  author: 'MiphamAI',
105
+ builtin: true,
95
106
  },
96
107
  {
97
108
  name: 'frontend-design',
98
- description: 'Distinctive visual design guidance for UI components',
109
+ description: 'Distinctive visual design guidance for UI components — typography, color, layout',
99
110
  url: 'https://github.com/anthropics/skills',
100
111
  file: 'frontend-design.SKILL.md',
101
112
  category: 'Design',
@@ -146,6 +157,15 @@ export function installSkill(skillName: string): InstallResult {
146
157
  }
147
158
  }
148
159
 
160
+ // Built-in skills are already available — no download needed
161
+ if (entry.builtin) {
162
+ return {
163
+ success: true,
164
+ name: skillName,
165
+ message: `Skill "${skillName}" is already built-in and ready to use. No installation needed.`,
166
+ }
167
+ }
168
+
149
169
  const destDir = join(SKILLS_DIR)
150
170
  const destPath = join(destDir, `${skillName}.SKILL.md`)
151
171
 
package/src/ui/app.tsx CHANGED
@@ -3,6 +3,7 @@ import { Box, Text, useInput } from 'ink'
3
3
  import type { QueryEngine } from '../core/engine'
4
4
  import type { MiphamConfig } from '../shared/index.ts'
5
5
  import type { SkillsLoader } from '../skills/loader'
6
+ import type { PluginManager } from '../plugin/plugin-manager'
6
7
  import { AgentRegistry } from '../agent/agent-registry'
7
8
  import { ChatPanel } from './chat'
8
9
  import { InputBar } from './input'
@@ -22,6 +23,7 @@ interface AppProps {
22
23
  initialModel?: string
23
24
  lang?: string
24
25
  skillsLoader?: SkillsLoader
26
+ pluginManager?: PluginManager
25
27
  version?: string
26
28
  }
27
29
 
@@ -63,6 +65,7 @@ export function App({
63
65
  initialModel,
64
66
  lang: _lang,
65
67
  skillsLoader,
68
+ pluginManager,
66
69
  version,
67
70
  }: AppProps) {
68
71
  const [messages, setMessages] = useState<ChatMessage[]>([])
@@ -113,8 +116,9 @@ export function App({
113
116
  setFocusMode: (on: boolean) => setFocusMode(on),
114
117
  setGoal: (text: string) => setGoalText(text),
115
118
  skillsLoader,
119
+ pluginManager,
116
120
  }),
117
- [engine, config, providerId, modelId, skillsLoader],
121
+ [engine, config, providerId, modelId, skillsLoader, pluginManager],
118
122
  )
119
123
 
120
124
  const handleSubmit = useCallback(