@miphamai/cli 0.7.7 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
package/src/ui/app.tsx CHANGED
@@ -175,12 +175,12 @@ export function App({
175
175
  return
176
176
  }
177
177
 
178
- let injectMessage: string | undefined
178
+ let forwardToAI: string | undefined
179
179
 
180
180
  const handler = getCommand(command)
181
181
  if (handler) {
182
182
  const result = await handler(mkCtx(), args)
183
- injectMessage = result.injectMessage
183
+ forwardToAI = result.forwardToAI
184
184
  setMessages((prev) => [
185
185
  ...prev,
186
186
  { role: 'user', content: input },
@@ -206,12 +206,12 @@ export function App({
206
206
  }
207
207
  }
208
208
 
209
- // Bridge: if command set injectMessage, route to AI processing
210
- if (injectMessage) {
211
- input = injectMessage
209
+ // Bridge: if command set forwardToAI, route the message to AI processing
210
+ if (forwardToAI) {
211
+ input = forwardToAI
212
212
  // fall through to normal AI processing below
213
213
  } else {
214
- // Unknown slash command or handler returned: proceed to normal AI processing
214
+ // No handler matched or handler didn't request AI routing — stop here
215
215
  return
216
216
  }
217
217
  }
@@ -40,8 +40,9 @@ 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
+ /** If set, route this message to the AI engine — bridges slash commands → skill/agent invocation.
44
+ * The app layer replaces the user input with this string and falls through to AI processing. */
45
+ forwardToAI?: string
45
46
  }
46
47
 
47
48
  type CommandHandler = (
@@ -121,8 +122,8 @@ const helpCmd: CommandHandler = (ctx) => {
121
122
  ── Workflow ────────────────────────
122
123
  /plan Enter plan mode (read-only)
123
124
  /no-plan Exit plan mode
124
- /tdd TDD mode [stub]
125
- /todos Task management
125
+ /tdd [goal] Test-Driven Development workflow
126
+ /todos [list|create] Task management
126
127
  /tasks Background tasks
127
128
  /review Code review workflow
128
129
  /pr-comments PR review summary
@@ -132,7 +133,7 @@ const helpCmd: CommandHandler = (ctx) => {
132
133
  /loop init Scaffold .mipham/ vault structure
133
134
  /batch Apply changes across files
134
135
  /hooks Manage lifecycle hook scripts
135
- /schedule View scheduled tasks [stub]
136
+ /schedule View scheduled tasks
136
137
 
137
138
  ── Git & GitHub ─────────────────────
138
139
  /commit Review staged changes + commit
@@ -401,25 +402,71 @@ const planCmd: CommandHandler = (_ctx) => ({
401
402
  `,
402
403
  })
403
404
 
404
- const tddCmd: CommandHandler = (_ctx) => ({
405
- content: stripIndent`
406
- ── TDD Mode ── [stub]
407
- Test-Driven Development workflow: RED → GREEN → REFACTOR.
408
- Full TDD integration coming in a future release.
409
- `,
410
- })
405
+ const tddCmd: CommandHandler = (_ctx, args) => {
406
+ const target = args.join(' ') || 'the current task'
407
+ return {
408
+ content: stripIndent`
409
+ ── TDD Mode ──
410
+ Starting Test-Driven Development workflow for: ${target}
411
411
 
412
- const todosCmd: CommandHandler = (_ctx) => ({
413
- content: stripIndent`
414
- ── Task Management ──
415
- Use the Task tool for structured task tracking:
416
- • Create: Task tool with action=create
417
- • List: Task tool with action=list
418
- • Update: Task tool with action=update
412
+ Cycle: 🔴 RED → 🟢 GREEN → 🔵 REFACTOR
413
+ RED: Write a failing test first
414
+ GREEN: Write minimal code to pass
415
+ REFACTOR: Clean up while keeping tests green
419
416
 
420
- Full /todos integration coming in a future release.
421
- `,
422
- })
417
+ The AI will guide you through each cycle.
418
+ `,
419
+ forwardToAI: `Follow the Test-Driven Development workflow for ${target}:
420
+ 1. RED — Write a failing test that defines the expected behavior. Use the project's test framework (Vitest/Jest/pytest). Show me the test code and confirm it fails.
421
+ 2. GREEN — Write the minimum code needed to make the test pass. Run the test to verify it passes.
422
+ 3. REFACTOR — Clean up both test and implementation code. Remove duplication, improve names, simplify. Keep tests green.
423
+ Repeat for each behavior. Do NOT write implementation before tests.`,
424
+ }
425
+ }
426
+
427
+ const todosCmd: CommandHandler = (_ctx, args) => {
428
+ const sub = args[0]
429
+ if (sub === 'create') {
430
+ const title = args.slice(1).join(' ')
431
+ if (!title.trim()) {
432
+ return {
433
+ content:
434
+ 'Usage: /todos create <task-title>\n\nExample: /todos create Add user authentication',
435
+ }
436
+ }
437
+ return {
438
+ content: `── Create Task ──\n\nCreating task: "${title.trim()}"\n\nPassing to AI for structured task creation with TaskCreate...`,
439
+ forwardToAI: `Create a new task using TaskCreate with subject "${title.trim()}". Set a clear description and activeForm.`,
440
+ }
441
+ }
442
+
443
+ if (sub === 'list' || !sub) {
444
+ return {
445
+ content: stripIndent`
446
+ ── Task Management ──
447
+ Fetching current task list...
448
+
449
+ Shortcuts:
450
+ /todos list Show all tasks
451
+ /todos create <title> Create a new task
452
+ `,
453
+ forwardToAI:
454
+ 'Use TaskList to show all current tasks. Present them in a clear summary grouped by status (pending/in_progress/completed). If there are no tasks, suggest creating one.',
455
+ }
456
+ }
457
+
458
+ return {
459
+ content: stripIndent`
460
+ ── Task Management ──
461
+ /todos list Show all tasks
462
+ /todos create <title> Create a new task
463
+
464
+ The AI manages task state via TaskCreate, TaskList, TaskUpdate, and TaskGet tools.
465
+ Tasks appear in the /tasks view and persist across the session.
466
+ `,
467
+ forwardToAI: 'Use TaskList to show all current tasks, then present them clearly.',
468
+ }
469
+ }
423
470
 
424
471
  // ═══════════════════════════════════════════════════════════════
425
472
  // Project
@@ -1196,7 +1243,7 @@ const loopCmd: CommandHandler = async (_ctx, args) => {
1196
1243
 
1197
1244
  return {
1198
1245
  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."`,
1246
+ forwardToAI: `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."`,
1200
1247
  }
1201
1248
  }
1202
1249
 
@@ -1204,16 +1251,17 @@ const scheduleCmd: CommandHandler = (_ctx) => ({
1204
1251
  content: stripIndent`
1205
1252
  ── Scheduled Tasks ──
1206
1253
 
1254
+ Fetching active scheduled tasks and loops...
1255
+
1207
1256
  Active loops are managed via ScheduleWakeup (in-session) and
1208
1257
  CronCreate (durable, survives restarts).
1209
1258
 
1210
1259
  Use /loop <interval> <prompt> to start a recurring task.
1211
1260
  Use CronList to view all scheduled jobs.
1212
1261
  Use CronDelete <id> to cancel a durable job.
1213
-
1214
- The ScheduleWakeup mechanism automatically re-schedules on
1215
- each wake, creating a self-perpetuating loop within the session.
1216
1262
  `,
1263
+ forwardToAI:
1264
+ 'Use CronList to show all currently scheduled cron jobs (both durable and session-only). Present them in a clear table with: name/ID, schedule (cron expression), type (recurring vs one-shot), and status. Also note any active ScheduleWakeup loops if visible in the current session. If no scheduled tasks exist, suggest: "No scheduled tasks. Use /loop <interval> <prompt> to create a recurring task."',
1217
1265
  })
1218
1266
 
1219
1267
  // ═══════════════════════════════════════════════════════════════
@@ -1430,82 +1478,71 @@ const issueCmd: CommandHandler = async () => {
1430
1478
  }
1431
1479
  }
1432
1480
 
1433
- // ═══════════════════════════════════════════════════════════════
1434
- // Code Quality Commands (Claude Code parity)
1435
- // ═══════════════════════════════════════════════════════════════
1436
-
1437
1481
  // ═══════════════════════════════════════════════════════════════
1438
1482
  // Code Quality — bridge slash commands to skills (Claude Code parity)
1439
1483
  // ═══════════════════════════════════════════════════════════════
1440
1484
 
1441
- const codeReviewCmd: CommandHandler = async () => {
1442
- try {
1443
- const { execSync } = await import('node:child_process')
1444
- const diff = execSync('git diff --stat', { encoding: 'utf-8', timeout: 5000 }).trim()
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',
1485
+ /** Factory for git-diff-based commands that bridge to AI skills via forwardToAI. */
1486
+ function gitDiffBridgeCmd(opts: {
1487
+ label: string
1488
+ noChangesHint: string
1489
+ runningMsg: string
1490
+ forwardToAI: string
1491
+ }): CommandHandler {
1492
+ return async () => {
1493
+ try {
1494
+ const { execSync } = await import('node:child_process')
1495
+ const diff = execSync('git diff --stat', { encoding: 'utf-8', timeout: 5000 }).trim()
1496
+ if (!diff) {
1497
+ return { content: `─ ${opts.label} ─\n\n${opts.noChangesHint}` }
1449
1498
  }
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
- }
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()
1466
- if (!diff) {
1467
1499
  return {
1468
- content:
1469
- '─ Simplify ─\n\nNo uncommitted changes to simplify.\n\nMake changes first, then run /simplify for cleanup review.',
1500
+ content: `─ ${opts.label} ─\n\n${opts.runningMsg}\n\nChanged files:\n${diff}`,
1501
+ forwardToAI: opts.forwardToAI,
1470
1502
  }
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
- }
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) {
1503
+ } catch {
1488
1504
  return {
1489
- content:
1490
- '─ Verify ─\n\nNo uncommitted changes to verify.\n\nMake changes first, then run /verify for runtime verification.',
1505
+ content: `─ ${opts.label} ─\n\nCould not detect changes. Are you in a git repository?`,
1491
1506
  }
1492
1507
  }
1493
- return {
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.',
1498
- }
1499
- } catch {
1500
- return { content: '─ Verify ─\n\nCould not detect changes. Are you in a git repository?' }
1501
1508
  }
1502
1509
  }
1503
1510
 
1504
- const designCmd: CommandHandler = async (_ctx, args) => {
1511
+ const codeReviewCmd = gitDiffBridgeCmd({
1512
+ label: 'Code Review',
1513
+ noChangesHint:
1514
+ 'No uncommitted changes to review.\n\nTo review a specific file: /code-review path/to/file.ts',
1515
+ runningMsg:
1516
+ 'Reviewing uncommitted changes with the code-review skill (7 dimensions: correctness, security, performance, code quality, architecture, testing, language-specific)...',
1517
+ forwardToAI:
1518
+ '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.',
1519
+ })
1520
+
1521
+ const simplifyCmd = gitDiffBridgeCmd({
1522
+ label: 'Simplify',
1523
+ noChangesHint:
1524
+ 'No uncommitted changes to simplify.\n\nMake changes first, then run /simplify for cleanup review.',
1525
+ runningMsg:
1526
+ 'Running cleanup review — 4 passes: reuse, simplification, efficiency, abstraction level...',
1527
+ forwardToAI:
1528
+ '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.',
1529
+ })
1530
+
1531
+ const verifyCmd = gitDiffBridgeCmd({
1532
+ label: 'Verify',
1533
+ noChangesHint:
1534
+ 'No uncommitted changes to verify.\n\nMake changes first, then run /verify for runtime verification.',
1535
+ runningMsg:
1536
+ 'Running runtime verification — observing actual execution behavior (not tests, not typecheck)...',
1537
+ forwardToAI:
1538
+ '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.',
1539
+ })
1540
+
1541
+ const designCmd: CommandHandler = (_ctx, args) => {
1505
1542
  const topic = args.join(' ') || 'the current task'
1506
1543
  return {
1507
1544
  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.`,
1545
+ forwardToAI: `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.`,
1509
1546
  }
1510
1547
  }
1511
1548
 
@@ -3590,7 +3627,17 @@ const registry = new Map<string, CommandHandler>()
3590
3627
 
3591
3628
  // Session
3592
3629
  registry.set('/help', helpCmd)
3593
- registry.set('/pick', () => ({ content: 'Opening model picker... (use Ctrl+P or /pick)' }))
3630
+ const pickCmd: CommandHandler = (ctx) => ({
3631
+ content: `── Model Picker ──
3632
+
3633
+ Use ↑↓ to navigate, Enter to select, Esc to close.
3634
+
3635
+ Current: ${ctx.providerId} / ${ctx.modelId}
3636
+ Available: ${ctx.config.providers.filter((p) => p.status === 'active').length} providers, ${ctx.config.providers.flatMap((p) => p.models.filter((m) => m.status === 'active')).length} models
3637
+
3638
+ Tip: Press Ctrl+P or type /pick from the chat input.`,
3639
+ })
3640
+ registry.set('/pick', pickCmd)
3594
3641
  registry.set('/version', versionCmd)
3595
3642
  registry.set('/clear', clearCmd)
3596
3643
  registry.set('/exit', exitCmd)
@@ -3618,6 +3665,7 @@ registry.set('/providers', providersCmd)
3618
3665
  registry.set('/config', configCmd)
3619
3666
  registry.set('/fast', fastCmd)
3620
3667
  registry.set('/effort', effortCmd)
3668
+ registry.set('/switch', switchCmd)
3621
3669
 
3622
3670
  // Tools & Skills
3623
3671
  registry.set('/tools', toolsCmd)
@@ -3769,8 +3817,8 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
3769
3817
  '/plugin-disable': 'Disable an enabled plugin',
3770
3818
  '/plan': 'Enter plan mode',
3771
3819
  '/no-plan': 'Exit plan mode',
3772
- '/tdd': 'TDD mode',
3773
- '/todos': 'Task management',
3820
+ '/tdd': 'Test-Driven Development workflow (RED → GREEN → REFACTOR)',
3821
+ '/todos': 'Task management (list/create tasks)',
3774
3822
  '/tasks': 'Background tasks',
3775
3823
  '/review': 'Code review workflow',
3776
3824
  '/pr-comments': 'PR review summary',
@@ -3795,7 +3843,7 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
3795
3843
  '/agents': 'Agent view dashboard',
3796
3844
  '/bg': 'Run a background agent task',
3797
3845
  '/artifact': 'Manage artifacts',
3798
- '/schedule': 'View scheduled tasks',
3846
+ '/schedule': 'View scheduled tasks and cron jobs',
3799
3847
  '/commit': 'Generate commit message and review staged changes',
3800
3848
  '/push': 'Push the current branch',
3801
3849
  '/pr': 'Create a pull request',