@miphamai/cli 0.81.6 → 0.81.8
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/README.md +9 -9
- package/bin/daemon.ts +7 -32
- package/bin/mipham.ts +43 -29
- package/package.json +5 -2
- package/skills/standard/mipham-code-setup.SKILL.md +3 -3
- package/src/agent/sub-agent.ts +12 -1
- package/src/artifacts/manifest.ts +90 -34
- package/src/artifacts/paths.ts +19 -0
- package/src/artifacts/server.ts +48 -8
- package/src/commands/project.ts +92 -12
- package/src/config/keys-manager.ts +10 -11
- package/src/config/loader.ts +82 -1
- package/src/config/preferences.ts +5 -2
- package/src/core/context.ts +10 -2
- package/src/core/cron-poller.ts +30 -6
- package/src/core/engine.ts +19 -4
- package/src/core/metrics.ts +8 -0
- package/src/core/paths.ts +79 -0
- package/src/core/permission-rules.ts +261 -17
- package/src/core/permission.ts +3 -0
- package/src/core/session-log.ts +55 -3
- package/src/core/session-store.ts +11 -1
- package/src/daemon/engine-capabilities.ts +131 -0
- package/src/daemon/index.ts +4 -1
- package/src/daemon/launch.ts +287 -0
- package/src/daemon/remote-engine.ts +2 -0
- package/src/daemon/server.ts +9 -0
- package/src/daemon/session-worker.ts +21 -3
- package/src/i18n-core/locales/en-US.json +6 -7
- package/src/i18n-core/locales/zh-CN.json +6 -7
- package/src/index.tsx +82 -2
- package/src/mcp/client.ts +4 -2
- package/src/plugin/plugin-manager.ts +17 -6
- package/src/providers/anthropic.ts +28 -2
- package/src/providers/openai-compat.ts +14 -1
- package/src/security/path.ts +6 -1
- package/src/shared/atomic-write.ts +28 -5
- package/src/shared/package-info.ts +1 -1
- package/src/shared/types.ts +24 -0
- package/src/skills/bundled-skills.ts +1 -1
- package/src/telemetry/consent.ts +209 -0
- package/src/telemetry/crash.ts +197 -0
- package/src/telemetry/endpoint.ts +82 -0
- package/src/telemetry/index.ts +153 -0
- package/src/telemetry/payload.ts +141 -0
- package/src/telemetry/queue.ts +95 -0
- package/src/telemetry/redact.ts +127 -0
- package/src/telemetry/transport.ts +81 -0
- package/src/tools/agent/workflow.ts +11 -4
- package/src/tools/artifact/artifact.ts +14 -4
- package/src/tools/exec/bash.ts +45 -21
- package/src/tools/exec/enter-worktree.ts +6 -5
- package/src/tools/exec/exit-worktree.ts +10 -5
- package/src/tools/exec/git.ts +25 -10
- package/src/tools/file/grep.ts +37 -13
- package/src/tools/file/read.ts +151 -45
- package/src/tools/scheduling/cron.ts +34 -5
- package/src/tools/system/config.ts +9 -5
- package/src/ui/app.tsx +40 -11
- package/src/ui/commands.ts +186 -45
- package/src/workflow/primitives/agent.ts +4 -2
- package/src/artifacts/versioning.ts +0 -127
- package/src/core/task-runner-tasks.json +0 -14
- package/src/core/task-runner.ts +0 -163
- package/src/skills/mipham/runtime.ts +0 -66
- package/src/skills/standard/runtime.ts +0 -62
package/src/core/task-runner.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
// apps/cli/src/core/task-runner.ts
|
|
2
|
-
// CRSI 端到端任务运行器(C-MVP)——行为效果度量基建。
|
|
3
|
-
import { existsSync, readFileSync, mkdirSync, rmSync } from 'node:fs'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import tasksFile from './task-runner-tasks.json' with { type: 'json' }
|
|
6
|
-
import { QueryEngine } from './engine'
|
|
7
|
-
import { ContextManager } from './context'
|
|
8
|
-
import { PermissionSystem } from './permission'
|
|
9
|
-
import { ProviderRegistry } from '../providers/registry'
|
|
10
|
-
import type { Llm } from '../providers/llm'
|
|
11
|
-
import { createToolRegistry } from '../tools'
|
|
12
|
-
import type { PermissionLevel } from '../shared'
|
|
13
|
-
|
|
14
|
-
export type RunnerGroundTruth = { kind: 'file-contains'; file: string; contains: string[] }
|
|
15
|
-
|
|
16
|
-
export interface RunnerTask {
|
|
17
|
-
id: string
|
|
18
|
-
instruction: string
|
|
19
|
-
groundTruth: RunnerGroundTruth
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function loadRunnerTasks(): RunnerTask[] {
|
|
23
|
-
return tasksFile.tasks as unknown as RunnerTask[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function judgeTask(task: RunnerTask, taskDir: string): { passed: boolean; detail?: string } {
|
|
27
|
-
if (task.groundTruth.kind !== 'file-contains') {
|
|
28
|
-
return { passed: false, detail: `unsupported groundTruth kind: ${task.groundTruth.kind}` }
|
|
29
|
-
}
|
|
30
|
-
const filePath = join(taskDir, task.groundTruth.file)
|
|
31
|
-
if (!existsSync(filePath)) {
|
|
32
|
-
return { passed: false, detail: `file not found: ${task.groundTruth.file}` }
|
|
33
|
-
}
|
|
34
|
-
const content = readFileSync(filePath, 'utf-8')
|
|
35
|
-
for (const needle of task.groundTruth.contains) {
|
|
36
|
-
if (!content.includes(needle)) {
|
|
37
|
-
return { passed: false, detail: `missing substring: ${needle}` }
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return { passed: true }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface TaskRunResult {
|
|
44
|
-
taskId: string
|
|
45
|
-
passed: boolean
|
|
46
|
-
detail?: string
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const TASK_DIR_PLACEHOLDER = '<taskDir>'
|
|
50
|
-
|
|
51
|
-
function buildEngine(llm: Llm, permission: PermissionLevel, systemPrompt?: string): QueryEngine {
|
|
52
|
-
const registry = new ProviderRegistry([], 'test', 'test-model')
|
|
53
|
-
// 注册一个永不 chat 的占位 provider——llm 被 setLlm 覆盖,但 process() 内部
|
|
54
|
-
// 多处调用 registry.getActive().config.id 记录 provider id,必须能取到。
|
|
55
|
-
registry.register('test', {
|
|
56
|
-
config: { id: 'test', name: 'Test', protocol: 'openai-compatible', apiKey: 'key', models: [] },
|
|
57
|
-
chat: async function* () {
|
|
58
|
-
yield { type: 'stop' }
|
|
59
|
-
},
|
|
60
|
-
listModels: async () => [],
|
|
61
|
-
healthCheck: async () => true,
|
|
62
|
-
})
|
|
63
|
-
const context = new ContextManager({ maxTokens: 100_000, compactionThreshold: 0.9 })
|
|
64
|
-
if (systemPrompt !== undefined) context.setSystemPrompt(systemPrompt)
|
|
65
|
-
const tools = createToolRegistry()
|
|
66
|
-
const engine = new QueryEngine(registry, context, tools, new PermissionSystem(permission))
|
|
67
|
-
engine.setLlm(llm)
|
|
68
|
-
return engine
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export async function runTask(
|
|
72
|
-
task: RunnerTask,
|
|
73
|
-
llm: Llm,
|
|
74
|
-
opts: { taskDir?: string; permission?: PermissionLevel; systemPrompt?: string } = {},
|
|
75
|
-
): Promise<TaskRunResult> {
|
|
76
|
-
const taskDir = opts.taskDir ?? join(process.cwd(), '.mipham', 'task-runner')
|
|
77
|
-
const permission = opts.permission ?? 'bypassPermissions'
|
|
78
|
-
|
|
79
|
-
rmSync(taskDir, { recursive: true, force: true })
|
|
80
|
-
mkdirSync(taskDir, { recursive: true })
|
|
81
|
-
|
|
82
|
-
const instruction = task.instruction.replaceAll(TASK_DIR_PLACEHOLDER, taskDir)
|
|
83
|
-
const engine = buildEngine(llm, permission, opts.systemPrompt)
|
|
84
|
-
|
|
85
|
-
for await (const _ of engine.process(instruction)) {
|
|
86
|
-
/* drain agentic loop */
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const verdict = judgeTask(task, taskDir)
|
|
90
|
-
return { taskId: task.id, passed: verdict.passed, detail: verdict.detail }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface TaskRunStats {
|
|
94
|
-
taskId: string
|
|
95
|
-
samples: number
|
|
96
|
-
passed: number
|
|
97
|
-
/** 0-1 */
|
|
98
|
-
passRate: number
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function runTaskN(
|
|
102
|
-
task: RunnerTask,
|
|
103
|
-
llm: Llm,
|
|
104
|
-
n: number,
|
|
105
|
-
opts: { taskDir?: string; permission?: PermissionLevel; systemPrompt?: string } = {},
|
|
106
|
-
): Promise<TaskRunStats> {
|
|
107
|
-
let passed = 0
|
|
108
|
-
for (let i = 0; i < n; i++) {
|
|
109
|
-
const result = await runTask(task, llm, opts)
|
|
110
|
-
if (result.passed) passed++
|
|
111
|
-
}
|
|
112
|
-
return { taskId: task.id, samples: n, passed, passRate: n > 0 ? passed / n : 0 }
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface RunComparison {
|
|
116
|
-
baseline: TaskRunStats
|
|
117
|
-
candidate: TaskRunStats
|
|
118
|
-
/** 弱判:candidate 不退化(不低于 baseline 且至少 1 次成功) */
|
|
119
|
-
notDegraded: boolean
|
|
120
|
-
/** candidate 严格更好(通过率更高) */
|
|
121
|
-
improved: boolean
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function isNotDegraded(baseline: TaskRunStats, candidate: TaskRunStats): boolean {
|
|
125
|
-
return candidate.passRate >= baseline.passRate && candidate.passed >= 1
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function isImproved(baseline: TaskRunStats, candidate: TaskRunStats): boolean {
|
|
129
|
-
return candidate.passRate > baseline.passRate
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function compareRuns(baseline: TaskRunStats, candidate: TaskRunStats): RunComparison {
|
|
133
|
-
return {
|
|
134
|
-
baseline,
|
|
135
|
-
candidate,
|
|
136
|
-
notDegraded: isNotDegraded(baseline, candidate),
|
|
137
|
-
improved: isImproved(baseline, candidate),
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export async function runBeforeAfter(
|
|
142
|
-
task: RunnerTask,
|
|
143
|
-
llm: Llm,
|
|
144
|
-
n: number,
|
|
145
|
-
opts: {
|
|
146
|
-
beforePrompt?: string
|
|
147
|
-
afterPrompt?: string
|
|
148
|
-
taskDir?: string
|
|
149
|
-
permission?: PermissionLevel
|
|
150
|
-
} = {},
|
|
151
|
-
): Promise<RunComparison> {
|
|
152
|
-
const baseline = await runTaskN(task, llm, n, {
|
|
153
|
-
taskDir: opts.taskDir,
|
|
154
|
-
permission: opts.permission,
|
|
155
|
-
systemPrompt: opts.beforePrompt,
|
|
156
|
-
})
|
|
157
|
-
const candidate = await runTaskN(task, llm, n, {
|
|
158
|
-
taskDir: opts.taskDir,
|
|
159
|
-
permission: opts.permission,
|
|
160
|
-
systemPrompt: opts.afterPrompt,
|
|
161
|
-
})
|
|
162
|
-
return compareRuns(baseline, candidate)
|
|
163
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { SkillDefinition } from '../../shared/index.ts'
|
|
2
|
-
|
|
3
|
-
export interface MiphamRuntimeContext {
|
|
4
|
-
skill: SkillDefinition
|
|
5
|
-
cwd: string
|
|
6
|
-
sessionId: string
|
|
7
|
-
modelId: string
|
|
8
|
-
providerId: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Mipham exclusive skill runtime.
|
|
13
|
-
* Mipham skills use `.mipham-skill.md` extension and have access to
|
|
14
|
-
* Mipham-specific features: model optimization, security features, etc.
|
|
15
|
-
*/
|
|
16
|
-
export class MiphamRuntime {
|
|
17
|
-
private context: MiphamRuntimeContext
|
|
18
|
-
|
|
19
|
-
constructor(context: MiphamRuntimeContext) {
|
|
20
|
-
this.context = context
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
getSkill(): SkillDefinition {
|
|
24
|
-
return this.context.skill
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getPrompts(): Record<string, string> {
|
|
28
|
-
return this.context.skill.prompts || {}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getTools(): SkillDefinition['tools'] {
|
|
32
|
-
return this.context.skill.tools || []
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
getHooks(): SkillDefinition['hooks'] {
|
|
36
|
-
return this.context.skill.hooks || []
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Execute a named prompt with Mipham-specific context.
|
|
41
|
-
*/
|
|
42
|
-
async executePrompt(name: string, variables?: Record<string, string>): Promise<string> {
|
|
43
|
-
const prompt = this.context.skill.prompts?.[name]
|
|
44
|
-
if (!prompt) {
|
|
45
|
-
throw new Error(`Prompt "${name}" not found in skill "${this.context.skill.name}"`)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
let result = prompt
|
|
49
|
-
const allVars: Record<string, string> = {
|
|
50
|
-
provider: this.context.providerId,
|
|
51
|
-
model: this.context.modelId,
|
|
52
|
-
session: this.context.sessionId,
|
|
53
|
-
cwd: this.context.cwd,
|
|
54
|
-
...variables,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Single-pass substitution: replacement values are NOT re-scanned for more
|
|
58
|
-
// template markers, so a variable containing `${key}` can't be re-expanded
|
|
59
|
-
// into another variable's value.
|
|
60
|
-
result = result.replace(/\$\{([^}]+)\}/g, (match, key: string) =>
|
|
61
|
-
Object.prototype.hasOwnProperty.call(allVars, key) ? allVars[key]! : match,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
return result
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { SkillDefinition } from '../../shared/index.ts'
|
|
2
|
-
|
|
3
|
-
export interface StandardRuntimeContext {
|
|
4
|
-
skill: SkillDefinition
|
|
5
|
-
cwd: string
|
|
6
|
-
sessionId: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Standard skill runtime — executes SKILL.md definitions.
|
|
11
|
-
* Standard skills follow the open-source SKILL.md specification.
|
|
12
|
-
*/
|
|
13
|
-
export class StandardRuntime {
|
|
14
|
-
private context: StandardRuntimeContext
|
|
15
|
-
|
|
16
|
-
constructor(context: StandardRuntimeContext) {
|
|
17
|
-
this.context = context
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
getSkill(): SkillDefinition {
|
|
21
|
-
return this.context.skill
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getPrompts(): Record<string, string> {
|
|
25
|
-
return this.context.skill.prompts || {}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
getPrompt(name: string): string | undefined {
|
|
29
|
-
return this.context.skill.prompts?.[name]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
getTools(): SkillDefinition['tools'] {
|
|
33
|
-
return this.context.skill.tools || []
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getHooks(): SkillDefinition['hooks'] {
|
|
37
|
-
return this.context.skill.hooks || []
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Execute a named prompt from the skill.
|
|
42
|
-
* Returns the prompt text with any variable substitution applied.
|
|
43
|
-
*/
|
|
44
|
-
async executePrompt(name: string, variables?: Record<string, string>): Promise<string> {
|
|
45
|
-
const prompt = this.getPrompt(name)
|
|
46
|
-
if (!prompt) {
|
|
47
|
-
throw new Error(`Prompt "${name}" not found in skill "${this.context.skill.name}"`)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let result = prompt
|
|
51
|
-
if (variables) {
|
|
52
|
-
// Single-pass substitution: replacement values are NOT re-scanned for
|
|
53
|
-
// more template markers, so an argument containing `${key}` can't be
|
|
54
|
-
// re-expanded into another variable's value.
|
|
55
|
-
result = result.replace(/\$\{([^}]+)\}/g, (match, key: string) =>
|
|
56
|
-
Object.prototype.hasOwnProperty.call(variables, key) ? variables[key]! : match,
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return result
|
|
61
|
-
}
|
|
62
|
-
}
|