@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.
- package/bin/mipham.ts +11 -0
- package/dist/mipham +0 -0
- package/package.json +1 -1
- package/skills/standard/web-access.SKILL.md +54 -0
- package/src/commands/loop-scaffold.ts +342 -0
- package/src/config/loader.ts +65 -1
- package/src/core/engine.ts +1 -0
- package/src/index.tsx +5 -0
- package/src/plugin/plugin-registry.ts +69 -0
- package/src/providers/openai-compat.ts +85 -15
- package/src/shared/constants.ts +9 -0
- package/src/skills/registry.ts +26 -6
- package/src/ui/app.tsx +5 -1
- package/src/ui/commands.ts +765 -6
|
@@ -150,30 +150,100 @@ export class OpenAICompatProvider implements ProviderInstance {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
private convertMessages(
|
|
154
|
-
|
|
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 (
|
|
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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
package/src/shared/constants.ts
CHANGED
|
@@ -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',
|
package/src/skills/registry.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
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:
|
|
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(
|