@realseek/mmflow 0.1.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/.claude/commands/mmf-analyze.md +49 -0
- package/.claude/commands/mmf-codex.md +51 -0
- package/.claude/commands/mmf-gemini.md +51 -0
- package/.claude/commands/mmf-review.md +53 -0
- package/.claude/commands/mmf-workflow.md +104 -0
- package/.claude/skills/codex-task/SKILL.md +59 -0
- package/.claude/skills/gemini-task/SKILL.md +59 -0
- package/.claude/skills/multi-model-task/SKILL.md +94 -0
- package/CLAUDE.md +60 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +183 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +20 -0
- package/dist/client.js.map +1 -0
- package/dist/completion.d.ts +15 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +86 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +187 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +18 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +67 -0
- package/dist/session.js.map +1 -0
- package/dist/task.d.ts +19 -0
- package/dist/task.d.ts.map +1 -0
- package/dist/task.js +138 -0
- package/dist/task.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, readdirSync } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const PKG_ROOT = path.resolve(__dirname, "..");
|
|
8
|
+
// ============================================================
|
|
9
|
+
// Readline helpers
|
|
10
|
+
// ============================================================
|
|
11
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
12
|
+
function ask(question) {
|
|
13
|
+
return new Promise((resolve) => rl.question(question, (answer) => resolve(answer.trim())));
|
|
14
|
+
}
|
|
15
|
+
async function askWithDefault(label, defaultVal) {
|
|
16
|
+
const answer = await ask(` ? ${label} (默认: ${defaultVal}): `);
|
|
17
|
+
return answer || defaultVal;
|
|
18
|
+
}
|
|
19
|
+
async function askRequired(label) {
|
|
20
|
+
let answer = "";
|
|
21
|
+
while (!answer) {
|
|
22
|
+
answer = await ask(` ? ${label}: `);
|
|
23
|
+
if (!answer)
|
|
24
|
+
console.log(" ⚠ 此项为必填");
|
|
25
|
+
}
|
|
26
|
+
return answer;
|
|
27
|
+
}
|
|
28
|
+
async function askOptional(label, defaultVal) {
|
|
29
|
+
const hint = defaultVal ? `回车使用默认: ${defaultVal}` : "回车跳过";
|
|
30
|
+
const answer = await ask(` ? ${label} (${hint}): `);
|
|
31
|
+
return answer || defaultVal;
|
|
32
|
+
}
|
|
33
|
+
// PLACEHOLDER_FOR_APPEND_1
|
|
34
|
+
// ============================================================
|
|
35
|
+
// File installation helpers
|
|
36
|
+
// ============================================================
|
|
37
|
+
function copyDir(src, dest) {
|
|
38
|
+
if (!existsSync(src))
|
|
39
|
+
return 0;
|
|
40
|
+
mkdirSync(dest, { recursive: true });
|
|
41
|
+
cpSync(src, dest, { recursive: true, force: true });
|
|
42
|
+
// Count files copied
|
|
43
|
+
let count = 0;
|
|
44
|
+
const entries = readdirSync(src, { withFileTypes: true });
|
|
45
|
+
for (const e of entries) {
|
|
46
|
+
count += e.isDirectory() ? countFiles(path.join(src, e.name)) : 1;
|
|
47
|
+
}
|
|
48
|
+
return count;
|
|
49
|
+
}
|
|
50
|
+
function countFiles(dir) {
|
|
51
|
+
if (!existsSync(dir))
|
|
52
|
+
return 0;
|
|
53
|
+
let count = 0;
|
|
54
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
55
|
+
for (const e of entries) {
|
|
56
|
+
count += e.isDirectory() ? countFiles(path.join(dir, e.name)) : 1;
|
|
57
|
+
}
|
|
58
|
+
return count;
|
|
59
|
+
}
|
|
60
|
+
// ============================================================
|
|
61
|
+
// MCP config helpers
|
|
62
|
+
// ============================================================
|
|
63
|
+
function loadJson(filePath) {
|
|
64
|
+
if (!existsSync(filePath))
|
|
65
|
+
return {};
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function saveJson(filePath, data) {
|
|
74
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
75
|
+
}
|
|
76
|
+
function getServerEntryPath() {
|
|
77
|
+
return path.join(PKG_ROOT, "dist", "index.js").replace(/\\/g, "/");
|
|
78
|
+
}
|
|
79
|
+
// PLACEHOLDER_FOR_APPEND_2
|
|
80
|
+
// ============================================================
|
|
81
|
+
// Main
|
|
82
|
+
// ============================================================
|
|
83
|
+
async function main() {
|
|
84
|
+
const command = process.argv[2];
|
|
85
|
+
if (command !== "init") {
|
|
86
|
+
console.log("用法: mmflow init");
|
|
87
|
+
console.log(" 在当前项目中初始化多模型协作工作流");
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(" ╔══════════════════════════════════════╗");
|
|
92
|
+
console.log(" ║ MMFlow - 多模型协作工作流 ║");
|
|
93
|
+
console.log(" ╚══════════════════════════════════════╝");
|
|
94
|
+
console.log();
|
|
95
|
+
// ── Step 1: Codex ──────────────────────────────────────
|
|
96
|
+
console.log(" 步骤 1/3: 配置 Codex (OpenAI)");
|
|
97
|
+
console.log(" ─────────────────────────────────");
|
|
98
|
+
const codexKey = await askRequired("API Key");
|
|
99
|
+
const codexUrl = await askOptional("接口地址", "https://api.openai.com/v1");
|
|
100
|
+
const codexModel = await askWithDefault("模型名称", "gpt-5.4");
|
|
101
|
+
console.log();
|
|
102
|
+
// ── Step 2: Gemini ─────────────────────────────────────
|
|
103
|
+
console.log(" 步骤 2/3: 配置 Gemini");
|
|
104
|
+
console.log(" ─────────────────────────────────");
|
|
105
|
+
const geminiKey = await askRequired("API Key");
|
|
106
|
+
const geminiUrl = await askOptional("接口地址", "https://generativelanguage.googleapis.com/v1beta/openai/");
|
|
107
|
+
const geminiModel = await askWithDefault("模型名称", "gemini-3.1-pro-preview");
|
|
108
|
+
console.log();
|
|
109
|
+
// ── Step 3: Install ────────────────────────────────────
|
|
110
|
+
console.log(" 步骤 3/3: 安装中...");
|
|
111
|
+
console.log(" ─────────────────────────────────");
|
|
112
|
+
const projectRoot = process.cwd();
|
|
113
|
+
const claudeDir = path.join(projectRoot, ".claude");
|
|
114
|
+
// Copy commands
|
|
115
|
+
const cmdSrc = path.join(PKG_ROOT, ".claude", "commands");
|
|
116
|
+
const cmdDest = path.join(claudeDir, "commands");
|
|
117
|
+
const cmdCount = copyDir(cmdSrc, cmdDest);
|
|
118
|
+
console.log(` ✓ 已安装 ${cmdCount} 个命令到 .claude/commands/`);
|
|
119
|
+
// Copy skills
|
|
120
|
+
const skillSrc = path.join(PKG_ROOT, ".claude", "skills");
|
|
121
|
+
const skillDest = path.join(claudeDir, "skills");
|
|
122
|
+
const skillCount = copyDir(skillSrc, skillDest);
|
|
123
|
+
console.log(` ✓ 已安装 ${skillCount} 个技能到 .claude/skills/`);
|
|
124
|
+
// Register MCP server in .mcp.json
|
|
125
|
+
const mcpPath = path.join(projectRoot, ".mcp.json");
|
|
126
|
+
const mcpConfig = loadJson(mcpPath);
|
|
127
|
+
if (!mcpConfig.mcpServers)
|
|
128
|
+
mcpConfig.mcpServers = {};
|
|
129
|
+
mcpConfig.mcpServers["diy-workflow"] = {
|
|
130
|
+
type: "stdio",
|
|
131
|
+
command: "node",
|
|
132
|
+
args: [getServerEntryPath()],
|
|
133
|
+
env: {
|
|
134
|
+
OPENAI_API_KEY: codexKey,
|
|
135
|
+
OPENAI_BASE_URL: codexUrl,
|
|
136
|
+
OPENAI_MODEL: codexModel,
|
|
137
|
+
GEMINI_API_KEY: geminiKey,
|
|
138
|
+
GEMINI_BASE_URL: geminiUrl,
|
|
139
|
+
GEMINI_MODEL: geminiModel,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
saveJson(mcpPath, mcpConfig);
|
|
143
|
+
console.log(" ✓ 已注册 MCP 服务到 .mcp.json");
|
|
144
|
+
// Copy CLAUDE.md
|
|
145
|
+
const claudeMdSrc = path.join(PKG_ROOT, "CLAUDE.md");
|
|
146
|
+
const claudeMdDest = path.join(claudeDir, "CLAUDE.md");
|
|
147
|
+
if (existsSync(claudeMdSrc)) {
|
|
148
|
+
// Append to existing or create new
|
|
149
|
+
if (existsSync(claudeMdDest)) {
|
|
150
|
+
const existing = readFileSync(claudeMdDest, "utf-8");
|
|
151
|
+
if (!existing.includes("Workflow MCP")) {
|
|
152
|
+
const content = readFileSync(claudeMdSrc, "utf-8");
|
|
153
|
+
writeFileSync(claudeMdDest, existing + "\n\n" + content, "utf-8");
|
|
154
|
+
console.log(" ✓ 已追加工作流配置到 .claude/CLAUDE.md");
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.log(" - .claude/CLAUDE.md 已包含工作流配置,跳过");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
162
|
+
cpSync(claudeMdSrc, claudeMdDest);
|
|
163
|
+
console.log(" ✓ 已创建 .claude/CLAUDE.md");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
console.log();
|
|
167
|
+
console.log(" 完成!重启 Claude Code 即可使用。");
|
|
168
|
+
console.log();
|
|
169
|
+
console.log(" 可用命令:");
|
|
170
|
+
console.log(" /mmf-workflow — 完整多模型开发流程");
|
|
171
|
+
console.log(" /mmf-codex — 单独调 Codex");
|
|
172
|
+
console.log(" /mmf-gemini — 单独调 Gemini");
|
|
173
|
+
console.log(" /mmf-review — 双模型代码审查");
|
|
174
|
+
console.log(" /mmf-analyze — 并行分析");
|
|
175
|
+
console.log();
|
|
176
|
+
rl.close();
|
|
177
|
+
}
|
|
178
|
+
main().catch((err) => {
|
|
179
|
+
console.error("安装失败:", err);
|
|
180
|
+
rl.close();
|
|
181
|
+
process.exit(1);
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAoBnD"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
const clients = new Map();
|
|
3
|
+
export function getClient(route) {
|
|
4
|
+
const cached = clients.get(route.configFile);
|
|
5
|
+
if (cached)
|
|
6
|
+
return cached;
|
|
7
|
+
const apiKey = process.env[route.apiKeyEnv] || "";
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
throw new Error(`${route.apiKeyEnv} is not set. Configure it in MCP server env.`);
|
|
10
|
+
}
|
|
11
|
+
const baseURL = process.env[route.baseUrlEnv] || route.defaultBaseUrl || "";
|
|
12
|
+
const client = new OpenAI({
|
|
13
|
+
apiKey,
|
|
14
|
+
...(baseURL && { baseURL }),
|
|
15
|
+
maxRetries: 3,
|
|
16
|
+
});
|
|
17
|
+
clients.set(route.configFile, client);
|
|
18
|
+
return client;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE1C,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,SAAS,8CAA8C,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IAE5E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM;QACN,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,UAAU,EAAE,CAAC;KACd,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type OpenAI from "openai";
|
|
2
|
+
import type { CompletionRequest, CompletionResult, CompletionProvider } from "./types.js";
|
|
3
|
+
export declare class OpenAICompletionProvider implements CompletionProvider {
|
|
4
|
+
private readonly client;
|
|
5
|
+
private readonly options;
|
|
6
|
+
constructor(client: OpenAI, options?: {
|
|
7
|
+
defaultTimeoutMs?: number;
|
|
8
|
+
});
|
|
9
|
+
complete(request: CompletionRequest): Promise<CompletionResult>;
|
|
10
|
+
completeStream(request: CompletionRequest, onChunk: (chunk: string) => void): Promise<CompletionResult>;
|
|
11
|
+
}
|
|
12
|
+
export declare function formatTokens(n: number): string;
|
|
13
|
+
export declare function formatDuration(ms: number): string;
|
|
14
|
+
export declare function formatUsageLine(result: CompletionResult): string;
|
|
15
|
+
//# sourceMappingURL=completion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAI1F,qBAAa,wBAAyB,YAAW,kBAAkB;IAE/D,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAO;IAGxD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgB/D,cAAc,CAClB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,gBAAgB,CAAC;CA6B7B;AA6BD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAIhE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
2
|
+
export class OpenAICompletionProvider {
|
|
3
|
+
client;
|
|
4
|
+
options;
|
|
5
|
+
constructor(client, options = {}) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
async complete(request) {
|
|
10
|
+
const completion = await this.client.chat.completions.create({
|
|
11
|
+
model: request.model,
|
|
12
|
+
messages: request.messages,
|
|
13
|
+
stream: false,
|
|
14
|
+
...request.extra,
|
|
15
|
+
}, {
|
|
16
|
+
timeout: request.timeoutMs ?? this.options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
17
|
+
signal: request.signal ?? undefined,
|
|
18
|
+
});
|
|
19
|
+
return extractResult(completion);
|
|
20
|
+
}
|
|
21
|
+
async completeStream(request, onChunk) {
|
|
22
|
+
const stream = await this.client.chat.completions.create({
|
|
23
|
+
model: request.model,
|
|
24
|
+
messages: request.messages,
|
|
25
|
+
stream: true,
|
|
26
|
+
...request.extra,
|
|
27
|
+
}, {
|
|
28
|
+
timeout: request.timeoutMs ?? this.options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
29
|
+
signal: request.signal ?? undefined,
|
|
30
|
+
});
|
|
31
|
+
let fullContent = "";
|
|
32
|
+
let model = request.model;
|
|
33
|
+
for await (const chunk of stream) {
|
|
34
|
+
const delta = chunk.choices?.[0]?.delta?.content;
|
|
35
|
+
if (delta) {
|
|
36
|
+
fullContent += delta;
|
|
37
|
+
onChunk(delta);
|
|
38
|
+
}
|
|
39
|
+
if (chunk.model)
|
|
40
|
+
model = chunk.model;
|
|
41
|
+
}
|
|
42
|
+
if (!fullContent)
|
|
43
|
+
fullContent = "(empty response)";
|
|
44
|
+
return { content: fullContent, model };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function extractResult(completion) {
|
|
48
|
+
const choice = completion.choices?.[0];
|
|
49
|
+
if (!choice)
|
|
50
|
+
throw new Error("Model returned no choices");
|
|
51
|
+
const content = typeof choice.message?.content === "string" && choice.message.content.length > 0
|
|
52
|
+
? choice.message.content
|
|
53
|
+
: "(empty response)";
|
|
54
|
+
const usage = completion.usage;
|
|
55
|
+
return {
|
|
56
|
+
content,
|
|
57
|
+
model: completion.model,
|
|
58
|
+
usage: usage
|
|
59
|
+
? {
|
|
60
|
+
promptTokens: usage.prompt_tokens,
|
|
61
|
+
completionTokens: usage.completion_tokens,
|
|
62
|
+
totalTokens: usage.total_tokens,
|
|
63
|
+
}
|
|
64
|
+
: undefined,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// ============================================================
|
|
68
|
+
// Formatting Utilities
|
|
69
|
+
// ============================================================
|
|
70
|
+
export function formatTokens(n) {
|
|
71
|
+
if (n < 1000)
|
|
72
|
+
return String(n);
|
|
73
|
+
return `${(n / 1000).toFixed(1)}k`;
|
|
74
|
+
}
|
|
75
|
+
export function formatDuration(ms) {
|
|
76
|
+
if (ms < 1000)
|
|
77
|
+
return `${ms}ms`;
|
|
78
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
79
|
+
}
|
|
80
|
+
export function formatUsageLine(result) {
|
|
81
|
+
if (!result.usage)
|
|
82
|
+
return "";
|
|
83
|
+
const { promptTokens, completionTokens, totalTokens } = result.usage;
|
|
84
|
+
return `\n\n[${result.model} | ${formatTokens(promptTokens)} in + ${formatTokens(completionTokens)} out = ${formatTokens(totalTokens)} tokens]`;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ModelRoute, TaskDomain, RouteDecision } from "./types.js";
|
|
2
|
+
export declare const MODEL_ROUTES: ModelRoute[];
|
|
3
|
+
export declare function resolveModelRoute(model: string): ModelRoute;
|
|
4
|
+
export declare function routeByDomain(domain: TaskDomain): RouteDecision;
|
|
5
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMxE,eAAO,MAAM,YAAY,EAAE,UAAU,EAuBpC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAK3D;AAiCD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAK/D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Model Route Table
|
|
3
|
+
// ============================================================
|
|
4
|
+
export const MODEL_ROUTES = [
|
|
5
|
+
{
|
|
6
|
+
prefix: "gemini",
|
|
7
|
+
provider: "Gemini",
|
|
8
|
+
configFile: "gemini.json",
|
|
9
|
+
apiKeyEnv: "GEMINI_API_KEY",
|
|
10
|
+
baseUrlEnv: "GEMINI_BASE_URL",
|
|
11
|
+
modelEnv: "GEMINI_MODEL",
|
|
12
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
13
|
+
defaultModel: "gemini-3.1-pro-preview",
|
|
14
|
+
defaultTimeout: 120_000,
|
|
15
|
+
},
|
|
16
|
+
// Default fallback — OpenAI/Codex (must be last)
|
|
17
|
+
{
|
|
18
|
+
prefix: "",
|
|
19
|
+
provider: "Codex",
|
|
20
|
+
configFile: "codex.json",
|
|
21
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
22
|
+
baseUrlEnv: "OPENAI_BASE_URL",
|
|
23
|
+
modelEnv: "OPENAI_MODEL",
|
|
24
|
+
defaultModel: "gpt-5.4",
|
|
25
|
+
defaultTimeout: 60_000,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
export function resolveModelRoute(model) {
|
|
29
|
+
for (const route of MODEL_ROUTES) {
|
|
30
|
+
if (route.prefix && model.startsWith(route.prefix))
|
|
31
|
+
return route;
|
|
32
|
+
}
|
|
33
|
+
return MODEL_ROUTES[MODEL_ROUTES.length - 1];
|
|
34
|
+
}
|
|
35
|
+
// ============================================================
|
|
36
|
+
// Smart Routing (domain → model + system prompt)
|
|
37
|
+
// ============================================================
|
|
38
|
+
/** Get the effective default model for a route (env > hardcoded default) */
|
|
39
|
+
function getDefaultModel(route) {
|
|
40
|
+
return process.env[route.modelEnv] || route.defaultModel;
|
|
41
|
+
}
|
|
42
|
+
const DOMAIN_PROMPTS = {
|
|
43
|
+
frontend: "You are a senior frontend architect. Focus on UI/UX, component architecture, accessibility, responsive design, and performance. " +
|
|
44
|
+
"You have ZERO file write permission — return analysis and Unified Diff patches only. NEVER execute actual modifications.",
|
|
45
|
+
backend: "You are a senior backend architect. Focus on API design, database architecture, security, scalability, and reliability. " +
|
|
46
|
+
"You have ZERO file write permission — return analysis and Unified Diff patches only. NEVER execute actual modifications.",
|
|
47
|
+
review: "You are a senior code reviewer. Review code for bugs, security vulnerabilities, performance issues, and maintainability. " +
|
|
48
|
+
"Rate findings as Critical/Major/Minor/Suggestion with specific line numbers. You have ZERO file write permission.",
|
|
49
|
+
general: "You are a senior software engineer. Analyze context and complete the requested task with specific references. " +
|
|
50
|
+
"If suggesting code changes, return Unified Diff patches. You have ZERO file write permission.",
|
|
51
|
+
};
|
|
52
|
+
const DOMAIN_PROVIDER = {
|
|
53
|
+
frontend: "gemini",
|
|
54
|
+
backend: "",
|
|
55
|
+
review: "",
|
|
56
|
+
general: "",
|
|
57
|
+
};
|
|
58
|
+
export function routeByDomain(domain) {
|
|
59
|
+
const prefix = DOMAIN_PROVIDER[domain];
|
|
60
|
+
const route = MODEL_ROUTES.find((r) => r.prefix === prefix) ?? MODEL_ROUTES[MODEL_ROUTES.length - 1];
|
|
61
|
+
const model = getDefaultModel(route);
|
|
62
|
+
return { model, provider: route.provider, systemPrompt: DOMAIN_PROMPTS[domain] };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC;QACE,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,aAAa;QACzB,SAAS,EAAE,gBAAgB;QAC3B,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,cAAc;QACxB,cAAc,EAAE,0DAA0D;QAC1E,YAAY,EAAE,wBAAwB;QACtC,cAAc,EAAE,OAAO;KACxB;IACD,iDAAiD;IACjD;QACE,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,YAAY;QACxB,SAAS,EAAE,gBAAgB;QAC3B,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,cAAc;QACxB,YAAY,EAAE,SAAS;QACvB,cAAc,EAAE,MAAM;KACvB;CACF,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IACnE,CAAC;IACD,OAAO,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,iDAAiD;AACjD,+DAA+D;AAE/D,4EAA4E;AAC5E,SAAS,eAAe,CAAC,KAAiB;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC;AAC3D,CAAC;AAED,MAAM,cAAc,GAA+B;IACjD,QAAQ,EACN,kIAAkI;QAClI,0HAA0H;IAC5H,OAAO,EACL,0HAA0H;QAC1H,0HAA0H;IAC5H,MAAM,EACJ,2HAA2H;QAC3H,mHAAmH;IACrH,OAAO,EACL,gHAAgH;QAChH,+FAA+F;CAClG,CAAC;AAEF,MAAM,eAAe,GAA+B;IAClD,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,MAAkB;IAC9C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;AACnF,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,GAAG,YAAY,CAalF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
export function mapErrorToResponse(error, ctx) {
|
|
3
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4
|
+
return errorResponse(`${ctx.serviceName} request was cancelled or timed out.`);
|
|
5
|
+
}
|
|
6
|
+
if (error instanceof Error && error.message.includes("is not set")) {
|
|
7
|
+
return errorResponse(`${ctx.serviceName} API key not configured. Check .workflow/ config.`);
|
|
8
|
+
}
|
|
9
|
+
if (error instanceof OpenAI.APIError) {
|
|
10
|
+
return errorResponse(mapApiStatus(error, ctx));
|
|
11
|
+
}
|
|
12
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13
|
+
console.error(`[mmf] ${ctx.serviceName} error:`, error);
|
|
14
|
+
return errorResponse(`Unexpected error: ${msg}`);
|
|
15
|
+
}
|
|
16
|
+
function mapApiStatus(error, ctx) {
|
|
17
|
+
const s = ctx.serviceName;
|
|
18
|
+
switch (error.status) {
|
|
19
|
+
case 401:
|
|
20
|
+
return `Invalid or missing ${s} API key.`;
|
|
21
|
+
case 404:
|
|
22
|
+
return `Model not found${ctx.model ? `: ${ctx.model}` : ""}.`;
|
|
23
|
+
case 429:
|
|
24
|
+
return `${s} rate limit exceeded. Please wait and retry.`;
|
|
25
|
+
default:
|
|
26
|
+
if (error.status !== undefined && error.status >= 500) {
|
|
27
|
+
return `${s} service temporarily unavailable (${error.status}).`;
|
|
28
|
+
}
|
|
29
|
+
return `${s} API error (${error.status}): ${error.message}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function errorResponse(text) {
|
|
33
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,GAAiB;IAClE,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1D,OAAO,aAAa,CAAC,GAAG,GAAG,CAAC,WAAW,sCAAsC,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnE,OAAO,aAAa,CAAC,GAAG,GAAG,CAAC,WAAW,mDAAmD,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,KAAK,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,OAAO,aAAa,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,WAAW,SAAS,EAAE,KAAK,CAAC,CAAC;IACxD,OAAO,aAAa,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,KAA2C,EAAE,GAAiB;IAClF,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC;IAC1B,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,GAAG;YACN,OAAO,sBAAsB,CAAC,WAAW,CAAC;QAC5C,KAAK,GAAG;YACN,OAAO,kBAAkB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QAChE,KAAK,GAAG;YACN,OAAO,GAAG,CAAC,8CAA8C,CAAC;QAC5D;YACE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBACtD,OAAO,GAAG,CAAC,qCAAqC,KAAK,CAAC,MAAM,IAAI,CAAC;YACnE,CAAC;YACD,OAAO,GAAG,CAAC,eAAe,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|