@miphamai/cli 0.57.0 → 0.59.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/bin/mipham.ts +35 -0
- package/package.json +1 -1
- package/skills/standard/mipham-code-setup.SKILL.md +5 -9
- package/src/agent/sub-agent.ts +0 -3
- package/src/agent/types.ts +1 -2
- package/src/commands/project.ts +2 -4
- package/src/config/defaults.ts +1 -1
- package/src/core/crsi-producer.ts +41 -0
- package/src/core/engine.ts +16 -0
- package/src/core/instructions.ts +35 -3
- package/src/core/permission-config.ts +0 -2
- package/src/core/permission.ts +5 -60
- package/src/core/project-scaffold.ts +158 -0
- package/src/daemon/server.ts +0 -2
- package/src/i18n-core/locales/en-US.json +1 -2
- package/src/i18n-core/locales/zh-CN.json +1 -2
- package/src/index.tsx +8 -0
- package/src/providers/fetch-utils.ts +18 -4
- package/src/shared/package-info.ts +1 -1
- package/src/shared/types.ts +5 -6
- package/src/skills/bundled-skills.ts +1 -1
- package/src/ui/app.tsx +52 -31
- package/src/ui/input.tsx +28 -7
package/bin/mipham.ts
CHANGED
|
@@ -1057,6 +1057,36 @@ async function runTokenCLI(): Promise<boolean> {
|
|
|
1057
1057
|
process.exit(1)
|
|
1058
1058
|
}
|
|
1059
1059
|
|
|
1060
|
+
// ── mipham init [dir] — 生成规范项目文档 (CLAUDE.md/MIPHAM.md/README.md) ──
|
|
1061
|
+
async function runInitCLI(): Promise<boolean> {
|
|
1062
|
+
const args = process.argv.slice(2)
|
|
1063
|
+
if (args[0] !== 'init') return false
|
|
1064
|
+
|
|
1065
|
+
const { resolve } = await import('node:path')
|
|
1066
|
+
const { homedir } = await import('node:os')
|
|
1067
|
+
const { scaffoldProject } = await import('../src/core/project-scaffold')
|
|
1068
|
+
|
|
1069
|
+
const rawTarget = args.slice(1).find((a) => !a.startsWith('--'))
|
|
1070
|
+
const targetDir = rawTarget ? resolve(rawTarget.replace(/^~/, homedir())) : process.cwd()
|
|
1071
|
+
|
|
1072
|
+
const gitInit = !args.includes('--no-git')
|
|
1073
|
+
const result = scaffoldProject(targetDir, { gitInit })
|
|
1074
|
+
|
|
1075
|
+
const lines: string[] = ['', `✅ Mipham Code 项目已初始化:${targetDir}`, '']
|
|
1076
|
+
if (result.created.length > 0) {
|
|
1077
|
+
lines.push('已创建:')
|
|
1078
|
+
for (const c of result.created) lines.push(` ✅ ${c}`)
|
|
1079
|
+
}
|
|
1080
|
+
if (result.skipped.length > 0) {
|
|
1081
|
+
lines.push('已存在(跳过):')
|
|
1082
|
+
for (const s of result.skipped) lines.push(` ⏭ ${s}`)
|
|
1083
|
+
}
|
|
1084
|
+
if (result.gitInitialized) lines.push(' ✅ git init')
|
|
1085
|
+
lines.push('', '下一步:', ' 1. 填写各文档中的 [占位符]', ' 2. 运行 mipham 开始协作')
|
|
1086
|
+
console.log(lines.join('\n'))
|
|
1087
|
+
process.exit(0)
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1060
1090
|
async function main() {
|
|
1061
1091
|
// ── Deleted-cwd guard ──────────────────────────────────────────────────
|
|
1062
1092
|
// `process.cwd()` throws ENOENT when the directory the process was launched
|
|
@@ -1129,6 +1159,7 @@ async function main() {
|
|
|
1129
1159
|
|
|
1130
1160
|
Usage:
|
|
1131
1161
|
mipham Launch interactive CLI
|
|
1162
|
+
mipham init [dir] Scaffold a project (CLAUDE.md/MIPHAM.md/README.md)
|
|
1132
1163
|
mipham update Update to the latest version
|
|
1133
1164
|
mipham upgrade Same as 'mipham update'
|
|
1134
1165
|
mipham daemon <cmd> Daemon lifecycle (start, stop, status, restart)
|
|
@@ -1183,6 +1214,10 @@ npm: https://www.npmjs.com/package/@miphamai/cli`)
|
|
|
1183
1214
|
const handledUpdate = await runUpdate()
|
|
1184
1215
|
if (handledUpdate) return
|
|
1185
1216
|
|
|
1217
|
+
// ── Init command ─────────────────────────────────────────────────────────
|
|
1218
|
+
const handledInit = await runInitCLI()
|
|
1219
|
+
if (handledInit) return
|
|
1220
|
+
|
|
1186
1221
|
// ── Daemon commands ───────────────────────────────────────────────────────
|
|
1187
1222
|
const handledDaemon = await runDaemonCLI()
|
|
1188
1223
|
if (handledDaemon) return
|
package/package.json
CHANGED
|
@@ -77,7 +77,7 @@ Project: [✅/⬜] .mipham/ [✅/⬜] config.yml [✅/⬜] MIPHAM.md
|
|
|
77
77
|
User Config: [✅/⬜] ~/.mipham/config.yml
|
|
78
78
|
API Keys: [N] set (list names or "none")
|
|
79
79
|
Skills: [N] installed
|
|
80
|
-
Permissions: [mode] (default/acceptEdits/plan/
|
|
80
|
+
Permissions: [mode] (default/acceptEdits/plan/bypassPermissions)
|
|
81
81
|
Trust: [✅/⬜] workspace trusted
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -336,8 +336,6 @@ Or directly:
|
|
|
336
336
|
| `default` | Prompt for each tool | Normal development (recommended) |
|
|
337
337
|
| `acceptEdits` | Auto-allow edits, prompt others | Active coding sessions |
|
|
338
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
339
|
| `bypassPermissions` | Skip all checks | ⚠️ Only for fully trusted codebases |
|
|
342
340
|
|
|
343
341
|
### 6.2 — Configure
|
|
@@ -345,7 +343,7 @@ Or directly:
|
|
|
345
343
|
In `.mipham/config.yml`:
|
|
346
344
|
|
|
347
345
|
```yaml
|
|
348
|
-
permission:
|
|
346
|
+
permission: default
|
|
349
347
|
```
|
|
350
348
|
|
|
351
349
|
Or via slash command:
|
|
@@ -357,11 +355,9 @@ Or via slash command:
|
|
|
357
355
|
|
|
358
356
|
### 6.3 — CI/CD Safety
|
|
359
357
|
|
|
360
|
-
For CI/CD environments, use `
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
permission: dontAsk
|
|
364
|
-
```
|
|
358
|
+
For CI/CD environments, use the `default` mode (the daemon default): headless
|
|
359
|
+
sessions never prompt, so `ask`-level tools (Bash/Write/Edit) are blocked rather
|
|
360
|
+
than auto-approved.
|
|
365
361
|
|
|
366
362
|
### ✅ Verification
|
|
367
363
|
|
package/src/agent/sub-agent.ts
CHANGED
|
@@ -210,9 +210,6 @@ export class SubAgent {
|
|
|
210
210
|
? agentDef.permissionMode
|
|
211
211
|
: 'inherit'
|
|
212
212
|
subPermission = this.permission.createSubAgentPermission(agentPermMode)
|
|
213
|
-
// P0-5: Enable sub-agent safety mode — auto mode returns 'ask' for
|
|
214
|
-
// Bash/Write/Edit so hooks remain the safety gate in background agents.
|
|
215
|
-
subPermission.setSubAgentMode(true)
|
|
216
213
|
}
|
|
217
214
|
|
|
218
215
|
// Resolve execution directory: worktree isolation or process cwd
|
package/src/agent/types.ts
CHANGED
|
@@ -10,8 +10,7 @@ export interface AgentFrontmatter {
|
|
|
10
10
|
tools?: string // comma-separated allowlist
|
|
11
11
|
disallowedTools?: string
|
|
12
12
|
model?: string // 'sonnet' | 'opus' | 'haiku' | 'inherit' | full model ID
|
|
13
|
-
permissionMode?:
|
|
14
|
-
'default' | 'acceptEdits' | 'auto' | 'bypass' | 'plan' | 'bypassPermissions' | 'dontAsk'
|
|
13
|
+
permissionMode?: 'default' | 'acceptEdits' | 'bypass' | 'plan' | 'bypassPermissions'
|
|
15
14
|
maxTurns?: number
|
|
16
15
|
skills?: string
|
|
17
16
|
background?: boolean
|
package/src/commands/project.ts
CHANGED
|
@@ -111,7 +111,7 @@ const permissionsCmd: CommandHandler = (ctx) => {
|
|
|
111
111
|
return {
|
|
112
112
|
content: `─ Permission Settings ─
|
|
113
113
|
|
|
114
|
-
Mode: ${ctx.
|
|
114
|
+
Mode: ${ctx.engine.getPermission().getMode()}
|
|
115
115
|
Messages: ${msgs.length} in context
|
|
116
116
|
Tools: ${ctx.engine.getTools().size} available
|
|
117
117
|
|
|
@@ -119,12 +119,10 @@ Switch mode with Shift+Tab. Modes (least → most permissive):
|
|
|
119
119
|
default — per-tool defaults (Bash/Write/Edit ask first)
|
|
120
120
|
acceptEdits — reads + edits free; Bash auto-runs read/check commands
|
|
121
121
|
plan — reads only (Read/Grep/Glob); nothing writes or runs
|
|
122
|
-
auto — run everything without asking (hooks are the safety gate)
|
|
123
|
-
dontAsk — only allowlisted tools free; everything else asks
|
|
124
122
|
bypassPermissions — skip ALL permission checks (⚠️ use with caution)
|
|
125
123
|
|
|
126
124
|
To let Bash run without asking: press Shift+Tab until the status line shows
|
|
127
|
-
"acceptEdits"
|
|
125
|
+
"acceptEdits", then send your message again.
|
|
128
126
|
|
|
129
127
|
Current directory permissions:
|
|
130
128
|
CWD: ${process.cwd()}
|
package/src/config/defaults.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const DEFAULT_CONFIG: MiphamConfig = {
|
|
|
12
12
|
version: PACKAGE_VERSION,
|
|
13
13
|
defaultProvider: 'deepseek',
|
|
14
14
|
defaultModel: 'deepseek-v4-pro',
|
|
15
|
-
permission: '
|
|
15
|
+
permission: 'default',
|
|
16
16
|
// Org 级权限限制(可选):forbiddenModes 禁指定模式 / maxAllowedMode 封顶层级;
|
|
17
17
|
// 请求被禁模式时 fail-closed 降级(如 forbiddenModes:['bypassPermissions'])。
|
|
18
18
|
// permissionRestrictions: { forbiddenModes: ['bypassPermissions'] },
|
|
@@ -80,6 +80,47 @@ export function buildLessonContent(signal: CrsiSignal, timestamp: string): strin
|
|
|
80
80
|
return lines.join('\n')
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/** 教训精华(标题 + 建议),用于运行时召回注入系统提示。 */
|
|
84
|
+
export interface CrsiLessonSummary {
|
|
85
|
+
title: string
|
|
86
|
+
suggestion: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 从 crsi-lessons.md 提取每条教训的「精华」(标题 + 建议),跳过证据段落。
|
|
91
|
+
* 这是「只写不读」缺口 → 「写后召回」的读取侧。
|
|
92
|
+
*/
|
|
93
|
+
export function extractCrsiLessonSummaries(content: string): CrsiLessonSummary[] {
|
|
94
|
+
const out: CrsiLessonSummary[] = []
|
|
95
|
+
let title = ''
|
|
96
|
+
for (const line of content.split('\n')) {
|
|
97
|
+
const h = line.match(/^##\s+(.+?)\s*$/)
|
|
98
|
+
if (h) {
|
|
99
|
+
title = h[1]!.trim()
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
const s = line.match(/^-\s*建议[::]\s*(.+)$/)
|
|
103
|
+
if (s && title) {
|
|
104
|
+
out.push({ title, suggestion: s[1]!.trim() })
|
|
105
|
+
title = ''
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return out
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** 把教训精华渲染为系统提示召回块。无教训时返回空串。 */
|
|
112
|
+
export function buildCrsiLessonsBlock(summaries: CrsiLessonSummary[]): string {
|
|
113
|
+
if (summaries.length === 0) return ''
|
|
114
|
+
const items = summaries.map((s, i) => `${i + 1}. **${s.title}**\n ${s.suggestion}`).join('\n\n')
|
|
115
|
+
return `## CRSI Lessons (Self-Improvement Recall)
|
|
116
|
+
|
|
117
|
+
These are hard-won lessons consolidated by the CRSI self-improvement
|
|
118
|
+
loop from past sessions. Apply them proactively — do not repeat these
|
|
119
|
+
mistakes:
|
|
120
|
+
|
|
121
|
+
${items}`
|
|
122
|
+
}
|
|
123
|
+
|
|
83
124
|
/** 产出教训文件变更候选。无合格信号时返回 null。 */
|
|
84
125
|
export function produceCrsiProposal(
|
|
85
126
|
insights: CrsiInsight[],
|
package/src/core/engine.ts
CHANGED
|
@@ -767,9 +767,23 @@ export class QueryEngine {
|
|
|
767
767
|
// Tool-calling round cap. 20 was too low for real multi-step tasks — the model
|
|
768
768
|
// hit "max turns" and dropped pending tools mid-task. 100 stays bounded.
|
|
769
769
|
const MAX_TURNS = 100
|
|
770
|
+
// Task-level stall guard: a turn that produces no text or tool result for
|
|
771
|
+
// this long is considered stalled and stopped (prevents ~40-min idle spins).
|
|
772
|
+
const TURN_TIMEOUT_MS = 15 * 60 * 1000
|
|
773
|
+
let lastActivity = Date.now()
|
|
770
774
|
const toolDefs = this.getToolDefinitions()
|
|
771
775
|
|
|
772
776
|
for (let turn = 0; turn < MAX_TURNS; turn++) {
|
|
777
|
+
if (Date.now() - lastActivity > TURN_TIMEOUT_MS) {
|
|
778
|
+
yield {
|
|
779
|
+
type: 'warning',
|
|
780
|
+
content: t('errors.turn_timeout', {
|
|
781
|
+
minutes: String(Math.round(TURN_TIMEOUT_MS / 60000)),
|
|
782
|
+
}),
|
|
783
|
+
}
|
|
784
|
+
yield { type: 'stop' }
|
|
785
|
+
return
|
|
786
|
+
}
|
|
773
787
|
const systemPrompt = this.context.getSystemPrompt()
|
|
774
788
|
const messages = this.context.getMessages()
|
|
775
789
|
|
|
@@ -814,6 +828,7 @@ export class QueryEngine {
|
|
|
814
828
|
if (chunk.type === 'text' && chunk.content) {
|
|
815
829
|
assistantContent += chunk.content
|
|
816
830
|
this.context.recordChunk(chunk.content)
|
|
831
|
+
lastActivity = Date.now()
|
|
817
832
|
}
|
|
818
833
|
|
|
819
834
|
if (chunk.reasoning_content) {
|
|
@@ -913,6 +928,7 @@ export class QueryEngine {
|
|
|
913
928
|
// Execute tools and feed results back to the model for the next turn
|
|
914
929
|
for (const toolUse of toolUses) {
|
|
915
930
|
const result = await this.executeTool(toolUse.name, toolUse.input)
|
|
931
|
+
lastActivity = Date.now()
|
|
916
932
|
yield {
|
|
917
933
|
type: 'tool_result',
|
|
918
934
|
tool_use_id: toolUse.id,
|
package/src/core/instructions.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
|
+
import { execSync } from 'node:child_process'
|
|
3
4
|
import { parse as parseYaml } from 'yaml'
|
|
4
5
|
import type { InstructionFile } from '../shared/index.ts'
|
|
5
6
|
import { COAUTHOR_TRAILER } from '../shared/index.ts'
|
|
7
|
+
import {
|
|
8
|
+
LESSONS_FILE,
|
|
9
|
+
extractCrsiLessonSummaries,
|
|
10
|
+
buildCrsiLessonsBlock,
|
|
11
|
+
type CrsiLessonSummary,
|
|
12
|
+
} from './crsi-producer'
|
|
6
13
|
|
|
7
14
|
interface FrontmatterResult {
|
|
8
15
|
data: Record<string, unknown>
|
|
@@ -54,6 +61,7 @@ export function parsePromptExclude(value: unknown): string[] {
|
|
|
54
61
|
|
|
55
62
|
export class InstructionsLoader {
|
|
56
63
|
private instructions: InstructionFile[] = []
|
|
64
|
+
private crsiLessonSummaries: CrsiLessonSummary[] = []
|
|
57
65
|
|
|
58
66
|
loadAll(cwd: string): void {
|
|
59
67
|
this.instructions = []
|
|
@@ -74,6 +82,9 @@ export class InstructionsLoader {
|
|
|
74
82
|
// Tier 3: User-level ~/.mipham/USER.md
|
|
75
83
|
const home = process.env.HOME || '~'
|
|
76
84
|
this.tryLoad(join(home, '.mipham', 'USER.md'), 'user')
|
|
85
|
+
|
|
86
|
+
// CRSI 教训召回:读 crsi-lessons.md 提取精华,注入系统提示(只写不读 → 写后召回)
|
|
87
|
+
this.crsiLessonSummaries = this.loadCrsiLessons(cwd)
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
buildSystemPrompt(permissionMode?: string): string {
|
|
@@ -206,6 +217,10 @@ its live CRSI / SIS / constitution state. Report the numbers you read
|
|
|
206
217
|
from it as live counts; if it shows a subsystem as 未初始化 (uninitialized),
|
|
207
218
|
say so explicitly instead of claiming it exists.`)
|
|
208
219
|
|
|
220
|
+
// CRSI 教训召回 — 把 crsi-lessons.md 的教训精华注入,让模型「写后召回」而非只写不读
|
|
221
|
+
const lessonsBlock = buildCrsiLessonsBlock(this.crsiLessonSummaries)
|
|
222
|
+
if (lessonsBlock) parts.push(lessonsBlock)
|
|
223
|
+
|
|
209
224
|
// AI 署名披露:提交时附带 Co-Authored-By 署名(与 Undercover 式隐瞒相反)
|
|
210
225
|
parts.push(`## Commit Attribution
|
|
211
226
|
|
|
@@ -219,6 +234,26 @@ Never omit it or present the work as purely human-authored.`)
|
|
|
219
234
|
return parts.join('\n\n---\n\n')
|
|
220
235
|
}
|
|
221
236
|
|
|
237
|
+
/** 读 crsi-lessons.md(按仓库根定位)提取教训精华。读不到则返回空。 */
|
|
238
|
+
private loadCrsiLessons(cwd: string): CrsiLessonSummary[] {
|
|
239
|
+
let root = cwd
|
|
240
|
+
try {
|
|
241
|
+
root = execSync('git rev-parse --show-toplevel', {
|
|
242
|
+
cwd,
|
|
243
|
+
timeout: 5000,
|
|
244
|
+
encoding: 'utf-8',
|
|
245
|
+
}).trim()
|
|
246
|
+
} catch {
|
|
247
|
+
// 非 git 目录 → 回退 cwd
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const content = readFileSync(join(root, LESSONS_FILE), 'utf-8')
|
|
251
|
+
return extractCrsiLessonSummaries(content)
|
|
252
|
+
} catch {
|
|
253
|
+
return []
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
222
257
|
/**
|
|
223
258
|
* P2-2: Build a permission-mode context block for the system prompt.
|
|
224
259
|
* Tells the model its current permission level and what to expect.
|
|
@@ -230,9 +265,6 @@ Never omit it or present the work as purely human-authored.`)
|
|
|
230
265
|
acceptEdits:
|
|
231
266
|
'You are in **acceptEdits** mode. File reads and edits are allowed; Bash requires approval.',
|
|
232
267
|
plan: 'You are in **plan** mode. Only Read/Grep/Glob are allowed — no file modifications or command execution.',
|
|
233
|
-
auto: 'You are in **auto** mode. Most tools run without approval. If a tool is blocked by security policy or hooks, try a different approach instead of retrying.',
|
|
234
|
-
dontAsk:
|
|
235
|
-
'You are in **dontAsk** mode. All tools blocked unless explicitly allowlisted. Check your allow rules before acting.',
|
|
236
268
|
bypassPermissions:
|
|
237
269
|
'You are in **bypassPermissions** mode. All tools are allowed. Use this power responsibly.',
|
|
238
270
|
}
|
package/src/core/permission.ts
CHANGED
|
@@ -9,20 +9,6 @@ import type { PermissionRuleEntry } from '../shared/index.ts'
|
|
|
9
9
|
import { matchBashRule, compileRule } from './permission-rules'
|
|
10
10
|
import { loadPermissionConfig, nextMode, clampMode, MODE_CYCLE } from './permission-config'
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Check if a Bash command is a git/gh operation using a destructive flag
|
|
14
|
-
* (--force, --amend, --no-verify, --hard) that must never be auto-approved.
|
|
15
|
-
* v2.1.229 alignment: these rewrite history / force-push, so they fall back
|
|
16
|
-
* to explicit user confirmation even in auto mode.
|
|
17
|
-
*/
|
|
18
|
-
function hasDangerousGitFlags(input: Record<string, unknown>): boolean {
|
|
19
|
-
const cmd = (input.command as string) || ''
|
|
20
|
-
// Detect a git/gh invocation anywhere in the command (not just `^git`), so
|
|
21
|
-
// `echo ok && git push --force` is still caught.
|
|
22
|
-
if (!/(?:^|[\s;&|])(?:sudo\s+)?(?:git|gh)\s+/.test(cmd)) return false
|
|
23
|
-
return /--force(?!-with-lease)\b|--amend\b|--no-verify\b|--hard\b/.test(cmd)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
12
|
/**
|
|
27
13
|
* Check if a Bash command is a "verification-only" command that should be
|
|
28
14
|
* auto-approved in acceptEdits mode. These are non-destructive read/check
|
|
@@ -94,9 +80,6 @@ export class PermissionSystem {
|
|
|
94
80
|
// ── Org-level restrictions (P0 security) ──
|
|
95
81
|
private restrictions: PermissionRestrictions | undefined = undefined
|
|
96
82
|
|
|
97
|
-
// ── P0-5: Sub-agent mode (auto mode hardening for background tasks) ──
|
|
98
|
-
private isSubAgent = false
|
|
99
|
-
|
|
100
83
|
// ── P1-4: Consecutive block counter (prevents infinite retry loops) ──
|
|
101
84
|
private consecutiveBlockCount = 0
|
|
102
85
|
private static readonly MAX_CONSECUTIVE_BLOCKS = 3
|
|
@@ -149,16 +132,6 @@ export class PermissionSystem {
|
|
|
149
132
|
return this.restrictions
|
|
150
133
|
}
|
|
151
134
|
|
|
152
|
-
/**
|
|
153
|
-
* P0-5 (v2.1.222 alignment): Enable sub-agent safety mode.
|
|
154
|
-
* When true, auto mode returns 'ask' for Bash/Write/Edit tools instead of
|
|
155
|
-
* 'bypass', ensuring PreToolUse hooks remain the safety gate in background agents.
|
|
156
|
-
*/
|
|
157
|
-
setSubAgentMode(enabled: boolean): void {
|
|
158
|
-
this.isSubAgent = enabled
|
|
159
|
-
this.invalidateCache()
|
|
160
|
-
}
|
|
161
|
-
|
|
162
135
|
/**
|
|
163
136
|
* P1-4 (v2.1.225 alignment): Increment the consecutive block counter
|
|
164
137
|
* when a tool is denied. Safety-filter refusals should NOT count.
|
|
@@ -216,8 +189,6 @@ export class PermissionSystem {
|
|
|
216
189
|
|
|
217
190
|
const modeMap: Record<string, PermissionMode> = {
|
|
218
191
|
bypassPermissions: 'bypassPermissions',
|
|
219
|
-
dontAsk: 'dontAsk',
|
|
220
|
-
auto: 'auto',
|
|
221
192
|
plan: 'plan',
|
|
222
193
|
acceptEdits: 'acceptEdits',
|
|
223
194
|
default: 'default',
|
|
@@ -418,30 +389,6 @@ export class PermissionSystem {
|
|
|
418
389
|
? 'bypass'
|
|
419
390
|
: 'ask'
|
|
420
391
|
|
|
421
|
-
case 'auto':
|
|
422
|
-
// Safety checks handled by hook layer (PreToolUse hooks).
|
|
423
|
-
// Bypass the static permission system so hooks are the sole gate.
|
|
424
|
-
// Exception: SendMessage always goes through the permission classifier
|
|
425
|
-
// so deny/allow rules are honored for cross-session messages.
|
|
426
|
-
if (tool.name === 'SendMessage') {
|
|
427
|
-
return 'mode-baseline'
|
|
428
|
-
}
|
|
429
|
-
// P0-5: In sub-agent context, enforce 'ask' for destructive tools
|
|
430
|
-
// so hooks remain the sole safety gate. Without hooks, these tools
|
|
431
|
-
// would otherwise run completely un-gated in auto mode.
|
|
432
|
-
if (this.isSubAgent && ['Bash', 'Write', 'Edit'].includes(tool.name)) {
|
|
433
|
-
return 'ask'
|
|
434
|
-
}
|
|
435
|
-
// v2.1.229 alignment: destructive git/gh flags are never auto-approved.
|
|
436
|
-
if (tool.name === 'Bash' && input && hasDangerousGitFlags(input)) {
|
|
437
|
-
return 'ask'
|
|
438
|
-
}
|
|
439
|
-
return 'bypass'
|
|
440
|
-
|
|
441
|
-
case 'dontAsk':
|
|
442
|
-
// Only allowlisted tools free (already handled above); everything else requires approval
|
|
443
|
-
return 'ask'
|
|
444
|
-
|
|
445
392
|
case 'bypassPermissions':
|
|
446
393
|
return 'bypass'
|
|
447
394
|
|
|
@@ -453,11 +400,10 @@ export class PermissionSystem {
|
|
|
453
400
|
// ── Legacy compatibility ──
|
|
454
401
|
|
|
455
402
|
setDefaultLevel(level: PermissionLevel): void {
|
|
456
|
-
// Map legacy 3-level to new mode
|
|
457
|
-
let
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
else newMode = 'default'
|
|
403
|
+
// Map legacy 3-level (auto/ask/bypass) to new 4-level mode.
|
|
404
|
+
// Legacy 'auto'/'ask' = "let each tool self-decide" → 'default'.
|
|
405
|
+
// Legacy 'bypass' → 'bypassPermissions'.
|
|
406
|
+
const newMode: PermissionMode = level === 'bypass' ? 'bypassPermissions' : 'default'
|
|
461
407
|
this.mode = clampMode(newMode, this.restrictions)
|
|
462
408
|
this.invalidateCache()
|
|
463
409
|
}
|
|
@@ -465,8 +411,7 @@ export class PermissionSystem {
|
|
|
465
411
|
getDefaultLevel(): PermissionLevel {
|
|
466
412
|
// Legacy constructor fallback takes priority
|
|
467
413
|
if (this.legacyDefaultFallback) return this.legacyDefaultFallback
|
|
468
|
-
if (this.mode === '
|
|
469
|
-
return 'bypass'
|
|
414
|
+
if (this.mode === 'bypassPermissions') return 'bypass'
|
|
470
415
|
if (this.mode === 'plan') return 'ask'
|
|
471
416
|
return 'auto'
|
|
472
417
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mipham Code — Project Scaffold
|
|
3
|
+
*
|
|
4
|
+
* `mipham init` 生成规范的项目文档(CLAUDE.md + MIPHAM.md + README.md),
|
|
5
|
+
* 避免用户「冷建立文件」。模板遵循 One Mipham Corporation 规范。
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'node:fs'
|
|
8
|
+
import { join, basename } from 'node:path'
|
|
9
|
+
import { execSync } from 'node:child_process'
|
|
10
|
+
|
|
11
|
+
export interface ScaffoldResult {
|
|
12
|
+
created: string[]
|
|
13
|
+
skipped: string[]
|
|
14
|
+
gitInitialized: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function renderMiphamMd(projectName: string): string {
|
|
18
|
+
return `---
|
|
19
|
+
model: mipham-code
|
|
20
|
+
version: 1.0.0
|
|
21
|
+
privacy: project
|
|
22
|
+
language: zh-CN
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# MIPHAM.md — ${projectName}
|
|
26
|
+
|
|
27
|
+
> 本文件定义 ${projectName} 项目中 AI 助手的交互人格和项目规范。
|
|
28
|
+
> 继承自 One Mipham Corporation 集团 MIPHAM.md。
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 项目概述
|
|
33
|
+
|
|
34
|
+
[简要描述项目目的和定位]
|
|
35
|
+
|
|
36
|
+
## 技术栈
|
|
37
|
+
|
|
38
|
+
[列出主要技术栈]
|
|
39
|
+
|
|
40
|
+
## 项目规范
|
|
41
|
+
|
|
42
|
+
- [添加项目特有的编码规则]
|
|
43
|
+
- [添加团队约定]
|
|
44
|
+
|
|
45
|
+
## AI 交互偏好
|
|
46
|
+
|
|
47
|
+
- 回复语言:[中文/英文]
|
|
48
|
+
- 代码风格:[偏好]
|
|
49
|
+
- 注释语言:[中文/英文]
|
|
50
|
+
`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function renderClaudeMd(projectName: string): string {
|
|
54
|
+
return `# CLAUDE.md
|
|
55
|
+
|
|
56
|
+
> 项目:${projectName}
|
|
57
|
+
> 版本:0.1.0
|
|
58
|
+
> 初始化:\`mipham init\`
|
|
59
|
+
|
|
60
|
+
## 项目概述
|
|
61
|
+
|
|
62
|
+
[简要描述项目目的和定位]
|
|
63
|
+
|
|
64
|
+
## 技术栈
|
|
65
|
+
|
|
66
|
+
[列出主要技术栈]
|
|
67
|
+
|
|
68
|
+
## 开发命令
|
|
69
|
+
|
|
70
|
+
- 构建:[\`填入 build 命令\`]
|
|
71
|
+
- 测试:[\`填入 test 命令\`]
|
|
72
|
+
- Lint:[\`填入 lint 命令\`]
|
|
73
|
+
|
|
74
|
+
## 项目规范
|
|
75
|
+
|
|
76
|
+
- [添加项目特有的编码规则]
|
|
77
|
+
- [添加团队约定]
|
|
78
|
+
|
|
79
|
+
## 关键约束
|
|
80
|
+
|
|
81
|
+
- 遵循上级 One Mipham Corporation CLAUDE.md 技术规范
|
|
82
|
+
- 提交信息遵循 Conventional Commits
|
|
83
|
+
- 禁止在代码、日志、配置或提交历史中硬编码凭据
|
|
84
|
+
`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function renderReadmeMd(projectName: string): string {
|
|
88
|
+
return `# ${projectName}
|
|
89
|
+
|
|
90
|
+
[一句话描述项目]
|
|
91
|
+
|
|
92
|
+
## 快速开始
|
|
93
|
+
|
|
94
|
+
\`\`\`bash
|
|
95
|
+
# 安装依赖 / 运行项目
|
|
96
|
+
\`\`\`
|
|
97
|
+
|
|
98
|
+
## 技术栈
|
|
99
|
+
|
|
100
|
+
[列出技术栈]
|
|
101
|
+
|
|
102
|
+
## 文档
|
|
103
|
+
|
|
104
|
+
- \`CLAUDE.md\` — AI 协作规范
|
|
105
|
+
- \`MIPHAM.md\` — AI 交互人格
|
|
106
|
+
- \`README.md\` — 项目说明(本文件)
|
|
107
|
+
|
|
108
|
+
## 许可
|
|
109
|
+
|
|
110
|
+
[填入许可证]
|
|
111
|
+
`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** 检测目录是否为「愣建文件夹」——无任何条目(忽略 .DS_Store)。目录不存在则视为非空。 */
|
|
115
|
+
export function isEmptyProject(dir: string): boolean {
|
|
116
|
+
try {
|
|
117
|
+
const entries = readdirSync(dir).filter((e) => e !== '.DS_Store')
|
|
118
|
+
return entries.length === 0
|
|
119
|
+
} catch {
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function scaffoldProject(targetDir: string, opts?: { gitInit?: boolean }): ScaffoldResult {
|
|
125
|
+
mkdirSync(targetDir, { recursive: true })
|
|
126
|
+
|
|
127
|
+
const name = basename(targetDir) || 'my-project'
|
|
128
|
+
const files = [
|
|
129
|
+
{ path: 'CLAUDE.md', content: renderClaudeMd(name) },
|
|
130
|
+
{ path: 'MIPHAM.md', content: renderMiphamMd(name) },
|
|
131
|
+
{ path: 'README.md', content: renderReadmeMd(name) },
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
const created: string[] = []
|
|
135
|
+
const skipped: string[] = []
|
|
136
|
+
|
|
137
|
+
for (const f of files) {
|
|
138
|
+
const full = join(targetDir, f.path)
|
|
139
|
+
if (existsSync(full)) {
|
|
140
|
+
skipped.push(f.path)
|
|
141
|
+
} else {
|
|
142
|
+
writeFileSync(full, f.content, 'utf-8')
|
|
143
|
+
created.push(f.path)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let gitInitialized = false
|
|
148
|
+
if (opts?.gitInit && !existsSync(join(targetDir, '.git'))) {
|
|
149
|
+
try {
|
|
150
|
+
execSync('git init', { cwd: targetDir, stdio: 'ignore' })
|
|
151
|
+
gitInitialized = true
|
|
152
|
+
} catch {
|
|
153
|
+
// git 不可用或失败 — 不阻断脚手架
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { created, skipped, gitInitialized }
|
|
158
|
+
}
|
package/src/daemon/server.ts
CHANGED
|
@@ -757,8 +757,6 @@
|
|
|
757
757
|
"manual": "manual mode",
|
|
758
758
|
"accept_edits": "accept edits on",
|
|
759
759
|
"plan_mode": "plan mode / read-only",
|
|
760
|
-
"auto": "auto mode",
|
|
761
|
-
"dont_ask": "don't ask",
|
|
762
760
|
"bypass": "bypass"
|
|
763
761
|
},
|
|
764
762
|
"loading": {
|
|
@@ -962,6 +960,7 @@
|
|
|
962
960
|
"mcp_register_failed": "[mcp] Failed to register tool \"{tool}\" from server \"{server}\": {error}",
|
|
963
961
|
"max_tool_turns": "Max tool-calling turns ({max}) reached. Some tool calls were not executed.",
|
|
964
962
|
"max_tool_turns_warning": "You've reached the maximum of {max} tool-calling rounds. {pending} tool call(s) were not executed. Please summarize what you found so far and any next steps the user should take.",
|
|
963
|
+
"turn_timeout": "Task produced no substantial output for {minutes} minutes and was stopped. Break the task into smaller steps or clarify the next step, then retry.",
|
|
965
964
|
"mcp_not_connected": "Error: MCP server \"{server}\" not connected",
|
|
966
965
|
"mcp_tool_error": "MCP tool error: {error}",
|
|
967
966
|
"mcp_no_connection": "No connection for \"{name}\""
|
|
@@ -757,8 +757,6 @@
|
|
|
757
757
|
"manual": "手动模式",
|
|
758
758
|
"accept_edits": "接受编辑",
|
|
759
759
|
"plan_mode": "计划模式 / 只读",
|
|
760
|
-
"auto": "自动模式",
|
|
761
|
-
"dont_ask": "不再询问",
|
|
762
760
|
"bypass": "绕过权限"
|
|
763
761
|
},
|
|
764
762
|
"loading": {
|
|
@@ -962,6 +960,7 @@
|
|
|
962
960
|
"mcp_register_failed": "[mcp] 注册工具 \"{tool}\"(来自服务器 \"{server}\")失败:{error}",
|
|
963
961
|
"max_tool_turns": "超出最大工具调用轮次({max})。部分工具调用未执行。",
|
|
964
962
|
"max_tool_turns_warning": "已达到最大 {max} 轮工具调用。{pending} 个工具调用未执行。请总结当前发现及后续步骤。",
|
|
963
|
+
"turn_timeout": "任务已超过 {minutes} 分钟无实质产出,已自动停止。建议拆分任务或明确下一步后重新发起。",
|
|
965
964
|
"mcp_not_connected": "错误:MCP 服务器 \"{server}\" 未连接",
|
|
966
965
|
"mcp_tool_error": "MCP 工具错误:{error}",
|
|
967
966
|
"mcp_no_connection": "未找到 \"{name}\" 的连接"
|
package/src/index.tsx
CHANGED
|
@@ -305,6 +305,14 @@ export async function runApp(options: RunOptions): Promise<void> {
|
|
|
305
305
|
const instructions = new InstructionsLoader()
|
|
306
306
|
instructions.loadAll(process.cwd())
|
|
307
307
|
|
|
308
|
+
// 空目录提示:愣建文件夹时温和提醒走 mipham init,而非默默开始(寒暄克制——一句即可)
|
|
309
|
+
const { isEmptyProject } = await import('./core/project-scaffold')
|
|
310
|
+
if (isEmptyProject(process.cwd())) {
|
|
311
|
+
console.log(
|
|
312
|
+
'\n💡 空目录。运行 `mipham init` 生成规范项目文档(CLAUDE.md / MIPHAM.md / README.md),或直接开始对话。\n',
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
|
|
308
316
|
// Load skills
|
|
309
317
|
const skillsLoader = new SkillsLoader()
|
|
310
318
|
skillsLoader.loadBuiltinFromPackage()
|
|
@@ -24,8 +24,9 @@ function isRetryableError(err: unknown): boolean {
|
|
|
24
24
|
/**
|
|
25
25
|
* Fetch with optional timeout and retry with exponential backoff.
|
|
26
26
|
*
|
|
27
|
-
* Retries on: network errors, 5xx, 429
|
|
28
|
-
*
|
|
27
|
+
* Retries on: network errors, 5xx, 429, and the internal timeout firing
|
|
28
|
+
* (first-byte never arrived) — retried once as a transient network issue.
|
|
29
|
+
* Does NOT retry on: caller-initiated abort (init.signal), 4xx (except 429).
|
|
29
30
|
*/
|
|
30
31
|
export async function fetchWithRetry(
|
|
31
32
|
url: string,
|
|
@@ -38,7 +39,11 @@ export async function fetchWithRetry(
|
|
|
38
39
|
|
|
39
40
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
40
41
|
const controller = new AbortController()
|
|
41
|
-
|
|
42
|
+
let timedOut = false
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
timedOut = true
|
|
45
|
+
controller.abort()
|
|
46
|
+
}, timeout)
|
|
42
47
|
const signal = init.signal ? anySignal([init.signal, controller.signal]) : controller.signal
|
|
43
48
|
|
|
44
49
|
try {
|
|
@@ -57,7 +62,16 @@ export async function fetchWithRetry(
|
|
|
57
62
|
return response
|
|
58
63
|
} catch (err) {
|
|
59
64
|
lastErr = err
|
|
60
|
-
|
|
65
|
+
// First-byte timeout is transient → retry once. Caller abort is not.
|
|
66
|
+
const retryable = timedOut || isRetryableError(err)
|
|
67
|
+
if (!retryable || attempt >= maxRetries) {
|
|
68
|
+
if (timedOut) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`API Error: No response from API (timed out after ${Math.round(timeout / 1000)}s)`,
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
throw err
|
|
74
|
+
}
|
|
61
75
|
await sleep(baseDelay * Math.pow(2, attempt))
|
|
62
76
|
} finally {
|
|
63
77
|
clearTimeout(timer)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
export const PACKAGE_NAME = '@miphamai/cli' as const
|
|
10
10
|
|
|
11
11
|
/** 当前发布版本 */
|
|
12
|
-
export const PACKAGE_VERSION = '0.
|
|
12
|
+
export const PACKAGE_VERSION = '0.59.0' as const
|
|
13
13
|
|
|
14
14
|
/** npm install 全局安装命令 */
|
|
15
15
|
export const NPM_INSTALL_COMMAND = `npm install -g ${PACKAGE_NAME}` as const
|
package/src/shared/types.ts
CHANGED
|
@@ -130,7 +130,7 @@ export interface MiphamConfig {
|
|
|
130
130
|
version: string
|
|
131
131
|
defaultProvider: string
|
|
132
132
|
defaultModel: string
|
|
133
|
-
permission:
|
|
133
|
+
permission: PermissionLevel
|
|
134
134
|
/** Org-level permission restrictions (forbiddenModes, maxAllowedMode). */
|
|
135
135
|
permissionRestrictions?: PermissionRestrictions
|
|
136
136
|
/** User-defined permission rules (allow/deny patterns), wired into the runtime PermissionSystem. */
|
|
@@ -269,12 +269,11 @@ export interface InstructionFile {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
// ── Permission Types ──
|
|
272
|
-
/**
|
|
273
|
-
export type PermissionMode =
|
|
274
|
-
'default' | 'acceptEdits' | 'plan' | 'auto' | 'dontAsk' | 'bypassPermissions'
|
|
272
|
+
/** Four explicit permission modes matching Claude Code's permission architecture */
|
|
273
|
+
export type PermissionMode = 'default' | 'acceptEdits' | 'plan' | 'bypassPermissions'
|
|
275
274
|
|
|
276
|
-
/** Backward-compatible alias: PermissionMode plus legacy 'ask'
|
|
277
|
-
export type PermissionLevel = PermissionMode | 'ask' | 'bypass'
|
|
275
|
+
/** Backward-compatible alias: PermissionMode plus legacy 'auto'/'ask'/'bypass' */
|
|
276
|
+
export type PermissionLevel = PermissionMode | 'auto' | 'ask' | 'bypass'
|
|
278
277
|
|
|
279
278
|
/** Org-level restrictions that cap or forbid specific permission modes. */
|
|
280
279
|
export interface PermissionRestrictions {
|
|
@@ -17,7 +17,7 @@ export const BUNDLED_SKILLS: ReadonlyArray<BundledSkill> = [
|
|
|
17
17
|
{ type: 'standard', raw: "---\nname: grill-with-docs\ndescription: A relentless interview to sharpen a plan or design, creating CONTEXT.md (shared language) and ADRs (architectural decisions) as we go. Use before any non-trivial implementation to align on requirements and terminology.\nversion: 1.0.0\nuser-invocable: true\nallowed-tools:\n - Read\n - Write\n - Edit\n - Bash\n - Glob\n - Grep\n - WebSearch\n - WebFetch\n---\n\n# Grill With Docs — Deep Requirements Alignment\n\nInspired by Matt Pocock's `grill-with-docs` and `domain-modeling` skills. Before writing code, run a structured interview to align on requirements, establish shared language, and record architectural decisions.\n\n## When to Use\n\n- Before any non-trivial feature implementation\n- When requirements are fuzzy (\"make it faster\", \"add X\")\n- When you need to establish project terminology\n- When architectural decisions need to be recorded\n- User says: \"plan X\", \"design Y\", \"what should we do about Z\"\n\n## When NOT to Use\n\n- Trivial bug fixes with clear expected behavior\n- One-line changes\n- Tasks where the requirements are already crystal clear\n\n---\n\n## The Interview Flow\n\n### Phase 1: Understand the Intent\n\nStart by understanding what the user actually wants. Don't ask \"what should I build?\" — ask about their goal.\n\n**Core Questions:**\n\n1. What problem are you solving? (Not what feature you're building)\n2. Who is this for? (End user, developer, internal tool?)\n3. What does success look like? (How will you know when it's done?)\n4. What's the deadline or priority context?\n\n**Anti-pattern**: Jumping to implementation questions (\"Do you want REST or GraphQL?\") before understanding the problem.\n\n### Phase 2: Sharpen the Language\n\nIdentify vague or overloaded terms and pin them down **immediately**. This is the single highest-leverage activity — shared language reduces token waste and prevents misunderstandings.\n\n**Technique: The Canonical Term**\n\n- When the user uses multiple words for the same thing, pick one as canonical\n- List rejected alternatives under `_Avoid_`\n- Be opinionated — the glossary is prescriptive, not descriptive\n\n```\nUser: \"We need a way for users to save articles for later.\"\nYou: \"Let's pin that down. 'Save for later' could mean bookmarking, or a reading list, or offline download. Which one?\"\nUser: \"Like a reading list — they can come back to it.\"\nYou: \"Got it. Let's call it a **Reading List**. Avoid 'bookmark', 'save', 'favorites'.\"\n→ Write to CONTEXT.md immediately.\n```\n\n**Technique: The Boundary Test**\n\n- When a term is proposed, test its boundaries with edge cases\n- \"Does X include Y? What about Z?\"\n\n**Technique: The Code Cross-Reference**\n\n- When the user describes how something works, check if existing code agrees\n- Surface contradictions immediately\n\n### Phase 3: Probe Edge Cases\n\nBefore accepting any requirement, stress-test it with edge cases.\n\n**Edge Case Inventory:**\n\n- **Empty state**: What does the user see when there's nothing yet?\n- **Error state**: What happens when things go wrong?\n- **Extreme values**: What about 0? What about 10,000?\n- **Concurrency**: What if two people do this at the same time?\n- **Permissions**: Who can do this? Who cannot?\n- **Scale**: What changes at 10x the current volume?\n\n**Technique: The 5 Whys**\nWhen a requirement seems odd, dig deeper:\n\n```\nUser: \"We need real-time updates.\"\nYou: \"Why real-time?\"\nUser: \"Because users need to see changes immediately.\"\nYou: \"Why do they need to see changes immediately?\"\nUser: \"Because they're collaborating on the same document.\"\n→ Now you know the REAL requirement is collaboration, not real-time.\n```\n\n### Phase 4: Make Architecture Decisions\n\nWhen a design decision meets ALL three criteria, offer to record it as an ADR:\n\n1. **Hard to reverse** — changing your mind later has real cost\n2. **Surprising without context** — a future reader would wonder \"why?\"\n3. **The result of a real trade-off** — there were genuine alternatives\n\n**What qualifies for an ADR:**\n\n- Architecture shape (monorepo vs polyrepo, event sourcing vs CRUD)\n- Integration patterns between contexts\n- Technology choices with lock-in (database, message bus, auth provider)\n- Deliberate deviations from convention (\"we use raw SQL because...\")\n- Constraints not visible in code (\"we can't use X because compliance\")\n\n**ADR Format** (write to `docs/adr/NNNN-slug.md`):\n\n```markdown\n# {Short title of the decision}\n\n{1-3 sentences: context, decision, and why.}\n```\n\nOnly add optional sections (Status, Considered Options, Consequences) when they add genuine value. Most ADRs are a single paragraph.\n\n### Phase 5: Write the CONTEXT.md\n\nAfter the interview, synthesize everything into `CONTEXT.md`.\n\n**Format** (`CONTEXT.md` at project root):\n\n```markdown\n# {Project Name} Context\n\n{One or two sentence description of the project domain.}\n\n## Language\n\n**{Term}**:\n{One or two sentence definition of what it IS.}\n_Avoid_: {alternative terms that should not be used}\n\n## Decisions\n\n- [ADR 0001: {Title}](docs/adr/0001-slug.md) — {one-line summary}\n```\n\n**Rules:**\n\n- Be opinionated — pick the best term, ban the rest\n- Only include domain-specific terms (not general programming concepts)\n- Keep definitions tight — one or two sentences\n- Update inline during the conversation, don't batch\n- CONTEXT.md is a glossary, NOT a spec or implementation plan\n\n---\n\n## During the Conversation\n\n### DO\n\n- Challenge the user when they use vague terms — \"What do you mean by 'fast'?\"\n- Propose canonical terms and write them down immediately\n- Invent edge cases and probe boundaries\n- Offer ADRs sparingly (only when all 3 criteria are met)\n- Cross-reference with existing code if available\n- Call out contradictions between what the user says and what the code does\n\n### DON'T\n\n- Rush to implementation questions before understanding the problem\n- Write ADRs for trivial decisions\n- Let fuzzy language slide — pin it down now or pay later\n- Treat CONTEXT.md as a spec or scratch pad\n- Ask yes/no questions when open-ended ones would reveal more\n\n---\n\n## Output\n\nAfter the interview, the user should have:\n\n1. **CONTEXT.md** — shared language glossary (created or updated)\n2. **ADRs** (if needed) — architectural decisions in `docs/adr/`\n3. **Clear requirements** — edge cases explored, assumptions surfaced\n4. **Shared understanding** — you and the user now mean the same thing by the same words\n\n---\n\n## Integration with Mipham Code\n\n- **Memory System**: Key terms go to project memory for persistence across sessions\n- **Critical Thinking Layer**: Apply the 5-dimension self-check (evidence standard, equivalence verification, counter-example search, confidence calibration, depth check) to your own interview questions\n- **Workflow**: For complex projects, the output of this skill feeds directly into `/implement`\n" },
|
|
18
18
|
{ type: 'standard', raw: "---\nname: implement\ndescription: Build work from a spec or tickets with systematic discipline — TDD at pre-agreed seams, incremental verification, code review before commit. Use when implementing features, bugfixes, or any planned work.\nversion: 1.0.0\nuser-invocable: true\n---\n\n# Implement — Structured Build Execution\n\n融合 Superpowers executing-plans(计划审阅 + 隔离工作区)+ Matt Pocock implement(TDD 接缝 + 增量验证 + 提交前审查)。\n\n## When to Use\n\n- Implementing work from a written spec or ticket set\n- Executing a development plan with clear deliverables\n- Building a feature with predefined success criteria\n\n## When NOT to Use\n\n- Exploratory coding / prototyping → use `prototype` skill\n- Quick one-line fixes → just fix it\n- No spec or tickets exist → use `to-tickets` or `to-spec` first\n\n---\n\n## Step 1: Load and Review\n\n### 1.1 Ensure isolated workspace\n\nUse git worktree or a feature branch. Never implement on main/master without explicit consent.\n\n### 1.2 Read the plan/spec/tickets\n\nRead the full spec or ticket set. Understand:\n\n- What is being built?\n- What are the acceptance criteria?\n- What are the pre-agreed seams (where TDD should be applied)?\n\n### 1.3 Review critically\n\nBefore writing any code:\n\n- Are there gaps or ambiguities in the spec?\n- Are the success criteria testable?\n- Do you understand every instruction?\n\n**If concerns exist, raise them before starting.** Don't guess.\n\n---\n\n## Step 2: Execute Tasks\n\nFor each task in order:\n\n### 2.1 At pre-agreed seams: TDD\n\nWhere the spec specifies (or where interfaces are well-defined):\n\n1. Write a **failing test** that asserts the expected behavior\n2. Watch it fail (red)\n3. Write the **minimum code** to make it pass (green)\n4. Refactor if needed, keeping tests green\n\nUse the `tdd` skill for full red-green-refactor discipline.\n\n### 2.2 Incremental verification\n\nDuring implementation:\n\n- **Run typecheck** after each significant change: `pnpm typecheck`\n- **Run relevant test file** after each task: `pnpm test -- <file>`\n- **Don't wait** until everything is done to discover type errors\n\n### 2.3 One task at a time\n\n- Follow each step exactly — the plan has bite-sized steps for a reason\n- One change at a time. No \"while I'm here\" improvements.\n- Mark tasks as complete after verification passes\n\n---\n\n## Step 3: Final Verification\n\nAfter all tasks are complete:\n\n### 3.1 Full test suite\n\n```bash\npnpm test\n```\n\nAll tests must pass. If any fail, fix before proceeding.\n\n### 3.2 Lint and format\n\n```bash\npnpm lint\npnpm format\n```\n\nCI must be green.\n\n---\n\n## Step 4: Code Review\n\n**Before committing**, run code review:\n\nUse the `code-review` skill for a two-axis review:\n\n- **Standards**: Does the diff follow the repo's coding standards?\n- **Spec**: Does it faithfully implement the originating issue/spec?\n\nFix any findings before committing.\n\n---\n\n## Step 5: Commit\n\nCommit your work to the current branch.\n\n```bash\ngit add -A\ngit commit -m \"<type>: <description>\"\n```\n\n- Follow Conventional Commits\n- Reference the spec/ticket in the commit message\n- **Do NOT commit unless explicitly asked** (per CLAUDE.md §关键约束)\n\n---\n\n## When to Stop and Ask\n\n**STOP immediately when:**\n\n- A task is blocked (missing dependency, unclear instruction, verification fails repeatedly)\n- The spec has a critical gap that prevents starting\n- You don't understand an instruction\n- 3+ fix attempts fail — this may be an architectural issue\n\n**Ask for clarification rather than guessing.**\n\n---\n\n## Quick Reference\n\n| Step | Key Activities | Done When |\n| -------------- | ------------------------------------------------------------ | -------------------------------- |\n| **1. Review** | Load spec, isolate workspace, review critically | All concerns raised and resolved |\n| **2. Execute** | TDD at seams, incremental typecheck/test, one task at a time | All tasks complete and verified |\n| **3. Verify** | Full test suite, lint, format | CI-ready (all green) |\n| **4. Review** | Two-axis code review (standards + spec) | Findings addressed |\n| **5. Commit** | Conventional Commits, reference spec/ticket | Work committed to branch |\n" },
|
|
19
19
|
{ type: 'standard', raw: "---\nname: memory\ndescription: Read and write persistent memory files for context retention across sessions — one fact per file with frontmatter\nversion: 2.0.0\n---\n\n# Memory Skill\n\nManage persistent memory stored as markdown files with YAML frontmatter.\n\n## File Format\n\nEach memory is one `.md` file under the `memory/` directory:\n\n```markdown\n---\nname: <kebab-case-slug>\ndescription: <one-line summary>\nmetadata:\n type: user | feedback | project | reference\n---\n\n<the fact body>\n\n**Why:** <rationale>\n**How to apply:** <practical guidance>\n```\n\n## File Path Conventions\n\n- Directory: `~/.mipham/memory/` (user-level) or `./.mipham/memory/` (project-level)\n- Filename: `<name-slug>.md` (lowercase, hyphens)\n- Index: `MEMORY.md` — one line per memory file, maintained automatically\n\n## Operations\n\n### List Memories\n\nScan `MEMORY.md` index for available memories. The index has one line per memory:\n\n```markdown\n- [Title](file.md) — brief hook\n```\n\n### Read Memory\n\nRead the full markdown file including frontmatter. Parse YAML frontmatter for metadata.\n\n### Write Memory\n\n1. Check for existing file with same `name:` slug — update if found\n2. Create new file if no match\n3. Add/update entry in `MEMORY.md` index\n4. Never write what the repo already records (code structure, git history, CLAUDE.md)\n\n### Delete Memory\n\nRemove the file and its index entry. Use when a memory is incorrect or superseded.\n\n## Best Practices\n\n- **One fact per file** — atomic, focused, easy to find\n- **Descriptive slugs** — `npm-publish-workflow` not `memory-1`\n- **Link related memories** — use `[[slug-name]]` wikilinks in body\n- **Check before writing** — search existing memories to avoid duplicates\n- **Types matter**: `user` (who), `feedback` (corrections), `project` (goals), `reference` (external)\n\n## Example\n\n```markdown\n---\nname: api-rate-limit\ndescription: OpenAI API has 500 RPM limit on our tier\nmetadata:\n type: reference\n---\n\nThe OpenAI API key for production has a hard 500 requests/minute limit.\nExceeding it returns HTTP 429 with a Retry-After header.\n\n**Why:** We hit this in production during peak usage\n**How to apply:** Use exponential backoff; batch requests where possible\n```\n" },
|
|
20
|
-
{ type: 'standard', raw: "---\nname: mipham-code-setup\ndescription: 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.\nversion: 2.0.0\nuser-invocable: true\nallowed-tools:\n - Read\n - Write\n - Edit\n - Bash\n - Skill\n---\n\n# Mipham Code Setup — Executable Setup Workflow\n\n**Type**: Rigid — follow the decision tree exactly. Don't skip diagnostic phases.\n\n**Purpose**: Guide users from zero to fully configured Mipham Code. This skill is BOTH:\n\n1. A self-contained diagnostic + configuration workflow the AI can execute\n2. A reference for `/setup` command behavior and slash commands\n\n**Triggers**: \"setup mipham\", \"configure mipham\", \"install mipham code\", \"mipham not working\", \"mipham setup\", \"first time using mipham\", \"help me set up\", \"getting started\", `/setup`\n\n---\n\n## Phase 0: Environment Detection (ALWAYS RUN FIRST)\n\nBefore doing anything, run these diagnostic checks. Report results in a status table.\n\n### 0.1 — Detect Installation\n\n```bash\nwhich mipham 2>/dev/null\nmipham --version 2>/dev/null\nbun --version 2>/dev/null\nnode --version 2>/dev/null\n```\n\n### 0.2 — Detect Configuration\n\n```bash\nls -la .mipham/config.yml 2>/dev/null\nls -la ~/.mipham/config.yml 2>/dev/null\nls -la MIPHAM.md 2>/dev/null\nls -la CLAUDE.md 2>/dev/null\n```\n\n### 0.3 — Detect API Keys\n\n```bash\nenv | 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\n```\n\n### 0.4 — Detect Skills & Permissions\n\n```bash\nls .mipham/skills/ 2>/dev/null\ncat .mipham/config.yml 2>/dev/null | grep -E 'permission|trust' || echo \"no config\"\n```\n\n### 0.5 — Detect Workspace Trust\n\n```bash\ncat ~/.mipham/trusted-workspaces.json 2>/dev/null || echo \"no trust store\"\n```\n\n### Status Report Format\n\nAfter detection, present results as:\n\n```\n── Mipham Code Status ──\n\nInstallation: [✅/⬜] mipham CLI [✅/⬜] Bun [✅/⬜] Node.js\nProject: [✅/⬜] .mipham/ [✅/⬜] config.yml [✅/⬜] MIPHAM.md\nUser Config: [✅/⬜] ~/.mipham/config.yml\nAPI Keys: [N] set (list names or \"none\")\nSkills: [N] installed\nPermissions: [mode] (default/acceptEdits/plan/auto/dontAsk/bypass)\nTrust: [✅/⬜] workspace trusted\n```\n\nThen proceed to ONLY the phases where something is missing. Don't re-run already-configured steps unless asked.\n\n---\n\n## Phase 1: Installation\n\n**Trigger**: `mipham --version` fails.\n\n### Option A: Quick Install (recommended)\n\n```bash\ncurl -fsSL https://mipham.ai/install.sh | bash\n```\n\nThen restart the shell or run:\n\n```bash\nexport PATH=\"$HOME/.mipham/bin:$PATH\"\n```\n\n### Option B: npm Global Install\n\n```bash\nnpm install -g @miphamai/cli\nmipham\n```\n\n### Option C: From Source (developers)\n\n```bash\ngit clone https://github.com/One-Mipham/mipham-code\ncd mipham-code/apps/cli\nbun install && bun run bin/mipham\n```\n\n### ✅ Verification\n\n```bash\nmipham --version # Should print version ≥ 0.24.0\nmipham --help # Should print usage\n```\n\n---\n\n## Phase 2: Project Initialization\n\n**Trigger**: Missing `.mipham/` directory or `MIPHAM.md`.\n\n### 2.1 — Create .mipham/ directory\n\n```bash\nmkdir -p .mipham\n```\n\n### 2.2 — Create .mipham/config.yml\n\nWrite a minimal config. Ask the user which provider they want to use first, or pick a sensible default:\n\n```yaml\ndefaultProvider: anthropic\ndefaultModel: claude-sonnet-4-6\npermission: default\n```\n\n**Providers available** (alphabetical):\n\n| Provider | Type | Example Models |\n| --------- | ------------- | -------------------------------------- |\n| anthropic | Native SDK | Claude Haiku 4.5, Sonnet 4.6, Opus 4.8 |\n| deepseek | OpenAI Compat | V4 Flash, V4 Pro |\n| doubao | OpenAI Compat | Seed 1.6, Seed 2.0 |\n| gemini | OpenAI Compat | 3.0 Flash, 3.0 Pro, 2.5 Pro |\n| hunyuan | OpenAI Compat | Lite, TurboS, 2.0, T1 |\n| openai | OpenAI Compat | GPT-5.4 Mini, GPT-5.4, GPT-5.5, Codex |\n| qwen | OpenAI Compat | Qwen Plus, Qwen Max |\n\n### 2.3 — Create MIPHAM.md (optional but recommended)\n\nCreate `MIPHAM.md` in project root to define AI personality:\n\n```markdown\n# MIPHAM.md\n\n## Project Context\n\n- **Project**: [name]\n- **Language**: [zh-CN / en]\n- **Stack**: [TypeScript / Python / etc.]\n\n## Preferences\n\n- Code style: [e.g., functional, OOP]\n- Comment language: [e.g., English]\n- Test framework: [e.g., Vitest]\n```\n\n### ✅ Verification\n\n```bash\nls -la .mipham/config.yml MIPHAM.md\n```\n\n---\n\n## Phase 3: API Key Configuration\n\n**Trigger**: Missing API keys in environment.\n\n### 3.1 — Identify Required Providers\n\nAsk the user which providers they plan to use. For each, set the env var.\n\n### 3.2 — Set API Keys\n\n**Recommended: Environment variables** (not in config files — avoids accidental commits):\n\n```bash\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\nexport OPENAI_API_KEY=\"sk-...\"\nexport DEEPSEEK_API_KEY=\"sk-...\"\nexport QWEN_API_KEY=\"sk-...\"\nexport DOUBAO_API_KEY=\"...\"\nexport HUNYUAN_API_KEY=\"...\"\nexport GEMINI_API_KEY=\"...\"\n```\n\nAdd these to `~/.zshrc` or `~/.bashrc` for persistence:\n\n```bash\necho 'export ANTHROPIC_API_KEY=\"sk-ant-...\"' >> ~/.zshrc\nsource ~/.zshrc\n```\n\n**Alternative**: Store in `~/.mipham/config.yml`:\n\n```yaml\nproviders:\n - id: anthropic\n apiKey: $ANTHROPIC_API_KEY\n - id: openai\n apiKey: $OPENAI_API_KEY\n```\n\n### 3.3 — Verify Keys\n\n```bash\nenv | grep API_KEY\n```\n\n### ❗Security Rules\n\n- NEVER hardcode API keys in project config files (`.mipham/config.yml` in project root should use `$ENV_VAR` references, not raw keys)\n- NEVER commit API keys to git\n- Add to `.gitignore`: `.mipham/config.yml` (if it contains keys), `.env`, `*.pem`\n\n---\n\n## Phase 4: Provider & Model Configuration\n\n**Trigger**: Need to set default or enable/disable providers.\n\n### 4.1 — Set Default Provider & Model\n\nIn `.mipham/config.yml`:\n\n```yaml\ndefaultProvider: anthropic\ndefaultModel: claude-sonnet-4-6\n```\n\nOr use slash commands:\n\n```\n/model # Interactive model picker (Ctrl+P)\n/switch # Switch provider\n/providers # List all configured providers\n```\n\n### 4.2 — Enable/Disable Providers\n\n```yaml\nproviders:\n - id: anthropic\n status: active\n - id: openai\n status: active\n - id: deepseek\n status: disabled\n```\n\n### ✅ Verification\n\n```\n/model # Should show available models\n/providers # Should list active providers\n```\n\n---\n\n## Phase 5: Skills Installation\n\n**Trigger**: No or few skills installed.\n\n### 5.1 — Built-in Skills\n\nMipham Code ships with 17 built-in skills loaded automatically:\n\n- **Standard (14)**: code-review, compassionate-communication, doc-generator, github-ops, memory, mipham-code-setup, security-review, self-review, superpower, systematic-debugging, tdd, test-driven-development, web-access, web-search\n- **Mipham (3)**: om-artifact, om-model-optimize, om-security\n\n### 5.2 — Community Skills\n\nInstall from the community registry:\n\n```\n/setup 4 # Guided skill browser\n```\n\nOr directly:\n\n```bash\n# Skills are loaded from:\n# - apps/cli/skills/standard/ (built-in standard)\n# - apps/cli/skills/mipham/ (built-in mipham)\n# - ~/.mipham/skills/ (user-installed)\n# - .mipham/skills/ (project-local)\n```\n\n### 5.3 — Install Specific Skills\n\n```\n/skills install <name> # Install from registry\n/skills list # List available\n/skills search <query> # Search registry\n```\n\n### ✅ Verification\n\n```\n/skills list # Should show installed skills with counts\n```\n\n---\n\n## Phase 6: Permissions Configuration\n\n**Trigger**: Permission mode not configured or wrong for use case.\n\n### 6.1 — Permission Modes\n\n| Mode | Behavior | Use Case |\n| ------------------- | ------------------------------- | ----------------------------------- |\n| `default` | Prompt for each tool | Normal development (recommended) |\n| `acceptEdits` | Auto-allow edits, prompt others | Active coding sessions |\n| `plan` | Plan-only, no tool execution | Design & architecture work |\n| `auto` | Auto-allow all | Trusted, frequent use |\n| `dontAsk` | Never auto-allow | CI/CD safety |\n| `bypassPermissions` | Skip all checks | ⚠️ Only for fully trusted codebases |\n\n### 6.2 — Configure\n\nIn `.mipham/config.yml`:\n\n```yaml\npermission: auto\n```\n\nOr via slash command:\n\n```\n/permissions # View current settings\n/setup 5 # Permission setup wizard\n```\n\n### 6.3 — CI/CD Safety\n\nFor CI/CD environments, use `dontAsk` mode to prevent the AI from executing tools without explicit approval:\n\n```yaml\npermission: dontAsk\n```\n\n### ✅ Verification\n\n```\n/permissions # Should show current mode\n```\n\n---\n\n## Phase 7: Workspace Trust\n\n**Trigger**: Untrusted workspace (prompted on startup in v0.24.3+).\n\n### 7.1 — Understanding Workspace Trust\n\nWorkspace trust is a security mechanism that prevents AI from operating in untrusted directories. Trust is **hierarchical**: trusting `/Users/me/Projects` implicitly trusts all subdirectories.\n\n### 7.2 — Trust a Workspace\n\n**Interactive**: Accept the trust prompt when launching Mipham Code in a new directory.\n\n**Manual**:\n\n```\n/trust # Show trust status\n/trust add <dir> # Trust a directory\n/trust remove <dir> # Revoke trust\n```\n\n### 7.3 — Trust Store\n\n```\n~/.mipham/trusted-workspaces.json\n```\n\n### 7.4 — Auto-Trust for Worktrees\n\nWhen using git worktrees, Mipham Code automatically trusts worktree directories if the parent workspace is already trusted (via `EnterWorktree`).\n\n### ✅ Verification\n\n```\n/trust # Should show \"✅ Yes\" for current directory\n```\n\n---\n\n## Phase 8: Shell & IDE Integration\n\n**Trigger**: Want terminal integration, aliases, or IDE plugins.\n\n### 8.1 — Shell Alias\n\nAdd to `~/.zshrc` or `~/.bashrc`:\n\n```bash\nalias mipham='cd ~/your-project && bun run ~/path/to/mipham-code/apps/cli/bin/mipham.ts'\n# Or if installed globally:\nalias mipham='mipham'\n```\n\n### 8.2 — VS Code Integration\n\nRun `/ide` to auto-generate `.vscode/` config files:\n\n- `settings.json` — terminal profile \"mipham\" using Bun\n- `keybindings.json` — Cmd+Esc to focus terminal, Cmd+Shift+M for new terminal\n- `extensions.json` — recommends `miphamai.mipham-code` extension\n\nTo use after generation:\n\n1. Restart VS Code (or Cmd+Shift+P → Reload Window)\n2. Open terminal: Ctrl+` or Cmd+Esc\n3. Select \"mipham\" profile from terminal dropdown\n\nInstall the VS Code extension:\n\n```bash\ncode --install-extension miphamai.mipham-code\n```\n\n### 8.3 — JetBrains Integration\n\nSettings → Tools → Terminal → Shell path → `bun run mipham`\n\n### 8.4 — Terminal Setup\n\n```\n/terminal-setup # Shell & terminal config wizard\n/setup 6 # Shell integration (part of full wizard)\n```\n\n### ✅ Verification\n\n```bash\nwhich mipham # Should resolve\n# In VS Code: Ctrl+` → select \"mipham\" profile\n```\n\n---\n\n## Phase 9: Full Verification\n\nRun after all configuration phases complete.\n\n### 9.1 — System Diagnostics\n\n```\n/doctor # System diagnostics check\n```\n\n### 9.2 — End-to-End Test\n\nStart a conversation and verify:\n\n1. Model responds (not stuck on \"connecting...\")\n2. File tools work: \"read CLAUDE.md\"\n3. Bash works: \"list files in current directory\"\n4. Skills load: `/skills list`\n\n### 9.3 — Common Issues & Fixes\n\n| Symptom | Diagnosis | Fix |\n| ------------------------- | -------------------------------------- | ------------------------------------------------ |\n| \"Provider not registered\" | Missing or invalid API key | `env \\| grep API_KEY`; check key format |\n| \"Model not found\" | Model ID mismatch or disabled provider | `/models` to list available; `/switch` to change |\n| Slow responses | Large model, network, or context full | `/fast on` or switch to Flash model; `/compact` |\n| Context full | Too many messages in history | `/compact` to compress; `/clear` to reset |\n| Permission denied | Tool blocked by permission mode | `/permissions` to check; adjust mode |\n| \"Workspace not trusted\" | New directory, not yet trusted | Accept startup prompt or run `/trust` |\n| MCP tools not available | Server not connected | `/mcp connect <name>` or check config |\n| Update not applying | Cached binary | `mipham update --force` then restart |\n| Config changes ignored | YAML syntax error | Validate with `mipham --check-config` |\n\n### 9.4 — Get Help\n\n```\n/help # Full command reference\n/setup # Re-run setup wizard\n/doctor # Run diagnostics\n```\n\nChat-based help: \"help me configure X\" or \"why isn't Y working?\"\n\n---\n\n## Quick Reference: Essential Slash Commands\n\n| Category | Command | Purpose |\n| ------------- | ----------------- | ------------------------------------------------------ |\n| **Setup** | `/setup` | Full 6-step setup wizard |\n| | `/setup 1` | Initialize project (.mipham/ + MIPHAM.md + config.yml) |\n| | `/setup 2` | Configure providers & API keys |\n| | `/setup 3` | Choose default model |\n| | `/setup 4` | Browse & install skills |\n| | `/setup 5` | Configure permissions |\n| | `/setup 6` | Shell & IDE integration |\n| **Diagnosis** | `/doctor` | System diagnostics |\n| | `/trust` | Workspace trust status |\n| | `/permissions` | Tool permission settings |\n| **Model** | `/model` | Interactive model picker (Ctrl+P) |\n| | `/switch` | Switch provider |\n| | `/models` | List available models |\n| **Session** | `/clear` | Reset conversation |\n| | `/compact` | Compress context |\n| | `/rename` | Rename session |\n| **Workflow** | `/plan` | Enter plan mode |\n| | `/review` | Code review |\n| | `/todos` | Task list |\n| **IDE** | `/ide` | Generate VS Code integration files |\n| | `/terminal-setup` | Shell & terminal config |\n| **Skills** | `/skills list` | List installed skills |\n| | `/skills search` | Search skill registry |\n| | `/skills install` | Install a skill |\n\n---\n\n## Post-Setup: What to Do Next\n\nAfter configuration is verified:\n\n1. **Initialize your project**: \"help me understand this codebase\"\n2. **Set up CLAUDE.md**: `/init` to generate project documentation for the AI\n3. **Install relevant skills**: `/setup 4` or `/skills search`\n4. **Configure MCP servers**: `/mcp connect` for external tool integration\n5. **Start coding**: Just start a conversation — the AI will use tools and skills automatically\n" },
|
|
20
|
+
{ type: 'standard', raw: "---\nname: mipham-code-setup\ndescription: 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.\nversion: 2.0.0\nuser-invocable: true\nallowed-tools:\n - Read\n - Write\n - Edit\n - Bash\n - Skill\n---\n\n# Mipham Code Setup — Executable Setup Workflow\n\n**Type**: Rigid — follow the decision tree exactly. Don't skip diagnostic phases.\n\n**Purpose**: Guide users from zero to fully configured Mipham Code. This skill is BOTH:\n\n1. A self-contained diagnostic + configuration workflow the AI can execute\n2. A reference for `/setup` command behavior and slash commands\n\n**Triggers**: \"setup mipham\", \"configure mipham\", \"install mipham code\", \"mipham not working\", \"mipham setup\", \"first time using mipham\", \"help me set up\", \"getting started\", `/setup`\n\n---\n\n## Phase 0: Environment Detection (ALWAYS RUN FIRST)\n\nBefore doing anything, run these diagnostic checks. Report results in a status table.\n\n### 0.1 — Detect Installation\n\n```bash\nwhich mipham 2>/dev/null\nmipham --version 2>/dev/null\nbun --version 2>/dev/null\nnode --version 2>/dev/null\n```\n\n### 0.2 — Detect Configuration\n\n```bash\nls -la .mipham/config.yml 2>/dev/null\nls -la ~/.mipham/config.yml 2>/dev/null\nls -la MIPHAM.md 2>/dev/null\nls -la CLAUDE.md 2>/dev/null\n```\n\n### 0.3 — Detect API Keys\n\n```bash\nenv | 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\n```\n\n### 0.4 — Detect Skills & Permissions\n\n```bash\nls .mipham/skills/ 2>/dev/null\ncat .mipham/config.yml 2>/dev/null | grep -E 'permission|trust' || echo \"no config\"\n```\n\n### 0.5 — Detect Workspace Trust\n\n```bash\ncat ~/.mipham/trusted-workspaces.json 2>/dev/null || echo \"no trust store\"\n```\n\n### Status Report Format\n\nAfter detection, present results as:\n\n```\n── Mipham Code Status ──\n\nInstallation: [✅/⬜] mipham CLI [✅/⬜] Bun [✅/⬜] Node.js\nProject: [✅/⬜] .mipham/ [✅/⬜] config.yml [✅/⬜] MIPHAM.md\nUser Config: [✅/⬜] ~/.mipham/config.yml\nAPI Keys: [N] set (list names or \"none\")\nSkills: [N] installed\nPermissions: [mode] (default/acceptEdits/plan/bypassPermissions)\nTrust: [✅/⬜] workspace trusted\n```\n\nThen proceed to ONLY the phases where something is missing. Don't re-run already-configured steps unless asked.\n\n---\n\n## Phase 1: Installation\n\n**Trigger**: `mipham --version` fails.\n\n### Option A: Quick Install (recommended)\n\n```bash\ncurl -fsSL https://mipham.ai/install.sh | bash\n```\n\nThen restart the shell or run:\n\n```bash\nexport PATH=\"$HOME/.mipham/bin:$PATH\"\n```\n\n### Option B: npm Global Install\n\n```bash\nnpm install -g @miphamai/cli\nmipham\n```\n\n### Option C: From Source (developers)\n\n```bash\ngit clone https://github.com/One-Mipham/mipham-code\ncd mipham-code/apps/cli\nbun install && bun run bin/mipham\n```\n\n### ✅ Verification\n\n```bash\nmipham --version # Should print version ≥ 0.24.0\nmipham --help # Should print usage\n```\n\n---\n\n## Phase 2: Project Initialization\n\n**Trigger**: Missing `.mipham/` directory or `MIPHAM.md`.\n\n### 2.1 — Create .mipham/ directory\n\n```bash\nmkdir -p .mipham\n```\n\n### 2.2 — Create .mipham/config.yml\n\nWrite a minimal config. Ask the user which provider they want to use first, or pick a sensible default:\n\n```yaml\ndefaultProvider: anthropic\ndefaultModel: claude-sonnet-4-6\npermission: default\n```\n\n**Providers available** (alphabetical):\n\n| Provider | Type | Example Models |\n| --------- | ------------- | -------------------------------------- |\n| anthropic | Native SDK | Claude Haiku 4.5, Sonnet 4.6, Opus 4.8 |\n| deepseek | OpenAI Compat | V4 Flash, V4 Pro |\n| doubao | OpenAI Compat | Seed 1.6, Seed 2.0 |\n| gemini | OpenAI Compat | 3.0 Flash, 3.0 Pro, 2.5 Pro |\n| hunyuan | OpenAI Compat | Lite, TurboS, 2.0, T1 |\n| openai | OpenAI Compat | GPT-5.4 Mini, GPT-5.4, GPT-5.5, Codex |\n| qwen | OpenAI Compat | Qwen Plus, Qwen Max |\n\n### 2.3 — Create MIPHAM.md (optional but recommended)\n\nCreate `MIPHAM.md` in project root to define AI personality:\n\n```markdown\n# MIPHAM.md\n\n## Project Context\n\n- **Project**: [name]\n- **Language**: [zh-CN / en]\n- **Stack**: [TypeScript / Python / etc.]\n\n## Preferences\n\n- Code style: [e.g., functional, OOP]\n- Comment language: [e.g., English]\n- Test framework: [e.g., Vitest]\n```\n\n### ✅ Verification\n\n```bash\nls -la .mipham/config.yml MIPHAM.md\n```\n\n---\n\n## Phase 3: API Key Configuration\n\n**Trigger**: Missing API keys in environment.\n\n### 3.1 — Identify Required Providers\n\nAsk the user which providers they plan to use. For each, set the env var.\n\n### 3.2 — Set API Keys\n\n**Recommended: Environment variables** (not in config files — avoids accidental commits):\n\n```bash\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\nexport OPENAI_API_KEY=\"sk-...\"\nexport DEEPSEEK_API_KEY=\"sk-...\"\nexport QWEN_API_KEY=\"sk-...\"\nexport DOUBAO_API_KEY=\"...\"\nexport HUNYUAN_API_KEY=\"...\"\nexport GEMINI_API_KEY=\"...\"\n```\n\nAdd these to `~/.zshrc` or `~/.bashrc` for persistence:\n\n```bash\necho 'export ANTHROPIC_API_KEY=\"sk-ant-...\"' >> ~/.zshrc\nsource ~/.zshrc\n```\n\n**Alternative**: Store in `~/.mipham/config.yml`:\n\n```yaml\nproviders:\n - id: anthropic\n apiKey: $ANTHROPIC_API_KEY\n - id: openai\n apiKey: $OPENAI_API_KEY\n```\n\n### 3.3 — Verify Keys\n\n```bash\nenv | grep API_KEY\n```\n\n### ❗Security Rules\n\n- NEVER hardcode API keys in project config files (`.mipham/config.yml` in project root should use `$ENV_VAR` references, not raw keys)\n- NEVER commit API keys to git\n- Add to `.gitignore`: `.mipham/config.yml` (if it contains keys), `.env`, `*.pem`\n\n---\n\n## Phase 4: Provider & Model Configuration\n\n**Trigger**: Need to set default or enable/disable providers.\n\n### 4.1 — Set Default Provider & Model\n\nIn `.mipham/config.yml`:\n\n```yaml\ndefaultProvider: anthropic\ndefaultModel: claude-sonnet-4-6\n```\n\nOr use slash commands:\n\n```\n/model # Interactive model picker (Ctrl+P)\n/switch # Switch provider\n/providers # List all configured providers\n```\n\n### 4.2 — Enable/Disable Providers\n\n```yaml\nproviders:\n - id: anthropic\n status: active\n - id: openai\n status: active\n - id: deepseek\n status: disabled\n```\n\n### ✅ Verification\n\n```\n/model # Should show available models\n/providers # Should list active providers\n```\n\n---\n\n## Phase 5: Skills Installation\n\n**Trigger**: No or few skills installed.\n\n### 5.1 — Built-in Skills\n\nMipham Code ships with 17 built-in skills loaded automatically:\n\n- **Standard (14)**: code-review, compassionate-communication, doc-generator, github-ops, memory, mipham-code-setup, security-review, self-review, superpower, systematic-debugging, tdd, test-driven-development, web-access, web-search\n- **Mipham (3)**: om-artifact, om-model-optimize, om-security\n\n### 5.2 — Community Skills\n\nInstall from the community registry:\n\n```\n/setup 4 # Guided skill browser\n```\n\nOr directly:\n\n```bash\n# Skills are loaded from:\n# - apps/cli/skills/standard/ (built-in standard)\n# - apps/cli/skills/mipham/ (built-in mipham)\n# - ~/.mipham/skills/ (user-installed)\n# - .mipham/skills/ (project-local)\n```\n\n### 5.3 — Install Specific Skills\n\n```\n/skills install <name> # Install from registry\n/skills list # List available\n/skills search <query> # Search registry\n```\n\n### ✅ Verification\n\n```\n/skills list # Should show installed skills with counts\n```\n\n---\n\n## Phase 6: Permissions Configuration\n\n**Trigger**: Permission mode not configured or wrong for use case.\n\n### 6.1 — Permission Modes\n\n| Mode | Behavior | Use Case |\n| ------------------- | ------------------------------- | ----------------------------------- |\n| `default` | Prompt for each tool | Normal development (recommended) |\n| `acceptEdits` | Auto-allow edits, prompt others | Active coding sessions |\n| `plan` | Plan-only, no tool execution | Design & architecture work |\n| `bypassPermissions` | Skip all checks | ⚠️ Only for fully trusted codebases |\n\n### 6.2 — Configure\n\nIn `.mipham/config.yml`:\n\n```yaml\npermission: default\n```\n\nOr via slash command:\n\n```\n/permissions # View current settings\n/setup 5 # Permission setup wizard\n```\n\n### 6.3 — CI/CD Safety\n\nFor CI/CD environments, use the `default` mode (the daemon default): headless\nsessions never prompt, so `ask`-level tools (Bash/Write/Edit) are blocked rather\nthan auto-approved.\n\n### ✅ Verification\n\n```\n/permissions # Should show current mode\n```\n\n---\n\n## Phase 7: Workspace Trust\n\n**Trigger**: Untrusted workspace (prompted on startup in v0.24.3+).\n\n### 7.1 — Understanding Workspace Trust\n\nWorkspace trust is a security mechanism that prevents AI from operating in untrusted directories. Trust is **hierarchical**: trusting `/Users/me/Projects` implicitly trusts all subdirectories.\n\n### 7.2 — Trust a Workspace\n\n**Interactive**: Accept the trust prompt when launching Mipham Code in a new directory.\n\n**Manual**:\n\n```\n/trust # Show trust status\n/trust add <dir> # Trust a directory\n/trust remove <dir> # Revoke trust\n```\n\n### 7.3 — Trust Store\n\n```\n~/.mipham/trusted-workspaces.json\n```\n\n### 7.4 — Auto-Trust for Worktrees\n\nWhen using git worktrees, Mipham Code automatically trusts worktree directories if the parent workspace is already trusted (via `EnterWorktree`).\n\n### ✅ Verification\n\n```\n/trust # Should show \"✅ Yes\" for current directory\n```\n\n---\n\n## Phase 8: Shell & IDE Integration\n\n**Trigger**: Want terminal integration, aliases, or IDE plugins.\n\n### 8.1 — Shell Alias\n\nAdd to `~/.zshrc` or `~/.bashrc`:\n\n```bash\nalias mipham='cd ~/your-project && bun run ~/path/to/mipham-code/apps/cli/bin/mipham.ts'\n# Or if installed globally:\nalias mipham='mipham'\n```\n\n### 8.2 — VS Code Integration\n\nRun `/ide` to auto-generate `.vscode/` config files:\n\n- `settings.json` — terminal profile \"mipham\" using Bun\n- `keybindings.json` — Cmd+Esc to focus terminal, Cmd+Shift+M for new terminal\n- `extensions.json` — recommends `miphamai.mipham-code` extension\n\nTo use after generation:\n\n1. Restart VS Code (or Cmd+Shift+P → Reload Window)\n2. Open terminal: Ctrl+` or Cmd+Esc\n3. Select \"mipham\" profile from terminal dropdown\n\nInstall the VS Code extension:\n\n```bash\ncode --install-extension miphamai.mipham-code\n```\n\n### 8.3 — JetBrains Integration\n\nSettings → Tools → Terminal → Shell path → `bun run mipham`\n\n### 8.4 — Terminal Setup\n\n```\n/terminal-setup # Shell & terminal config wizard\n/setup 6 # Shell integration (part of full wizard)\n```\n\n### ✅ Verification\n\n```bash\nwhich mipham # Should resolve\n# In VS Code: Ctrl+` → select \"mipham\" profile\n```\n\n---\n\n## Phase 9: Full Verification\n\nRun after all configuration phases complete.\n\n### 9.1 — System Diagnostics\n\n```\n/doctor # System diagnostics check\n```\n\n### 9.2 — End-to-End Test\n\nStart a conversation and verify:\n\n1. Model responds (not stuck on \"connecting...\")\n2. File tools work: \"read CLAUDE.md\"\n3. Bash works: \"list files in current directory\"\n4. Skills load: `/skills list`\n\n### 9.3 — Common Issues & Fixes\n\n| Symptom | Diagnosis | Fix |\n| ------------------------- | -------------------------------------- | ------------------------------------------------ |\n| \"Provider not registered\" | Missing or invalid API key | `env \\| grep API_KEY`; check key format |\n| \"Model not found\" | Model ID mismatch or disabled provider | `/models` to list available; `/switch` to change |\n| Slow responses | Large model, network, or context full | `/fast on` or switch to Flash model; `/compact` |\n| Context full | Too many messages in history | `/compact` to compress; `/clear` to reset |\n| Permission denied | Tool blocked by permission mode | `/permissions` to check; adjust mode |\n| \"Workspace not trusted\" | New directory, not yet trusted | Accept startup prompt or run `/trust` |\n| MCP tools not available | Server not connected | `/mcp connect <name>` or check config |\n| Update not applying | Cached binary | `mipham update --force` then restart |\n| Config changes ignored | YAML syntax error | Validate with `mipham --check-config` |\n\n### 9.4 — Get Help\n\n```\n/help # Full command reference\n/setup # Re-run setup wizard\n/doctor # Run diagnostics\n```\n\nChat-based help: \"help me configure X\" or \"why isn't Y working?\"\n\n---\n\n## Quick Reference: Essential Slash Commands\n\n| Category | Command | Purpose |\n| ------------- | ----------------- | ------------------------------------------------------ |\n| **Setup** | `/setup` | Full 6-step setup wizard |\n| | `/setup 1` | Initialize project (.mipham/ + MIPHAM.md + config.yml) |\n| | `/setup 2` | Configure providers & API keys |\n| | `/setup 3` | Choose default model |\n| | `/setup 4` | Browse & install skills |\n| | `/setup 5` | Configure permissions |\n| | `/setup 6` | Shell & IDE integration |\n| **Diagnosis** | `/doctor` | System diagnostics |\n| | `/trust` | Workspace trust status |\n| | `/permissions` | Tool permission settings |\n| **Model** | `/model` | Interactive model picker (Ctrl+P) |\n| | `/switch` | Switch provider |\n| | `/models` | List available models |\n| **Session** | `/clear` | Reset conversation |\n| | `/compact` | Compress context |\n| | `/rename` | Rename session |\n| **Workflow** | `/plan` | Enter plan mode |\n| | `/review` | Code review |\n| | `/todos` | Task list |\n| **IDE** | `/ide` | Generate VS Code integration files |\n| | `/terminal-setup` | Shell & terminal config |\n| **Skills** | `/skills list` | List installed skills |\n| | `/skills search` | Search skill registry |\n| | `/skills install` | Install a skill |\n\n---\n\n## Post-Setup: What to Do Next\n\nAfter configuration is verified:\n\n1. **Initialize your project**: \"help me understand this codebase\"\n2. **Set up CLAUDE.md**: `/init` to generate project documentation for the AI\n3. **Install relevant skills**: `/setup 4` or `/skills search`\n4. **Configure MCP servers**: `/mcp connect` for external tool integration\n5. **Start coding**: Just start a conversation — the AI will use tools and skills automatically\n" },
|
|
21
21
|
{ type: 'standard', raw: "---\nname: research\ndescription: Deep research against primary sources, executed as a background agent. Collects findings into a single cited Markdown file. Use for investigation that requires reading official docs, source code, specs, or first-party APIs — not secondary summaries.\nversion: 1.0.0\nuser-invocable: true\nallowed-tools:\n - WebSearch\n - WebFetch\n - Agent\n - Bash\n - Write\n - Read\n---\n\n# Research — Background Deep Research\n\n融合 Mipham web-search v3.0(查询构建+验证)+ Matt Pocock research(后台代理+一手来源+Markdown 报告)。\n\n## When to Use\n\n- \"Research X for me\"\n- \"Find out everything about Y from primary sources\"\n- \"Investigate Z and write up findings\"\n- Any question where googling + reading multiple sources is the right answer\n\n## When NOT to Use\n\n- Quick fact lookup → use `/web-search` directly\n- Question answerable from code already in context\n- Pure logic/algorithmic question\n\n---\n\n## Phase 0: Route\n\n```\nResearch task is...\n├── Quick (1-2 sources, immediate answer)?\n│ └── → Use web-search skill directly (Phase 0-4)\n│\n├── Deep (multiple sources, needs synthesis)?\n│ └── → THIS SKILL — background agent\n│\n└── Login-walled / SPA-only sources?\n └── → web-access skill (ComputerUse browser)\n```\n\n---\n\n## Phase 1: Spin Up Background Agent\n\nLaunch a **background agent** to do the heavy reading, so you keep working while it researches.\n\nThe agent's instructions:\n\n```\nYou are a research agent. Your task:\n\n1. Investigate the question against PRIMARY SOURCES ONLY:\n - Official documentation (docs.*.com, *.org)\n - Source code repositories (GitHub, GitLab)\n - Technical specifications (RFCs, standards)\n - First-party API references\n - NOT: blog posts, Medium articles, forum threads, secondary summaries\n\n2. For every claim, follow it back to the source that owns it.\n If a secondary source makes a claim, find the primary source and cite that.\n\n3. Use WebSearch to find sources.\n Use WebFetch to deep-read promising pages.\n Cross-reference critical claims across 2+ independent primary sources.\n\n4. Write findings to a SINGLE Markdown file.\n - Cite every claim with its primary source URL\n - Distinguish between facts (needs citation) and reasoning (your own)\n - Flag outdated content (\"article from 2024, may be stale\")\n - Note if a source is official docs vs community\n\n5. Save the file where the repo already keeps such notes.\n Match existing conventions. If none exist, put it in docs/research/.\n```\n\n---\n\n## Phase 2: Report Format\n\nThe agent writes findings in this structure:\n\n```markdown\n# [Research Topic]\n\n**Date**: YYYY-MM-DD\n**Sources**: N primary, M cross-references\n\n## Key Findings\n\n- [Finding 1] — [Source](URL)\n- [Finding 2] — [Source](URL)\n\n## Detailed Analysis\n\n### [Subtopic A]\n\n[Claim and citation]\n\n### [Subtopic B]\n\n[Claim and citation]\n\n## Source Evaluation\n\n| Source | Type | Authority | Notes |\n| ----------- | ------------- | --------- | --------------------- |\n| [Name](URL) | Official docs | High | Current as of YYYY-MM |\n| [Name](URL) | Source code | High | Tag vX.Y.Z |\n\n## Open Questions\n\n- [Question 1]\n- [Question 2]\n\nSources:\n\n- [Title](URL) — brief note\n```\n\n---\n\n## Phase 3: Review\n\nWhen the background agent completes:\n\n1. Read the output file\n2. Spot-check: did it follow the chain back to primary sources?\n3. Flag any claims that need further verification\n4. Surface uncertainties to the user\n\n---\n\n## Research Quality Checklist\n\n- [ ] Every factual claim has a primary source citation\n- [ ] At least one critical claim is cross-referenced (2+ sources)\n- [ ] Source type is clearly identified (official docs / source code / spec / community)\n- [ ] Outdated content is flagged with publication year\n- [ ] Reasoning vs facts are clearly distinguished\n- [ ] File saved in repo-appropriate location\n" },
|
|
22
22
|
{ type: 'standard', raw: "---\nname: security-review\ndescription: Security audit skill — vulnerability scanning, OWASP Top 10, secrets detection, supply chain analysis, and compliance checking\nversion: 1.0.0\n---\n\n# Security Review\n\nComprehensive security audit for codebases. Covers vulnerability detection, compliance, and hardening recommendations.\n\n## Audit Checklist\n\n### 1. Secrets & Credentials\n\n- [ ] No hardcoded API keys, tokens, or passwords in source files\n- [ ] `.env` and `*.pem` files in `.gitignore`\n- [ ] API keys use environment variables or secret managers\n- [ ] No credentials in git history (check `git log -p`)\n- [ ] CI/CD secrets stored securely (not in workflow files)\n\n### 2. OWASP Top 10\n\n- [ ] **Injection**: SQL, NoSQL, OS command, LDAP injection points\n- [ ] **Broken Authentication**: Weak password policies, missing MFA\n- [ ] **Sensitive Data Exposure**: Unencrypted PII, missing TLS\n- [ ] **XXE**: XML external entity processing\n- [ ] **Broken Access Control**: Missing authorization checks\n- [ ] **Security Misconfiguration**: Default credentials, verbose errors\n- [ ] **XSS**: Reflected, stored, DOM-based cross-site scripting\n- [ ] **Insecure Deserialization**: Untrusted data deserialization\n- [ ] **Using Vulnerable Components**: Outdated dependencies with CVEs\n- [ ] **Insufficient Logging**: Missing audit trails for auth events\n\n### 3. Supply Chain\n\n- [ ] All dependencies have known licenses (no copyleft/GPL)\n- [ ] No dependencies with critical CVEs\n- [ ] Lock files committed (pnpm-lock.yaml, package-lock.json)\n- [ ] Dependency update policy in place\n- [ ] SBOM (Software Bill of Materials) available\n\n### 4. Network & API Security\n\n- [ ] TLS 1.3 enforced for all external communications\n- [ ] API endpoints have rate limiting\n- [ ] CORS configured with explicit origins (not `*`)\n- [ ] SSRF protections in place (URL validation, IP filtering)\n- [ ] WebSocket connections use WSS\n- [ ] GraphQL endpoints have query depth limits\n\n### 5. File System & Path Security\n\n- [ ] Path traversal protections (no `../../../etc/passwd`)\n- [ ] File upload validation (type, size, content inspection)\n- [ ] Symlink attacks prevented\n- [ ] Sensitive directories blocked (`/etc`, `/proc`, `/sys`)\n- [ ] Temporary files cleaned up after use\n\n### 6. Code-Level Security\n\n- [ ] No `eval()` or `Function()` with user input\n- [ ] No `child_process.exec()` with unsanitized input\n- [ ] Regex patterns safe from ReDoS\n- [ ] Prototype pollution prevented\n- [ ] No `dangerouslySetInnerHTML` without sanitization (React)\n- [ ] SQL queries use parameterized statements\n\n### 7. Authentication & Sessions\n\n- [ ] Passwords hashed with bcrypt/argon2 (not MD5/SHA1)\n- [ ] Session tokens use `httpOnly`, `secure`, `SameSite=Strict`\n- [ ] JWT tokens have reasonable expiration\n- [ ] Account lockout after failed attempts\n- [ ] Password reset tokens expire and are single-use\n\n### 8. Data Protection\n\n- [ ] PII data encrypted at rest (AES-256-GCM)\n- [ ] Data encrypted in transit (TLS 1.3)\n- [ ] Logs do not contain sensitive data\n- [ ] Database backups encrypted\n- [ ] Data retention policies defined\n\n### 9. Infrastructure\n\n- [ ] Infrastructure as Code (Terraform/Pulumi) used\n- [ ] Cloud resources not publicly exposed unless intended\n- [ ] Security groups / firewalls restrict inbound traffic\n- [ ] Container images scanned for vulnerabilities\n- [ ] Kubernetes pods run as non-root\n\n### 10. Logging & Monitoring\n\n- [ ] Authentication events logged\n- [ ] Failed access attempts logged and alerted\n- [ ] Structured logging format (JSON)\n- [ ] No PII in log messages\n- [ ] Alert thresholds configured for critical events\n\n## Report Format\n\n```\nSecurity Review Report\n======================\nDate: YYYY-MM-DD\nSeverity: Critical | High | Medium | Low\n\nFinding #N: [Title]\nSeverity: Critical/High/Medium/Low\nLocation: file:line\nDescription: [What was found]\nRisk: [What could happen]\nFix: [How to resolve]\n```\n\n## Compliance Standards\n\n- OWASP ASVS Level 2\n- PCI DSS (if handling payment data)\n- GDPR (if handling EU personal data)\n- SOC 2 Type II\n- ISO 27001\n" },
|
|
23
23
|
{ type: 'standard', raw: "---\nname: self-review\ndescription: Self-review of staged or recently changed code — reuse, simplification, efficiency, and architectural alignment\nversion: 2.0.0\n---\n\n# Self Review\n\nReview your own code changes before committing or merging. Focus on quality improvements, not bug hunting.\n\n## When to Run\n\n- Before committing changes\n- After completing a feature or fix\n- Before requesting a peer review\n- As the final step before merging\n\n## Review Passes\n\n### Pass 1: Reuse\n\n- Is there existing code that does the same thing?\n- Are there utility functions or shared libraries you missed?\n- Could this be solved with a standard library method?\n- Are you reimplementing something the framework provides?\n\n### Pass 2: Simplification\n\n- Can a complex function be split into smaller, named functions?\n- Are there unnecessary abstractions (interfaces with one impl, unused generics)?\n- Can nested conditionals be flattened with early returns?\n- Is there dead code, unused imports, or commented-out blocks?\n\n### Pass 3: Efficiency\n\n- Are you looping over data multiple times when once would suffice?\n- Are large objects being copied unnecessarily?\n- Could a synchronous operation be made async/non-blocking?\n- Are regex patterns compiled once or on every call?\n\n### Pass 4: Altitude (Architectural Alignment)\n\n- Does this code belong where it is?\n- Is it in the right layer (UI / business logic / data access)?\n- Does it follow existing patterns in the codebase?\n- Would a new developer understand where to find this?\n\n## Output\n\nAfter each pass, either:\n\n- Apply the improvement directly (for clear wins)\n- Note the observation with a recommendation (for trade-off decisions)\n\n## Anti-Patterns\n\n- ❌ Rewriting working code for style preference\n- ❌ Adding abstractions \"just in case\"\n- ❌ Changing code outside the scope of your changes\n- ❌ \"This could be a microservice\" — no it couldn't\n" },
|
package/src/ui/app.tsx
CHANGED
|
@@ -90,25 +90,14 @@ interface AgentProgress {
|
|
|
90
90
|
// Version is read fresh from package.json at startup via runApp prop
|
|
91
91
|
// (bypasses Bun module caching after npm update)
|
|
92
92
|
|
|
93
|
-
// Cycle order: Claude Code modes
|
|
94
|
-
|
|
95
|
-
const PERMISSION_MODES: PermissionMode[] = [
|
|
96
|
-
'default',
|
|
97
|
-
'acceptEdits',
|
|
98
|
-
'bypassPermissions',
|
|
99
|
-
'plan',
|
|
100
|
-
'auto',
|
|
101
|
-
'dontAsk',
|
|
102
|
-
]
|
|
93
|
+
// Cycle order: Claude Code modes (manual → accept edits → plan → bypass).
|
|
94
|
+
const PERMISSION_MODES: PermissionMode[] = ['default', 'acceptEdits', 'plan', 'bypassPermissions']
|
|
103
95
|
// Labels aligned with Claude Code terminology: describe behavior, not capability.
|
|
104
|
-
// Claude Code modes: manual mode → accept edits on → bypass
|
|
105
|
-
// Mipham extends with 3 extra modes (plan, auto, dontAsk) for finer control.
|
|
96
|
+
// Claude Code modes: manual mode → accept edits on → plan → bypass.
|
|
106
97
|
const PERMISSION_COLORS: Record<PermissionMode, string> = {
|
|
107
98
|
default: 'white',
|
|
108
99
|
acceptEdits: 'blue',
|
|
109
100
|
plan: 'yellow',
|
|
110
|
-
auto: 'green',
|
|
111
|
-
dontAsk: 'cyan',
|
|
112
101
|
bypassPermissions: 'red',
|
|
113
102
|
}
|
|
114
103
|
|
|
@@ -165,8 +154,6 @@ export function App({
|
|
|
165
154
|
default: t('ui.permission.manual'),
|
|
166
155
|
acceptEdits: t('ui.permission.accept_edits'),
|
|
167
156
|
plan: t('ui.permission.plan_mode'),
|
|
168
|
-
auto: t('ui.permission.auto'),
|
|
169
|
-
dontAsk: t('ui.permission.dont_ask'),
|
|
170
157
|
bypassPermissions: t('ui.permission.bypass'),
|
|
171
158
|
}),
|
|
172
159
|
[t],
|
|
@@ -191,6 +178,9 @@ export function App({
|
|
|
191
178
|
const [goalText, setGoalText] = useState('')
|
|
192
179
|
const [permissionMode, setPermissionMode] = useState<PermissionMode>('default')
|
|
193
180
|
const abortRef = useRef<AbortController | null>(null)
|
|
181
|
+
// Monotonic turn id — lets a stale turn's finally() skip resetting shared UI
|
|
182
|
+
// state (isLoading/abortRef/progress) after a newer turn has already started.
|
|
183
|
+
const turnIdRef = useRef(0)
|
|
194
184
|
// Stream buffer: accumulate text chunks and throttle state updates to ~16fps.
|
|
195
185
|
// Without this, every SSE chunk triggers setMessages → copies full array →
|
|
196
186
|
// re-renders ChatPanel → re-runs compactToolGroups O(n). At 20-50 chunks/sec
|
|
@@ -200,6 +190,11 @@ export function App({
|
|
|
200
190
|
isFirst: boolean
|
|
201
191
|
timer: ReturnType<typeof setTimeout> | null
|
|
202
192
|
}>({ turnContent: '', isFirst: true, timer: null })
|
|
193
|
+
// Reasoning/thinking transparency: accumulate reasoning tokens and surface them
|
|
194
|
+
// as a live "thinking" indicator instead of silently dropping them.
|
|
195
|
+
const [thinkingText, setThinkingText] = useState('')
|
|
196
|
+
const thinkingRef = useRef('')
|
|
197
|
+
const thinkingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
203
198
|
const [agentProgress, setAgentProgress] = useState<AgentProgress | null>(null)
|
|
204
199
|
// Multi-agent tracking: keyed by agent/task ID, shows all running + recently completed agents
|
|
205
200
|
const [runningAgents, setRunningAgents] = useState<Record<string, AgentEntry>>({})
|
|
@@ -345,6 +340,7 @@ export function App({
|
|
|
345
340
|
const handleSubmit = useCallback(
|
|
346
341
|
async (input: string) => {
|
|
347
342
|
if (!input.trim()) return
|
|
343
|
+
const turnId = ++turnIdRef.current
|
|
348
344
|
|
|
349
345
|
// ── @mention: direct cross-session message — only when the name resolves
|
|
350
346
|
// to a live session; otherwise fall through to normal AI processing so a
|
|
@@ -585,15 +581,36 @@ export function App({
|
|
|
585
581
|
emotionPrefix ? emotionPrefix + input : input,
|
|
586
582
|
controller.signal,
|
|
587
583
|
)) {
|
|
588
|
-
// Reasoning content (DeepSeek V4 thinking mode) —
|
|
589
|
-
//
|
|
584
|
+
// Reasoning content (DeepSeek V4 thinking mode) — surface as a live
|
|
585
|
+
// "thinking" indicator so long reasoning passes don't look like a stall.
|
|
590
586
|
if (chunk.reasoning_content) {
|
|
587
|
+
thinkingRef.current += chunk.reasoning_content
|
|
588
|
+
if (!thinkingTimerRef.current) {
|
|
589
|
+
thinkingTimerRef.current = setTimeout(() => {
|
|
590
|
+
thinkingTimerRef.current = null
|
|
591
|
+
setThinkingText(thinkingRef.current)
|
|
592
|
+
}, 60)
|
|
593
|
+
}
|
|
591
594
|
continue
|
|
592
595
|
}
|
|
593
596
|
|
|
594
597
|
if (chunk.type === 'text' && chunk.content) {
|
|
595
598
|
// New turn: push fresh assistant message, reset stream buffer
|
|
596
599
|
if (isNewTurn) {
|
|
600
|
+
// Flush any accumulated reasoning as a collapsed history line
|
|
601
|
+
if (thinkingRef.current) {
|
|
602
|
+
const thought = thinkingRef.current
|
|
603
|
+
thinkingRef.current = ''
|
|
604
|
+
setThinkingText('')
|
|
605
|
+
if (thinkingTimerRef.current) {
|
|
606
|
+
clearTimeout(thinkingTimerRef.current)
|
|
607
|
+
thinkingTimerRef.current = null
|
|
608
|
+
}
|
|
609
|
+
setMessages((prev) => [
|
|
610
|
+
...prev,
|
|
611
|
+
{ role: 'system' as const, content: `💭 ${thought}` },
|
|
612
|
+
])
|
|
613
|
+
}
|
|
597
614
|
turnContent = chunk.content
|
|
598
615
|
isNewTurn = false
|
|
599
616
|
streamBufferRef.current = { turnContent: chunk.content, isFirst: false, timer: null }
|
|
@@ -768,16 +785,20 @@ export function App({
|
|
|
768
785
|
} catch (err) {
|
|
769
786
|
setMessages((prev) => [...prev, { role: 'system', content: `Error: ${String(err)}` }])
|
|
770
787
|
} finally {
|
|
771
|
-
//
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
788
|
+
// Only the latest turn resets shared UI state — a stale turn's finally
|
|
789
|
+
// must not clobber a newer turn's isLoading/abortRef/progress.
|
|
790
|
+
if (turnIdRef.current === turnId) {
|
|
791
|
+
// Flush any remaining stream buffer before finishing
|
|
792
|
+
flushStreamBuffer()
|
|
793
|
+
setIsLoading(false)
|
|
794
|
+
abortRef.current = null
|
|
795
|
+
// Clear all progress/tool indicators
|
|
796
|
+
agentProgressRef.current = null
|
|
797
|
+
setAgentProgress(null)
|
|
798
|
+
activeToolRef.current = null
|
|
799
|
+
setActiveTool(null)
|
|
800
|
+
setAgentTick((t) => t + 1)
|
|
801
|
+
}
|
|
781
802
|
// Auto-save checkpoint after each AI response
|
|
782
803
|
if (assistantContent) {
|
|
783
804
|
engine.getContext().saveCheckpoint('post-turn')
|
|
@@ -881,6 +902,7 @@ export function App({
|
|
|
881
902
|
<>
|
|
882
903
|
{/* Chat panel */}
|
|
883
904
|
<ChatPanel messages={messages} focusMode={focusMode} />
|
|
905
|
+
{thinkingText ? <Text dimColor>💭 {thinkingText.slice(-200)}</Text> : null}
|
|
884
906
|
|
|
885
907
|
{/* Input with separator lines */}
|
|
886
908
|
{pickerOpen ? (
|
|
@@ -987,9 +1009,8 @@ export function App({
|
|
|
987
1009
|
<Text dimColor>
|
|
988
1010
|
{' '}
|
|
989
1011
|
({t('ui.status.shift_tab_cycle')}: {PERMISSION_LABELS.default} ·{' '}
|
|
990
|
-
{PERMISSION_LABELS.acceptEdits} · {PERMISSION_LABELS.
|
|
991
|
-
{PERMISSION_LABELS.
|
|
992
|
-
{' · '}
|
|
1012
|
+
{PERMISSION_LABELS.acceptEdits} · {PERMISSION_LABELS.plan} ·{' '}
|
|
1013
|
+
{PERMISSION_LABELS.bypassPermissions}){' · '}
|
|
993
1014
|
{t('ui.status.esc_to_interrupt')}
|
|
994
1015
|
{' · '}
|
|
995
1016
|
{t('ui.status.left_for_agents')}
|
package/src/ui/input.tsx
CHANGED
|
@@ -67,6 +67,14 @@ function pick<T>(arr: T[]): T {
|
|
|
67
67
|
return arr[Math.floor(Math.random() * arr.length)]!
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* 判断一次输入是否为「批量」(长度跳变 >1:粘贴 / IME 替换)。
|
|
72
|
+
* 批量输入需节流防渲染风暴;普通单字符输入应立即显示,无节流延迟。
|
|
73
|
+
*/
|
|
74
|
+
export function isBulkInput(prev: string, next: string): boolean {
|
|
75
|
+
return Math.abs(next.length - prev.length) > 1
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
export function InputBar({
|
|
71
79
|
onSubmit,
|
|
72
80
|
isLoading,
|
|
@@ -266,9 +274,15 @@ export function InputBar({
|
|
|
266
274
|
clearTimeout(onChangeTimerRef.current)
|
|
267
275
|
onChangeTimerRef.current = null
|
|
268
276
|
}
|
|
269
|
-
// Use latest value from ref
|
|
270
|
-
|
|
271
|
-
|
|
277
|
+
// Use the latest value from the ref — state lags behind during throttle, and
|
|
278
|
+
// the onSubmit `val` is the stale controlled prop in that window.
|
|
279
|
+
const finalValue = valueRef.current || val
|
|
280
|
+
if (!finalValue.trim()) return
|
|
281
|
+
// Submitting while a response streams interrupts it (Claude Code parity)
|
|
282
|
+
// instead of silently dropping the input.
|
|
283
|
+
if (isLoading) {
|
|
284
|
+
onCancel?.()
|
|
285
|
+
}
|
|
272
286
|
// Save to message history for arrow-key navigation
|
|
273
287
|
setSubmittedHistory((prev) => [...prev, finalValue])
|
|
274
288
|
historyIndexRef.current = -1
|
|
@@ -317,11 +331,18 @@ export function InputBar({
|
|
|
317
331
|
// Normalize newlines → spaces. ink-text-input is single-line; multi-line
|
|
318
332
|
// paste would trap arrow-key navigation on the first line.
|
|
319
333
|
const normalized = val.replace(/\n/g, ' ')
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
// cycle that starves the event loop and freezes the UI.
|
|
334
|
+
// 批量输入(paste/IME 替换)节流防渲染风暴;普通单字符输入立即显示,
|
|
335
|
+
// 避免 33ms trailing 的「慢半拍」尾巴。
|
|
336
|
+
const bulk = isBulkInput(valueRef.current, normalized)
|
|
324
337
|
valueRef.current = normalized
|
|
338
|
+
if (!bulk) {
|
|
339
|
+
if (onChangeTimerRef.current) {
|
|
340
|
+
clearTimeout(onChangeTimerRef.current)
|
|
341
|
+
onChangeTimerRef.current = null
|
|
342
|
+
}
|
|
343
|
+
setValue(normalized)
|
|
344
|
+
return
|
|
345
|
+
}
|
|
325
346
|
if (onChangeTimerRef.current) return // timer pending, latest value in ref
|
|
326
347
|
setValue(normalized)
|
|
327
348
|
onChangeTimerRef.current = setTimeout(() => {
|