@miphamai/cli 0.69.0 → 0.70.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.
- package/package.json +1 -1
- package/src/commands/loop-scaffold.ts +15 -44
- package/src/config/loader.ts +56 -1
- package/src/core/claude-md-fix.ts +28 -0
- package/src/core/fix-code.ts +167 -0
- package/src/core/fix.ts +176 -0
- package/src/core/hooks-config.ts +10 -5
- package/src/core/hooks-executor.ts +84 -5
- package/src/core/instructions.ts +2 -2
- package/src/i18n-core/locales/en-US.json +21 -1
- package/src/i18n-core/locales/zh-CN.json +21 -1
- package/src/index.tsx +12 -0
- package/src/shared/package-info.ts +1 -1
- package/src/shared/types.ts +2 -0
- package/src/skills/community-registry.json +16 -0
- package/src/skills/marketplace.ts +233 -0
- package/src/skills/registry.ts +77 -63
- package/src/ui/commands.ts +311 -33
package/src/ui/commands.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { McpClient } from '../mcp/client'
|
|
|
14
14
|
import { buildCapabilityReport } from '../core/capability-inventory'
|
|
15
15
|
import { InstructionsLoader } from '../core/instructions'
|
|
16
16
|
import { findDerivableSections, DERIVABLE_HINTS } from '../core/claude-md-audit'
|
|
17
|
+
import { fixDoctor, fixConfig, fixCache, selectRepoClaudeFiles } from '../core/fix'
|
|
18
|
+
import { fixCodeTarget } from '../core/fix-code'
|
|
17
19
|
import { runCrsiModification, approvePending, rejectPending, hasPending } from '../core/crsi-modify'
|
|
18
20
|
import {
|
|
19
21
|
produceCrsiProposal,
|
|
@@ -32,7 +34,11 @@ import {
|
|
|
32
34
|
import { prefilterProposal } from '../core/proposal-guard'
|
|
33
35
|
import { runEval, appendEvalScore } from '../core/eval-harness'
|
|
34
36
|
import { listRewardFns } from '../core/reward-fn'
|
|
35
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
runTaskPerformance,
|
|
39
|
+
measureSkillDeltaRepeated,
|
|
40
|
+
stripCodeFences,
|
|
41
|
+
} from '../core/task-performance'
|
|
36
42
|
import { randomUUID } from 'node:crypto'
|
|
37
43
|
import {
|
|
38
44
|
buildImprovementReport,
|
|
@@ -45,7 +51,7 @@ import {
|
|
|
45
51
|
} from '../core/improvement-track'
|
|
46
52
|
import { NPM_UPDATE_COMMAND, PACKAGE_VERSION, COAUTHOR_TRAILER } from '../shared/index.ts'
|
|
47
53
|
import { getPreference } from '../config/preferences'
|
|
48
|
-
import { loadCrossSessionConfig } from '../config/loader'
|
|
54
|
+
import { loadCrossSessionConfig, tryRestoreFromBackup } from '../config/loader'
|
|
49
55
|
import { getMemoryManager } from '../core/memory/memory-loader'
|
|
50
56
|
import { stripIndent } from './strip-indent.js'
|
|
51
57
|
import { createT } from '../i18n-core/t'
|
|
@@ -2359,9 +2365,9 @@ const installSkillCmd: CommandHandler = async (ctx, args) => {
|
|
|
2359
2365
|
let result: { success: boolean; name: string; message: string }
|
|
2360
2366
|
|
|
2361
2367
|
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
2362
|
-
result = installSkillFromUrl(target, marketplaceConfig)
|
|
2368
|
+
result = await installSkillFromUrl(target, marketplaceConfig)
|
|
2363
2369
|
} else {
|
|
2364
|
-
result = installSkill(target, marketplaceConfig)
|
|
2370
|
+
result = await installSkill(target, marketplaceConfig)
|
|
2365
2371
|
}
|
|
2366
2372
|
|
|
2367
2373
|
return {
|
|
@@ -2383,6 +2389,83 @@ const removeSkillCmd: CommandHandler = async (_ctx, args) => {
|
|
|
2383
2389
|
}
|
|
2384
2390
|
}
|
|
2385
2391
|
|
|
2392
|
+
const marketplaceCmd: CommandHandler = async (_ctx, args) => {
|
|
2393
|
+
const {
|
|
2394
|
+
readMarketplaces,
|
|
2395
|
+
addMarketplace,
|
|
2396
|
+
removeMarketplace,
|
|
2397
|
+
isValidMarketplaceRef,
|
|
2398
|
+
MARKETPLACES_PATH,
|
|
2399
|
+
} = await import('../skills/marketplace')
|
|
2400
|
+
const { readFileSync, writeFileSync, existsSync, mkdirSync } = await import('node:fs')
|
|
2401
|
+
const { dirname } = await import('node:path')
|
|
2402
|
+
|
|
2403
|
+
const readSources = () =>
|
|
2404
|
+
readMarketplaces((p) => (existsSync(p) ? readFileSync(p, 'utf-8') : null))
|
|
2405
|
+
|
|
2406
|
+
const sub = args[0]
|
|
2407
|
+
const ref = args[1]
|
|
2408
|
+
|
|
2409
|
+
if (!sub || sub === 'list') {
|
|
2410
|
+
const sources = readSources()
|
|
2411
|
+
const lines = ['── Marketplace Sources ──', '']
|
|
2412
|
+
for (const s of sources) lines.push(` ${s.owner}/${s.repo}`)
|
|
2413
|
+
lines.push(
|
|
2414
|
+
'',
|
|
2415
|
+
'Add: /marketplace add <owner>/<repo>',
|
|
2416
|
+
'Remove: /marketplace remove <owner>/<repo>',
|
|
2417
|
+
)
|
|
2418
|
+
return { content: lines.join('\n') }
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
if (sub === 'add' || sub === 'remove') {
|
|
2422
|
+
if (!ref) return { content: `Usage: /marketplace ${sub} <owner>/<repo>` }
|
|
2423
|
+
const [owner, repo] = ref.split('/')
|
|
2424
|
+
if (!owner || !repo || !isValidMarketplaceRef(owner, repo)) {
|
|
2425
|
+
return { content: `❌ Invalid marketplace ref "${ref}". Expected <owner>/<repo>.` }
|
|
2426
|
+
}
|
|
2427
|
+
const current = readSources()
|
|
2428
|
+
const result =
|
|
2429
|
+
sub === 'add' ? addMarketplace(current, owner, repo) : removeMarketplace(current, owner, repo)
|
|
2430
|
+
const changed = 'added' in result ? result.added : result.removed
|
|
2431
|
+
try {
|
|
2432
|
+
mkdirSync(dirname(MARKETPLACES_PATH), { recursive: true })
|
|
2433
|
+
writeFileSync(MARKETPLACES_PATH, JSON.stringify(result.sources, null, 2), 'utf-8')
|
|
2434
|
+
} catch (err) {
|
|
2435
|
+
return { content: `❌ Failed to save marketplaces: ${String(err)}` }
|
|
2436
|
+
}
|
|
2437
|
+
if (sub === 'add') {
|
|
2438
|
+
return {
|
|
2439
|
+
content: changed ? `✅ Added ${owner}/${repo}` : `ℹ ${owner}/${repo} already exists`,
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
return { content: changed ? `✅ Removed ${owner}/${repo}` : `ℹ ${owner}/${repo} not found` }
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
return { content: 'Usage: /marketplace add|list|remove [owner/repo]' }
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
const browseMarketplaceCmd: CommandHandler = async (_ctx) => {
|
|
2449
|
+
const { readMarketplaces, discoverSkills, downloadFile } = await import('../skills/marketplace')
|
|
2450
|
+
const { readFileSync, existsSync } = await import('node:fs')
|
|
2451
|
+
|
|
2452
|
+
const sources = readMarketplaces((p) => (existsSync(p) ? readFileSync(p, 'utf-8') : null))
|
|
2453
|
+
const lines = ['── Marketplace Skills ──', '']
|
|
2454
|
+
for (const source of sources) {
|
|
2455
|
+
lines.push(` ${source.owner}/${source.repo}:`)
|
|
2456
|
+
try {
|
|
2457
|
+
const skills = await discoverSkills(source, globalThis.fetch, downloadFile)
|
|
2458
|
+
if (skills.length === 0) lines.push(' (no skills found)')
|
|
2459
|
+
for (const s of skills) lines.push(` ${s.name.padEnd(24)} ${s.description}`)
|
|
2460
|
+
} catch {
|
|
2461
|
+
lines.push(' (failed to discover — check network / rate limit)')
|
|
2462
|
+
}
|
|
2463
|
+
lines.push('')
|
|
2464
|
+
}
|
|
2465
|
+
lines.push('Install: /install-skill <name>')
|
|
2466
|
+
return { content: lines.join('\n') }
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2386
2469
|
// ═══════════════════════════════════════════════════════════════
|
|
2387
2470
|
// Plugins — Community plugin marketplace + local management
|
|
2388
2471
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -3105,6 +3188,191 @@ const doctorCmd: CommandHandler = async (ctx) => {
|
|
|
3105
3188
|
return { content: lines.join('\n') }
|
|
3106
3189
|
}
|
|
3107
3190
|
|
|
3191
|
+
const fixCmd: CommandHandler = async (ctx, args) => {
|
|
3192
|
+
const t = resolveT(ctx)
|
|
3193
|
+
const { readFileSync, writeFileSync } = await import('node:fs')
|
|
3194
|
+
const { join } = await import('node:path')
|
|
3195
|
+
const { homedir } = await import('node:os')
|
|
3196
|
+
const { parse: parseYaml } = await import('yaml')
|
|
3197
|
+
|
|
3198
|
+
const target = args.find((a) => a === 'doctor' || a === 'config' || a === 'cache' || a === 'test')
|
|
3199
|
+
const dryRun = args.includes('--dry-run')
|
|
3200
|
+
const apply = args.includes('--apply')
|
|
3201
|
+
|
|
3202
|
+
const lines: string[] = [t('commands.fix.title')]
|
|
3203
|
+
if (dryRun) lines.push(t('commands.fix.dryrun_banner'))
|
|
3204
|
+
lines.push('')
|
|
3205
|
+
|
|
3206
|
+
const readSafe = (p: string): string | null => {
|
|
3207
|
+
try {
|
|
3208
|
+
return readFileSync(p, 'utf-8')
|
|
3209
|
+
} catch {
|
|
3210
|
+
return null
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
if (!target || target === 'doctor') {
|
|
3215
|
+
const loader = new InstructionsLoader()
|
|
3216
|
+
loader.loadAll(process.cwd())
|
|
3217
|
+
const files = selectRepoClaudeFiles(loader.list())
|
|
3218
|
+
const result = fixDoctor(files, {
|
|
3219
|
+
read: readSafe,
|
|
3220
|
+
write: (p, c) => {
|
|
3221
|
+
if (!dryRun) writeFileSync(p, c, 'utf-8')
|
|
3222
|
+
},
|
|
3223
|
+
})
|
|
3224
|
+
if (result.fixed.length === 0) {
|
|
3225
|
+
lines.push(t('commands.fix.doctor_clean'))
|
|
3226
|
+
} else {
|
|
3227
|
+
for (const f of result.fixed) {
|
|
3228
|
+
lines.push(t('commands.fix.doctor_fixed', { path: f.path, added: f.added.join(', ') }))
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
lines.push('')
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
if (!target || target === 'config') {
|
|
3235
|
+
const home = homedir()
|
|
3236
|
+
const configPaths = [
|
|
3237
|
+
join(process.cwd(), '.mipham', 'config.yml'),
|
|
3238
|
+
join(home, '.mipham', 'config.yml'),
|
|
3239
|
+
]
|
|
3240
|
+
const hookEngine = ctx.engine.getHookEngine?.()
|
|
3241
|
+
const result = fixConfig({
|
|
3242
|
+
configPaths,
|
|
3243
|
+
read: readSafe,
|
|
3244
|
+
parseYaml,
|
|
3245
|
+
restore: (p) => tryRestoreFromBackup(p),
|
|
3246
|
+
hookHealth: () =>
|
|
3247
|
+
hookEngine
|
|
3248
|
+
? hookEngine.getHookHealth().map((h) => ({ key: h.key, disabled: h.health.disabled }))
|
|
3249
|
+
: [],
|
|
3250
|
+
reEnableHook: (k) => (hookEngine ? hookEngine.reEnableHook(k) : false),
|
|
3251
|
+
dryRun,
|
|
3252
|
+
})
|
|
3253
|
+
if (result.corruptConfigs.length === 0 && result.disabledHooks.length === 0) {
|
|
3254
|
+
lines.push(t('commands.fix.config_clean'))
|
|
3255
|
+
} else {
|
|
3256
|
+
for (const p of result.restoredConfigs) {
|
|
3257
|
+
lines.push(t('commands.fix.config_restored', { path: p }))
|
|
3258
|
+
}
|
|
3259
|
+
for (const p of result.corruptConfigs.filter((p) => !result.restoredConfigs.includes(p))) {
|
|
3260
|
+
lines.push(t('commands.fix.config_corrupt', { path: p }))
|
|
3261
|
+
}
|
|
3262
|
+
for (const k of result.reenabledHooks) {
|
|
3263
|
+
lines.push(t('commands.fix.hook_reenabled', { key: k }))
|
|
3264
|
+
}
|
|
3265
|
+
for (const k of result.disabledHooks.filter((k) => !result.reenabledHooks.includes(k))) {
|
|
3266
|
+
lines.push(t('commands.fix.hook_disabled', { key: k }))
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
lines.push('')
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
if (!target || target === 'cache') {
|
|
3273
|
+
const crsiDir = join(homedir(), '.mipham', 'crsi')
|
|
3274
|
+
const cacheFiles = ['eval-scores.jsonl', 'improvements.jsonl', 'prose-proposals.jsonl'].map(
|
|
3275
|
+
(f) => join(crsiDir, f),
|
|
3276
|
+
)
|
|
3277
|
+
const result = fixCache(
|
|
3278
|
+
cacheFiles,
|
|
3279
|
+
{
|
|
3280
|
+
read: readSafe,
|
|
3281
|
+
write: (p, c) => writeFileSync(p, c, 'utf-8'),
|
|
3282
|
+
},
|
|
3283
|
+
apply && !dryRun,
|
|
3284
|
+
)
|
|
3285
|
+
if (result.files.length === 0) {
|
|
3286
|
+
lines.push(t('commands.fix.cache_clean'))
|
|
3287
|
+
} else {
|
|
3288
|
+
for (const f of result.files) {
|
|
3289
|
+
lines.push(
|
|
3290
|
+
t('commands.fix.cache_found', { path: f.path, count: String(f.corruptLines.length) }),
|
|
3291
|
+
)
|
|
3292
|
+
}
|
|
3293
|
+
if (apply && !dryRun) {
|
|
3294
|
+
for (const c of result.cleaned) {
|
|
3295
|
+
lines.push(t('commands.fix.cache_cleaned', { path: c.path, count: String(c.removed) }))
|
|
3296
|
+
}
|
|
3297
|
+
} else {
|
|
3298
|
+
lines.push(t('commands.fix.cache_hint'))
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
lines.push('')
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
if (!target || target === 'test') {
|
|
3305
|
+
const testFile = args.find(
|
|
3306
|
+
(a) =>
|
|
3307
|
+
!a.startsWith('--') && a !== 'test' && a !== 'doctor' && a !== 'config' && a !== 'cache',
|
|
3308
|
+
)
|
|
3309
|
+
if (!testFile) {
|
|
3310
|
+
lines.push(t('commands.fix.test_usage'))
|
|
3311
|
+
} else {
|
|
3312
|
+
const llm = ctx.engine.getLlm() ?? ctx.engine.getRegistry()
|
|
3313
|
+
if (!llm) {
|
|
3314
|
+
lines.push(t('commands.fix.test_no_llm'))
|
|
3315
|
+
} else {
|
|
3316
|
+
const { execSync } = await import('node:child_process')
|
|
3317
|
+
const { dirname, resolve } = await import('node:path')
|
|
3318
|
+
const result = await fixCodeTarget(
|
|
3319
|
+
{
|
|
3320
|
+
runVitest: (file) => {
|
|
3321
|
+
try {
|
|
3322
|
+
const output = execSync(`pnpm vitest run '${file}'`, {
|
|
3323
|
+
cwd: process.cwd(),
|
|
3324
|
+
encoding: 'utf-8',
|
|
3325
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
3326
|
+
})
|
|
3327
|
+
return { exitCode: 0, output }
|
|
3328
|
+
} catch (e) {
|
|
3329
|
+
const err = e as { stdout?: string; stderr?: string }
|
|
3330
|
+
return { exitCode: 1, output: `${err.stdout ?? ''}${err.stderr ?? ''}` }
|
|
3331
|
+
}
|
|
3332
|
+
},
|
|
3333
|
+
readFile: readSafe,
|
|
3334
|
+
writeFile: (p, c) => writeFileSync(p, c, 'utf-8'),
|
|
3335
|
+
generateFix: async (prompt) => {
|
|
3336
|
+
let text = ''
|
|
3337
|
+
for await (const chunk of llm.chat({
|
|
3338
|
+
model: '',
|
|
3339
|
+
messages: [{ role: 'user' as const, content: prompt }],
|
|
3340
|
+
temperature: 0,
|
|
3341
|
+
})) {
|
|
3342
|
+
if (chunk.type === 'text' && chunk.content) text += chunk.content
|
|
3343
|
+
}
|
|
3344
|
+
return stripCodeFences(text)
|
|
3345
|
+
},
|
|
3346
|
+
resolveSourceFile: (tf, specifier) => {
|
|
3347
|
+
const base = resolve(dirname(tf), specifier)
|
|
3348
|
+
return /\.[cm]?[jt]sx?$/.test(base) ? base : `${base}.ts`
|
|
3349
|
+
},
|
|
3350
|
+
},
|
|
3351
|
+
testFile,
|
|
3352
|
+
{ apply: apply && !dryRun, maxRetries: 3 },
|
|
3353
|
+
)
|
|
3354
|
+
if (result.fixed) {
|
|
3355
|
+
lines.push(
|
|
3356
|
+
t('commands.fix.test_fixed', {
|
|
3357
|
+
test: result.testFile,
|
|
3358
|
+
source: result.sourceFile ?? '-',
|
|
3359
|
+
attempts: String(result.attempts),
|
|
3360
|
+
}),
|
|
3361
|
+
)
|
|
3362
|
+
if (!apply) lines.push(t('commands.fix.test_hint'))
|
|
3363
|
+
} else {
|
|
3364
|
+
lines.push(
|
|
3365
|
+
t('commands.fix.test_failed', { test: result.testFile, detail: result.detail ?? '' }),
|
|
3366
|
+
)
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
lines.push('')
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
return { content: lines.join('\n').trimEnd() }
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3108
3376
|
// ═══════════════════════════════════════════════════════════════
|
|
3109
3377
|
// GitHub & Git Workflow Commands (Claude Code parity)
|
|
3110
3378
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -3422,42 +3690,44 @@ const cdCmd: CommandHandler = async (ctx, args) => {
|
|
|
3422
3690
|
|
|
3423
3691
|
const hooksCmd: CommandHandler = async (ctx) => {
|
|
3424
3692
|
const t = resolveT(ctx)
|
|
3425
|
-
const {
|
|
3426
|
-
const
|
|
3427
|
-
const cwd = process.cwd()
|
|
3428
|
-
const hooksDir = join(cwd, '.mipham', 'hooks')
|
|
3693
|
+
const { loadSettingsJson } = await import('../config/loader')
|
|
3694
|
+
const settingsJson = loadSettingsJson(process.cwd())
|
|
3429
3695
|
|
|
3430
|
-
|
|
3696
|
+
const hooks = settingsJson.hooks as Record<
|
|
3697
|
+
string,
|
|
3698
|
+
Array<{ matcher?: string; hooks: Array<{ type: string; command?: string }> }>
|
|
3699
|
+
>
|
|
3700
|
+
|
|
3701
|
+
const configured = Object.entries(hooks).filter(
|
|
3702
|
+
([, entries]) => Array.isArray(entries) && entries.length > 0,
|
|
3703
|
+
)
|
|
3704
|
+
|
|
3705
|
+
if (configured.length === 0) {
|
|
3431
3706
|
return { content: t('commands.hooks.no_hooks') }
|
|
3432
3707
|
}
|
|
3433
3708
|
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
'',
|
|
3441
|
-
]
|
|
3709
|
+
const lines: string[] = [
|
|
3710
|
+
t('commands.hooks.title'),
|
|
3711
|
+
'',
|
|
3712
|
+
t('commands.hooks.location', { path: '.mipham/settings.json' }),
|
|
3713
|
+
'',
|
|
3714
|
+
]
|
|
3442
3715
|
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
lines.push(` 📄 ${f}`)
|
|
3716
|
+
let count = 0
|
|
3717
|
+
for (const [eventName, entries] of configured) {
|
|
3718
|
+
for (const entry of entries) {
|
|
3719
|
+
for (const hook of entry.hooks) {
|
|
3720
|
+
count++
|
|
3721
|
+
const matcher = entry.matcher || '*'
|
|
3722
|
+
const cmd = hook.type === 'command' && hook.command ? hook.command : hook.type
|
|
3723
|
+
lines.push(` ${eventName} [${matcher}] → ${cmd}`)
|
|
3452
3724
|
}
|
|
3453
3725
|
}
|
|
3454
|
-
|
|
3455
|
-
lines.push('')
|
|
3456
|
-
lines.push(t('commands.hooks.found', { count: String(files.length) }))
|
|
3457
|
-
return { content: lines.join('\n') }
|
|
3458
|
-
} catch {
|
|
3459
|
-
return { content: t('commands.hooks.error') }
|
|
3460
3726
|
}
|
|
3727
|
+
|
|
3728
|
+
lines.push('')
|
|
3729
|
+
lines.push(t('commands.hooks.found', { count: String(count) }))
|
|
3730
|
+
return { content: lines.join('\n') }
|
|
3461
3731
|
}
|
|
3462
3732
|
|
|
3463
3733
|
const hooksHealthCmd: CommandHandler = (ctx) => {
|
|
@@ -4868,6 +5138,8 @@ const commandsListCmd: CommandHandler = () => {
|
|
|
4868
5138
|
'/reload-skills': 'Tools & Skills',
|
|
4869
5139
|
'/browse-skills': 'Tools & Skills',
|
|
4870
5140
|
'/install-skill': 'Tools & Skills',
|
|
5141
|
+
'/marketplace': 'Tools & Skills',
|
|
5142
|
+
'/browse-marketplace': 'Tools & Skills',
|
|
4871
5143
|
'/remove-skill': 'Tools & Skills',
|
|
4872
5144
|
'/mcp': 'Tools & Skills',
|
|
4873
5145
|
'/plugins': 'Plugins',
|
|
@@ -5028,6 +5300,8 @@ registry.set('/skills', skillsCmd)
|
|
|
5028
5300
|
registry.set('/reload-skills', reloadSkillsCmd)
|
|
5029
5301
|
registry.set('/browse-skills', browseSkillsCmd)
|
|
5030
5302
|
registry.set('/install-skill', installSkillCmd)
|
|
5303
|
+
registry.set('/marketplace', marketplaceCmd)
|
|
5304
|
+
registry.set('/browse-marketplace', browseMarketplaceCmd)
|
|
5031
5305
|
registry.set('/remove-skill', removeSkillCmd)
|
|
5032
5306
|
registry.set('/plugins', pluginsCmd)
|
|
5033
5307
|
registry.set('/browse-plugins', browsePluginsCmd)
|
|
@@ -5079,6 +5353,7 @@ registry.set('/pr-comments', prCommentsCmd)
|
|
|
5079
5353
|
|
|
5080
5354
|
// Session Management
|
|
5081
5355
|
registry.set('/doctor', doctorCmd)
|
|
5356
|
+
registry.set('/fix', fixCmd)
|
|
5082
5357
|
registry.set('/export', exportCmd)
|
|
5083
5358
|
registry.set('/resume', resumeCmd)
|
|
5084
5359
|
registry.set('/resume last', resumeLastCmd)
|
|
@@ -5183,6 +5458,7 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
5183
5458
|
'/save': 'Save conversation to Obsidian wiki (skill: save-to-wiki)',
|
|
5184
5459
|
'/export': 'Export conversation to file',
|
|
5185
5460
|
'/doctor': 'System diagnostics',
|
|
5461
|
+
'/fix': 'Deterministic self-repair: doctor/config/cache',
|
|
5186
5462
|
'/dream': 'Background memory consolidation',
|
|
5187
5463
|
'/constitution': 'View or reload constitutional principles',
|
|
5188
5464
|
'/bug-report': 'Generate diagnostic report for GitHub Issues',
|
|
@@ -5212,6 +5488,8 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
5212
5488
|
'/reload-skills': 'Reload all skills',
|
|
5213
5489
|
'/browse-skills': 'Browse community skill marketplace',
|
|
5214
5490
|
'/install-skill': 'Install a skill by name or URL',
|
|
5491
|
+
'/marketplace': 'Manage marketplace sources (add/list/remove)',
|
|
5492
|
+
'/browse-marketplace': 'Browse skills across all marketplace sources',
|
|
5215
5493
|
'/remove-skill': 'Remove an installed skill',
|
|
5216
5494
|
'/mcp': 'MCP server status',
|
|
5217
5495
|
'/plugins': 'List installed plugins',
|
|
@@ -5294,7 +5572,7 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
5294
5572
|
'/stats': 'Show session usage statistics',
|
|
5295
5573
|
'/summary': 'Generate session summary',
|
|
5296
5574
|
'/cd': 'Change session working directory',
|
|
5297
|
-
'/hooks': '
|
|
5575
|
+
'/hooks': 'List configured hooks from settings.json',
|
|
5298
5576
|
'/hooks health': 'Check hook health — see failures, disabled hooks, recovery status',
|
|
5299
5577
|
'/hooks enable': 'Manually re-enable a hook that was auto-disabled after repeated failures',
|
|
5300
5578
|
'/batch': 'Apply changes across multiple files',
|