@miphamai/cli 0.38.0 → 0.39.1

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.
Files changed (62) hide show
  1. package/bin/mipham.ts +25 -0
  2. package/package.json +1 -1
  3. package/src/agent/sub-agent.ts +4 -3
  4. package/src/config/defaults.ts +19 -1
  5. package/src/config/keys-manager.ts +11 -1
  6. package/src/config/loader.ts +20 -10
  7. package/src/core/context.ts +86 -56
  8. package/src/core/credential-masker/output-scrub.ts +5 -0
  9. package/src/core/crsi-sandbox.ts +19 -7
  10. package/src/core/engine.ts +50 -33
  11. package/src/core/instructions.ts +4 -42
  12. package/src/core/permission.ts +7 -1
  13. package/src/core/red-team.ts +4 -4
  14. package/src/core/self-critique.ts +3 -1
  15. package/src/core/session-log.ts +225 -0
  16. package/src/core/session-store.ts +119 -34
  17. package/src/daemon/auth.ts +9 -6
  18. package/src/daemon/cors.ts +24 -16
  19. package/src/daemon/rate-limiter.ts +4 -0
  20. package/src/daemon/server.ts +24 -3
  21. package/src/index.tsx +54 -28
  22. package/src/mcp/http-transport.ts +2 -0
  23. package/src/mcp/oauth.ts +1 -1
  24. package/src/providers/llm-replay.ts +36 -0
  25. package/src/providers/llm.ts +16 -0
  26. package/src/providers/registry.ts +2 -1
  27. package/src/security/gate.ts +10 -0
  28. package/src/security/url.ts +37 -14
  29. package/src/shared/constants.ts +40 -54
  30. package/src/shared/mipham-models.json +50 -0
  31. package/src/shared/types.ts +53 -49
  32. package/src/skills/fork-executor.ts +3 -1
  33. package/src/skills/loader.ts +2 -1
  34. package/src/skills/seam.ts +18 -0
  35. package/src/tools/agent/agent.ts +1 -0
  36. package/src/tools/agent/skill.ts +1 -0
  37. package/src/tools/exec/bash.ts +140 -128
  38. package/src/tools/exec/git.ts +17 -0
  39. package/src/tools/file/read.ts +73 -66
  40. package/src/tools/file/write.ts +1 -1
  41. package/src/tools/index.ts +54 -132
  42. package/src/tools/network/web-fetch.ts +41 -26
  43. package/src/tools/seam.ts +25 -0
  44. package/src/tools/validation.ts +91 -0
  45. package/src/ui/commands.ts +17 -5
  46. package/src/ui/input.tsx +8 -1
  47. package/src/vajra/compose/assemble.ts +19 -0
  48. package/src/vajra/compose/bundle.ts +39 -0
  49. package/src/vajra/compose/dump.ts +5 -0
  50. package/src/vajra/compose/index.ts +4 -0
  51. package/src/vajra/compose/mount.ts +30 -0
  52. package/src/vajra/context.ts +183 -0
  53. package/src/vajra/events.ts +13 -0
  54. package/src/vajra/index.ts +4 -0
  55. package/src/vajra/leaf/plan-runner.ts +94 -0
  56. package/src/vajra/service.ts +15 -0
  57. package/src/workflow/primitives/agent.ts +3 -1
  58. package/src/workflow/runtime.ts +23 -15
  59. package/src/workflow/sandbox.ts +51 -9
  60. package/src/core/compaction-progress.ts +0 -205
  61. package/src/core/context-compact.ts +0 -124
  62. package/src/core/context-drain.ts +0 -113
@@ -1,124 +0,0 @@
1
- import type { ContextManager, Summarizer } from './context'
2
- import { snipMessages } from './context-snip'
3
- import { CompactionProgressTracker } from './compaction-progress'
4
-
5
- /**
6
- * Layer 3: Reactive Compact — API-based summarization.
7
- *
8
- * When the context exceeds the compaction threshold, uses an LLM summarizer
9
- * to condense the conversation history, keeping recent messages intact.
10
- *
11
- * After compaction, the context contains:
12
- * 1. A summary message of the truncated history
13
- * 2. The most recent N messages (kept intact)
14
- * 3. The system prompt (unchanged)
15
- */
16
- /**
17
- * Adaptive keep-recent count: scales with context window size.
18
- * 128K → 20, 200K → 20, 500K → 40, 1M → 80
19
- */
20
- function getKeepRecent(contextWindow: number): number {
21
- return Math.max(20, Math.floor(contextWindow / 12500))
22
- }
23
-
24
- export interface CompactResult {
25
- /** Messages before compaction */
26
- beforeCount: number
27
- /** Messages after compaction */
28
- afterCount: number
29
- /** Whether compaction was actually performed */
30
- compacted: boolean
31
- /** Progress summary for display */
32
- summary: string
33
- }
34
-
35
- export async function reactiveCompact(
36
- context: ContextManager,
37
- summarizer: Summarizer,
38
- heading: string,
39
- keepRecent?: number,
40
- ): Promise<CompactResult> {
41
- // Use explicit override, or adaptive default based on context window
42
- const effectiveKeepRecent = keepRecent ?? getKeepRecent(context.getMaxTokens())
43
- const messages = context.getMessages()
44
- const tokensBefore = context.getEstimatedTokens()
45
-
46
- if (messages.length <= effectiveKeepRecent + 4) {
47
- return {
48
- beforeCount: messages.length,
49
- afterCount: messages.length,
50
- compacted: false,
51
- summary: `Context has ${messages.length} messages — no compaction needed (threshold: ${effectiveKeepRecent + 4}).`,
52
- }
53
- }
54
-
55
- // ── Progress tracker ──
56
- const tracker = new CompactionProgressTracker(messages.length, tokensBefore)
57
- tracker.update({ phase: 'snip', message: 'Snipping empty pairs...', percent: 5 })
58
-
59
- // First, run snip to remove empty pairs
60
- const { messages: snipped } = snipMessages(messages)
61
- tracker.update({
62
- phase: 'snip',
63
- message: `Snipped ${messages.length - snipped.length} empty pairs`,
64
- percent: 15,
65
- messagesAfter: snipped.length,
66
- })
67
-
68
- if (snipped.length <= effectiveKeepRecent + 4) {
69
- const afterCount = snipped.length
70
- tracker.complete(afterCount, tokensBefore)
71
- return {
72
- beforeCount: messages.length,
73
- afterCount,
74
- compacted: true,
75
- summary: `Snip-only: ${messages.length} → ${afterCount} messages (removed ${messages.length - afterCount} empty pairs).`,
76
- }
77
- }
78
-
79
- // Split: old messages to summarize, recent messages to keep
80
- const toSummarize = snipped.slice(0, -effectiveKeepRecent)
81
- const toKeep = snipped.slice(-effectiveKeepRecent)
82
-
83
- tracker.update({
84
- phase: 'reactive-compact',
85
- message: `Summarizing ${toSummarize.length} messages...`,
86
- percent: 20,
87
- })
88
-
89
- // Generate summary with retry logic
90
- let summary: string
91
- try {
92
- summary = await CompactionProgressTracker.retrySummarizer(
93
- () => summarizer(toSummarize, heading),
94
- tracker,
95
- toSummarize.length,
96
- )
97
- } catch {
98
- // On summarizer failure, do a simple truncation
99
- tracker.update({
100
- message: `Summarizer unavailable — truncating to last ${effectiveKeepRecent} messages.`,
101
- percent: 80,
102
- })
103
- summary = `Earlier conversation (${toSummarize.length} messages) omitted due to context limits.`
104
- }
105
-
106
- // Rebuild messages: summary + recent
107
- const summaryMsg = {
108
- role: 'user' as const,
109
- content: `[Earlier conversation summary — ${heading}]: ${summary.slice(0, 8000)}`,
110
- }
111
-
112
- const newMessages = [summaryMsg, ...toKeep]
113
- context.replaceMessages(newMessages)
114
-
115
- const tokensAfter = context.getEstimatedTokens()
116
- tracker.complete(newMessages.length, tokensAfter)
117
-
118
- return {
119
- beforeCount: messages.length,
120
- afterCount: newMessages.length,
121
- compacted: true,
122
- summary: tracker.getSummary(),
123
- }
124
- }
@@ -1,113 +0,0 @@
1
- import type { ContextManager } from './context'
2
- import type { CompactionProgressTracker } from './compaction-progress'
3
-
4
- const MINIMAL_KEEP = 5
5
- let drainLevel = 0
6
-
7
- /**
8
- * Layer 4: Emergency Drain — 413 error recovery.
9
- *
10
- * Called when a 413 (context too large) error is received.
11
- * Progressively strips messages until the context fits:
12
- *
13
- * Level 1: Drop earliest 50% of messages
14
- * Level 2+: Keep only system prompt + last 5 messages
15
- *
16
- * Returns drain result with progress summary.
17
- */
18
- export interface DrainResult {
19
- /** Whether recovery was possible */
20
- recovered: boolean
21
- /** Messages before drain */
22
- beforeCount: number
23
- /** Messages after drain */
24
- afterCount: number
25
- /** Current drain level */
26
- level: number
27
- /** Human-readable summary */
28
- summary: string
29
- }
30
-
31
- export async function emergencyDrain(
32
- context: ContextManager,
33
- progress?: CompactionProgressTracker,
34
- ): Promise<DrainResult> {
35
- const messages = context.getMessages()
36
-
37
- if (messages.length <= MINIMAL_KEEP) {
38
- return {
39
- recovered: false,
40
- beforeCount: messages.length,
41
- afterCount: messages.length,
42
- level: drainLevel,
43
- summary: `Cannot drain further: already at minimal ${messages.length} messages.`,
44
- }
45
- }
46
-
47
- progress?.update({
48
- phase: 'emergency-drain',
49
- message: `Emergency drain level ${drainLevel + 1}: recovering from 413 error...`,
50
- percent: 50,
51
- })
52
-
53
- if (drainLevel === 0) {
54
- // First attempt: drop earliest 50%
55
- const keepCount = Math.max(MINIMAL_KEEP, Math.floor(messages.length / 2))
56
- const kept = messages.slice(-keepCount)
57
- context.replaceMessages(kept)
58
- drainLevel++
59
- progress?.update({
60
- phase: 'emergency-drain',
61
- message: `Drain level 1: dropped ${messages.length - keepCount} messages (${messages.length} → ${keepCount})`,
62
- percent: 80,
63
- messagesAfter: keepCount,
64
- })
65
- return {
66
- recovered: true,
67
- beforeCount: messages.length,
68
- afterCount: keepCount,
69
- level: drainLevel,
70
- summary: `Emergency drain level 1: ${messages.length} → ${keepCount} messages (dropped earliest 50%).`,
71
- }
72
- }
73
-
74
- // Subsequent attempts: keep only system + last MINIMAL_KEEP messages
75
- const kept = messages.slice(-MINIMAL_KEEP)
76
-
77
- // Add a summary placeholder if we're dropping a lot
78
- if (messages.length > MINIMAL_KEEP * 2) {
79
- const summaryMsg = {
80
- role: 'user' as const,
81
- content: `[Emergency context drain level ${drainLevel + 1}: ${messages.length - MINIMAL_KEEP} earlier messages discarded due to token limit.]`,
82
- }
83
- context.replaceMessages([summaryMsg, ...kept])
84
- } else {
85
- context.replaceMessages(kept)
86
- }
87
-
88
- drainLevel++
89
- progress?.update({
90
- phase: 'emergency-drain',
91
- message: `Drain level ${drainLevel}: ${messages.length} → ${kept.length} messages`,
92
- percent: 90,
93
- messagesAfter: kept.length,
94
- })
95
-
96
- return {
97
- recovered: true,
98
- beforeCount: messages.length,
99
- afterCount: kept.length,
100
- level: drainLevel,
101
- summary: `Emergency drain level ${drainLevel}: ${messages.length} → ${kept.length} messages.`,
102
- }
103
- }
104
-
105
- /** Reset drain level (call at session start). */
106
- export function resetDrainLevel(): void {
107
- drainLevel = 0
108
- }
109
-
110
- /** Get current drain level for display. */
111
- export function getDrainLevel(): number {
112
- return drainLevel
113
- }