@miphamai/cli 0.7.5 → 0.7.7
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/mcp/transport.ts +1 -1
- package/src/ui/app.tsx +12 -2
- package/src/ui/commands.ts +101 -39
- package/dist/mipham +0 -0
package/package.json
CHANGED
package/src/mcp/transport.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { JsonRpcRequest, JsonRpcResponse, JsonRpcNotification } from './typ
|
|
|
3
3
|
|
|
4
4
|
type NotificationHandler = (notification: JsonRpcNotification) => void
|
|
5
5
|
|
|
6
|
-
const REQUEST_TIMEOUT_MS =
|
|
6
|
+
const REQUEST_TIMEOUT_MS = 60_000
|
|
7
7
|
|
|
8
8
|
// ── Environment variable security: block sensitive vars from MCP subprocess ──
|
|
9
9
|
//
|
package/src/ui/app.tsx
CHANGED
|
@@ -175,9 +175,12 @@ export function App({
|
|
|
175
175
|
return
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
let injectMessage: string | undefined
|
|
179
|
+
|
|
178
180
|
const handler = getCommand(command)
|
|
179
181
|
if (handler) {
|
|
180
182
|
const result = await handler(mkCtx(), args)
|
|
183
|
+
injectMessage = result.injectMessage
|
|
181
184
|
setMessages((prev) => [
|
|
182
185
|
...prev,
|
|
183
186
|
{ role: 'user', content: input },
|
|
@@ -202,8 +205,15 @@ export function App({
|
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
}
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
|
|
209
|
+
// Bridge: if command set injectMessage, route to AI processing
|
|
210
|
+
if (injectMessage) {
|
|
211
|
+
input = injectMessage
|
|
212
|
+
// fall through to normal AI processing below
|
|
213
|
+
} else {
|
|
214
|
+
// Unknown slash command or handler returned: proceed to normal AI processing
|
|
215
|
+
return
|
|
216
|
+
}
|
|
207
217
|
}
|
|
208
218
|
|
|
209
219
|
// ── Normal message processing (AI chat) ──
|
package/src/ui/commands.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface CommandResult {
|
|
|
40
40
|
clearMessages?: boolean
|
|
41
41
|
/** Content to copy to clipboard (handled by caller) */
|
|
42
42
|
copyContent?: string
|
|
43
|
+
/** If set, inject this as a user message and route to AI processing (bridges slash commands → skills) */
|
|
44
|
+
injectMessage?: string
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
type CommandHandler = (
|
|
@@ -1088,6 +1090,18 @@ const branchCmd: CommandHandler = (ctx, args) => {
|
|
|
1088
1090
|
}
|
|
1089
1091
|
}
|
|
1090
1092
|
|
|
1093
|
+
/** Parse human-readable interval to seconds. Returns null if invalid. */
|
|
1094
|
+
function parseInterval(raw: string): number | null {
|
|
1095
|
+
const m = raw.trim().match(/^(\d+)\s*(s|sec|m|min|h|hr|hour)$/i)
|
|
1096
|
+
if (!m) return null
|
|
1097
|
+
const n = parseInt(m[1]!, 10)
|
|
1098
|
+
const unit = m[2]!.toLowerCase()
|
|
1099
|
+
if (unit === 's' || unit === 'sec') return n
|
|
1100
|
+
if (unit === 'm' || unit === 'min') return n * 60
|
|
1101
|
+
if (unit === 'h' || unit === 'hr' || unit === 'hour') return n * 3600
|
|
1102
|
+
return null
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1091
1105
|
const loopCmd: CommandHandler = async (_ctx, args) => {
|
|
1092
1106
|
const sub = args[0]
|
|
1093
1107
|
|
|
@@ -1166,24 +1180,23 @@ const loopCmd: CommandHandler = async (_ctx, args) => {
|
|
|
1166
1180
|
/loop 5m check the deploy status
|
|
1167
1181
|
/loop init Create vault in current directory
|
|
1168
1182
|
/loop init ~/my-project Create vault in specific directory
|
|
1169
|
-
|
|
1170
|
-
Note: Continuous looping requires session persistence, coming in a future release.
|
|
1171
1183
|
`,
|
|
1172
1184
|
}
|
|
1173
1185
|
}
|
|
1174
1186
|
|
|
1175
1187
|
const interval = args[0]!
|
|
1176
1188
|
const prompt = args.slice(1).join(' ')
|
|
1189
|
+
const seconds = parseInterval(interval)
|
|
1177
1190
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1191
|
+
if (seconds === null) {
|
|
1192
|
+
return {
|
|
1193
|
+
content: `── Invalid Interval ──\n\n"${interval}" is not a recognised interval.\n\nUse formats like: 10s, 5m, 1h, 30min, 2hr`,
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1183
1196
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
`,
|
|
1197
|
+
return {
|
|
1198
|
+
content: `── Loop Started ──\n\nInterval: ${interval} (${seconds}s)\nPrompt: "${prompt}"\n\nScheduling via ScheduleWakeup — the prompt will re-schedule itself each cycle.\nUse /schedule to view active loops.`,
|
|
1199
|
+
injectMessage: `use ScheduleWakeup to set up a recurring loop. delaySeconds=${seconds}, prompt: "${prompt}". Include at the end of the prompt: "Then call ScheduleWakeup again with delaySeconds=${seconds} and the same prompt to continue the loop."`,
|
|
1187
1200
|
}
|
|
1188
1201
|
}
|
|
1189
1202
|
|
|
@@ -1191,14 +1204,15 @@ const scheduleCmd: CommandHandler = (_ctx) => ({
|
|
|
1191
1204
|
content: stripIndent`
|
|
1192
1205
|
── Scheduled Tasks ──
|
|
1193
1206
|
|
|
1194
|
-
|
|
1207
|
+
Active loops are managed via ScheduleWakeup (in-session) and
|
|
1208
|
+
CronCreate (durable, survives restarts).
|
|
1195
1209
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
• Durable persistence across sessions
|
|
1210
|
+
Use /loop <interval> <prompt> to start a recurring task.
|
|
1211
|
+
Use CronList to view all scheduled jobs.
|
|
1212
|
+
Use CronDelete <id> to cancel a durable job.
|
|
1200
1213
|
|
|
1201
|
-
|
|
1214
|
+
The ScheduleWakeup mechanism automatically re-schedules on
|
|
1215
|
+
each wake, creating a self-perpetuating loop within the session.
|
|
1202
1216
|
`,
|
|
1203
1217
|
})
|
|
1204
1218
|
|
|
@@ -1420,39 +1434,78 @@ const issueCmd: CommandHandler = async () => {
|
|
|
1420
1434
|
// Code Quality Commands (Claude Code parity)
|
|
1421
1435
|
// ═══════════════════════════════════════════════════════════════
|
|
1422
1436
|
|
|
1423
|
-
|
|
1437
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1438
|
+
// Code Quality — bridge slash commands to skills (Claude Code parity)
|
|
1439
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1440
|
+
|
|
1441
|
+
const codeReviewCmd: CommandHandler = async () => {
|
|
1424
1442
|
try {
|
|
1425
1443
|
const { execSync } = await import('node:child_process')
|
|
1426
1444
|
const diff = execSync('git diff --stat', { encoding: 'utf-8', timeout: 5000 }).trim()
|
|
1427
|
-
|
|
1445
|
+
if (!diff) {
|
|
1446
|
+
return {
|
|
1447
|
+
content:
|
|
1448
|
+
'─ Code Review ─\n\nNo uncommitted changes to review.\n\nTo review a specific file: /code-review path/to/file.ts',
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
return {
|
|
1452
|
+
content:
|
|
1453
|
+
'─ Code Review ─\n\nReviewing uncommitted changes with the code-review skill (7 dimensions: correctness, security, performance, code quality, architecture, testing, language-specific)...',
|
|
1454
|
+
injectMessage:
|
|
1455
|
+
'use the code-review skill to review all uncommitted changes. Check all 7 dimensions: correctness, security, performance, code quality, architecture & design, testing, and language-specific issues.',
|
|
1456
|
+
}
|
|
1457
|
+
} catch {
|
|
1458
|
+
return { content: '─ Code Review ─\n\nCould not detect changes. Are you in a git repository?' }
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1428
1461
|
|
|
1462
|
+
const simplifyCmd: CommandHandler = async () => {
|
|
1463
|
+
try {
|
|
1464
|
+
const { execSync } = await import('node:child_process')
|
|
1465
|
+
const diff = execSync('git diff --stat', { encoding: 'utf-8', timeout: 5000 }).trim()
|
|
1429
1466
|
if (!diff) {
|
|
1430
1467
|
return {
|
|
1431
1468
|
content:
|
|
1432
|
-
'
|
|
1469
|
+
'─ Simplify ─\n\nNo uncommitted changes to simplify.\n\nMake changes first, then run /simplify for cleanup review.',
|
|
1433
1470
|
}
|
|
1434
1471
|
}
|
|
1472
|
+
return {
|
|
1473
|
+
content:
|
|
1474
|
+
'─ Simplify ─\n\nRunning cleanup review — 4 passes: reuse, simplification, efficiency, abstraction level...',
|
|
1475
|
+
injectMessage:
|
|
1476
|
+
'use the self-review skill to review these uncommitted changes. Focus on 4 cleanup passes: 1) Reuse — find duplicated logic, replace with existing helpers; 2) Simplification — flatten nesting, remove redundant state and dead code; 3) Efficiency — fix repeated object creation, unnecessary I/O, memory issues; 4) Abstraction Level — ensure code sits at the right architectural layer. Apply equivalent transformations only — do NOT change logic or fix bugs.',
|
|
1477
|
+
}
|
|
1478
|
+
} catch {
|
|
1479
|
+
return { content: '─ Simplify ─\n\nCould not detect changes. Are you in a git repository?' }
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1435
1482
|
|
|
1483
|
+
const verifyCmd: CommandHandler = async () => {
|
|
1484
|
+
try {
|
|
1485
|
+
const { execSync } = await import('node:child_process')
|
|
1486
|
+
const diff = execSync('git diff --stat', { encoding: 'utf-8', timeout: 5000 }).trim()
|
|
1487
|
+
if (!diff) {
|
|
1488
|
+
return {
|
|
1489
|
+
content:
|
|
1490
|
+
'─ Verify ─\n\nNo uncommitted changes to verify.\n\nMake changes first, then run /verify for runtime verification.',
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1436
1493
|
return {
|
|
1437
|
-
content:
|
|
1438
|
-
'
|
|
1439
|
-
|
|
1440
|
-
'
|
|
1441
|
-
diff,
|
|
1442
|
-
'',
|
|
1443
|
-
'To run simplification review, type: "review these changes for simplification and quality"',
|
|
1444
|
-
'',
|
|
1445
|
-
'This will check for:',
|
|
1446
|
-
' • Code reuse opportunities',
|
|
1447
|
-
' • Overly complex logic',
|
|
1448
|
-
' • Dead code removal',
|
|
1449
|
-
' • Style and consistency',
|
|
1450
|
-
'',
|
|
1451
|
-
`Files to review: ${changed.split('\n').length}`,
|
|
1452
|
-
].join('\n'),
|
|
1494
|
+
content:
|
|
1495
|
+
'─ Verify ─\n\nRunning runtime verification — observing actual execution behavior (not tests, not typecheck)...',
|
|
1496
|
+
injectMessage:
|
|
1497
|
+
'verify these uncommitted changes through runtime observation only. For each change: 1) Find the user-facing surface (CLI command, API endpoint, UI interaction); 2) Drive the changed code to execute; 3) Push boundaries — pass null, repeated values, wrong types, interrupt mid-flow (Ctrl-C), resize window; 4) Report verdict per change: PASS (works as expected), FAIL (does not work or breaks something), BLOCKED (cannot reach observable state), SKIP (no runtime surface, e.g. pure documentation). Do NOT run the test suite — observe real execution behavior only.',
|
|
1453
1498
|
}
|
|
1454
1499
|
} catch {
|
|
1455
|
-
return { content: '
|
|
1500
|
+
return { content: '─ Verify ─\n\nCould not detect changes. Are you in a git repository?' }
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
const designCmd: CommandHandler = async (_ctx, args) => {
|
|
1505
|
+
const topic = args.join(' ') || 'the current task'
|
|
1506
|
+
return {
|
|
1507
|
+
content: `─ Design ─\n\nStarting architectural design session for: ${topic}\n\nExploring approaches, trade-offs, component breakdown, data flow...`,
|
|
1508
|
+
injectMessage: `help me design the architecture for ${topic}. Explore 2-3 approaches with trade-offs, then present a design covering: component breakdown, data flow, interfaces between components, error handling strategy, and testing approach. Use the plan sub-agent if deeper analysis would help. Prefer simplicity — YAGNI.`,
|
|
1456
1509
|
}
|
|
1457
1510
|
}
|
|
1458
1511
|
|
|
@@ -3495,8 +3548,11 @@ const commandsListCmd: CommandHandler = () => {
|
|
|
3495
3548
|
'/push': 'Workflow',
|
|
3496
3549
|
'/pr': 'Workflow',
|
|
3497
3550
|
'/issue': 'Workflow',
|
|
3498
|
-
'/
|
|
3499
|
-
'/
|
|
3551
|
+
'/code-review': 'Code Quality',
|
|
3552
|
+
'/simplify': 'Code Quality',
|
|
3553
|
+
'/verify': 'Code Quality',
|
|
3554
|
+
'/design': 'Code Quality',
|
|
3555
|
+
'/lint': 'Code Quality',
|
|
3500
3556
|
'/files': 'Session & Identity',
|
|
3501
3557
|
'/stats': 'Session & Identity',
|
|
3502
3558
|
'/summary': 'Session & Identity',
|
|
@@ -3634,7 +3690,10 @@ registry.set('/pr', prCmd)
|
|
|
3634
3690
|
registry.set('/issue', issueCmd)
|
|
3635
3691
|
|
|
3636
3692
|
// Code Quality (Claude Code parity)
|
|
3693
|
+
registry.set('/code-review', codeReviewCmd)
|
|
3637
3694
|
registry.set('/simplify', simplifyCmd)
|
|
3695
|
+
registry.set('/verify', verifyCmd)
|
|
3696
|
+
registry.set('/design', designCmd)
|
|
3638
3697
|
registry.set('/lint', lintCmd)
|
|
3639
3698
|
|
|
3640
3699
|
// Session Enhancement (Claude Code parity)
|
|
@@ -3741,7 +3800,10 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
3741
3800
|
'/push': 'Push the current branch',
|
|
3742
3801
|
'/pr': 'Create a pull request',
|
|
3743
3802
|
'/issue': 'File a GitHub issue',
|
|
3744
|
-
'/
|
|
3803
|
+
'/code-review': 'Review code for bugs, security, performance (7 dimensions)',
|
|
3804
|
+
'/simplify': 'Cleanup-only review: reuse, simplification, efficiency, abstraction',
|
|
3805
|
+
'/verify': 'Runtime verification — observe actual execution, not tests',
|
|
3806
|
+
'/design': 'Start architectural design session — explore approaches and trade-offs',
|
|
3745
3807
|
'/lint': 'Run linting on the project',
|
|
3746
3808
|
'/files': 'List files in current working directory',
|
|
3747
3809
|
'/stats': 'Show session usage statistics',
|
package/dist/mipham
DELETED
|
Binary file
|