@miphamai/cli 0.5.7 → 0.5.9
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 +95 -0
- package/package.json +1 -1
- package/src/config/loader.ts +178 -14
- package/src/plugin/plugin-manager.ts +77 -0
- package/src/providers/anthropic.ts +12 -2
- package/src/providers/bootstrap.ts +11 -1
- package/src/providers/openai-compat.ts +17 -4
- package/src/shared/constants.ts +45 -0
- package/src/shared/update.ts +158 -0
- package/src/skills/loader.ts +13 -0
- package/src/skills/registry.ts +325 -0
- package/src/ui/app.tsx +1 -1
- package/src/ui/chat.tsx +11 -1
- package/src/ui/command-picker.tsx +145 -0
- package/src/ui/commands.ts +788 -164
- package/src/ui/input.tsx +95 -26
- package/dist/mipham +0 -0
package/src/ui/commands.ts
CHANGED
|
@@ -49,107 +49,127 @@ type CommandHandler = (
|
|
|
49
49
|
// Session & Identity
|
|
50
50
|
// ═══════════════════════════════════════════════════════════════
|
|
51
51
|
|
|
52
|
-
const helpCmd: CommandHandler = (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
── Session ──────────────────────────
|
|
57
|
-
/help Show this help
|
|
58
|
-
/version Show version info
|
|
59
|
-
/clear Clear conversation
|
|
60
|
-
/compact Compact context window
|
|
61
|
-
/context Show context stats
|
|
62
|
-
/status Session and system status
|
|
63
|
-
/cost Token usage estimate
|
|
64
|
-
/usage Detailed usage dashboard
|
|
65
|
-
/rename <name> Rename current session
|
|
66
|
-
/goal <text> Set session goal
|
|
67
|
-
/recap Summarize session so far
|
|
68
|
-
/export Export conversation to file
|
|
69
|
-
/doctor System diagnostics
|
|
70
|
-
/resume List saved sessions
|
|
71
|
-
/branch <name> Fork conversation
|
|
72
|
-
|
|
73
|
-
── History ─────────────────────────
|
|
74
|
-
/rewind Undo last AI turn
|
|
75
|
-
/undo Same as /rewind
|
|
76
|
-
/copy [N] Copy last response to clipboard
|
|
77
|
-
/focus Toggle focus view (last exchange only)
|
|
78
|
-
|
|
79
|
-
── Model & Provider ────────────────
|
|
80
|
-
/pick Open model picker (or Ctrl+P)
|
|
81
|
-
/model Show current model
|
|
82
|
-
/models List all available models
|
|
83
|
-
/provider Show current provider
|
|
84
|
-
/providers List configured providers
|
|
85
|
-
/switch <p> <m> Switch provider and model
|
|
86
|
-
/config View configuration
|
|
87
|
-
/fast [on|off] Toggle fast mode
|
|
88
|
-
/effort <lvl> Set reasoning effort (low|medium|high|xhigh|max)
|
|
89
|
-
/theme [dark|light|auto] Set terminal theme
|
|
90
|
-
|
|
91
|
-
── Tools & Skills ──────────────────
|
|
92
|
-
/tools List available tools (16 total)
|
|
93
|
-
/skills List loaded skills (14 built-in)
|
|
94
|
-
/reload-skills Reload all skills
|
|
95
|
-
/mcp MCP server status
|
|
96
|
-
|
|
97
|
-
── Workflow ────────────────────────
|
|
98
|
-
/plan Enter plan mode (read-only)
|
|
99
|
-
/no-plan Exit plan mode
|
|
100
|
-
/tdd TDD mode [stub]
|
|
101
|
-
/todos Task management
|
|
102
|
-
/tasks Background tasks
|
|
103
|
-
/review Code review workflow
|
|
104
|
-
/pr-comments PR review summary
|
|
105
|
-
/diff Show git diff
|
|
106
|
-
/workflows List workflow scripts
|
|
107
|
-
/loop <int> <p> Run prompt on interval
|
|
108
|
-
/schedule View scheduled tasks [stub]
|
|
109
|
-
|
|
110
|
-
── Project ─────────────────────────
|
|
111
|
-
/init Initialize .mipham config
|
|
112
|
-
/setup Guided project setup wizard
|
|
113
|
-
/permissions Show permission settings
|
|
114
|
-
/add-dir <dir> Add workspace directory
|
|
115
|
-
/security Security review checklist
|
|
116
|
-
/audit Same as /security
|
|
117
|
-
|
|
118
|
-
── Environment ─────────────────────
|
|
119
|
-
/upgrade Show upgrade instructions
|
|
120
|
-
/release-notes View version changelog
|
|
121
|
-
/ide IDE integration guide
|
|
122
|
-
/terminal-setup Shell & terminal config
|
|
123
|
-
/memory Manage AI memories
|
|
124
|
-
|
|
125
|
-
── Account ─────────────────────────
|
|
126
|
-
/login Show API key status
|
|
127
|
-
/logout Clear credentials guide
|
|
128
|
-
/feedback Send feedback
|
|
129
|
-
|
|
130
|
-
── Agents ──────────────────────────
|
|
131
|
-
/agents Agent view dashboard
|
|
132
|
-
/bg <prompt> Run a background agent task
|
|
133
|
-
|
|
134
|
-
Type /exit or Esc to quit.
|
|
135
|
-
`,
|
|
136
|
-
})
|
|
52
|
+
const helpCmd: CommandHandler = (ctx) => {
|
|
53
|
+
const skillCount = ctx.skillsLoader?.list().length ?? 14
|
|
54
|
+
const toolsCount = ctx.engine.getTools().size
|
|
55
|
+
const cmdCount = getCommandNames().length
|
|
137
56
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
57
|
+
return {
|
|
58
|
+
content: stripIndent`
|
|
59
|
+
Mipham Code v${PACKAGE_VERSION} — Commands
|
|
60
|
+
|
|
61
|
+
── Session ──────────────────────────
|
|
62
|
+
/help Show this help
|
|
63
|
+
/commands List all ${cmdCount} commands
|
|
64
|
+
/version Show version info
|
|
65
|
+
/clear Clear conversation
|
|
66
|
+
/compact Compact context window
|
|
67
|
+
/context Show context stats
|
|
68
|
+
/status Session and system status
|
|
69
|
+
/cost Token usage estimate
|
|
70
|
+
/usage Detailed usage dashboard
|
|
71
|
+
/rename <name> Rename current session
|
|
72
|
+
/goal <text> Set session goal
|
|
73
|
+
/recap Summarize session so far
|
|
74
|
+
/export Export conversation to file
|
|
75
|
+
/doctor System diagnostics
|
|
76
|
+
/resume List saved sessions
|
|
77
|
+
/branch <name> Fork conversation
|
|
78
|
+
|
|
79
|
+
── History ─────────────────────────
|
|
80
|
+
/rewind Undo last AI turn
|
|
81
|
+
/undo Same as /rewind
|
|
82
|
+
/copy [N] Copy last response to clipboard
|
|
83
|
+
/focus Toggle focus view (last exchange only)
|
|
84
|
+
|
|
85
|
+
── Model & Provider ────────────────
|
|
86
|
+
/pick Open model picker (or Ctrl+P)
|
|
87
|
+
/model Show current model
|
|
88
|
+
/models List all available models
|
|
89
|
+
/provider Show current provider
|
|
90
|
+
/providers List configured providers
|
|
91
|
+
/switch <p> <m> Switch provider and model
|
|
92
|
+
/config View configuration
|
|
93
|
+
/fast [on|off] Toggle fast mode
|
|
94
|
+
/effort <lvl> Set reasoning effort (low|medium|high|xhigh|max)
|
|
95
|
+
/theme [dark|light|auto] Set terminal theme
|
|
96
|
+
|
|
97
|
+
── Tools & Skills ──────────────────
|
|
98
|
+
/tools List available tools (${toolsCount} total)
|
|
99
|
+
/skills List loaded skills (${skillCount} built-in)
|
|
100
|
+
/reload-skills Reload all skills
|
|
101
|
+
/browse-skills Browse community skill marketplace
|
|
102
|
+
/install-skill Install a skill by name or URL
|
|
103
|
+
/remove-skill Remove an installed skill
|
|
104
|
+
/commands List all slash commands
|
|
105
|
+
/mcp MCP server status
|
|
106
|
+
|
|
107
|
+
── Workflow ────────────────────────
|
|
108
|
+
/plan Enter plan mode (read-only)
|
|
109
|
+
/no-plan Exit plan mode
|
|
110
|
+
/tdd TDD mode [stub]
|
|
111
|
+
/todos Task management
|
|
112
|
+
/tasks Background tasks
|
|
113
|
+
/review Code review workflow
|
|
114
|
+
/pr-comments PR review summary
|
|
115
|
+
/diff Show git diff
|
|
116
|
+
/workflows List workflow scripts
|
|
117
|
+
/loop <int> <p> Run prompt on interval
|
|
118
|
+
/schedule View scheduled tasks [stub]
|
|
119
|
+
|
|
120
|
+
── Project ─────────────────────────
|
|
121
|
+
/init Initialize .mipham config
|
|
122
|
+
/setup Guided project setup wizard
|
|
123
|
+
/recommend Analyze project + recommend setup
|
|
124
|
+
/permissions Show permission settings
|
|
125
|
+
/add-dir <dir> Add workspace directory
|
|
126
|
+
/security Security review checklist
|
|
127
|
+
/audit Same as /security
|
|
128
|
+
|
|
129
|
+
── Environment ─────────────────────
|
|
130
|
+
/upgrade Show upgrade instructions
|
|
131
|
+
/release-notes View version changelog
|
|
132
|
+
/ide IDE integration guide
|
|
133
|
+
/terminal-setup Shell & terminal config
|
|
134
|
+
/memory Manage AI memories
|
|
135
|
+
|
|
136
|
+
── Account ─────────────────────────
|
|
137
|
+
/login Show API key status
|
|
138
|
+
/logout Clear credentials guide
|
|
139
|
+
/feedback Send feedback
|
|
140
|
+
|
|
141
|
+
── Agents ──────────────────────────
|
|
142
|
+
/agents Agent view dashboard
|
|
143
|
+
/bg <prompt> Run a background agent task
|
|
144
|
+
|
|
145
|
+
Type /exit or Esc to quit.
|
|
146
|
+
`,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
141
149
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
const versionCmd: CommandHandler = (ctx) => {
|
|
151
|
+
const skillCounts = ctx.skillsLoader?.countByType()
|
|
152
|
+
const skillsLine = skillCounts
|
|
153
|
+
? `Skills: ${skillCounts.total} built-in (${skillCounts.standard} standard + ${skillCounts.mipham} mipham)`
|
|
154
|
+
: `Skills: (loader unavailable)`
|
|
155
|
+
const toolsCount = ctx.engine.getTools().size
|
|
146
156
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
157
|
+
return {
|
|
158
|
+
content: stripIndent`
|
|
159
|
+
Mipham Code v${ctx.version}
|
|
160
|
+
|
|
161
|
+
Runtime: Bun ${typeof Bun !== 'undefined' ? Bun.version : '(Node.js)'}
|
|
162
|
+
Platform: ${process.platform} ${process.arch}
|
|
163
|
+
Node: ${process.version}
|
|
164
|
+
CWD: ${process.cwd()}
|
|
165
|
+
|
|
166
|
+
Provider: ${ctx.providerId} / ${ctx.modelId}
|
|
167
|
+
Tools: ${toolsCount} built-in
|
|
168
|
+
${skillsLine}
|
|
169
|
+
License: Apache 2.0
|
|
170
|
+
`,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
153
173
|
|
|
154
174
|
const clearCmd: CommandHandler = (ctx) => {
|
|
155
175
|
ctx.engine.getContext().clear()
|
|
@@ -317,29 +337,25 @@ const toolsCmd: CommandHandler = (ctx) => {
|
|
|
317
337
|
return { content: `Available tools (${tools.size}):\n\n${sections.join('\n\n')}` }
|
|
318
338
|
}
|
|
319
339
|
|
|
320
|
-
const skillsCmd: CommandHandler = (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
14 skills loaded. Use Skill tool to invoke.
|
|
341
|
-
`,
|
|
342
|
-
})
|
|
340
|
+
const skillsCmd: CommandHandler = (ctx) => {
|
|
341
|
+
if (!ctx.skillsLoader) {
|
|
342
|
+
return { content: 'SkillsLoader not available.' }
|
|
343
|
+
}
|
|
344
|
+
const counts = ctx.skillsLoader.countByType()
|
|
345
|
+
const standard = ctx.skillsLoader.listByType('standard')
|
|
346
|
+
const mipham = ctx.skillsLoader.listByType('mipham')
|
|
347
|
+
|
|
348
|
+
const lines: string[] = [
|
|
349
|
+
`── Standard Skills (${counts.standard}) ──`,
|
|
350
|
+
...standard.map((s) => ` ${s.name.padEnd(28)} ${s.description}`),
|
|
351
|
+
'',
|
|
352
|
+
`── Mipham Exclusive (${counts.mipham}) ──`,
|
|
353
|
+
...mipham.map((s) => ` ${s.name.padEnd(20)} ${s.description}`),
|
|
354
|
+
'',
|
|
355
|
+
`${counts.total} skills loaded. Use Skill tool to invoke.`,
|
|
356
|
+
]
|
|
357
|
+
return { content: lines.join('\n') }
|
|
358
|
+
}
|
|
343
359
|
|
|
344
360
|
// ═══════════════════════════════════════════════════════════════
|
|
345
361
|
// Workflow
|
|
@@ -382,24 +398,89 @@ const todosCmd: CommandHandler = (_ctx) => ({
|
|
|
382
398
|
// Project
|
|
383
399
|
// ═══════════════════════════════════════════════════════════════
|
|
384
400
|
|
|
385
|
-
const initCmd: CommandHandler = (
|
|
386
|
-
|
|
387
|
-
|
|
401
|
+
const initCmd: CommandHandler = async (ctx) => {
|
|
402
|
+
const { existsSync, mkdirSync, writeFileSync } = await import('node:fs')
|
|
403
|
+
const { join } = await import('node:path')
|
|
404
|
+
const { homedir } = await import('node:os')
|
|
405
|
+
|
|
406
|
+
const home = homedir()
|
|
407
|
+
const userConfigPath = join(home, '.mipham', 'config.yml')
|
|
408
|
+
|
|
409
|
+
// Generate user-friendly config if it doesn't exist yet
|
|
410
|
+
if (!existsSync(userConfigPath)) {
|
|
411
|
+
mkdirSync(join(home, '.mipham'), { recursive: true })
|
|
412
|
+
|
|
413
|
+
const activeProviders = ctx.config.providers.filter((p) => p.status === 'active')
|
|
414
|
+
const providerYaml = activeProviders
|
|
415
|
+
.map((p) => {
|
|
416
|
+
const tips: Record<string, string> = {
|
|
417
|
+
anthropic: '# Get key: https://console.anthropic.com/',
|
|
418
|
+
openai: '# Get key: https://platform.openai.com/api-keys',
|
|
419
|
+
deepseek: '# Get key: https://platform.deepseek.com/api_keys',
|
|
420
|
+
kimi: '# Get key: https://platform.moonshot.cn/',
|
|
421
|
+
doubao: '# Get key: https://console.volcengine.com/ark',
|
|
422
|
+
hunyuan: '# Get key: https://console.cloud.tencent.com/hunyuan',
|
|
423
|
+
qwen: '# Get key: https://dashscope.console.aliyun.com/apiKey',
|
|
424
|
+
google: '# Get key: https://aistudio.google.com/apikey',
|
|
425
|
+
}
|
|
426
|
+
const comment = tips[p.id] || ''
|
|
427
|
+
const baseUrlLine = p.baseUrl ? `\n baseUrl: "${p.baseUrl}"` : ''
|
|
428
|
+
return ` ${comment}
|
|
429
|
+
- id: ${p.id}
|
|
430
|
+
name: "${p.name}"${baseUrlLine}
|
|
431
|
+
apiKey: "\${${p.id.toUpperCase()}_API_KEY}"`
|
|
432
|
+
})
|
|
433
|
+
.join('\n\n')
|
|
434
|
+
|
|
435
|
+
const configContent = `# Mipham Code — User Configuration
|
|
436
|
+
# Location: ~/.mipham/config.yml
|
|
437
|
+
# Docs: https://mipham.ai/code/docs/config
|
|
438
|
+
#
|
|
439
|
+
# ═══ Quick Start ═══
|
|
440
|
+
# 1. Replace the API key placeholders below with your real keys
|
|
441
|
+
# 2. Save the file
|
|
442
|
+
# 3. Run 'mipham' — it auto-detects configured providers
|
|
443
|
+
#
|
|
444
|
+
# ═══ Environment Variables (Alternative) ═══
|
|
445
|
+
# Instead of editing this file, you can set env vars:
|
|
446
|
+
# export ANTHROPIC_API_KEY="sk-ant-..."
|
|
447
|
+
# export OPENAI_API_KEY="sk-..."
|
|
448
|
+
# (The \${VAR} syntax below reads from environment variables)
|
|
449
|
+
|
|
450
|
+
# ── Defaults ──
|
|
451
|
+
defaultProvider: ${ctx.providerId}
|
|
452
|
+
defaultModel: ${ctx.modelId}
|
|
453
|
+
permission: ask
|
|
388
454
|
|
|
389
|
-
|
|
455
|
+
# ── Providers (${activeProviders.length} pre-configured — just add your API keys) ──
|
|
456
|
+
providers:
|
|
457
|
+
${providerYaml}
|
|
458
|
+
`
|
|
390
459
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
defaultModel: claude-sonnet-4-6
|
|
395
|
-
permission: auto
|
|
460
|
+
writeFileSync(userConfigPath, configContent, 'utf-8')
|
|
461
|
+
return {
|
|
462
|
+
content: `✅ Mipham Code initialized!
|
|
396
463
|
|
|
397
|
-
|
|
398
|
-
Config set defaultProvider anthropic
|
|
464
|
+
Created: ~/.mipham/config.yml (${activeProviders.length} providers pre-configured)
|
|
399
465
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
466
|
+
Next steps:
|
|
467
|
+
1. Edit ~/.mipham/config.yml — replace API key placeholders with your real keys
|
|
468
|
+
2. Run mipham to start
|
|
469
|
+
|
|
470
|
+
Providers configured:
|
|
471
|
+
${activeProviders.map((p) => ` • ${p.name} — ${p.id.toUpperCase()}_API_KEY`).join('\n')}
|
|
472
|
+
|
|
473
|
+
Tip: /setup for the full 6-step wizard.`,
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Config already exists — show status
|
|
478
|
+
return {
|
|
479
|
+
content: `~/.mipham/config.yml already exists.
|
|
480
|
+
|
|
481
|
+
Run /setup for the full wizard, or /config to view current settings.`,
|
|
482
|
+
}
|
|
483
|
+
}
|
|
403
484
|
|
|
404
485
|
// ═══════════════════════════════════════════════════════════════
|
|
405
486
|
// Phase 1 — New Session Commands
|
|
@@ -508,6 +589,83 @@ const reloadSkillsCmd: CommandHandler = (ctx) => {
|
|
|
508
589
|
}
|
|
509
590
|
}
|
|
510
591
|
|
|
592
|
+
// ═══════════════════════════════════════════════════════════════
|
|
593
|
+
// Skill Marketplace — Community skill registry + installation
|
|
594
|
+
// ═══════════════════════════════════════════════════════════════
|
|
595
|
+
|
|
596
|
+
const browseSkillsCmd: CommandHandler = async () => {
|
|
597
|
+
const { getAvailableSkills, listInstalledSkills } = await import('../skills/registry')
|
|
598
|
+
const available = getAvailableSkills()
|
|
599
|
+
const installed = new Set(
|
|
600
|
+
listInstalledSkills().map((f: string) => f.replace(/\.(SKILL\.)?md$/i, '')),
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
const categories = new Map<string, string[]>()
|
|
604
|
+
for (const s of available) {
|
|
605
|
+
const list = categories.get(s.category) || []
|
|
606
|
+
list.push(s.name)
|
|
607
|
+
categories.set(s.category, list)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const lines: string[] = [
|
|
611
|
+
'── Community Skills ──',
|
|
612
|
+
'',
|
|
613
|
+
`${available.length} skills available · ${installed.size} installed`,
|
|
614
|
+
'',
|
|
615
|
+
]
|
|
616
|
+
|
|
617
|
+
for (const [cat, names] of categories) {
|
|
618
|
+
lines.push(` ${cat}:`)
|
|
619
|
+
for (const name of names) {
|
|
620
|
+
const entry = available.find((s) => s.name === name)!
|
|
621
|
+
const marker = installed.has(name) ? '✅' : '⬜'
|
|
622
|
+
lines.push(` ${marker} /${name.padEnd(26)} ${entry.description}`)
|
|
623
|
+
}
|
|
624
|
+
lines.push('')
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
lines.push('Install: /install-skill <name>')
|
|
628
|
+
lines.push('Install from URL: /install-skill <github-url>')
|
|
629
|
+
lines.push('Remove: /remove-skill <name>')
|
|
630
|
+
|
|
631
|
+
return { content: lines.join('\n') }
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const installSkillCmd: CommandHandler = async (_ctx, args) => {
|
|
635
|
+
const { installSkill, installSkillFromUrl } = await import('../skills/registry')
|
|
636
|
+
|
|
637
|
+
const target = args[0]
|
|
638
|
+
if (!target) {
|
|
639
|
+
return { content: 'Usage: /install-skill <skill-name> or /install-skill <url>' }
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
let result: { success: boolean; name: string; message: string }
|
|
643
|
+
|
|
644
|
+
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
645
|
+
result = installSkillFromUrl(target)
|
|
646
|
+
} else {
|
|
647
|
+
result = installSkill(target)
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return {
|
|
651
|
+
content: result.success ? `✅ ${result.message}` : `❌ ${result.message}`,
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
const removeSkillCmd: CommandHandler = async (_ctx, args) => {
|
|
656
|
+
const { removeSkill } = await import('../skills/registry')
|
|
657
|
+
|
|
658
|
+
const name = args[0]
|
|
659
|
+
if (!name) {
|
|
660
|
+
return { content: 'Usage: /remove-skill <skill-name>' }
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const result = removeSkill(name)
|
|
664
|
+
return {
|
|
665
|
+
content: result.success ? `✅ ${result.message}` : `❌ ${result.message}`,
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
511
669
|
// ═══════════════════════════════════════════════════════════════
|
|
512
670
|
// Phase 1 — History & Checkpoint Commands
|
|
513
671
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -1135,24 +1293,72 @@ const memoryCmd: CommandHandler = async () => {
|
|
|
1135
1293
|
// Upgrade
|
|
1136
1294
|
// ═══════════════════════════════════════════════════════════════
|
|
1137
1295
|
|
|
1138
|
-
const upgradeCmd: CommandHandler = () =>
|
|
1139
|
-
|
|
1296
|
+
const upgradeCmd: CommandHandler = async () => {
|
|
1297
|
+
const { checkForUpdates, backupConfig, performUpdate, restoreConfig, getConfigPath } =
|
|
1298
|
+
await import('../shared/update')
|
|
1140
1299
|
|
|
1141
|
-
|
|
1300
|
+
const update = checkForUpdates()
|
|
1142
1301
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1302
|
+
if (!update.available) {
|
|
1303
|
+
return {
|
|
1304
|
+
content: `── Upgrade Mipham Code ──
|
|
1145
1305
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1306
|
+
Current version: v${update.current}
|
|
1307
|
+
Latest: v${update.latest}
|
|
1148
1308
|
|
|
1149
|
-
|
|
1150
|
-
• stable — recommended for most users
|
|
1151
|
-
• beta — early access to new features
|
|
1152
|
-
• nightly — latest commits, may be unstable
|
|
1309
|
+
✓ Already up to date.
|
|
1153
1310
|
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1311
|
+
To check manually: https://www.npmjs.com/package/@miphamai/cli`,
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// Update available — back up config and perform the upgrade
|
|
1316
|
+
const backupPath = backupConfig(`upgrade-v${update.current}`)
|
|
1317
|
+
|
|
1318
|
+
const lines: string[] = [
|
|
1319
|
+
'── Upgrade Mipham Code ──',
|
|
1320
|
+
'',
|
|
1321
|
+
`Current version: v${update.current}`,
|
|
1322
|
+
`Latest: v${update.latest}`,
|
|
1323
|
+
'',
|
|
1324
|
+
`→ New version available! Updating...`,
|
|
1325
|
+
'',
|
|
1326
|
+
]
|
|
1327
|
+
|
|
1328
|
+
if (backupPath) {
|
|
1329
|
+
lines.push(`Config backed up to: ${backupPath}`)
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
const ok = performUpdate(update.latest)
|
|
1333
|
+
|
|
1334
|
+
if (ok) {
|
|
1335
|
+
const configPath = getConfigPath()
|
|
1336
|
+
const { existsSync } = await import('node:fs')
|
|
1337
|
+
lines.push('')
|
|
1338
|
+
lines.push(`✓ Updated to @miphamai/cli v${update.latest}`)
|
|
1339
|
+
|
|
1340
|
+
if (existsSync(configPath)) {
|
|
1341
|
+
lines.push(`✓ Config preserved: ${configPath}`)
|
|
1342
|
+
} else if (backupPath) {
|
|
1343
|
+
if (restoreConfig(backupPath)) {
|
|
1344
|
+
lines.push('✓ Config restored from backup.')
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
lines.push('')
|
|
1349
|
+
lines.push('⚠ The running Mipham Code process is still the old version.')
|
|
1350
|
+
lines.push(' Run `mipham` again to use the new version, or `mipham --version` to verify.')
|
|
1351
|
+
} else {
|
|
1352
|
+
lines.push('')
|
|
1353
|
+
lines.push('✗ Update failed.')
|
|
1354
|
+
lines.push(` Try manually: ${NPM_UPDATE_COMMAND}`)
|
|
1355
|
+
if (backupPath) {
|
|
1356
|
+
lines.push(` Your config backup is at: ${backupPath}`)
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
return { content: lines.join('\n') }
|
|
1361
|
+
}
|
|
1156
1362
|
|
|
1157
1363
|
// ═══════════════════════════════════════════════════════════════
|
|
1158
1364
|
// No-Plan — exit plan mode
|
|
@@ -1255,6 +1461,168 @@ Tool execution is sandboxed to the project directory by default.`,
|
|
|
1255
1461
|
}
|
|
1256
1462
|
}
|
|
1257
1463
|
|
|
1464
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1465
|
+
// Recommend — analyze project and recommend setup (like Claude Code
|
|
1466
|
+
// automation recommender)
|
|
1467
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1468
|
+
|
|
1469
|
+
const recommendCmd: CommandHandler = async (ctx) => {
|
|
1470
|
+
const { existsSync, readFileSync } = await import('node:fs')
|
|
1471
|
+
const { join } = await import('node:path')
|
|
1472
|
+
const { getAvailableSkills } = await import('../skills/registry')
|
|
1473
|
+
|
|
1474
|
+
const cwd = process.cwd()
|
|
1475
|
+
const lines: string[] = ['── Mipham Code: Setup Recommendations ──', '', `Project: ${cwd}`, '']
|
|
1476
|
+
|
|
1477
|
+
// ── Detect project type ──
|
|
1478
|
+
const hasPackageJson = existsSync(join(cwd, 'package.json'))
|
|
1479
|
+
const hasTsConfig = existsSync(join(cwd, 'tsconfig.json'))
|
|
1480
|
+
const hasPyProject = existsSync(join(cwd, 'pyproject.toml'))
|
|
1481
|
+
const hasRequirements = existsSync(join(cwd, 'requirements.txt'))
|
|
1482
|
+
const hasDockerfile = existsSync(join(cwd, 'Dockerfile'))
|
|
1483
|
+
const hasGitHubActions = existsSync(join(cwd, '.github', 'workflows'))
|
|
1484
|
+
const hasNextConfig =
|
|
1485
|
+
existsSync(join(cwd, 'next.config.js')) || existsSync(join(cwd, 'next.config.ts'))
|
|
1486
|
+
const hasVueConfig =
|
|
1487
|
+
existsSync(join(cwd, 'vite.config.ts')) || existsSync(join(cwd, 'vite.config.js'))
|
|
1488
|
+
const hasTailwind =
|
|
1489
|
+
existsSync(join(cwd, 'tailwind.config.ts')) || existsSync(join(cwd, 'tailwind.config.js'))
|
|
1490
|
+
|
|
1491
|
+
let pkgData: Record<string, unknown> = {}
|
|
1492
|
+
if (hasPackageJson) {
|
|
1493
|
+
try {
|
|
1494
|
+
pkgData = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'))
|
|
1495
|
+
} catch {
|
|
1496
|
+
/* ignore */
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
const deps = {
|
|
1500
|
+
...((pkgData.dependencies as Record<string, string>) || {}),
|
|
1501
|
+
...((pkgData.devDependencies as Record<string, string>) || {}),
|
|
1502
|
+
}
|
|
1503
|
+
const isTypeScript = hasTsConfig || 'typescript' in deps
|
|
1504
|
+
const isReact = 'react' in deps || 'next' in deps
|
|
1505
|
+
const isVue = 'vue' in deps
|
|
1506
|
+
const isNode = hasPackageJson
|
|
1507
|
+
const isPython = hasPyProject || hasRequirements
|
|
1508
|
+
const isFastAPI = 'fastapi' in deps
|
|
1509
|
+
const isNextJS = 'next' in deps
|
|
1510
|
+
const isExpress = 'express' in deps || 'fastify' in deps
|
|
1511
|
+
const isDocker = hasDockerfile
|
|
1512
|
+
|
|
1513
|
+
// ── Detection summary ──
|
|
1514
|
+
const tags: string[] = []
|
|
1515
|
+
if (isTypeScript) tags.push('TypeScript')
|
|
1516
|
+
if (isReact) tags.push('React')
|
|
1517
|
+
if (isVue) tags.push('Vue')
|
|
1518
|
+
if (isNextJS) tags.push('Next.js')
|
|
1519
|
+
if (isExpress) tags.push('Node.js API')
|
|
1520
|
+
if (isFastAPI) tags.push('FastAPI')
|
|
1521
|
+
if (isPython) tags.push('Python')
|
|
1522
|
+
if (isDocker) tags.push('Docker')
|
|
1523
|
+
if (hasTailwind) tags.push('Tailwind CSS')
|
|
1524
|
+
if (hasGitHubActions) tags.push('CI/CD')
|
|
1525
|
+
|
|
1526
|
+
lines.push('── Detected Stack ──')
|
|
1527
|
+
lines.push('')
|
|
1528
|
+
if (tags.length > 0) {
|
|
1529
|
+
lines.push(` ${tags.join(' · ')}`)
|
|
1530
|
+
} else {
|
|
1531
|
+
lines.push(' (generic project — no specific framework detected)')
|
|
1532
|
+
}
|
|
1533
|
+
lines.push('')
|
|
1534
|
+
|
|
1535
|
+
// ── Skill recommendations ──
|
|
1536
|
+
const communitySkills = getAvailableSkills()
|
|
1537
|
+
const recommendedSkills: string[] = []
|
|
1538
|
+
|
|
1539
|
+
// Always useful
|
|
1540
|
+
recommendedSkills.push('code-review')
|
|
1541
|
+
recommendedSkills.push('systematic-debugging')
|
|
1542
|
+
|
|
1543
|
+
if (isTypeScript || isNode) {
|
|
1544
|
+
recommendedSkills.push('github-ops')
|
|
1545
|
+
}
|
|
1546
|
+
if (isReact || isVue || isNextJS) {
|
|
1547
|
+
recommendedSkills.push('frontend-design')
|
|
1548
|
+
}
|
|
1549
|
+
if (hasGitHubActions) {
|
|
1550
|
+
recommendedSkills.push('security-review')
|
|
1551
|
+
}
|
|
1552
|
+
if (isPython) {
|
|
1553
|
+
recommendedSkills.push('doc-generator')
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Filter to only those in the registry
|
|
1557
|
+
const available = recommendedSkills.filter((name) => communitySkills.some((s) => s.name === name))
|
|
1558
|
+
|
|
1559
|
+
lines.push('── Recommended Skills ──')
|
|
1560
|
+
lines.push('')
|
|
1561
|
+
if (available.length > 0) {
|
|
1562
|
+
for (const name of available) {
|
|
1563
|
+
const entry = communitySkills.find((s) => s.name === name)!
|
|
1564
|
+
lines.push(` /install-skill ${name.padEnd(26)} ${entry.description}`)
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
lines.push(' /browse-skills Browse all community skills')
|
|
1568
|
+
lines.push('')
|
|
1569
|
+
|
|
1570
|
+
// ── Provider recommendations ──
|
|
1571
|
+
const activeProviders = ctx.config.providers.filter((p) => p.status === 'active')
|
|
1572
|
+
const configured = activeProviders.filter((p) => p.apiKey && p.apiKey.trim() !== '')
|
|
1573
|
+
|
|
1574
|
+
lines.push('── Provider Status ──')
|
|
1575
|
+
lines.push('')
|
|
1576
|
+
if (configured.length === 0) {
|
|
1577
|
+
lines.push(' ⚠ No providers have API keys configured.')
|
|
1578
|
+
lines.push(' Run /setup 2 to configure providers.')
|
|
1579
|
+
lines.push('')
|
|
1580
|
+
lines.push(' Recommended for this project:')
|
|
1581
|
+
if (isTypeScript || isNode || isReact) {
|
|
1582
|
+
lines.push(' • anthropic — Claude (code generation, review)')
|
|
1583
|
+
lines.push(' • openai — GPT-5 (general purpose)')
|
|
1584
|
+
}
|
|
1585
|
+
if (isPython) {
|
|
1586
|
+
lines.push(' • anthropic — Claude (data science, ML)')
|
|
1587
|
+
}
|
|
1588
|
+
} else {
|
|
1589
|
+
lines.push(` ${configured.length}/${activeProviders.length} providers configured`)
|
|
1590
|
+
for (const p of configured) {
|
|
1591
|
+
lines.push(` ✅ ${p.id.padEnd(14)} ${p.name}`)
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
lines.push('')
|
|
1595
|
+
|
|
1596
|
+
// ── Config recommendations ──
|
|
1597
|
+
lines.push('── Configuration Tips ──')
|
|
1598
|
+
lines.push('')
|
|
1599
|
+
|
|
1600
|
+
const hasProjectMipham = existsSync(join(cwd, '.mipham'))
|
|
1601
|
+
if (!hasProjectMipham) {
|
|
1602
|
+
lines.push(' /setup 1 Initialize .mipham/ + MIPHAM.md + config.yml')
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
const { listInstalledSkills } = await import('../skills/registry')
|
|
1606
|
+
const installed = listInstalledSkills()
|
|
1607
|
+
if (installed.length === 0 && available.length > 0) {
|
|
1608
|
+
lines.push(' Tip: Install recommended skills above for better AI assistance')
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
if (isDocker && !hasProjectMipham) {
|
|
1612
|
+
lines.push(' Tip: Add .mipham/ to .dockerignore for smaller images')
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (hasGitHubActions) {
|
|
1616
|
+
lines.push(' /setup 5 Configure tool permissions for CI/CD safety')
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
lines.push(' /setup Full setup wizard (6 steps)')
|
|
1620
|
+
lines.push(' /help All commands')
|
|
1621
|
+
lines.push('')
|
|
1622
|
+
|
|
1623
|
+
return { content: lines.join('\n') }
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1258
1626
|
// ═══════════════════════════════════════════════════════════════
|
|
1259
1627
|
// Setup — guided project initialization (mirrors Claude Code /setup)
|
|
1260
1628
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -1356,17 +1724,60 @@ async function setupStep1(ctx: CommandContext): Promise<CommandResult> {
|
|
|
1356
1724
|
|
|
1357
1725
|
// Create project config if missing
|
|
1358
1726
|
if (!existsSync(configPath)) {
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1727
|
+
// Generate a user-friendly config with all providers pre-populated.
|
|
1728
|
+
// Users just need to replace the API key placeholders with their real keys.
|
|
1729
|
+
const activeProviders = ctx.config.providers.filter((p) => p.status === 'active')
|
|
1730
|
+
const providerYaml = activeProviders
|
|
1731
|
+
.map((p) => {
|
|
1732
|
+
const comment =
|
|
1733
|
+
p.id === 'anthropic'
|
|
1734
|
+
? '# Get key: https://console.anthropic.com/'
|
|
1735
|
+
: p.id === 'openai'
|
|
1736
|
+
? '# Get key: https://platform.openai.com/api-keys'
|
|
1737
|
+
: p.id === 'deepseek'
|
|
1738
|
+
? '# Get key: https://platform.deepseek.com/api_keys'
|
|
1739
|
+
: p.id === 'kimi'
|
|
1740
|
+
? '# Get key: https://platform.moonshot.cn/'
|
|
1741
|
+
: p.id === 'doubao'
|
|
1742
|
+
? '# Get key: https://console.volcengine.com/ark'
|
|
1743
|
+
: p.id === 'hunyuan'
|
|
1744
|
+
? '# Get key: https://console.cloud.tencent.com/hunyuan'
|
|
1745
|
+
: p.id === 'qwen'
|
|
1746
|
+
? '# Get key: https://dashscope.console.aliyun.com/apiKey'
|
|
1747
|
+
: p.id === 'google'
|
|
1748
|
+
? '# Get key: https://aistudio.google.com/apikey'
|
|
1749
|
+
: ''
|
|
1750
|
+
const baseUrlLine = p.baseUrl ? `\n baseUrl: "${p.baseUrl}"` : ''
|
|
1751
|
+
return ` ${comment}
|
|
1752
|
+
- id: ${p.id}
|
|
1753
|
+
name: "${p.name}"${baseUrlLine}
|
|
1754
|
+
apiKey: "\${${p.id.toUpperCase()}_API_KEY}"`
|
|
1755
|
+
})
|
|
1756
|
+
.join('\n\n')
|
|
1757
|
+
|
|
1758
|
+
const defaultConfig = `# Mipham Code — User Configuration
|
|
1759
|
+
# Location: ~/.mipham/config.yml
|
|
1760
|
+
# Docs: https://mipham.ai/code/docs/config
|
|
1761
|
+
#
|
|
1762
|
+
# ═══ Quick Start ═══
|
|
1763
|
+
# 1. Set your API keys below (replace the placeholder values)
|
|
1764
|
+
# 2. Save the file
|
|
1765
|
+
# 3. Run 'mipham' — it auto-detects configured providers
|
|
1766
|
+
#
|
|
1767
|
+
# ═══ Environment Variables ═══
|
|
1768
|
+
# Instead of editing this file, you can set env vars:
|
|
1769
|
+
# export ANTHROPIC_API_KEY="sk-ant-..."
|
|
1770
|
+
# export OPENAI_API_KEY="sk-..."
|
|
1771
|
+
# (The \${VAR} syntax below reads from environment variables)
|
|
1772
|
+
|
|
1773
|
+
# ── Defaults ──
|
|
1362
1774
|
defaultProvider: ${ctx.providerId}
|
|
1363
1775
|
defaultModel: ${ctx.modelId}
|
|
1364
1776
|
permission: ask
|
|
1365
1777
|
|
|
1366
|
-
#
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
# apiKey: \$ANTHROPIC_API_KEY
|
|
1778
|
+
# ── Providers (8 configured, just add your API keys) ──
|
|
1779
|
+
providers:
|
|
1780
|
+
${providerYaml}
|
|
1370
1781
|
`
|
|
1371
1782
|
writeFileSync(configPath, defaultConfig, 'utf-8')
|
|
1372
1783
|
created.push('.mipham/config.yml')
|
|
@@ -1500,16 +1911,19 @@ async function setupStep3(ctx: CommandContext): Promise<CommandResult> {
|
|
|
1500
1911
|
return { content: lines.join('\n') }
|
|
1501
1912
|
}
|
|
1502
1913
|
|
|
1503
|
-
async function setupStep4(
|
|
1914
|
+
async function setupStep4(ctx: CommandContext): Promise<CommandResult> {
|
|
1915
|
+
const counts = ctx.skillsLoader?.countByType() ?? { standard: 0, mipham: 0, total: 0 }
|
|
1916
|
+
const standardNames = ctx.skillsLoader?.getNamesByType('standard') ?? []
|
|
1917
|
+
const miphamNames = ctx.skillsLoader?.getNamesByType('mipham') ?? []
|
|
1918
|
+
|
|
1504
1919
|
return {
|
|
1505
1920
|
content: `── Step 4: Install Skills ──
|
|
1506
1921
|
|
|
1507
1922
|
Skills extend Mipham Code with specialized capabilities.
|
|
1508
1923
|
|
|
1509
|
-
Built-in skills (
|
|
1510
|
-
Standard (
|
|
1511
|
-
|
|
1512
|
-
Mipham (2): om-model-optimize, om-security
|
|
1924
|
+
Built-in skills (${counts.total} total):
|
|
1925
|
+
Standard (${counts.standard}): ${standardNames.join(', ')}
|
|
1926
|
+
Mipham (${counts.mipham}): ${miphamNames.join(', ')}
|
|
1513
1927
|
|
|
1514
1928
|
Community skills:
|
|
1515
1929
|
Coming soon — the Mipham Code skills marketplace will let you
|
|
@@ -1705,6 +2119,7 @@ const securityCmd: CommandHandler = async () => {
|
|
|
1705
2119
|
}
|
|
1706
2120
|
|
|
1707
2121
|
// 2. Check for hardcoded secrets (quick grep for common patterns)
|
|
2122
|
+
// ⚠ Security: results are redacted — only file:line locations are shown, never values
|
|
1708
2123
|
try {
|
|
1709
2124
|
const { execSync } = await import('node:child_process')
|
|
1710
2125
|
const secretPatterns = execSync(
|
|
@@ -1712,11 +2127,20 @@ const securityCmd: CommandHandler = async () => {
|
|
|
1712
2127
|
{ encoding: 'utf-8', timeout: 5000 },
|
|
1713
2128
|
).trim()
|
|
1714
2129
|
if (secretPatterns) {
|
|
2130
|
+
// Redact the actual values — only show file:line locations
|
|
2131
|
+
const redacted = secretPatterns
|
|
2132
|
+
.split('\n')
|
|
2133
|
+
.map((l) => {
|
|
2134
|
+
const colonIdx = l.indexOf(':')
|
|
2135
|
+
const secondColon = l.indexOf(':', colonIdx + 1)
|
|
2136
|
+
if (secondColon > 0) {
|
|
2137
|
+
return ' ' + l.slice(0, secondColon) + ' [VALUE REDACTED]'
|
|
2138
|
+
}
|
|
2139
|
+
return ' ' + l + ' [REDACTED]'
|
|
2140
|
+
})
|
|
2141
|
+
.join('\n')
|
|
1715
2142
|
findings.push(
|
|
1716
|
-
|
|
1717
|
-
.split('\n')
|
|
1718
|
-
.map((l) => ' ' + l)
|
|
1719
|
-
.join('\n')}`,
|
|
2143
|
+
`⚠ Hardcoded secrets detected (values redacted for security):\n${redacted}\n\n Replace with env vars: \${VAR_NAME} syntax`,
|
|
1720
2144
|
)
|
|
1721
2145
|
} else {
|
|
1722
2146
|
ok.push('No hardcoded secrets detected')
|
|
@@ -2273,6 +2697,118 @@ const artifactBaseCmd: CommandHandler = (ctx, args) => {
|
|
|
2273
2697
|
// Remaining low-priority stubs (backend not yet available)
|
|
2274
2698
|
// ═══════════════════════════════════════════════════════════════
|
|
2275
2699
|
|
|
2700
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2701
|
+
// Commands — list all registered slash commands
|
|
2702
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2703
|
+
|
|
2704
|
+
const commandsListCmd: CommandHandler = () => {
|
|
2705
|
+
const names = getCommandNames()
|
|
2706
|
+
const categories: Record<string, string[]> = {
|
|
2707
|
+
'Session & Identity': [],
|
|
2708
|
+
History: [],
|
|
2709
|
+
'Model & Provider': [],
|
|
2710
|
+
'Tools & Skills': [],
|
|
2711
|
+
Workflow: [],
|
|
2712
|
+
Project: [],
|
|
2713
|
+
Environment: [],
|
|
2714
|
+
Account: [],
|
|
2715
|
+
Agents: [],
|
|
2716
|
+
Artifacts: [],
|
|
2717
|
+
Other: [],
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
const catMap: Record<string, string> = {
|
|
2721
|
+
'/help': 'Session & Identity',
|
|
2722
|
+
'/version': 'Session & Identity',
|
|
2723
|
+
'/clear': 'Session & Identity',
|
|
2724
|
+
'/exit': 'Session & Identity',
|
|
2725
|
+
'/quit': 'Session & Identity',
|
|
2726
|
+
'/compact': 'Session & Identity',
|
|
2727
|
+
'/context': 'Session & Identity',
|
|
2728
|
+
'/status': 'Session & Identity',
|
|
2729
|
+
'/cost': 'Session & Identity',
|
|
2730
|
+
'/usage': 'Session & Identity',
|
|
2731
|
+
'/rename': 'Session & Identity',
|
|
2732
|
+
'/goal': 'Session & Identity',
|
|
2733
|
+
'/recap': 'Session & Identity',
|
|
2734
|
+
'/export': 'Session & Identity',
|
|
2735
|
+
'/doctor': 'Session & Identity',
|
|
2736
|
+
'/resume': 'Session & Identity',
|
|
2737
|
+
'/branch': 'Session & Identity',
|
|
2738
|
+
'/rewind': 'History',
|
|
2739
|
+
'/undo': 'History',
|
|
2740
|
+
'/copy': 'History',
|
|
2741
|
+
'/focus': 'History',
|
|
2742
|
+
'/pick': 'Model & Provider',
|
|
2743
|
+
'/model': 'Model & Provider',
|
|
2744
|
+
'/models': 'Model & Provider',
|
|
2745
|
+
'/provider': 'Model & Provider',
|
|
2746
|
+
'/providers': 'Model & Provider',
|
|
2747
|
+
'/switch': 'Model & Provider',
|
|
2748
|
+
'/config': 'Model & Provider',
|
|
2749
|
+
'/fast': 'Model & Provider',
|
|
2750
|
+
'/effort': 'Model & Provider',
|
|
2751
|
+
'/theme': 'Model & Provider',
|
|
2752
|
+
'/upgrade': 'Model & Provider',
|
|
2753
|
+
'/tools': 'Tools & Skills',
|
|
2754
|
+
'/skills': 'Tools & Skills',
|
|
2755
|
+
'/reload-skills': 'Tools & Skills',
|
|
2756
|
+
'/browse-skills': 'Tools & Skills',
|
|
2757
|
+
'/install-skill': 'Tools & Skills',
|
|
2758
|
+
'/remove-skill': 'Tools & Skills',
|
|
2759
|
+
'/mcp': 'Tools & Skills',
|
|
2760
|
+
'/commands': 'Tools & Skills',
|
|
2761
|
+
'/plan': 'Workflow',
|
|
2762
|
+
'/no-plan': 'Workflow',
|
|
2763
|
+
'/tdd': 'Workflow',
|
|
2764
|
+
'/todos': 'Workflow',
|
|
2765
|
+
'/tasks': 'Workflow',
|
|
2766
|
+
'/review': 'Workflow',
|
|
2767
|
+
'/pr-comments': 'Workflow',
|
|
2768
|
+
'/diff': 'Workflow',
|
|
2769
|
+
'/workflows': 'Workflow',
|
|
2770
|
+
'/loop': 'Workflow',
|
|
2771
|
+
'/init': 'Project',
|
|
2772
|
+
'/setup': 'Project',
|
|
2773
|
+
'/permissions': 'Project',
|
|
2774
|
+
'/add-dir': 'Project',
|
|
2775
|
+
'/recommend': 'Project',
|
|
2776
|
+
'/security': 'Project',
|
|
2777
|
+
'/audit': 'Project',
|
|
2778
|
+
'/ide': 'Environment',
|
|
2779
|
+
'/terminal-setup': 'Environment',
|
|
2780
|
+
'/memory': 'Environment',
|
|
2781
|
+
'/release-notes': 'Environment',
|
|
2782
|
+
'/login': 'Account',
|
|
2783
|
+
'/logout': 'Account',
|
|
2784
|
+
'/feedback': 'Account',
|
|
2785
|
+
'/agents': 'Agents',
|
|
2786
|
+
'/bg': 'Agents',
|
|
2787
|
+
'/artifact': 'Artifacts',
|
|
2788
|
+
'/schedule': 'Other',
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
for (const name of names) {
|
|
2792
|
+
const cat = catMap[name] ?? 'Other'
|
|
2793
|
+
categories[cat]?.push(name)
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
const lines: string[] = [`── All Slash Commands (${names.length}) ──`, '']
|
|
2797
|
+
|
|
2798
|
+
for (const [cat, cmds] of Object.entries(categories)) {
|
|
2799
|
+
if (cmds.length === 0) continue
|
|
2800
|
+
lines.push(`── ${cat} (${cmds.length}) ──`)
|
|
2801
|
+
for (const c of cmds) {
|
|
2802
|
+
lines.push(` ${c}`)
|
|
2803
|
+
}
|
|
2804
|
+
lines.push('')
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
lines.push('Type /help for details, or /<command> to run.')
|
|
2808
|
+
|
|
2809
|
+
return { content: lines.join('\n') }
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2276
2812
|
// ═══════════════════════════════════════════════════════════════
|
|
2277
2813
|
// Command Registry
|
|
2278
2814
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -2314,6 +2850,10 @@ registry.set('/effort', effortCmd)
|
|
|
2314
2850
|
registry.set('/tools', toolsCmd)
|
|
2315
2851
|
registry.set('/skills', skillsCmd)
|
|
2316
2852
|
registry.set('/reload-skills', reloadSkillsCmd)
|
|
2853
|
+
registry.set('/browse-skills', browseSkillsCmd)
|
|
2854
|
+
registry.set('/install-skill', installSkillCmd)
|
|
2855
|
+
registry.set('/remove-skill', removeSkillCmd)
|
|
2856
|
+
registry.set('/commands', commandsListCmd)
|
|
2317
2857
|
|
|
2318
2858
|
// Workflow
|
|
2319
2859
|
registry.set('/plan', planCmd)
|
|
@@ -2337,6 +2877,7 @@ registry.set('/upgrade', upgradeCmd)
|
|
|
2337
2877
|
// Project
|
|
2338
2878
|
registry.set('/init', initCmd)
|
|
2339
2879
|
registry.set('/setup', setupCmd)
|
|
2880
|
+
registry.set('/recommend', recommendCmd)
|
|
2340
2881
|
registry.set('/permissions', permissionsCmd)
|
|
2341
2882
|
registry.set('/add-dir', addDirCmd)
|
|
2342
2883
|
registry.set('/security', securityCmd)
|
|
@@ -2375,6 +2916,89 @@ export function getCommandNames(): string[] {
|
|
|
2375
2916
|
return Array.from(registry.keys()).sort()
|
|
2376
2917
|
}
|
|
2377
2918
|
|
|
2919
|
+
export interface CommandEntry {
|
|
2920
|
+
name: string
|
|
2921
|
+
description: string
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
2925
|
+
'/help': 'Show help',
|
|
2926
|
+
'/commands': 'List all slash commands',
|
|
2927
|
+
'/version': 'Show version info',
|
|
2928
|
+
'/clear': 'Clear conversation',
|
|
2929
|
+
'/exit': 'Exit Mipham Code',
|
|
2930
|
+
'/quit': 'Exit Mipham Code',
|
|
2931
|
+
'/compact': 'Compact context window',
|
|
2932
|
+
'/context': 'Show context stats',
|
|
2933
|
+
'/status': 'Session and system status',
|
|
2934
|
+
'/cost': 'Token usage estimate',
|
|
2935
|
+
'/usage': 'Detailed usage dashboard',
|
|
2936
|
+
'/rename': 'Rename current session',
|
|
2937
|
+
'/goal': 'Set session goal',
|
|
2938
|
+
'/recap': 'Summarize session so far',
|
|
2939
|
+
'/export': 'Export conversation to file',
|
|
2940
|
+
'/doctor': 'System diagnostics',
|
|
2941
|
+
'/resume': 'List saved sessions',
|
|
2942
|
+
'/branch': 'Fork conversation',
|
|
2943
|
+
'/rewind': 'Undo last AI turn',
|
|
2944
|
+
'/undo': 'Same as /rewind',
|
|
2945
|
+
'/copy': 'Copy last response to clipboard',
|
|
2946
|
+
'/focus': 'Toggle focus view',
|
|
2947
|
+
'/pick': 'Open model picker',
|
|
2948
|
+
'/model': 'Show current model',
|
|
2949
|
+
'/models': 'List all available models',
|
|
2950
|
+
'/provider': 'Show current provider',
|
|
2951
|
+
'/providers': 'List configured providers',
|
|
2952
|
+
'/switch': 'Switch provider and model',
|
|
2953
|
+
'/config': 'View configuration',
|
|
2954
|
+
'/fast': 'Toggle fast mode',
|
|
2955
|
+
'/effort': 'Set reasoning effort',
|
|
2956
|
+
'/theme': 'Set terminal theme',
|
|
2957
|
+
'/tools': 'List available tools',
|
|
2958
|
+
'/skills': 'List loaded skills',
|
|
2959
|
+
'/reload-skills': 'Reload all skills',
|
|
2960
|
+
'/browse-skills': 'Browse community skill marketplace',
|
|
2961
|
+
'/install-skill': 'Install a skill by name or URL',
|
|
2962
|
+
'/remove-skill': 'Remove an installed skill',
|
|
2963
|
+
'/mcp': 'MCP server status',
|
|
2964
|
+
'/plan': 'Enter plan mode',
|
|
2965
|
+
'/no-plan': 'Exit plan mode',
|
|
2966
|
+
'/tdd': 'TDD mode',
|
|
2967
|
+
'/todos': 'Task management',
|
|
2968
|
+
'/tasks': 'Background tasks',
|
|
2969
|
+
'/review': 'Code review workflow',
|
|
2970
|
+
'/pr-comments': 'PR review summary',
|
|
2971
|
+
'/diff': 'Show git diff',
|
|
2972
|
+
'/workflows': 'List workflow scripts',
|
|
2973
|
+
'/loop': 'Run prompt on interval',
|
|
2974
|
+
'/init': 'Initialize .mipham config',
|
|
2975
|
+
'/setup': 'Guided project setup wizard',
|
|
2976
|
+
'/permissions': 'Show permission settings',
|
|
2977
|
+
'/add-dir': 'Add workspace directory',
|
|
2978
|
+
'/recommend': 'Analyze project + recommend skills & setup',
|
|
2979
|
+
'/security': 'Security review checklist',
|
|
2980
|
+
'/audit': 'Same as /security',
|
|
2981
|
+
'/ide': 'IDE integration guide',
|
|
2982
|
+
'/terminal-setup': 'Shell & terminal config',
|
|
2983
|
+
'/memory': 'Manage AI memories',
|
|
2984
|
+
'/release-notes': 'View version changelog',
|
|
2985
|
+
'/upgrade': 'Show upgrade instructions',
|
|
2986
|
+
'/login': 'Show API key status',
|
|
2987
|
+
'/logout': 'Clear credentials guide',
|
|
2988
|
+
'/feedback': 'Send feedback',
|
|
2989
|
+
'/agents': 'Agent view dashboard',
|
|
2990
|
+
'/bg': 'Run a background agent task',
|
|
2991
|
+
'/artifact': 'Manage artifacts',
|
|
2992
|
+
'/schedule': 'View scheduled tasks',
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
export function getCommandList(): CommandEntry[] {
|
|
2996
|
+
return getCommandNames().map((name) => ({
|
|
2997
|
+
name,
|
|
2998
|
+
description: COMMAND_DESCRIPTIONS[name] ?? '',
|
|
2999
|
+
}))
|
|
3000
|
+
}
|
|
3001
|
+
|
|
2378
3002
|
export function looksLikeSlashCommand(input: string): boolean {
|
|
2379
3003
|
return input.trim().startsWith('/')
|
|
2380
3004
|
}
|