@miphamai/cli 0.24.2 → 0.24.4

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.24.2",
3
+ "version": "0.24.4",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,29 +1,114 @@
1
1
  ---
2
2
  name: mipham-code-setup
3
- description: Guide for installing, configuring, and troubleshooting Mipham Code — the multi-model open-core intelligent coding terminal
4
- version: 1.0.0
3
+ description: Install, configure, diagnose, and troubleshoot Mipham Code — the multi-model open-core intelligent coding terminal. Covers setup wizard, API keys, providers, models, skills, permissions, workspace trust, shell/IDE integration, and first-run onboarding.
4
+ version: 2.0.0
5
+ user-invocable: true
6
+ allowed-tools:
7
+ - Read
8
+ - Write
9
+ - Edit
10
+ - Bash
11
+ - Skill
5
12
  ---
6
13
 
7
- # Mipham Code Setup
14
+ # Mipham Code Setup — Executable Setup Workflow
8
15
 
9
- Comprehensive setup and configuration guide for Mipham Code.
16
+ **Type**: Rigid — follow the decision tree exactly. Don't skip diagnostic phases.
10
17
 
11
- ## Installation
18
+ **Purpose**: Guide users from zero to fully configured Mipham Code. This skill is BOTH:
12
19
 
13
- **Quick install (recommended):**
20
+ 1. A self-contained diagnostic + configuration workflow the AI can execute
21
+ 2. A reference for `/setup` command behavior and slash commands
22
+
23
+ **Triggers**: "setup mipham", "configure mipham", "install mipham code", "mipham not working", "mipham setup", "first time using mipham", "help me set up", "getting started", `/setup`
24
+
25
+ ---
26
+
27
+ ## Phase 0: Environment Detection (ALWAYS RUN FIRST)
28
+
29
+ Before doing anything, run these diagnostic checks. Report results in a status table.
30
+
31
+ ### 0.1 — Detect Installation
32
+
33
+ ```bash
34
+ which mipham 2>/dev/null
35
+ mipham --version 2>/dev/null
36
+ bun --version 2>/dev/null
37
+ node --version 2>/dev/null
38
+ ```
39
+
40
+ ### 0.2 — Detect Configuration
41
+
42
+ ```bash
43
+ ls -la .mipham/config.yml 2>/dev/null
44
+ ls -la ~/.mipham/config.yml 2>/dev/null
45
+ ls -la MIPHAM.md 2>/dev/null
46
+ ls -la CLAUDE.md 2>/dev/null
47
+ ```
48
+
49
+ ### 0.3 — Detect API Keys
50
+
51
+ ```bash
52
+ env | grep -E 'ANTHROPIC_API_KEY|OPENAI_API_KEY|DEEPSEEK_API_KEY|QWEN_API_KEY|DOUBAO_API_KEY|HUNYUAN_API_KEY|GEMINI_API_KEY' | cut -d= -f1
53
+ ```
54
+
55
+ ### 0.4 — Detect Skills & Permissions
56
+
57
+ ```bash
58
+ ls .mipham/skills/ 2>/dev/null
59
+ cat .mipham/config.yml 2>/dev/null | grep -E 'permission|trust' || echo "no config"
60
+ ```
61
+
62
+ ### 0.5 — Detect Workspace Trust
63
+
64
+ ```bash
65
+ cat ~/.mipham/trusted-workspaces.json 2>/dev/null || echo "no trust store"
66
+ ```
67
+
68
+ ### Status Report Format
69
+
70
+ After detection, present results as:
71
+
72
+ ```
73
+ ── Mipham Code Status ──
74
+
75
+ Installation: [✅/⬜] mipham CLI [✅/⬜] Bun [✅/⬜] Node.js
76
+ Project: [✅/⬜] .mipham/ [✅/⬜] config.yml [✅/⬜] MIPHAM.md
77
+ User Config: [✅/⬜] ~/.mipham/config.yml
78
+ API Keys: [N] set (list names or "none")
79
+ Skills: [N] installed
80
+ Permissions: [mode] (default/acceptEdits/plan/auto/dontAsk/bypass)
81
+ Trust: [✅/⬜] workspace trusted
82
+ ```
83
+
84
+ Then proceed to ONLY the phases where something is missing. Don't re-run already-configured steps unless asked.
85
+
86
+ ---
87
+
88
+ ## Phase 1: Installation
89
+
90
+ **Trigger**: `mipham --version` fails.
91
+
92
+ ### Option A: Quick Install (recommended)
14
93
 
15
94
  ```bash
16
95
  curl -fsSL https://mipham.ai/install.sh | bash
17
96
  ```
18
97
 
19
- **npm global install:**
98
+ Then restart the shell or run:
99
+
100
+ ```bash
101
+ export PATH="$HOME/.mipham/bin:$PATH"
102
+ ```
103
+
104
+ ### Option B: npm Global Install
20
105
 
21
106
  ```bash
22
107
  npm install -g @miphamai/cli
23
108
  mipham
24
109
  ```
25
110
 
26
- **From source:**
111
+ ### Option C: From Source (developers)
27
112
 
28
113
  ```bash
29
114
  git clone https://github.com/One-Mipham/mipham-code
@@ -31,25 +116,86 @@ cd mipham-code/apps/cli
31
116
  bun install && bun run bin/mipham
32
117
  ```
33
118
 
34
- ## Configuration
119
+ ### ✅ Verification
35
120
 
36
- ### 1. Create project config
121
+ ```bash
122
+ mipham --version # Should print version ≥ 0.24.0
123
+ mipham --help # Should print usage
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Phase 2: Project Initialization
37
129
 
38
- Run `/setup` in Mipham Code for a guided 6-step wizard, or manually:
130
+ **Trigger**: Missing `.mipham/` directory or `MIPHAM.md`.
131
+
132
+ ### 2.1 — Create .mipham/ directory
39
133
 
40
134
  ```bash
41
135
  mkdir -p .mipham
42
136
  ```
43
137
 
44
- `.mipham/config.yml`:
138
+ ### 2.2 — Create .mipham/config.yml
139
+
140
+ Write a minimal config. Ask the user which provider they want to use first, or pick a sensible default:
45
141
 
46
142
  ```yaml
47
143
  defaultProvider: anthropic
48
144
  defaultModel: claude-sonnet-4-6
49
- permission: auto
145
+ permission: default
50
146
  ```
51
147
 
52
- ### 2. Set API Keys
148
+ **Providers available** (alphabetical):
149
+
150
+ | Provider | Type | Example Models |
151
+ | --------- | ------------- | -------------------------------------- |
152
+ | anthropic | Native SDK | Claude Haiku 4.5, Sonnet 4.6, Opus 4.8 |
153
+ | deepseek | OpenAI Compat | V4 Flash, V4 Pro |
154
+ | doubao | OpenAI Compat | Seed 1.6, Seed 2.0 |
155
+ | gemini | OpenAI Compat | 3.0 Flash, 3.0 Pro, 2.5 Pro |
156
+ | hunyuan | OpenAI Compat | Lite, TurboS, 2.0, T1 |
157
+ | openai | OpenAI Compat | GPT-5.4 Mini, GPT-5.4, GPT-5.5, Codex |
158
+ | qwen | OpenAI Compat | Qwen Plus, Qwen Max |
159
+
160
+ ### 2.3 — Create MIPHAM.md (optional but recommended)
161
+
162
+ Create `MIPHAM.md` in project root to define AI personality:
163
+
164
+ ```markdown
165
+ # MIPHAM.md
166
+
167
+ ## Project Context
168
+
169
+ - **Project**: [name]
170
+ - **Language**: [zh-CN / en]
171
+ - **Stack**: [TypeScript / Python / etc.]
172
+
173
+ ## Preferences
174
+
175
+ - Code style: [e.g., functional, OOP]
176
+ - Comment language: [e.g., English]
177
+ - Test framework: [e.g., Vitest]
178
+ ```
179
+
180
+ ### ✅ Verification
181
+
182
+ ```bash
183
+ ls -la .mipham/config.yml MIPHAM.md
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Phase 3: API Key Configuration
189
+
190
+ **Trigger**: Missing API keys in environment.
191
+
192
+ ### 3.1 — Identify Required Providers
193
+
194
+ Ask the user which providers they plan to use. For each, set the env var.
195
+
196
+ ### 3.2 — Set API Keys
197
+
198
+ **Recommended: Environment variables** (not in config files — avoids accidental commits):
53
199
 
54
200
  ```bash
55
201
  export ANTHROPIC_API_KEY="sk-ant-..."
@@ -61,53 +207,344 @@ export HUNYUAN_API_KEY="..."
61
207
  export GEMINI_API_KEY="..."
62
208
  ```
63
209
 
64
- Or add to `~/.mipham/config.yml`:
210
+ Add these to `~/.zshrc` or `~/.bashrc` for persistence:
211
+
212
+ ```bash
213
+ echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.zshrc
214
+ source ~/.zshrc
215
+ ```
216
+
217
+ **Alternative**: Store in `~/.mipham/config.yml`:
65
218
 
66
219
  ```yaml
67
220
  providers:
68
221
  - id: anthropic
69
222
  apiKey: $ANTHROPIC_API_KEY
223
+ - id: openai
224
+ apiKey: $OPENAI_API_KEY
225
+ ```
226
+
227
+ ### 3.3 — Verify Keys
228
+
229
+ ```bash
230
+ env | grep API_KEY
231
+ ```
232
+
233
+ ### ❗Security Rules
234
+
235
+ - NEVER hardcode API keys in project config files (`.mipham/config.yml` in project root should use `$ENV_VAR` references, not raw keys)
236
+ - NEVER commit API keys to git
237
+ - Add to `.gitignore`: `.mipham/config.yml` (if it contains keys), `.env`, `*.pem`
238
+
239
+ ---
240
+
241
+ ## Phase 4: Provider & Model Configuration
242
+
243
+ **Trigger**: Need to set default or enable/disable providers.
244
+
245
+ ### 4.1 — Set Default Provider & Model
246
+
247
+ In `.mipham/config.yml`:
248
+
249
+ ```yaml
250
+ defaultProvider: anthropic
251
+ defaultModel: claude-sonnet-4-6
70
252
  ```
71
253
 
72
- ### 3. Project personality (MIPHAM.md)
254
+ Or use slash commands:
255
+
256
+ ```
257
+ /model # Interactive model picker (Ctrl+P)
258
+ /switch # Switch provider
259
+ /providers # List all configured providers
260
+ ```
261
+
262
+ ### 4.2 — Enable/Disable Providers
263
+
264
+ ```yaml
265
+ providers:
266
+ - id: anthropic
267
+ status: active
268
+ - id: openai
269
+ status: active
270
+ - id: deepseek
271
+ status: disabled
272
+ ```
273
+
274
+ ### ✅ Verification
275
+
276
+ ```
277
+ /model # Should show available models
278
+ /providers # Should list active providers
279
+ ```
280
+
281
+ ---
282
+
283
+ ## Phase 5: Skills Installation
284
+
285
+ **Trigger**: No or few skills installed.
286
+
287
+ ### 5.1 — Built-in Skills
73
288
 
74
- Create `MIPHAM.md` in project root to define AI interaction style:
289
+ Mipham Code ships with 15 built-in skills loaded automatically:
75
290
 
76
- - Code preferences
77
- - Language (zh-CN / en)
78
- - Project-specific rules
291
+ - **Standard (12)**: code-review, compassionate-communication, doc-generator, github-ops, memory, mipham-code-setup, security-review, self-review, superpower, tdd, web-access, web-search
292
+ - **Mipham (3)**: om-artifact, om-model-optimize, om-security
79
293
 
80
- ### 4. Verify installation
294
+ ### 5.2 — Community Skills
295
+
296
+ Install from the community registry:
297
+
298
+ ```
299
+ /setup 4 # Guided skill browser
300
+ ```
301
+
302
+ Or directly:
303
+
304
+ ```bash
305
+ # Skills are loaded from:
306
+ # - apps/cli/skills/standard/ (built-in standard)
307
+ # - apps/cli/skills/mipham/ (built-in mipham)
308
+ # - ~/.mipham/skills/ (user-installed)
309
+ # - .mipham/skills/ (project-local)
310
+ ```
311
+
312
+ ### 5.3 — Install Specific Skills
313
+
314
+ ```
315
+ /skills install <name> # Install from registry
316
+ /skills list # List available
317
+ /skills search <query> # Search registry
318
+ ```
319
+
320
+ ### ✅ Verification
321
+
322
+ ```
323
+ /skills list # Should show installed skills with counts
324
+ ```
325
+
326
+ ---
327
+
328
+ ## Phase 6: Permissions Configuration
329
+
330
+ **Trigger**: Permission mode not configured or wrong for use case.
331
+
332
+ ### 6.1 — Permission Modes
333
+
334
+ | Mode | Behavior | Use Case |
335
+ | ------------------- | ------------------------------- | ----------------------------------- |
336
+ | `default` | Prompt for each tool | Normal development (recommended) |
337
+ | `acceptEdits` | Auto-allow edits, prompt others | Active coding sessions |
338
+ | `plan` | Plan-only, no tool execution | Design & architecture work |
339
+ | `auto` | Auto-allow all | Trusted, frequent use |
340
+ | `dontAsk` | Never auto-allow | CI/CD safety |
341
+ | `bypassPermissions` | Skip all checks | ⚠️ Only for fully trusted codebases |
342
+
343
+ ### 6.2 — Configure
344
+
345
+ In `.mipham/config.yml`:
346
+
347
+ ```yaml
348
+ permission: auto
349
+ ```
350
+
351
+ Or via slash command:
352
+
353
+ ```
354
+ /permissions # View current settings
355
+ /setup 5 # Permission setup wizard
356
+ ```
357
+
358
+ ### 6.3 — CI/CD Safety
359
+
360
+ For CI/CD environments, use `dontAsk` mode to prevent the AI from executing tools without explicit approval:
361
+
362
+ ```yaml
363
+ permission: dontAsk
364
+ ```
365
+
366
+ ### ✅ Verification
367
+
368
+ ```
369
+ /permissions # Should show current mode
370
+ ```
371
+
372
+ ---
373
+
374
+ ## Phase 7: Workspace Trust
375
+
376
+ **Trigger**: Untrusted workspace (prompted on startup in v0.24.3+).
377
+
378
+ ### 7.1 — Understanding Workspace Trust
379
+
380
+ Workspace trust is a security mechanism that prevents AI from operating in untrusted directories. Trust is **hierarchical**: trusting `/Users/me/Projects` implicitly trusts all subdirectories.
381
+
382
+ ### 7.2 — Trust a Workspace
383
+
384
+ **Interactive**: Accept the trust prompt when launching Mipham Code in a new directory.
385
+
386
+ **Manual**:
387
+
388
+ ```
389
+ /trust # Show trust status
390
+ /trust add <dir> # Trust a directory
391
+ /trust remove <dir> # Revoke trust
392
+ ```
393
+
394
+ ### 7.3 — Trust Store
395
+
396
+ ```
397
+ ~/.mipham/trusted-workspaces.json
398
+ ```
399
+
400
+ ### 7.4 — Auto-Trust for Worktrees
401
+
402
+ When using git worktrees, Mipham Code automatically trusts worktree directories if the parent workspace is already trusted (via `EnterWorktree`).
403
+
404
+ ### ✅ Verification
405
+
406
+ ```
407
+ /trust # Should show "✅ Yes" for current directory
408
+ ```
409
+
410
+ ---
411
+
412
+ ## Phase 8: Shell & IDE Integration
413
+
414
+ **Trigger**: Want terminal integration, aliases, or IDE plugins.
415
+
416
+ ### 8.1 — Shell Alias
417
+
418
+ Add to `~/.zshrc` or `~/.bashrc`:
419
+
420
+ ```bash
421
+ alias mipham='cd ~/your-project && bun run ~/path/to/mipham-code/apps/cli/bin/mipham.ts'
422
+ # Or if installed globally:
423
+ alias mipham='mipham'
424
+ ```
425
+
426
+ ### 8.2 — VS Code Integration
427
+
428
+ Run `/ide` to auto-generate `.vscode/` config files:
429
+
430
+ - `settings.json` — terminal profile "mipham" using Bun
431
+ - `keybindings.json` — Cmd+Esc to focus terminal, Cmd+Shift+M for new terminal
432
+ - `extensions.json` — recommends `miphamai.mipham-code` extension
433
+
434
+ To use after generation:
435
+
436
+ 1. Restart VS Code (or Cmd+Shift+P → Reload Window)
437
+ 2. Open terminal: Ctrl+` or Cmd+Esc
438
+ 3. Select "mipham" profile from terminal dropdown
439
+
440
+ Install the VS Code extension:
441
+
442
+ ```bash
443
+ code --install-extension miphamai.mipham-code
444
+ ```
445
+
446
+ ### 8.3 — JetBrains Integration
447
+
448
+ Settings → Tools → Terminal → Shell path → `bun run mipham`
449
+
450
+ ### 8.4 — Terminal Setup
451
+
452
+ ```
453
+ /terminal-setup # Shell & terminal config wizard
454
+ /setup 6 # Shell integration (part of full wizard)
455
+ ```
456
+
457
+ ### ✅ Verification
81
458
 
82
459
  ```bash
83
- mipham --version
84
- mipham --help
460
+ which mipham # Should resolve
461
+ # In VS Code: Ctrl+` → select "mipham" profile
85
462
  ```
86
463
 
87
- Use `/doctor` in Mipham Code for system diagnostics.
464
+ ---
465
+
466
+ ## Phase 9: Full Verification
467
+
468
+ Run after all configuration phases complete.
469
+
470
+ ### 9.1 — System Diagnostics
471
+
472
+ ```
473
+ /doctor # System diagnostics check
474
+ ```
88
475
 
89
- ## Supported Providers
476
+ ### 9.2 — End-to-End Test
90
477
 
91
- | Provider | Type | Models |
92
- | ------------- | ------------- | -------------------------------------- |
93
- | Anthropic | Native SDK | Claude Haiku 4.5, Sonnet 4.6, Opus 4.8 |
94
- | OpenAI | OpenAI Compat | GPT-5.4 Mini, GPT-5.4, GPT-5.5, Codex |
95
- | DeepSeek | OpenAI Compat | V4 Flash, V4 Pro |
96
- | Google Gemini | OpenAI Compat | 3.0 Flash/Pro, 2.5 Pro |
97
- | Qwen | OpenAI Compat | Qwen Plus, Qwen Max |
98
- | Doubao | OpenAI Compat | Seed 1.6/2.0 series |
99
- | Hunyuan | OpenAI Compat | Lite, TurboS, 2.0, T1 |
478
+ Start a conversation and verify:
100
479
 
101
- ## Slash Commands (60 total)
480
+ 1. Model responds (not stuck on "connecting...")
481
+ 2. File tools work: "read CLAUDE.md"
482
+ 3. Bash works: "list files in current directory"
483
+ 4. Skills load: `/skills list`
484
+
485
+ ### 9.3 — Common Issues & Fixes
486
+
487
+ | Symptom | Diagnosis | Fix |
488
+ | ------------------------- | -------------------------------------- | ------------------------------------------------ |
489
+ | "Provider not registered" | Missing or invalid API key | `env \| grep API_KEY`; check key format |
490
+ | "Model not found" | Model ID mismatch or disabled provider | `/models` to list available; `/switch` to change |
491
+ | Slow responses | Large model, network, or context full | `/fast on` or switch to Flash model; `/compact` |
492
+ | Context full | Too many messages in history | `/compact` to compress; `/clear` to reset |
493
+ | Permission denied | Tool blocked by permission mode | `/permissions` to check; adjust mode |
494
+ | "Workspace not trusted" | New directory, not yet trusted | Accept startup prompt or run `/trust` |
495
+ | MCP tools not available | Server not connected | `/mcp connect <name>` or check config |
496
+ | Update not applying | Cached binary | `mipham update --force` then restart |
497
+ | Config changes ignored | YAML syntax error | Validate with `mipham --check-config` |
498
+
499
+ ### 9.4 — Get Help
500
+
501
+ ```
502
+ /help # Full command reference
503
+ /setup # Re-run setup wizard
504
+ /doctor # Run diagnostics
505
+ ```
506
+
507
+ Chat-based help: "help me configure X" or "why isn't Y working?"
508
+
509
+ ---
510
+
511
+ ## Quick Reference: Essential Slash Commands
512
+
513
+ | Category | Command | Purpose |
514
+ | ------------- | ----------------- | ------------------------------------------------------ |
515
+ | **Setup** | `/setup` | Full 6-step setup wizard |
516
+ | | `/setup 1` | Initialize project (.mipham/ + MIPHAM.md + config.yml) |
517
+ | | `/setup 2` | Configure providers & API keys |
518
+ | | `/setup 3` | Choose default model |
519
+ | | `/setup 4` | Browse & install skills |
520
+ | | `/setup 5` | Configure permissions |
521
+ | | `/setup 6` | Shell & IDE integration |
522
+ | **Diagnosis** | `/doctor` | System diagnostics |
523
+ | | `/trust` | Workspace trust status |
524
+ | | `/permissions` | Tool permission settings |
525
+ | **Model** | `/model` | Interactive model picker (Ctrl+P) |
526
+ | | `/switch` | Switch provider |
527
+ | | `/models` | List available models |
528
+ | **Session** | `/clear` | Reset conversation |
529
+ | | `/compact` | Compress context |
530
+ | | `/rename` | Rename session |
531
+ | **Workflow** | `/plan` | Enter plan mode |
532
+ | | `/review` | Code review |
533
+ | | `/todos` | Task list |
534
+ | **IDE** | `/ide` | Generate VS Code integration files |
535
+ | | `/terminal-setup` | Shell & terminal config |
536
+ | **Skills** | `/skills list` | List installed skills |
537
+ | | `/skills search` | Search skill registry |
538
+ | | `/skills install` | Install a skill |
539
+
540
+ ---
102
541
 
103
- Essential: `/help`, `/switch`, `/model`, `/setup`, `/doctor`, `/mcp`
104
- Workflow: `/plan`, `/review`, `/diff`, `/todos`, `/tasks`
105
- Session: `/clear`, `/compact`, `/rename`, `/goal`, `/export`, `/resume`
542
+ ## Post-Setup: What to Do Next
106
543
 
107
- ## Troubleshooting
544
+ After configuration is verified:
108
545
 
109
- - **"Provider not registered"**: Check API key is set (`env | grep API_KEY`)
110
- - **"Model not found"**: Use `/models` to list available models
111
- - **Slow responses**: Toggle `/fast on` or switch to a Flash model
112
- - **Context full**: Use `/compact` to free token space
113
- - **Permission denied**: Use `/permissions` to check tool access settings
546
+ 1. **Initialize your project**: "help me understand this codebase"
547
+ 2. **Set up CLAUDE.md**: `/init` to generate project documentation for the AI
548
+ 3. **Install relevant skills**: `/setup 4` or `/skills search`
549
+ 4. **Configure MCP servers**: `/mcp connect` for external tool integration
550
+ 5. **Start coding**: Just start a conversation — the AI will use tools and skills automatically
@@ -8,6 +8,7 @@ import type { HookEngine } from '../core/hooks'
8
8
  import type { PermissionSystem } from '../core/permission'
9
9
  import { AgentExperience } from './agent-experience'
10
10
  import { PatternAnalyzer } from './pattern-analyzer.js'
11
+ import { getWorkspaceTrust } from '../core/workspace-trust'
11
12
  import type { ExperienceRuleEngine } from '../core/rule-engine.js'
12
13
 
13
14
  // Singleton instances (created lazily)
@@ -200,6 +201,19 @@ export class SubAgent {
200
201
  // Resolve execution directory: worktree isolation or process cwd
201
202
  const execCwd = options.worktreePath || process.cwd()
202
203
 
204
+ // Check workspace trust for the execution directory.
205
+ // For worktree-isolated agents, auto-trust the worktree if the parent is trusted.
206
+ if (options.worktreePath) {
207
+ const trust = getWorkspaceTrust()
208
+ if (!trust.isTrusted(execCwd)) {
209
+ // Auto-trust worktree directories when the parent workspace is trusted
210
+ if (trust.isTrusted(process.cwd())) {
211
+ trust.trust(execCwd)
212
+ }
213
+ // Otherwise, proceed with a warning — don't block agent execution
214
+ }
215
+ }
216
+
203
217
  // Resolve system prompt: agentDef > options.systemPrompt > builtin type
204
218
  const systemPrompt =
205
219
  agentDef?.systemPrompt || options.systemPrompt || TYPE_SYSTEM_PROMPTS[agentType]
@@ -6,8 +6,18 @@
6
6
  * /security, /audit, /prompt-audit
7
7
  */
8
8
  import type { CommandHandler, CommandContext, CommandResult } from '../ui/commands.js'
9
-
10
- export { initCmd, permissionsCmd, recommendCmd, setupCmd, addDirCmd, promptAuditCmd, securityCmd }
9
+ import { getWorkspaceTrust } from '../core/workspace-trust'
10
+
11
+ export {
12
+ initCmd,
13
+ permissionsCmd,
14
+ recommendCmd,
15
+ setupCmd,
16
+ addDirCmd,
17
+ promptAuditCmd,
18
+ securityCmd,
19
+ trustCmd,
20
+ }
11
21
 
12
22
  const initCmd: CommandHandler = async (ctx) => {
13
23
  const { existsSync, mkdirSync, writeFileSync } = await import('node:fs')
@@ -1004,3 +1014,35 @@ const securityCmd: CommandHandler = async () => {
1004
1014
 
1005
1015
  return { content: lines.join('\n') }
1006
1016
  }
1017
+
1018
+ const trustCmd: CommandHandler = (ctx) => {
1019
+ const trust = getWorkspaceTrust()
1020
+ const cwd = process.cwd()
1021
+ const trusted = trust.listTrusted()
1022
+
1023
+ const lines: string[] = [
1024
+ '── Workspace Trust ──',
1025
+ '',
1026
+ `Current directory: ${cwd}`,
1027
+ `Trusted: ${trust.isTrusted(cwd) ? '✅ Yes' : '⚠️ No (restart to trust)'}`,
1028
+ `Trust store: ${trust.getStorePath()}`,
1029
+ '',
1030
+ ]
1031
+
1032
+ if (trusted.length === 0) {
1033
+ lines.push('No trusted workspaces configured.')
1034
+ lines.push('')
1035
+ lines.push('Trust a workspace: restart Mipham Code in the directory')
1036
+ lines.push('and accept the trust prompt.')
1037
+ } else {
1038
+ lines.push(`Trusted workspaces (${trusted.length}):`)
1039
+ for (const dir of trusted) {
1040
+ const marker = cwd.startsWith(dir) ? ' ← current' : ''
1041
+ lines.push(` • ${dir}${marker}`)
1042
+ }
1043
+ lines.push('')
1044
+ lines.push('Remove a workspace: delete the directory entry from the trust store.')
1045
+ }
1046
+
1047
+ return { content: lines.join('\n') }
1048
+ }
@@ -0,0 +1,144 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs'
2
+ import { join, dirname, resolve } from 'node:path'
3
+ import { homedir } from 'node:os'
4
+
5
+ const MIPHAM_HOME = join(homedir(), '.mipham')
6
+ const TRUST_STORE_PATH = join(MIPHAM_HOME, 'trusted-workspaces.json')
7
+
8
+ export interface TrustedWorkspaces {
9
+ version: 1
10
+ directories: string[]
11
+ updatedAt: string
12
+ }
13
+
14
+ /**
15
+ * Resolves a directory to its real absolute path, following symlinks.
16
+ * Falls back to the resolved path if realpath fails.
17
+ */
18
+ function realPath(dir: string): string {
19
+ try {
20
+ // Use resolve to normalize, but don't require the directory to exist yet
21
+ const resolved = resolve(dir)
22
+ return resolved
23
+ } catch {
24
+ return resolve(dir)
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Manages the workspace trust store.
30
+ *
31
+ * Trust is hierarchical: a directory is trusted if it or any of its
32
+ * ancestor directories are in the trust store. This means trusting
33
+ * /Users/me/Projects implicitly trusts all subdirectories.
34
+ */
35
+ export class WorkspaceTrust {
36
+ private store: TrustedWorkspaces
37
+
38
+ constructor() {
39
+ this.store = this.load()
40
+ }
41
+
42
+ /** Load the trust store from disk, or return a fresh default. */
43
+ private load(): TrustedWorkspaces {
44
+ try {
45
+ if (!existsSync(TRUST_STORE_PATH)) {
46
+ return { version: 1, directories: [], updatedAt: new Date().toISOString() }
47
+ }
48
+ const raw = readFileSync(TRUST_STORE_PATH, 'utf-8')
49
+ const parsed = JSON.parse(raw) as TrustedWorkspaces
50
+ if (parsed.version !== 1) {
51
+ // Unknown version — reset
52
+ return { version: 1, directories: [], updatedAt: new Date().toISOString() }
53
+ }
54
+ return parsed
55
+ } catch {
56
+ return { version: 1, directories: [], updatedAt: new Date().toISOString() }
57
+ }
58
+ }
59
+
60
+ /** Persist the trust store to disk. */
61
+ private save(): void {
62
+ try {
63
+ if (!existsSync(MIPHAM_HOME)) {
64
+ mkdirSync(MIPHAM_HOME, { recursive: true })
65
+ }
66
+ this.store.updatedAt = new Date().toISOString()
67
+ writeFileSync(TRUST_STORE_PATH, JSON.stringify(this.store, null, 2), 'utf-8')
68
+ } catch {
69
+ // Best-effort: don't crash if we can't save
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Check whether a directory is trusted.
75
+ * A directory is trusted if it or any ancestor is in the trust list.
76
+ */
77
+ isTrusted(dir: string): boolean {
78
+ const resolved = realPath(dir)
79
+ const resolvedLower = resolved.toLowerCase()
80
+
81
+ for (const trusted of this.store.directories) {
82
+ const trustedLower = trusted.toLowerCase()
83
+ // Exact match
84
+ if (resolvedLower === trustedLower) return true
85
+ // Ancestor match: trusted dir is a parent of the target
86
+ if (resolvedLower.startsWith(trustedLower + '/')) return true
87
+ }
88
+
89
+ return false
90
+ }
91
+
92
+ /** Add a directory to the trust store. */
93
+ trust(dir: string): void {
94
+ const resolved = realPath(dir)
95
+ // Don't add duplicates
96
+ if (this.store.directories.includes(resolved)) return
97
+ // Don't add subdirectories of already-trusted paths
98
+ if (this.isTrusted(resolved)) return
99
+
100
+ this.store.directories.push(resolved)
101
+ // Sort for readability
102
+ this.store.directories.sort()
103
+ this.save()
104
+ }
105
+
106
+ /** Remove a directory from the trust store (and any subdirectories). */
107
+ untrust(dir: string): void {
108
+ const resolved = realPath(dir)
109
+ const resolvedLower = resolved.toLowerCase()
110
+
111
+ this.store.directories = this.store.directories.filter((d) => {
112
+ const lower = d.toLowerCase()
113
+ // Remove exact match and all subdirectories
114
+ return lower !== resolvedLower && !lower.startsWith(resolvedLower + '/')
115
+ })
116
+ this.save()
117
+ }
118
+
119
+ /** List all trusted directories. */
120
+ listTrusted(): string[] {
121
+ return [...this.store.directories]
122
+ }
123
+
124
+ /** Get the path to the trust store. */
125
+ getStorePath(): string {
126
+ return TRUST_STORE_PATH
127
+ }
128
+ }
129
+
130
+ // ── Singleton ──
131
+
132
+ let _instance: WorkspaceTrust | null = null
133
+
134
+ export function getWorkspaceTrust(): WorkspaceTrust {
135
+ if (!_instance) {
136
+ _instance = new WorkspaceTrust()
137
+ }
138
+ return _instance
139
+ }
140
+
141
+ /** Reset the singleton (for tests). */
142
+ export function resetWorkspaceTrust(): void {
143
+ _instance = null
144
+ }
package/src/index.tsx CHANGED
@@ -1,7 +1,9 @@
1
1
  import React from 'react'
2
2
  import { join } from 'node:path'
3
+ import { homedir } from 'node:os'
3
4
  import { existsSync } from 'node:fs'
4
5
  import { render } from 'ink'
6
+ import * as readline from 'node:readline'
5
7
  import { App } from './ui/app'
6
8
  import {
7
9
  loadConfig,
@@ -33,6 +35,7 @@ import { AgentRegistry } from './agent/agent-registry'
33
35
  import { HookEngine } from './core/hooks'
34
36
  import { ArtifactServer } from './artifacts/server'
35
37
  import { getMetrics } from './core/metrics'
38
+ import { getWorkspaceTrust } from './core/workspace-trust'
36
39
  import { ARTIFACTS_DIR, ARTIFACT_PORT, MIPHAM_DIR } from './shared/constants'
37
40
  import { AgentViewManager } from './agent-view/agent-view-manager'
38
41
  import { AgentViewDashboard } from './agent-view/dashboard'
@@ -52,10 +55,69 @@ interface RunOptions {
52
55
  version?: string
53
56
  }
54
57
 
58
+ /**
59
+ * Check workspace trust before starting the session.
60
+ * If the cwd is not trusted, prompt the user via stdin.
61
+ * Exits the process if the user declines.
62
+ */
63
+ async function checkWorkspaceTrust(): Promise<void> {
64
+ const cwd = process.cwd()
65
+ const trust = getWorkspaceTrust()
66
+
67
+ if (trust.isTrusted(cwd)) return
68
+
69
+ // Non-interactive mode (piped stdin, headless) — skip prompt, proceed
70
+ if (!process.stdin.isTTY) return
71
+
72
+ const rl = readline.createInterface({
73
+ input: process.stdin,
74
+ output: process.stderr, // use stderr to avoid interfering with stdout rendering
75
+ })
76
+
77
+ const question = (prompt: string): Promise<string> =>
78
+ new Promise((resolve) => {
79
+ rl.question(prompt, (answer) => {
80
+ resolve(answer.trim().toLowerCase())
81
+ })
82
+ })
83
+
84
+ process.stderr.write('\n')
85
+ process.stderr.write('╔══════════════════════════════════════════════╗\n')
86
+ process.stderr.write('║ ⚠️ Workspace Trust ║\n')
87
+ process.stderr.write('╠══════════════════════════════════════════════╣\n')
88
+ process.stderr.write('║ ║\n')
89
+ process.stderr.write(`║ Directory not trusted: ║\n`)
90
+ process.stderr.write(`║ ${cwd.slice(0, 42).padEnd(42)}║\n`)
91
+ process.stderr.write('║ ║\n')
92
+ process.stderr.write('║ Trust this workspace? ║\n')
93
+ process.stderr.write('║ [Y] Trust and continue ║\n')
94
+ process.stderr.write('║ [N] Exit ║\n')
95
+ process.stderr.write('║ ║\n')
96
+ process.stderr.write('╚══════════════════════════════════════════════╝\n')
97
+ process.stderr.write('\n')
98
+
99
+ try {
100
+ const answer = await question('Trust this workspace? [Y/N]: ')
101
+ if (answer === 'y' || answer === 'yes') {
102
+ trust.trust(cwd)
103
+ process.stderr.write(`✓ Workspace trusted: ${cwd}\n\n`)
104
+ } else {
105
+ process.stderr.write('✗ Workspace not trusted. Exiting.\n')
106
+ rl.close()
107
+ process.exit(1)
108
+ }
109
+ } finally {
110
+ rl.close()
111
+ }
112
+ }
113
+
55
114
  export async function runApp(options: RunOptions): Promise<void> {
56
115
  // Metrics: count CLI invocation
57
116
  getMetrics().cliInvocations.inc()
58
117
 
118
+ // ── Workspace Trust Check ──
119
+ await checkWorkspaceTrust()
120
+
59
121
  // Handle `mipham agents` subcommand — launch standalone dashboard
60
122
  const args = process.argv.slice(2)
61
123
  if (args[0] === 'agents') {
@@ -202,6 +264,52 @@ export async function runApp(options: RunOptions): Promise<void> {
202
264
  prompt = `${prompt}\n\n<system-reminder name="key-expiry">\n${keyReminder}\n</system-reminder>`
203
265
  }
204
266
 
267
+ // First-run setup detection: inject mipham-code-setup guidance when
268
+ // no project or user config exists. This mirrors Claude Code's first-run
269
+ // onboarding flow — the AI proactively offers to help configure the tool.
270
+ const hasProjectConfig = existsSync(join(process.cwd(), '.mipham', 'config.yml'))
271
+ const hasUserConfig = existsSync(join(homedir(), '.mipham', 'config.yml'))
272
+ const hasMiphamMd = existsSync(join(process.cwd(), 'MIPHAM.md'))
273
+ if (!hasProjectConfig && !hasUserConfig) {
274
+ const setupReminder = [
275
+ '── First-Run Setup ──',
276
+ '',
277
+ `This appears to be a first run: no .mipham/config.yml found in project or ~/.mipham/.`,
278
+ '',
279
+ 'Invoke the mipham-code-setup skill to guide the user through setup:',
280
+ '- Installation verification',
281
+ '- API key configuration',
282
+ '- Project initialization (.mipham/ + MIPHAM.md + config.yml)',
283
+ '- Provider & model selection',
284
+ '- Skills & permissions setup',
285
+ '- Workspace trust',
286
+ '- Shell & IDE integration',
287
+ '',
288
+ 'The user may also run /setup for the guided 6-step wizard.',
289
+ 'Be proactive: offer to help configure Mipham Code before diving into',
290
+ 'their task. A properly configured environment makes everything smoother.',
291
+ ].join('\n')
292
+ prompt = `${prompt}\n\n<system-reminder name="first-run-setup">\n${setupReminder}\n</system-reminder>`
293
+ } else if (!hasMiphamMd) {
294
+ // Partial setup: has config but no MIPHAM.md
295
+ const partialReminder = [
296
+ '── Missing MIPHAM.md ──',
297
+ '',
298
+ 'No MIPHAM.md found in project root. This file tells the AI about',
299
+ 'project-specific preferences (language, code style, test framework).',
300
+ '',
301
+ 'Suggest creating one: /setup 1 or "help me create a MIPHAM.md"',
302
+ '',
303
+ 'A basic MIPHAM.md includes:',
304
+ '- Project name and description',
305
+ '- Primary language (zh-CN / en)',
306
+ '- Tech stack',
307
+ '- Code style preferences',
308
+ '- Test framework',
309
+ ].join('\n')
310
+ prompt = `${prompt}\n\n<system-reminder name="missing-mipham-md">\n${partialReminder}\n</system-reminder>`
311
+ }
312
+
205
313
  context.setSystemPrompt(prompt)
206
314
  }
207
315
 
@@ -52,6 +52,15 @@
52
52
  "author": "MiphamAI",
53
53
  "builtin": true
54
54
  },
55
+ {
56
+ "name": "mipham-code-setup",
57
+ "description": "Install, configure, diagnose, and troubleshoot Mipham Code — executable setup workflow with 9-phase decision tree covering installation, API keys, providers, models, skills, permissions, workspace trust, and shell/IDE integration",
58
+ "url": "https://github.com/One-Mipham/mipham-code",
59
+ "file": "mipham-code-setup.SKILL.md",
60
+ "category": "Setup",
61
+ "author": "MiphamAI",
62
+ "builtin": true
63
+ },
55
64
  {
56
65
  "name": "security-review",
57
66
  "description": "Security audit and vulnerability scanning for code changes — OWASP, secrets, supply chain",
@@ -35,6 +35,7 @@ import {
35
35
  addDirCmd,
36
36
  securityCmd,
37
37
  promptAuditCmd,
38
+ trustCmd,
38
39
  } from '../commands/project.js'
39
40
  import { themeCmd, releaseNotesCmd, ideCmd, terminalSetupCmd } from '../commands/environment.js'
40
41
  import { commitCmd, pushCmd, prCmd, issueCmd } from '../commands/git.js'
@@ -3215,6 +3216,7 @@ const commandsListCmd: CommandHandler = () => {
3215
3216
  '/recommend': 'Project',
3216
3217
  '/security': 'Project',
3217
3218
  '/audit': 'Project',
3219
+ '/trust': 'Project',
3218
3220
  '/prompt-audit': 'Code Quality',
3219
3221
  '/ide': 'Environment',
3220
3222
  '/terminal-setup': 'Environment',
@@ -3371,6 +3373,7 @@ registry.set('/permissions', permissionsCmd)
3371
3373
  registry.set('/add-dir', addDirCmd)
3372
3374
  registry.set('/security', securityCmd)
3373
3375
  registry.set('/audit', securityCmd)
3376
+ registry.set('/trust', trustCmd)
3374
3377
  registry.set('/prompt-audit', promptAuditCmd)
3375
3378
 
3376
3379
  // Environment
@@ -3513,6 +3516,7 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
3513
3516
  '/recommend': 'Analyze project + recommend skills & setup',
3514
3517
  '/security': 'Security review checklist',
3515
3518
  '/audit': 'Same as /security',
3519
+ '/trust': 'Show and manage trusted workspaces',
3516
3520
  '/prompt-audit': 'Audit prompts for modern model optimization',
3517
3521
  '/ide': 'IDE integration guide',
3518
3522
  '/terminal-setup': 'Shell & terminal config',