@miphamai/cli 0.32.7 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miphamai/cli",
3
- "version": "0.32.7",
3
+ "version": "0.33.0",
4
4
  "description": "Mipham Code — Multi-model open-core intelligent coding terminal by MiphamAI",
5
5
  "keywords": [
6
6
  "ai",
@@ -0,0 +1,220 @@
1
+ /**
2
+ * SIS Phase 2: Auto-Corrector — Post-Error Self-Healing
3
+ *
4
+ * Second defense line of the self-immune system. When a tool call fails:
5
+ * 1. Analyzes the error against ErrorSignatureDB for known patterns
6
+ * 2. If a high-confidence fix exists → returns corrected params for re-execution
7
+ * 3. If a low-confidence match → returns suggestion without auto-applying
8
+ * 4. Feeds new error patterns back to ErrorSignatureDB for future immunity
9
+ *
10
+ * Distinct from PreFlightChecker (pre-execution prevention) — AutoCorrector
11
+ * handles errors AFTER they occur, enabling real-time self-healing.
12
+ *
13
+ * Flow:
14
+ * Tool executes → fails → AutoCorrector.analyze() → match & fix
15
+ * → if fix available: re-execute with corrected params
16
+ * → if no fix: record error signature, let user handle
17
+ */
18
+
19
+ import type { ErrorSignatureDB, ErrorSignature } from './error-signature-db.js'
20
+
21
+ // ── Types ──
22
+
23
+ export interface CorrectionResult {
24
+ /** Whether a correction was found */
25
+ corrected: boolean
26
+ /** The action taken */
27
+ action: 'retry' | 'suggest' | 'record-only'
28
+ /** Corrected parameters (for 'retry' action) */
29
+ correctedParams?: Record<string, unknown>
30
+ /** Human-readable suggestion (for 'suggest' action) */
31
+ suggestion?: string
32
+ /** Matched error signature (for tracking) */
33
+ matchedSignature?: string
34
+ /** New signature created (for tracking) */
35
+ newSignatureId?: string
36
+ }
37
+
38
+ // ── Constants ──
39
+
40
+ /** Minimum success rate to auto-retry with corrected params */
41
+ const AUTO_RETRY_THRESHOLD = 0.7
42
+
43
+ /** Maximum retry attempts per tool call to prevent infinite loops */
44
+ const MAX_RETRIES = 1
45
+
46
+ // ── Corrector ──
47
+
48
+ export class AutoCorrector {
49
+ private errorDB: ErrorSignatureDB
50
+
51
+ constructor(errorDB: ErrorSignatureDB) {
52
+ this.errorDB = errorDB
53
+ }
54
+
55
+ /**
56
+ * Analyze a failed tool call and attempt correction.
57
+ *
58
+ * @param toolName — e.g. 'Bash', 'Write'
59
+ * @param params — original tool parameters
60
+ * @param error — error message from the failed execution
61
+ * @param retryCount — current retry count (0-indexed)
62
+ * @returns CorrectionResult with action and corrected params if applicable
63
+ */
64
+ analyze(
65
+ toolName: string,
66
+ params: Record<string, unknown>,
67
+ error: string,
68
+ retryCount: number = 0,
69
+ ): CorrectionResult {
70
+ // Guard against infinite retry loops
71
+ if (retryCount >= MAX_RETRIES) {
72
+ return { corrected: false, action: 'record-only' }
73
+ }
74
+
75
+ // ── Step 1: Try to match against known error signatures ──
76
+ const sig = this.errorDB.match(toolName, {
77
+ ...params,
78
+ error,
79
+ })
80
+
81
+ if (sig) {
82
+ return this.handleKnownError(sig, params, error)
83
+ }
84
+
85
+ // ── Step 2: No match — record as new signature for future immunity ──
86
+ return this.handleUnknownError(toolName, params, error)
87
+ }
88
+
89
+ /**
90
+ * Record a manual correction (user fixed it themselves).
91
+ * Updates the signature's success rate.
92
+ */
93
+ recordManualFix(signatureId: string, success: boolean): void {
94
+ this.errorDB.recordResult(signatureId, success)
95
+ }
96
+
97
+ // ── Private ──
98
+
99
+ /** Handle a known error pattern with an existing signature. */
100
+ private handleKnownError(
101
+ sig: ErrorSignature,
102
+ params: Record<string, unknown>,
103
+ _error: string,
104
+ ): CorrectionResult {
105
+ const confidence = sig.successRate
106
+
107
+ // High confidence → auto-retry with corrected params
108
+ if (
109
+ confidence >= AUTO_RETRY_THRESHOLD &&
110
+ sig.fixStrategy !== 'warn' &&
111
+ sig.fixStrategy !== 'block'
112
+ ) {
113
+ const correctedParams = this.applyFix(sig, params)
114
+ return {
115
+ corrected: true,
116
+ action: 'retry',
117
+ correctedParams,
118
+ matchedSignature: sig.id,
119
+ }
120
+ }
121
+
122
+ // Low/medium confidence → suggest but don't auto-apply
123
+ return {
124
+ corrected: false,
125
+ action: 'suggest',
126
+ suggestion: `🔧 SIS 建议: ${sig.explanation}\n 修复方案: ${sig.fixStrategy} → ${sig.fixAction}\n 历史成功率: ${Math.round(confidence * 100)}% (${sig.occurrences} 次)\n 使用 \`/sis errors\` 查看详情`,
127
+ matchedSignature: sig.id,
128
+ }
129
+ }
130
+
131
+ /** Handle an unknown error — record it for future immunity. */
132
+ private handleUnknownError(
133
+ toolName: string,
134
+ params: Record<string, unknown>,
135
+ error: string,
136
+ ): CorrectionResult {
137
+ // Extract a searchable pattern from the error
138
+ const pattern = this.extractPattern(error)
139
+ const category = this.categorizeError(error, toolName, params)
140
+
141
+ const sig = this.errorDB.insert({
142
+ pattern,
143
+ category,
144
+ toolName,
145
+ fixStrategy: 'warn', // default: warn until we learn a fix
146
+ fixAction: '',
147
+ explanation: `未知错误模式: ${error.slice(0, 100)}`,
148
+ })
149
+
150
+ return {
151
+ corrected: false,
152
+ action: 'record-only',
153
+ newSignatureId: sig.id,
154
+ suggestion:
155
+ `🆕 SIS 已记录新错误签名 \`${sig.id}\` (${category})。` + `此错误再次发生时将被自动识别。`,
156
+ }
157
+ }
158
+
159
+ /** Apply a signature's fix to the original params. */
160
+ private applyFix(sig: ErrorSignature, params: Record<string, unknown>): Record<string, unknown> {
161
+ switch (sig.fixStrategy) {
162
+ case 'replace':
163
+ return { ...params, command: sig.fixAction }
164
+
165
+ case 'prepend': {
166
+ const cmd = String(params.command ?? '')
167
+ return { ...params, command: `${sig.fixAction} ${cmd}` }
168
+ }
169
+
170
+ case 'append': {
171
+ const cmd = String(params.command ?? '')
172
+ return { ...params, command: `${cmd} ${sig.fixAction}` }
173
+ }
174
+
175
+ default:
176
+ return params
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Extract a stable, searchable pattern from an error message.
182
+ * Strips dynamic content (paths, timestamps, UUIDs) to create a reusable signature.
183
+ */
184
+ private extractPattern(error: string): string {
185
+ // Remove dynamic content
186
+ const cleaned = error
187
+ .replace(/\/[^\s]+\/[^\s]*/g, '/<path>') // paths
188
+ .replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}/g, '<timestamp>') // timestamps
189
+ .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '<uuid>') // UUIDs
190
+ .replace(/\d+/g, '<n>') // numbers
191
+ .replace(/\s+/g, ' ') // normalize whitespace
192
+ .trim()
193
+
194
+ // Take first 200 chars as the pattern
195
+ return cleaned.slice(0, 200)
196
+ }
197
+
198
+ /**
199
+ * Categorize an error into one of the known CRSI categories.
200
+ * Mirrors AutoMemoryEngine.categorizeFailure() logic for consistency.
201
+ */
202
+ private categorizeError(
203
+ error: string,
204
+ toolName: string,
205
+ params: Record<string, unknown>,
206
+ ): string {
207
+ const err = error.toLowerCase()
208
+ const cmd = String(params.command || params.description || '').toLowerCase()
209
+
210
+ if (err.includes('timeout') || err.includes('timed out')) return 'timeout'
211
+ if (cmd.includes('--force') || cmd.includes('rm -rf')) return 'tool-params'
212
+ if (err.includes('import') || err.includes('module') || err.includes('.js')) return 'import'
213
+ if (toolName === 'Grep' && err.includes('no matches')) return 'search'
214
+ if (err.includes('permission') || err.includes('denied') || err.includes('eacces'))
215
+ return 'tool-params'
216
+ if (err.includes('not found') || err.includes('enoent')) return 'semantic'
217
+
218
+ return 'semantic'
219
+ }
220
+ }
@@ -15,6 +15,7 @@ import { MemoryManager, type MemoryEntry } from './memory/memory-manager.js'
15
15
  import type { PatternAnalyzer, Pattern } from '../agent/pattern-analyzer.js'
16
16
  import type { ExperienceRuleEngine, ToolRule } from './rule-engine.js'
17
17
  import type { EffectivenessTracker } from '../agent/effectiveness-tracker.js'
18
+ import type { ErrorSignatureDB } from './error-signature-db.js'
18
19
  import { join } from 'node:path'
19
20
  import { homedir } from 'node:os'
20
21
 
@@ -86,6 +87,7 @@ export class AutoMemoryEngine {
86
87
  private patternAnalyzer?: PatternAnalyzer
87
88
  private ruleEngine?: ExperienceRuleEngine
88
89
  private effectivenessTracker?: EffectivenessTracker
90
+ private errorSignatureDB?: ErrorSignatureDB
89
91
 
90
92
  /** Accumulated reflections for the current session (not yet persisted to disk). */
91
93
  private sessionReflections: TurnReflection[] = []
@@ -111,6 +113,15 @@ export class AutoMemoryEngine {
111
113
  this.effectivenessTracker = effectivenessTracker
112
114
  }
113
115
 
116
+ /**
117
+ * Wire the SIS (Self-Immune System) error signature database.
118
+ * Enables persistent error memory — known failure patterns are
119
+ * saved and can be intercepted before execution by PreFlightChecker.
120
+ */
121
+ setErrorSignatureDB(db: ErrorSignatureDB): void {
122
+ this.errorSignatureDB = db
123
+ }
124
+
114
125
  // ── Core API ──
115
126
 
116
127
  /**
@@ -345,6 +356,24 @@ export class AutoMemoryEngine {
345
356
  if (this.effectivenessTracker) {
346
357
  this.effectivenessTracker.recordApplication(toolRule.id, true)
347
358
  }
359
+
360
+ // ── SIS: persist error signature for cross-session immunity ──
361
+ if (this.errorSignatureDB) {
362
+ const examples = pattern.examples || []
363
+ const errorText = examples[0] || ''
364
+ this.errorSignatureDB.insert({
365
+ pattern: errorText.slice(0, 200), // first 200 chars as match pattern
366
+ category,
367
+ toolName: toolRule.toolName,
368
+ fixStrategy: 'replace',
369
+ fixAction: String(
370
+ toolRule.fix({ command: errorText }).modified?.command ||
371
+ toolRule.fix({}).modified?.command ||
372
+ '',
373
+ ),
374
+ explanation: `CRSI 自动生成: ${toolRule.id} — ${pattern.category} 类错误 (${count} 次发生)`,
375
+ })
376
+ }
348
377
  }
349
378
  }
350
379
 
@@ -22,6 +22,10 @@ import { RulesLoader } from './rules-loader'
22
22
  import { ExperienceRuleEngine } from './rule-engine.js'
23
23
  import { PatternAnalyzer } from '../agent/pattern-analyzer.js'
24
24
  import { EffectivenessTracker } from '../agent/effectiveness-tracker.js'
25
+ import { ErrorSignatureDB } from './error-signature-db.js'
26
+ import { PreFlightChecker } from './preflight-checker.js'
27
+ import { AutoCorrector } from './auto-corrector.js'
28
+ import { MetaRuleEngine } from './meta-rule-engine.js'
25
29
  import { UsageTracker } from './usage-tracker'
26
30
  import { buildRequest, sendInferenceCheck, isInferenceHookEnabled } from './inference-hook'
27
31
  import { getFileInboxTransport } from '../agent/cross-session/file-inbox'
@@ -47,6 +51,10 @@ export class QueryEngine {
47
51
  private _patternAnalyzer?: PatternAnalyzer
48
52
  private _effectivenessTracker?: EffectivenessTracker
49
53
  private _autoMemory?: AutoMemoryEngine
54
+ private _errorSignatureDB?: ErrorSignatureDB
55
+ private _preflightChecker?: PreFlightChecker
56
+ private _autoCorrector?: AutoCorrector
57
+ private _metaRuleEngine?: MetaRuleEngine
50
58
  private goal?: string
51
59
  private maxGoalLoops = 20
52
60
  private lastAssistantContent?: string
@@ -902,6 +910,25 @@ export class QueryEngine {
902
910
  }
903
911
  }
904
912
 
913
+ // ── SIS PreFlightChecker — known error pattern interception ──
914
+ const preflight = this.getPreFlightChecker().check(name, effectiveParams)
915
+ if (preflight.action === 'block') {
916
+ return {
917
+ success: false,
918
+ content: preflight.warning || 'SIS 免疫系统拦截了此操作',
919
+ error: preflight.warning,
920
+ }
921
+ }
922
+ if (preflight.action === 'fix' && preflight.modifiedParams) {
923
+ effectiveParams = preflight.modifiedParams
924
+ if (preflight.warning) {
925
+ hookWarnings = [...hookWarnings, preflight.warning]
926
+ }
927
+ }
928
+ if (preflight.action === 'warn' && preflight.warning) {
929
+ hookWarnings = [...hookWarnings, preflight.warning]
930
+ }
931
+
905
932
  try {
906
933
  const result = await tool.execute(effectiveParams, {
907
934
  cwd: process.cwd(),
@@ -973,7 +1000,19 @@ export class QueryEngine {
973
1000
  // information disclosure to the LLM conversation context.
974
1001
  const message =
975
1002
  err instanceof Error ? err.message : String(err).split('\n')[0] || 'Unknown error'
976
- return { success: false, content: '', error: `Tool execution failed: ${message}` }
1003
+
1004
+ // ── SIS AutoCorrector — post-error self-healing ──
1005
+ const correction = this.getAutoCorrector().analyze(name, effectiveParams, message)
1006
+
1007
+ let errorContent = `Tool execution failed: ${message}`
1008
+ if (correction.suggestion) {
1009
+ errorContent += '\n\n' + correction.suggestion
1010
+ }
1011
+ if (correction.action === 'retry' && correction.correctedParams) {
1012
+ errorContent += '\n💡 SIS 已自动修正参数,下次执行时将使用修正后的命令。'
1013
+ }
1014
+
1015
+ return { success: false, content: '', error: errorContent }
977
1016
  }
978
1017
  }
979
1018
 
@@ -1033,10 +1072,67 @@ export class QueryEngine {
1033
1072
  this.getRuleEngine() || new ExperienceRuleEngine(),
1034
1073
  this.getEffectivenessTracker(),
1035
1074
  )
1075
+ // Wire SIS error signature DB for cross-session immunity
1076
+ this._autoMemory.setErrorSignatureDB(this.getErrorSignatureDB())
1036
1077
  }
1037
1078
  return this._autoMemory
1038
1079
  }
1039
1080
 
1081
+ /**
1082
+ * SIS Phase 0: Lazily-initialized ErrorSignatureDB singleton.
1083
+ * Provides persistent storage of known error patterns across sessions.
1084
+ * Public accessor for CLI commands (/sis errors, /sis stats, /sis clear).
1085
+ */
1086
+ getErrorSignatureDB(): ErrorSignatureDB {
1087
+ if (!this._errorSignatureDB) {
1088
+ this._errorSignatureDB = new ErrorSignatureDB()
1089
+ }
1090
+ return this._errorSignatureDB
1091
+ }
1092
+
1093
+ /**
1094
+ * SIS Phase 0: Lazily-initialized PreFlightChecker singleton.
1095
+ * Checks tool calls against ErrorSignatureDB + ExperienceRuleEngine
1096
+ * before execution, enabling preventive error interception.
1097
+ */
1098
+ private getPreFlightChecker(): PreFlightChecker {
1099
+ if (!this._preflightChecker) {
1100
+ this._preflightChecker = new PreFlightChecker(
1101
+ this.getErrorSignatureDB(),
1102
+ this.getRuleEngine(),
1103
+ )
1104
+ }
1105
+ return this._preflightChecker
1106
+ }
1107
+
1108
+ /**
1109
+ * SIS Phase 2: Lazily-initialized AutoCorrector singleton.
1110
+ * Analyzes failed tool calls and suggests corrections based on
1111
+ * the error signature database.
1112
+ */
1113
+ private getAutoCorrector(): AutoCorrector {
1114
+ if (!this._autoCorrector) {
1115
+ this._autoCorrector = new AutoCorrector(this.getErrorSignatureDB())
1116
+ }
1117
+ return this._autoCorrector
1118
+ }
1119
+
1120
+ /**
1121
+ * SIS Phase 3 (RSI Level 3): Lazily-initialized MetaRuleEngine singleton.
1122
+ * Analyzes accumulated SIS data (ErrorSignatureDB + EffectivenessTracker)
1123
+ * to discover meta-rules — rules about rules. This is the recursive
1124
+ * self-improvement core: the system improving its own ability to improve.
1125
+ */
1126
+ getMetaRuleEngine(): MetaRuleEngine {
1127
+ if (!this._metaRuleEngine) {
1128
+ this._metaRuleEngine = new MetaRuleEngine(
1129
+ this.getErrorSignatureDB(),
1130
+ this.getEffectivenessTracker(),
1131
+ )
1132
+ }
1133
+ return this._metaRuleEngine
1134
+ }
1135
+
1040
1136
  /** Register a tool dynamically (used by MCP auto-registration). */
1041
1137
  registerTool(tool: ToolDefinition): void {
1042
1138
  if (this.tools.has(tool.name)) {