monk-pi 0.10.0 → 0.10.2
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/dist/chunk-GGAUER4O.js +1005 -0
- package/dist/cli.js +169 -29
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/monk-extension.ts +853 -0
- package/package.json +1 -1
- package/dist/chunk-37UZNIY3.js +0 -1772
|
@@ -0,0 +1,1005 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var MONK_BASE_URL = "https://monk.party/v1";
|
|
5
|
+
var MONK_WEBSITE = "https://monk.party";
|
|
6
|
+
var MONK_ACCOUNT_URL = "https://monk.party/account/";
|
|
7
|
+
var MONK_MODELS = [
|
|
8
|
+
{
|
|
9
|
+
id: "monk-coding",
|
|
10
|
+
name: "Monk Coding (\u4EE3\u7801\u4E3B\u529B - \u63A8\u8350)",
|
|
11
|
+
description: "\u4E13\u4E3A Agent \u6DF1\u5EA6\u4F18\u5316\uFF0C\u517C\u5907\u9AD8\u541E\u5410\u903B\u8F91\u63A8\u6F14\u4E0E\u5DE5\u5177\u8C03\u7528\u80FD\u529B",
|
|
12
|
+
reasoning: true,
|
|
13
|
+
contextWindow: 1e6,
|
|
14
|
+
maxTokens: 64e3
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "monk-fast",
|
|
18
|
+
name: "Monk Fast (\u6781\u901F\u63A8\u7406)",
|
|
19
|
+
description: "\u6781\u901F\u54CD\u5E94\uFF0C\u9002\u5408\u65E5\u5E38\u95EE\u7B54\u3001\u5FEB\u901F\u4EE3\u7801\u63A2\u7D22\u4E0E\u5355\u6587\u4EF6\u9605\u8BFB",
|
|
20
|
+
reasoning: true,
|
|
21
|
+
contextWindow: 1e6,
|
|
22
|
+
maxTokens: 64e3
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "monk",
|
|
26
|
+
name: "Monk (\u878D\u5408\u6A21\u578B)",
|
|
27
|
+
description: "\u96C6\u4E09\u5927 Flash \u4E4B\u6240\u957F\uFF0C\u7EFC\u5408\u8D28\u91CF\u4E0E\u601D\u8003\u80FD\u529B\u4F18\u5148",
|
|
28
|
+
reasoning: true,
|
|
29
|
+
contextWindow: 1e6,
|
|
30
|
+
maxTokens: 64e3
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
var DEFAULT_MONK_MODEL = "monk-coding";
|
|
34
|
+
function getMonkHomeDir() {
|
|
35
|
+
return path.join(os.homedir(), ".monk-pi");
|
|
36
|
+
}
|
|
37
|
+
function getMonkConfigFile() {
|
|
38
|
+
return path.join(getMonkHomeDir(), "config.json");
|
|
39
|
+
}
|
|
40
|
+
function getPiHomeDir() {
|
|
41
|
+
return process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".pi", "agent");
|
|
42
|
+
}
|
|
43
|
+
function getPiModelsFile() {
|
|
44
|
+
return path.join(getPiHomeDir(), "models.json");
|
|
45
|
+
}
|
|
46
|
+
function getPiSettingsFile() {
|
|
47
|
+
return path.join(getPiHomeDir(), "settings.json");
|
|
48
|
+
}
|
|
49
|
+
function getPiExtensionsDir() {
|
|
50
|
+
return path.join(getPiHomeDir(), "extensions");
|
|
51
|
+
}
|
|
52
|
+
function getPiMonkExtensionFile() {
|
|
53
|
+
return path.join(getPiExtensionsDir(), "monk.ts");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/config.ts
|
|
57
|
+
import fs from "fs";
|
|
58
|
+
import path2 from "path";
|
|
59
|
+
import { fileURLToPath } from "url";
|
|
60
|
+
function loadMonkConfig() {
|
|
61
|
+
const configFile = getMonkConfigFile();
|
|
62
|
+
try {
|
|
63
|
+
if (fs.existsSync(configFile)) {
|
|
64
|
+
const content = fs.readFileSync(configFile, "utf-8");
|
|
65
|
+
return JSON.parse(content);
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
function saveMonkConfig(config) {
|
|
72
|
+
const homeDir = getMonkHomeDir();
|
|
73
|
+
if (!fs.existsSync(homeDir)) {
|
|
74
|
+
fs.mkdirSync(homeDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
const configFile = getMonkConfigFile();
|
|
77
|
+
const existing = loadMonkConfig();
|
|
78
|
+
const merged = { ...existing, ...config };
|
|
79
|
+
fs.writeFileSync(configFile, JSON.stringify(merged, null, 2), "utf-8");
|
|
80
|
+
}
|
|
81
|
+
function resolveApiKey() {
|
|
82
|
+
const envKey = process.env.MONK_API_KEY?.trim();
|
|
83
|
+
if (envKey) {
|
|
84
|
+
return { key: envKey, source: "env" };
|
|
85
|
+
}
|
|
86
|
+
const localConfig = loadMonkConfig();
|
|
87
|
+
if (localConfig.apiKey?.trim()) {
|
|
88
|
+
return { key: localConfig.apiKey.trim(), source: "local" };
|
|
89
|
+
}
|
|
90
|
+
const piModelsFile = getPiModelsFile();
|
|
91
|
+
try {
|
|
92
|
+
if (fs.existsSync(piModelsFile)) {
|
|
93
|
+
const data = JSON.parse(fs.readFileSync(piModelsFile, "utf-8"));
|
|
94
|
+
const key = data?.providers?.monk?.apiKey;
|
|
95
|
+
if (typeof key === "string" && key.trim() && !key.startsWith("$")) {
|
|
96
|
+
return { key: key.trim(), source: "pi" };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
return { key: "", source: "none" };
|
|
102
|
+
}
|
|
103
|
+
function syncPiModelsJson(apiKey) {
|
|
104
|
+
const piDir = getPiHomeDir();
|
|
105
|
+
const piModelsFile = getPiModelsFile();
|
|
106
|
+
try {
|
|
107
|
+
if (!fs.existsSync(piDir)) {
|
|
108
|
+
fs.mkdirSync(piDir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
let modelsData = { providers: {} };
|
|
111
|
+
if (fs.existsSync(piModelsFile)) {
|
|
112
|
+
const raw = fs.readFileSync(piModelsFile, "utf-8");
|
|
113
|
+
try {
|
|
114
|
+
modelsData = JSON.parse(raw);
|
|
115
|
+
if (!modelsData.providers) {
|
|
116
|
+
modelsData.providers = {};
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
modelsData = { providers: {} };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const monkProviderConfig = {
|
|
123
|
+
name: "Monk",
|
|
124
|
+
baseUrl: MONK_BASE_URL,
|
|
125
|
+
api: "openai-completions",
|
|
126
|
+
apiKey: apiKey && !apiKey.startsWith("$") ? apiKey : "$MONK_API_KEY",
|
|
127
|
+
compat: {
|
|
128
|
+
supportsDeveloperRole: false,
|
|
129
|
+
maxTokensField: "max_tokens",
|
|
130
|
+
requiresToolResultName: true
|
|
131
|
+
},
|
|
132
|
+
models: MONK_MODELS.map((m) => ({
|
|
133
|
+
id: m.id,
|
|
134
|
+
name: m.name,
|
|
135
|
+
reasoning: m.reasoning,
|
|
136
|
+
input: ["text"],
|
|
137
|
+
contextWindow: m.contextWindow,
|
|
138
|
+
maxTokens: m.maxTokens,
|
|
139
|
+
cost: {
|
|
140
|
+
input: 0,
|
|
141
|
+
output: 0,
|
|
142
|
+
cacheRead: 0,
|
|
143
|
+
cacheWrite: 0
|
|
144
|
+
}
|
|
145
|
+
}))
|
|
146
|
+
};
|
|
147
|
+
modelsData.providers.monk = monkProviderConfig;
|
|
148
|
+
fs.writeFileSync(piModelsFile, JSON.stringify(modelsData, null, 2), "utf-8");
|
|
149
|
+
return { success: true, path: piModelsFile };
|
|
150
|
+
} catch (err) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
path: piModelsFile,
|
|
154
|
+
error: err instanceof Error ? err.message : String(err)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function getMonkExtensionRaw() {
|
|
159
|
+
try {
|
|
160
|
+
const distPath = path2.resolve(
|
|
161
|
+
path2.dirname(fileURLToPath(import.meta.url)),
|
|
162
|
+
"monk-extension.ts"
|
|
163
|
+
);
|
|
164
|
+
if (fs.existsSync(distPath)) {
|
|
165
|
+
return fs.readFileSync(distPath, "utf-8");
|
|
166
|
+
}
|
|
167
|
+
const srcPath = path2.resolve(
|
|
168
|
+
path2.dirname(fileURLToPath(import.meta.url)),
|
|
169
|
+
"../src/extension/monk-extension.ts"
|
|
170
|
+
);
|
|
171
|
+
if (fs.existsSync(srcPath)) {
|
|
172
|
+
return fs.readFileSync(srcPath, "utf-8");
|
|
173
|
+
}
|
|
174
|
+
const cwdPath = path2.resolve(process.cwd(), "src/extension/monk-extension.ts");
|
|
175
|
+
if (fs.existsSync(cwdPath)) {
|
|
176
|
+
return fs.readFileSync(cwdPath, "utf-8");
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
return "";
|
|
181
|
+
}
|
|
182
|
+
function syncPiExtension(force = false) {
|
|
183
|
+
const extDir = getPiExtensionsDir();
|
|
184
|
+
const extFile = getPiMonkExtensionFile();
|
|
185
|
+
try {
|
|
186
|
+
if (!fs.existsSync(extDir)) {
|
|
187
|
+
fs.mkdirSync(extDir, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
const targetContent = getMonkExtensionRaw().trim() + "\n";
|
|
190
|
+
if (!targetContent.trim()) {
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
path: extFile,
|
|
194
|
+
updated: false,
|
|
195
|
+
error: "\u672A\u627E\u5230\u6269\u5C55\u6E90\u6587\u4EF6 monk-extension.ts"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (fs.existsSync(extFile)) {
|
|
199
|
+
const existing = fs.readFileSync(extFile, "utf-8");
|
|
200
|
+
if (existing === targetContent && !force) {
|
|
201
|
+
return { success: true, path: extFile, updated: false };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
fs.writeFileSync(extFile, targetContent, "utf-8");
|
|
205
|
+
return { success: true, path: extFile, updated: true };
|
|
206
|
+
} catch (err) {
|
|
207
|
+
return {
|
|
208
|
+
success: false,
|
|
209
|
+
path: extFile,
|
|
210
|
+
updated: false,
|
|
211
|
+
error: err instanceof Error ? err.message : String(err)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function getDefaultModel() {
|
|
216
|
+
const config = loadMonkConfig();
|
|
217
|
+
if (config.defaultModel && MONK_MODELS.some((m) => m.id === config.defaultModel)) {
|
|
218
|
+
return config.defaultModel;
|
|
219
|
+
}
|
|
220
|
+
return DEFAULT_MONK_MODEL;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/monk-api.ts
|
|
224
|
+
async function validateApiKey(apiKey, baseUrl = MONK_BASE_URL) {
|
|
225
|
+
const trimmedKey = apiKey.trim();
|
|
226
|
+
if (!trimmedKey) {
|
|
227
|
+
return {
|
|
228
|
+
valid: false,
|
|
229
|
+
latencyMs: 0,
|
|
230
|
+
models: [],
|
|
231
|
+
error: "API Key \u4E0D\u80FD\u4E3A\u7A7A"
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const endpoint = `${baseUrl.replace(/\/+$/, "")}/models`;
|
|
235
|
+
const startTime = Date.now();
|
|
236
|
+
try {
|
|
237
|
+
const controller = new AbortController();
|
|
238
|
+
const timeoutId = setTimeout(() => controller.abort(), 8e3);
|
|
239
|
+
const response = await fetch(endpoint, {
|
|
240
|
+
method: "GET",
|
|
241
|
+
headers: {
|
|
242
|
+
Authorization: `Bearer ${trimmedKey}`,
|
|
243
|
+
Accept: "application/json"
|
|
244
|
+
},
|
|
245
|
+
signal: controller.signal
|
|
246
|
+
});
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
const latencyMs = Date.now() - startTime;
|
|
249
|
+
if (response.status === 401 || response.status === 403) {
|
|
250
|
+
const body = await response.json().catch(() => ({}));
|
|
251
|
+
return {
|
|
252
|
+
valid: false,
|
|
253
|
+
latencyMs,
|
|
254
|
+
models: [],
|
|
255
|
+
statusCode: response.status,
|
|
256
|
+
error: body.error?.message || "API Key \u65E0\u6548\u6216\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u68C0\u67E5 monk.party \u7684\u8BA2\u9605\u51ED\u8BC1"
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
return {
|
|
261
|
+
valid: false,
|
|
262
|
+
latencyMs,
|
|
263
|
+
models: [],
|
|
264
|
+
statusCode: response.status,
|
|
265
|
+
error: `Monk API \u54CD\u5E94\u5F02\u5E38 (HTTP ${response.status})`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const data = await response.json().catch(() => ({}));
|
|
269
|
+
const models = Array.isArray(data.data) ? data.data.map((m) => m.id) : [];
|
|
270
|
+
return {
|
|
271
|
+
valid: true,
|
|
272
|
+
latencyMs,
|
|
273
|
+
models,
|
|
274
|
+
statusCode: response.status
|
|
275
|
+
};
|
|
276
|
+
} catch (err) {
|
|
277
|
+
const latencyMs = Date.now() - startTime;
|
|
278
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
279
|
+
return {
|
|
280
|
+
valid: false,
|
|
281
|
+
latencyMs,
|
|
282
|
+
models: [],
|
|
283
|
+
error: isAbort ? "\u8FDE\u63A5 Monk \u670D\u52A1\u8D85\u65F6\uFF08\u8D85\u8FC7 8 \u79D2\uFF09\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5" : `\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function extractFirstJson(text) {
|
|
288
|
+
try {
|
|
289
|
+
return JSON.parse(text);
|
|
290
|
+
} catch {
|
|
291
|
+
const cleaned = text.replace(/^data:\s*/gm, "");
|
|
292
|
+
const start = cleaned.indexOf("{");
|
|
293
|
+
const end = cleaned.lastIndexOf("}");
|
|
294
|
+
if (start === -1 || end <= start) return {};
|
|
295
|
+
try {
|
|
296
|
+
return JSON.parse(cleaned.slice(start, end + 1));
|
|
297
|
+
} catch {
|
|
298
|
+
return {};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function testChatCompletion(apiKey, model = "monk-fast", baseUrl = MONK_BASE_URL) {
|
|
303
|
+
const endpoint = `${baseUrl.replace(/\/+$/, "")}/chat/completions`;
|
|
304
|
+
const startTime = Date.now();
|
|
305
|
+
try {
|
|
306
|
+
const controller = new AbortController();
|
|
307
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
308
|
+
const response = await fetch(endpoint, {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: {
|
|
311
|
+
"Content-Type": "application/json",
|
|
312
|
+
Authorization: `Bearer ${apiKey.trim()}`
|
|
313
|
+
},
|
|
314
|
+
body: JSON.stringify({
|
|
315
|
+
model,
|
|
316
|
+
messages: [{ role: "user", content: "pong" }],
|
|
317
|
+
max_tokens: 10,
|
|
318
|
+
temperature: 0.1
|
|
319
|
+
}),
|
|
320
|
+
signal: controller.signal
|
|
321
|
+
});
|
|
322
|
+
clearTimeout(timeoutId);
|
|
323
|
+
const latencyMs = Date.now() - startTime;
|
|
324
|
+
const payload = extractFirstJson(await response.text());
|
|
325
|
+
if (!response.ok) {
|
|
326
|
+
return {
|
|
327
|
+
success: false,
|
|
328
|
+
latencyMs,
|
|
329
|
+
error: payload.error?.message || `HTTP ${response.status}`
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
const reply = (payload.choices?.[0]?.message?.content ?? "").trim();
|
|
333
|
+
return {
|
|
334
|
+
success: true,
|
|
335
|
+
latencyMs,
|
|
336
|
+
reply
|
|
337
|
+
};
|
|
338
|
+
} catch (err) {
|
|
339
|
+
const latencyMs = Date.now() - startTime;
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
latencyMs,
|
|
343
|
+
error: err instanceof Error ? err.message : String(err)
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/ui.ts
|
|
349
|
+
import spawn from "cross-spawn";
|
|
350
|
+
import pc from "picocolors";
|
|
351
|
+
import { password, select, confirm } from "@inquirer/prompts";
|
|
352
|
+
function openBrowser(url) {
|
|
353
|
+
try {
|
|
354
|
+
if (process.platform === "darwin") {
|
|
355
|
+
spawn("open", [url], { stdio: "ignore", detached: true });
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
if (process.platform === "win32") {
|
|
359
|
+
spawn("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true });
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
spawn("xdg-open", [url], { stdio: "ignore", detached: true });
|
|
363
|
+
return true;
|
|
364
|
+
} catch {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function printBanner() {
|
|
369
|
+
const line = pc.dim("\u2500".repeat(54));
|
|
370
|
+
console.log();
|
|
371
|
+
console.log(pc.bold(pc.yellow(" \u2588\u2580\u2584\u2580\u2588 \u2588\u2580\u2588 \u2588\u2584\u2591\u2588 \u2588\u2584\u2580") + " \u2715 " + pc.cyan("\u2588\u2580\u2588 \u2588")));
|
|
372
|
+
console.log(pc.bold(pc.yellow(" \u2588\u2591\u2580\u2591\u2588 \u2588\u2584\u2588 \u2588\u2591\u2580\u2588 \u2588\u2591\u2588") + " " + pc.cyan("\u2588\u2580\u2580 \u2588")));
|
|
373
|
+
console.log(line);
|
|
374
|
+
console.log(
|
|
375
|
+
` ${pc.bold("Monk \xD7 Pi Harness")} ${pc.dim("\xB7")} ${pc.green("OpenAI-Compatible Fusion Agent")}`
|
|
376
|
+
);
|
|
377
|
+
console.log(
|
|
378
|
+
` ${pc.dim("\u6A21\u578B:")} ${pc.yellow("monk-coding")} ${pc.dim("|")} ${pc.cyan("monk-fast")} ${pc.dim("|")} ${pc.magenta("monk")}`
|
|
379
|
+
);
|
|
380
|
+
console.log(line);
|
|
381
|
+
console.log();
|
|
382
|
+
}
|
|
383
|
+
function logSuccess(msg) {
|
|
384
|
+
console.log(` ${pc.green("\u2714")} ${msg}`);
|
|
385
|
+
}
|
|
386
|
+
function logInfo(msg) {
|
|
387
|
+
console.log(` ${pc.cyan("\u2139")} ${msg}`);
|
|
388
|
+
}
|
|
389
|
+
function logWarn(msg) {
|
|
390
|
+
console.log(` ${pc.yellow("\u25B2")} ${msg}`);
|
|
391
|
+
}
|
|
392
|
+
function logError(msg) {
|
|
393
|
+
console.log(` ${pc.red("\u2716")} ${msg}`);
|
|
394
|
+
}
|
|
395
|
+
function logStep(step, total, msg) {
|
|
396
|
+
console.log(` ${pc.dim(`[${step}/${total}]`)} ${pc.bold(msg)}`);
|
|
397
|
+
}
|
|
398
|
+
async function promptForApiKey(currentKey) {
|
|
399
|
+
console.log();
|
|
400
|
+
console.log(` ${pc.bold("\u6B22\u8FCE\u4F7F\u7528 Monk \xD7 Pi \u7F16\u7801\u4F34\u4FA3\uFF01")}`);
|
|
401
|
+
console.log(
|
|
402
|
+
` ${pc.dim("Monk \u4E13\u4E3A Agent \u63D0\u4F9B\u6781\u901F\u9AD8\u541E\u5410\u878D\u5408\u6A21\u578B (\u6708\u5361 \xA530 / 100\u4E07 Token \u4E0A\u4E0B\u6587)")}`
|
|
403
|
+
);
|
|
404
|
+
console.log();
|
|
405
|
+
if (!currentKey) {
|
|
406
|
+
const action = await select({
|
|
407
|
+
message: "\u8BF7\u9009\u62E9\u914D\u7F6E\u6216\u83B7\u53D6 Monk API Key \u7684\u65B9\u5F0F:",
|
|
408
|
+
choices: [
|
|
409
|
+
{
|
|
410
|
+
name: `1. \u6211\u5DF2\u6709 API Key\uFF0C\u76F4\u63A5\u7C98\u8D34\u8F93\u5165 ${pc.dim("(sk-monk-...)")}`,
|
|
411
|
+
value: "input"
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: `2. \u6211\u8FD8\u6CA1\u6709 Key\uFF0C\u7ACB\u5373\u6253\u5F00 monk.party \u8BA2\u9605 ${pc.green("(\u63A8\u8350 \xB7 \u56DE\u8F66\u6D4F\u89C8\u5668\u626B\u7801)")}`,
|
|
415
|
+
value: "open_browser"
|
|
416
|
+
}
|
|
417
|
+
]
|
|
418
|
+
});
|
|
419
|
+
if (action === "open_browser") {
|
|
420
|
+
logInfo(`\u6B63\u5728\u4E3A\u60A8\u5728\u9ED8\u8BA4\u6D4F\u89C8\u5668\u6253\u5F00\u5B98\u7F51: ${pc.cyan(MONK_WEBSITE)} ...`);
|
|
421
|
+
openBrowser(MONK_WEBSITE);
|
|
422
|
+
console.log();
|
|
423
|
+
logSuccess("\u5DF2\u5524\u8D77\u6D4F\u89C8\u5668\uFF01\u8BF7\u5728\u7F51\u9875\u5B8C\u6210\u8BA2\u9605\u540E\uFF0C\u5C06\u751F\u6210\u7684 sk-monk-... Key \u590D\u5236\u5E76\u7C98\u8D34\u5230\u4E0B\u65B9\uFF1A");
|
|
424
|
+
console.log();
|
|
425
|
+
}
|
|
426
|
+
} else {
|
|
427
|
+
const action = await select({
|
|
428
|
+
message: `\u68C0\u6D4B\u5230\u5DF2\u914D\u7F6E Key (${maskKey(currentKey)})\uFF0C\u8BF7\u9009\u62E9\u64CD\u4F5C:`,
|
|
429
|
+
choices: [
|
|
430
|
+
{
|
|
431
|
+
name: "1. \u4FDD\u6301\u5E76\u6D4B\u8BD5\u5F53\u524D Key",
|
|
432
|
+
value: "keep"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "2. \u66F4\u6362\u4E3A\u65B0\u7684 API Key",
|
|
436
|
+
value: "replace"
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
name: `3. \u5728\u6D4F\u89C8\u5668\u6253\u5F00 monk.party \u5B98\u7F51 (\u67E5\u8BE2/\u7EED\u8D39)`,
|
|
440
|
+
value: "open_browser"
|
|
441
|
+
}
|
|
442
|
+
]
|
|
443
|
+
});
|
|
444
|
+
if (action === "keep") {
|
|
445
|
+
return currentKey;
|
|
446
|
+
}
|
|
447
|
+
if (action === "open_browser") {
|
|
448
|
+
logInfo(`\u6B63\u5728\u4E3A\u60A8\u5728\u6D4F\u89C8\u5668\u6253\u5F00\u5B98\u7F51: ${pc.cyan(MONK_ACCOUNT_URL)} ...`);
|
|
449
|
+
openBrowser(MONK_ACCOUNT_URL);
|
|
450
|
+
console.log();
|
|
451
|
+
logInfo("\u5DF2\u6253\u5F00\u67E5\u8BE2\u9875\u9762\u3002\u5982\u9700\u66F4\u6362 Key \u8BF7\u5728\u4E0B\u65B9\u7C98\u8D34\uFF0C\u76F4\u63A5\u56DE\u8F66\u4FDD\u6301\u5F53\u524D Key\uFF1A");
|
|
452
|
+
console.log();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const key = await password({
|
|
456
|
+
message: currentKey ? `\u8BF7\u8F93\u5165 Monk API Key (\u76F4\u63A5\u56DE\u8F66\u4FDD\u6301\u5F53\u524D: ${maskKey(currentKey)}):` : "\u8BF7\u7C98\u8D34\u60A8\u7684 Monk API Key (sk-monk-...):",
|
|
457
|
+
mask: "*",
|
|
458
|
+
validate: (val) => {
|
|
459
|
+
const trimmed = val.trim();
|
|
460
|
+
if (!trimmed && currentKey) return true;
|
|
461
|
+
if (!trimmed) return "API Key \u4E0D\u80FD\u4E3A\u7A7A";
|
|
462
|
+
if (!trimmed.startsWith("sk-")) {
|
|
463
|
+
return "Key \u683C\u5F0F\u901A\u5E38\u4EE5 sk- \u5F00\u5934\uFF0C\u8BF7\u786E\u8BA4\u590D\u5236\u5B8C\u6574";
|
|
464
|
+
}
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
const finalKey = key.trim() || currentKey || "";
|
|
469
|
+
return finalKey;
|
|
470
|
+
}
|
|
471
|
+
async function promptSelectModel(currentModel) {
|
|
472
|
+
const choices = MONK_MODELS.map((m) => ({
|
|
473
|
+
name: `${m.name.padEnd(28)} ${pc.dim(m.description)}`,
|
|
474
|
+
value: m.id,
|
|
475
|
+
description: m.description
|
|
476
|
+
}));
|
|
477
|
+
const selected = await select({
|
|
478
|
+
message: "\u8BF7\u9009\u62E9\u9ED8\u8BA4\u4E3B\u529B\u6A21\u578B:",
|
|
479
|
+
choices,
|
|
480
|
+
default: currentModel || "monk-coding"
|
|
481
|
+
});
|
|
482
|
+
return selected;
|
|
483
|
+
}
|
|
484
|
+
async function promptInstallPi() {
|
|
485
|
+
logWarn("\u672A\u68C0\u6D4B\u5230\u5168\u5C40\u5B89\u88C5\u7684 pi \u7F16\u7801\u52A9\u624B (@earendil-works/pi-coding-agent)\u3002");
|
|
486
|
+
console.log(` ${pc.dim("Monk Harness \u4F9D\u8D56 Pi \u4F5C\u4E3A\u5E95\u5C42 TUI/Agent \u8FD0\u884C\u65F6\u3002")}`);
|
|
487
|
+
console.log();
|
|
488
|
+
return await confirm({
|
|
489
|
+
message: "\u662F\u5426\u7ACB\u5373\u4F7F\u7528 npm \u5168\u5C40\u5B89\u88C5 @earendil-works/pi-coding-agent\uFF1F",
|
|
490
|
+
default: true
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
function maskKey(key) {
|
|
494
|
+
if (!key || key.length < 10) return "******";
|
|
495
|
+
return `${key.slice(0, 7)}...${key.slice(-4)}`;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/pi-runner.ts
|
|
499
|
+
import fs2 from "fs";
|
|
500
|
+
import path3 from "path";
|
|
501
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
502
|
+
import spawn2 from "cross-spawn";
|
|
503
|
+
import pc2 from "picocolors";
|
|
504
|
+
function resolvePiBinary() {
|
|
505
|
+
try {
|
|
506
|
+
const globalCheck = spawn2.sync("pi", ["--version"], {
|
|
507
|
+
encoding: "utf-8",
|
|
508
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
509
|
+
});
|
|
510
|
+
if (globalCheck.status === 0 && globalCheck.stdout) {
|
|
511
|
+
return {
|
|
512
|
+
type: "global",
|
|
513
|
+
command: "pi",
|
|
514
|
+
argsPrefix: [],
|
|
515
|
+
version: globalCheck.stdout.trim(),
|
|
516
|
+
sourceDescription: "\u7CFB\u7EDF\u5168\u5C40\u547D\u4EE4 (PATH)"
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
const candidateBinDirs = [
|
|
522
|
+
path3.resolve(path3.dirname(fileURLToPath2(import.meta.url)), "../node_modules/.bin/pi"),
|
|
523
|
+
path3.resolve(process.cwd(), "node_modules/.bin/pi")
|
|
524
|
+
];
|
|
525
|
+
for (const binPath of candidateBinDirs) {
|
|
526
|
+
if (fs2.existsSync(binPath)) {
|
|
527
|
+
try {
|
|
528
|
+
const localCheck = spawn2.sync(binPath, ["--version"], {
|
|
529
|
+
encoding: "utf-8",
|
|
530
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
531
|
+
});
|
|
532
|
+
if (localCheck.status === 0 && localCheck.stdout) {
|
|
533
|
+
return {
|
|
534
|
+
type: "local",
|
|
535
|
+
command: binPath,
|
|
536
|
+
argsPrefix: [],
|
|
537
|
+
version: localCheck.stdout.trim(),
|
|
538
|
+
sourceDescription: `\u672C\u5730\u4F9D\u8D56 (${path3.basename(path3.dirname(binPath))})`
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
const mainEntry = fileURLToPath2(import.meta.resolve("@earendil-works/pi-coding-agent"));
|
|
547
|
+
const cliEntry = path3.join(path3.dirname(mainEntry), "bundle", "cli.js");
|
|
548
|
+
if (fs2.existsSync(cliEntry)) {
|
|
549
|
+
const moduleCheck = spawn2.sync(process.execPath, [cliEntry, "--version"], {
|
|
550
|
+
encoding: "utf-8",
|
|
551
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
552
|
+
});
|
|
553
|
+
if (moduleCheck.status === 0 && moduleCheck.stdout) {
|
|
554
|
+
return {
|
|
555
|
+
type: "bundled",
|
|
556
|
+
command: process.execPath,
|
|
557
|
+
argsPrefix: [cliEntry],
|
|
558
|
+
version: moduleCheck.stdout.trim(),
|
|
559
|
+
sourceDescription: "Monk-Pi \u5185\u5D4C\u6838\u5FC3 (\u514D\u5B89\u88C5\u8FD0\u884C)"
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
} catch {
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
type: "missing",
|
|
567
|
+
command: "",
|
|
568
|
+
argsPrefix: [],
|
|
569
|
+
sourceDescription: "\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684 Pi \u6838\u5FC3"
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function detectPi() {
|
|
573
|
+
const resolved = resolvePiBinary();
|
|
574
|
+
return {
|
|
575
|
+
installed: resolved.type !== "missing",
|
|
576
|
+
version: resolved.version,
|
|
577
|
+
type: resolved.type,
|
|
578
|
+
description: resolved.sourceDescription
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
function detectPackageManager() {
|
|
582
|
+
try {
|
|
583
|
+
const bunCheck = spawn2.sync("bun", ["--version"], { stdio: "ignore" });
|
|
584
|
+
if (bunCheck.status === 0) return "bun";
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
const pnpmCheck = spawn2.sync("pnpm", ["--version"], { stdio: "ignore" });
|
|
589
|
+
if (pnpmCheck.status === 0) return "pnpm";
|
|
590
|
+
} catch {
|
|
591
|
+
}
|
|
592
|
+
return "npm";
|
|
593
|
+
}
|
|
594
|
+
async function installPi() {
|
|
595
|
+
const pm = detectPackageManager();
|
|
596
|
+
let cmd = "npm";
|
|
597
|
+
let args = ["install", "-g", "@earendil-works/pi-coding-agent"];
|
|
598
|
+
if (pm === "bun") {
|
|
599
|
+
cmd = "bun";
|
|
600
|
+
args = ["add", "-g", "@earendil-works/pi-coding-agent"];
|
|
601
|
+
} else if (pm === "pnpm") {
|
|
602
|
+
cmd = "pnpm";
|
|
603
|
+
args = ["add", "-g", "@earendil-works/pi-coding-agent"];
|
|
604
|
+
}
|
|
605
|
+
logInfo(`\u68C0\u6D4B\u5230\u5305\u7BA1\u7406\u5668: ${pc2.bold(pm)}\uFF0C\u6B63\u5728\u6267\u884C: ${pc2.yellow(`${cmd} ${args.join(" ")}`)} ...`);
|
|
606
|
+
try {
|
|
607
|
+
const child = spawn2.sync(cmd, args, {
|
|
608
|
+
stdio: "inherit"
|
|
609
|
+
});
|
|
610
|
+
if (child.status === 0) {
|
|
611
|
+
logSuccess("Pi \u6838\u5FC3\u5957\u4EF6\u5B89\u88C5\u6210\u529F\uFF01");
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
logError(`\u5B89\u88C5\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${child.status}`);
|
|
615
|
+
logWarn(`\u82E5\u56E0\u6743\u9650\u95EE\u9898 (EACCES) \u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5:`);
|
|
616
|
+
console.log(` ${pc2.cyan(`sudo ${cmd} ${args.join(" ")}`)}`);
|
|
617
|
+
console.log(` \u6216\u76F4\u63A5\u4F7F\u7528\u514D\u5B89\u88C5\u65B9\u6848: ${pc2.cyan("npx monk-pi")}`);
|
|
618
|
+
return false;
|
|
619
|
+
} catch (err) {
|
|
620
|
+
logError(`\u6267\u884C\u5B89\u88C5\u5F02\u5E38: ${err instanceof Error ? err.message : String(err)}`);
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function launchPi(options) {
|
|
625
|
+
const resolved = resolvePiBinary();
|
|
626
|
+
if (resolved.type === "missing") {
|
|
627
|
+
logError("\u672A\u627E\u5230\u53EF\u7528\u7684 Pi \u6838\u5FC3\u8FD0\u884C\u73AF\u5883\u3002");
|
|
628
|
+
return 1;
|
|
629
|
+
}
|
|
630
|
+
const { apiKey, defaultModel, passthroughArgs } = options;
|
|
631
|
+
const extraArgs = [];
|
|
632
|
+
const hasProvider = passthroughArgs.includes("--provider");
|
|
633
|
+
const hasModel = passthroughArgs.some((arg, idx) => {
|
|
634
|
+
return arg === "--model" || arg === "-m" || passthroughArgs[idx - 1] === "--model";
|
|
635
|
+
});
|
|
636
|
+
if (!hasProvider && !hasModel) {
|
|
637
|
+
extraArgs.push("--provider", "monk", "--model", defaultModel);
|
|
638
|
+
} else if (!hasProvider && hasModel) {
|
|
639
|
+
extraArgs.push("--provider", "monk");
|
|
640
|
+
}
|
|
641
|
+
const fullArgs = [...resolved.argsPrefix, ...extraArgs, ...passthroughArgs];
|
|
642
|
+
const env = {
|
|
643
|
+
...process.env,
|
|
644
|
+
MONK_API_KEY: apiKey
|
|
645
|
+
};
|
|
646
|
+
const child = spawn2(resolved.command, fullArgs, {
|
|
647
|
+
stdio: "inherit",
|
|
648
|
+
env
|
|
649
|
+
});
|
|
650
|
+
const forwardSignal = (signal) => {
|
|
651
|
+
try {
|
|
652
|
+
child.kill(signal);
|
|
653
|
+
} catch {
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
process.on("SIGINT", () => forwardSignal("SIGINT"));
|
|
657
|
+
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
|
|
658
|
+
return new Promise((resolve) => {
|
|
659
|
+
child.on("close", (code) => {
|
|
660
|
+
resolve(code ?? 0);
|
|
661
|
+
});
|
|
662
|
+
child.on("error", (err) => {
|
|
663
|
+
logError(`\u542F\u52A8 Pi \u53D1\u751F\u9519\u8BEF: ${err.message}`);
|
|
664
|
+
resolve(1);
|
|
665
|
+
});
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// src/commands/doctor.ts
|
|
670
|
+
import fs3 from "fs";
|
|
671
|
+
import os2 from "os";
|
|
672
|
+
import pc3 from "picocolors";
|
|
673
|
+
async function doctorCommand() {
|
|
674
|
+
printBanner();
|
|
675
|
+
console.log(` ${pc3.bold("\u3010Monk \xD7 Pi \u73AF\u5883\u8BCA\u65AD (Doctor)\u3011")}`);
|
|
676
|
+
console.log();
|
|
677
|
+
let hasIssue = false;
|
|
678
|
+
const nodeVersion = process.version;
|
|
679
|
+
const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
680
|
+
if (major >= 18) {
|
|
681
|
+
logSuccess(`Node.js \u7248\u672C: ${pc3.bold(nodeVersion)} (\u6EE1\u8DB3 >= 18 \u8981\u6C42)`);
|
|
682
|
+
} else {
|
|
683
|
+
hasIssue = true;
|
|
684
|
+
logError(`Node.js \u7248\u672C: ${pc3.bold(nodeVersion)} (\u8FC7\u4F4E\uFF0C\u8BF7\u5347\u7EA7\u5230 Node 18+)`);
|
|
685
|
+
}
|
|
686
|
+
logInfo(`\u64CD\u4F5C\u7CFB\u7EDF: ${os2.type()} ${os2.release()} (${os2.arch()})`);
|
|
687
|
+
const pi = detectPi();
|
|
688
|
+
if (pi.installed) {
|
|
689
|
+
logSuccess(
|
|
690
|
+
`Pi \u6838\u5FC3\u5957\u4EF6: ${pc3.bold(`\u5DF2\u5C31\u7EEA (v${pi.version})`)} \xB7 ${pc3.dim(`[\u6765\u6E90: ${pi.description}]`)}`
|
|
691
|
+
);
|
|
692
|
+
} else {
|
|
693
|
+
hasIssue = true;
|
|
694
|
+
logError(`Pi \u6838\u5FC3\u5957\u4EF6: ${pc3.bold("\u672A\u627E\u5230\u53EF\u7528\u8FD0\u884C\u65F6")}`);
|
|
695
|
+
console.log(` ${pc3.dim("\u89E3\u51B3\u529E\u6CD5: \u8FD0\u884C npm install -g @earendil-works/pi-coding-agent")}`);
|
|
696
|
+
}
|
|
697
|
+
const { key, source } = resolveApiKey();
|
|
698
|
+
if (key) {
|
|
699
|
+
logSuccess(`Monk API Key: ${pc3.bold(maskKey(key))} (\u6765\u6E90: ${source})`);
|
|
700
|
+
} else {
|
|
701
|
+
hasIssue = true;
|
|
702
|
+
logError(`Monk API Key: \u672A\u914D\u7F6E`);
|
|
703
|
+
console.log(` ${pc3.dim("\u89E3\u51B3\u529E\u6CD5: \u8FD0\u884C monk-pi login")}`);
|
|
704
|
+
}
|
|
705
|
+
const modelsFile = getPiModelsFile();
|
|
706
|
+
if (fs3.existsSync(modelsFile)) {
|
|
707
|
+
try {
|
|
708
|
+
const data = JSON.parse(fs3.readFileSync(modelsFile, "utf-8"));
|
|
709
|
+
const monk = data?.providers?.monk;
|
|
710
|
+
if (monk) {
|
|
711
|
+
const hasCompat = monk.compat?.supportsDeveloperRole === false && monk.compat?.maxTokensField === "max_tokens";
|
|
712
|
+
if (hasCompat) {
|
|
713
|
+
logSuccess(`Pi \u914D\u7F6E\u6587\u4EF6: ${pc3.bold("\u5DF2\u914D\u7F6E Monk \u4E13\u5C5E\u4F18\u5316\u517C\u5BB9\u53C2\u6570")}`);
|
|
714
|
+
} else {
|
|
715
|
+
logWarn(`Pi \u914D\u7F6E\u6587\u4EF6: \u5B58\u5728 Monk \u914D\u7F6E\uFF0C\u4F46\u7F3A\u5C11\u6700\u4F73 compat \u53C2\u6570`);
|
|
716
|
+
console.log(` ${pc3.dim("\u6B63\u5728\u4E3A\u60A8\u81EA\u52A8\u7EA0\u6B63...")}`);
|
|
717
|
+
syncPiModelsJson(key);
|
|
718
|
+
logSuccess(`Pi \u914D\u7F6E\u6587\u4EF6: \u5DF2\u81EA\u52A8\u4FEE\u590D\u4F18\u5316`);
|
|
719
|
+
}
|
|
720
|
+
} else {
|
|
721
|
+
logWarn(`Pi \u914D\u7F6E\u6587\u4EF6: \u5C1A\u672A\u6CE8\u5165 Monk \u4F9B\u5E94\u5546`);
|
|
722
|
+
syncPiModelsJson(key);
|
|
723
|
+
logSuccess(`Pi \u914D\u7F6E\u6587\u4EF6: \u5DF2\u6210\u529F\u81EA\u52A8\u6CE8\u5165`);
|
|
724
|
+
}
|
|
725
|
+
} catch {
|
|
726
|
+
logError(`Pi \u914D\u7F6E\u6587\u4EF6: ${modelsFile} \u5B58\u5728\u8BED\u6CD5\u9519\u8BEF`);
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
logWarn(`Pi \u914D\u7F6E\u6587\u4EF6: \u5C1A\u672A\u521B\u5EFA\uFF0C\u6B63\u5728\u4E3A\u60A8\u81EA\u52A8\u521B\u5EFA...`);
|
|
730
|
+
syncPiModelsJson(key);
|
|
731
|
+
logSuccess(`Pi \u914D\u7F6E\u6587\u4EF6: \u521B\u5EFA\u5B8C\u6210`);
|
|
732
|
+
}
|
|
733
|
+
const extRes = syncPiExtension();
|
|
734
|
+
if (extRes.success) {
|
|
735
|
+
if (extRes.updated) {
|
|
736
|
+
logSuccess(
|
|
737
|
+
`Pi \u539F\u751F\u6269\u5C55: ${pc3.bold("\u5DF2\u81EA\u52A8\u66F4\u65B0\u81F3\u6700\u65B0\u7248")} (\u4E2D\u6587\u5DE5\u7A0B\u63D0\u793A\u8BCD\u3001/monk \u6307\u4EE4\u4E0E\u81EA\u52A8\u91CD\u8BD5\u5C31\u7EEA)`
|
|
738
|
+
);
|
|
739
|
+
} else {
|
|
740
|
+
logSuccess(
|
|
741
|
+
`Pi \u539F\u751F\u6269\u5C55: ${pc3.bold("\u5DF2\u5C31\u7EEA")} (\u4E2D\u6587\u5DE5\u7A0B\u63D0\u793A\u8BCD\u3001/monk \u6307\u4EE4\u4E0E\u81EA\u52A8\u91CD\u8BD5\u5C31\u7EEA)`
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
logError(`Pi \u539F\u751F\u6269\u5C55\u90E8\u7F72\u5931\u8D25: ${extRes.error}`);
|
|
746
|
+
}
|
|
747
|
+
if (key) {
|
|
748
|
+
process.stdout.write(` ${pc3.dim("\u23F3 \u6B63\u5728\u63A2\u6D4B\u4E0E monk.party \u63A5\u53E3\u7684\u8FDE\u901A\u6027...")} `);
|
|
749
|
+
const val = await validateApiKey(key);
|
|
750
|
+
process.stdout.write("\r" + " ".repeat(50) + "\r");
|
|
751
|
+
if (val.valid) {
|
|
752
|
+
logSuccess(`Monk \u8FDE\u901A\u6027: ${pc3.green("\u4F18\u79C0")} \xB7 \u5EF6\u8FDF ${val.latencyMs}ms`);
|
|
753
|
+
} else {
|
|
754
|
+
hasIssue = true;
|
|
755
|
+
logError(`Monk \u8FDE\u901A\u6027\u5F02\u5E38: ${val.error}`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
console.log();
|
|
759
|
+
console.log(pc3.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
760
|
+
if (hasIssue) {
|
|
761
|
+
logWarn("\u68C0\u6D4B\u5230\u73AF\u5883\u5B58\u5728\u90E8\u5206\u95EE\u9898\uFF0C\u8BF7\u53C2\u8003\u4E0A\u65B9\u63D0\u793A\u5904\u7406\u3002");
|
|
762
|
+
} else {
|
|
763
|
+
logSuccess(pc3.bold("\u592A\u68D2\u4E86\uFF01\u6240\u6709\u68C0\u67E5\u9879\u5168\u90E8\u901A\u8FC7\uFF0C\u73AF\u5883\u5904\u4E8E\u6700\u4F73\u72B6\u6001\u3002"));
|
|
764
|
+
}
|
|
765
|
+
console.log();
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// src/commands/login.ts
|
|
769
|
+
import pc4 from "picocolors";
|
|
770
|
+
async function loginCommand() {
|
|
771
|
+
printBanner();
|
|
772
|
+
const current = resolveApiKey();
|
|
773
|
+
const apiKey = await promptForApiKey(current.key || void 0);
|
|
774
|
+
if (!apiKey) {
|
|
775
|
+
logWarn("\u672A\u8F93\u5165 API Key\uFF0C\u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002");
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
logInfo("\u6B63\u5728\u8FDE\u63A5 Monk API \u9A8C\u8BC1\u5BC6\u94A5...");
|
|
779
|
+
const result = await validateApiKey(apiKey);
|
|
780
|
+
if (!result.valid) {
|
|
781
|
+
logError(`\u9A8C\u8BC1\u5931\u8D25: ${result.error || "\u672A\u77E5\u9519\u8BEF"}`);
|
|
782
|
+
logWarn("\u8BF7\u6838\u5BF9\u540E\u91CD\u65B0\u8FD0\u884C `monk-pi login`\u3002");
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
logSuccess(`\u9A8C\u8BC1\u901A\u8FC7\uFF01\u7F51\u7EDC\u5EF6\u8FDF: ${pc4.green(`${result.latencyMs}ms`)}`);
|
|
786
|
+
if (result.models.length > 0) {
|
|
787
|
+
logInfo(`\u53EF\u7528\u6A21\u578B: ${pc4.yellow(result.models.join(", "))}`);
|
|
788
|
+
}
|
|
789
|
+
saveMonkConfig({
|
|
790
|
+
apiKey,
|
|
791
|
+
lastVerified: (/* @__PURE__ */ new Date()).toISOString()
|
|
792
|
+
});
|
|
793
|
+
logSuccess(`\u51ED\u8BC1\u5DF2\u4FDD\u5B58\u81F3\u672C\u5730\u914D\u7F6E`);
|
|
794
|
+
const syncResult = syncPiModelsJson(apiKey);
|
|
795
|
+
const extResult = syncPiExtension();
|
|
796
|
+
if (syncResult.success) {
|
|
797
|
+
logSuccess(`\u5DF2\u6210\u529F\u540C\u6B65\u5E76\u4F18\u5316 Pi \u914D\u7F6E\u6587\u4EF6: ${pc4.dim(syncResult.path)}`);
|
|
798
|
+
} else {
|
|
799
|
+
logWarn(`\u540C\u6B65 Pi \u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${syncResult.error}`);
|
|
800
|
+
}
|
|
801
|
+
if (extResult.success) {
|
|
802
|
+
logSuccess(`\u5DF2\u5B89\u88C5 Monk \u539F\u751F TUI \u6269\u5C55: ${pc4.dim(extResult.path)}`);
|
|
803
|
+
}
|
|
804
|
+
console.log();
|
|
805
|
+
logSuccess(`Monk \xD7 Pi \u5C31\u7EEA\uFF01\u73B0\u5728\u60A8\u53EF\u4EE5\u76F4\u63A5\u8F93\u5165 ${pc4.bold(pc4.yellow("monk-pi"))} \u5F00\u59CB\u7F16\u7801\u3002`);
|
|
806
|
+
console.log();
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/commands/model.ts
|
|
811
|
+
import pc5 from "picocolors";
|
|
812
|
+
async function modelCommand(targetModel) {
|
|
813
|
+
printBanner();
|
|
814
|
+
const currentModel = getDefaultModel();
|
|
815
|
+
if (targetModel) {
|
|
816
|
+
const matched2 = MONK_MODELS.find(
|
|
817
|
+
(m) => m.id === targetModel || m.id.endsWith(targetModel)
|
|
818
|
+
);
|
|
819
|
+
if (!matched2) {
|
|
820
|
+
logWarn(`\u672A\u77E5\u6A21\u578B: "${targetModel}"`);
|
|
821
|
+
logInfo(`\u652F\u6301\u7684\u6A21\u578B\u5217\u8868: ${MONK_MODELS.map((m) => m.id).join(", ")}`);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
saveMonkConfig({ defaultModel: matched2.id });
|
|
825
|
+
logSuccess(`\u9ED8\u8BA4\u4E3B\u529B\u6A21\u578B\u5DF2\u5207\u6362\u4E3A: ${pc5.bold(pc5.yellow(matched2.name))}`);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
const selected = await promptSelectModel(currentModel);
|
|
829
|
+
saveMonkConfig({ defaultModel: selected });
|
|
830
|
+
const matched = MONK_MODELS.find((m) => m.id === selected);
|
|
831
|
+
console.log();
|
|
832
|
+
logSuccess(`\u9ED8\u8BA4\u4E3B\u529B\u6A21\u578B\u5DF2\u6210\u529F\u8BBE\u5B9A\u4E3A: ${pc5.bold(pc5.yellow(matched?.name || selected))}`);
|
|
833
|
+
console.log();
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// src/commands/run.ts
|
|
837
|
+
import pc6 from "picocolors";
|
|
838
|
+
|
|
839
|
+
// src/extension/monk-extension.ts
|
|
840
|
+
import fs4 from "fs";
|
|
841
|
+
import path4 from "path";
|
|
842
|
+
var PRO_TIPS = [
|
|
843
|
+
"\u5728\u8F93\u5165\u6846\u8F93\u5165 @diff \u5373\u53EF\u79D2\u7EA7\u628A\u5F53\u524D\u672A\u63D0\u4EA4\u6539\u52A8\u5E26\u5165\u5206\u6790",
|
|
844
|
+
"\u8F93\u5165 /commit \u53EF\u6309 Conventional Commits \u89C4\u8303\u81EA\u52A8\u751F\u6210\u4E2D\u6587\u63D0\u4EA4",
|
|
845
|
+
"AI \u6539\u4E71\u4E86\u4EE3\u7801\u4E0D\u7528\u614C\uFF0C\u968F\u65F6\u8F93\u5165 /undo \u6216 /\u56DE\u9000 \u77AC\u95F4\u4E00\u952E\u590D\u539F",
|
|
846
|
+
"\u8F93\u5165 /review \u53EF\u4ECE\u7F3A\u9677\u3001\u6027\u80FD\u3001\u67B6\u6784\u56DB\u4E2A\u7EF4\u5EA6\u5BF9\u4EE3\u7801\u8FDB\u884C\u6DF1\u5EA6\u5BA1\u67E5",
|
|
847
|
+
"\u8F93\u5165 /monk \u53EF\u547C\u51FA\u56FE\u5F62\u5316\u63A7\u5236\u53F0\uFF0C\u79D2\u7EA7\u514D\u91CD\u542F\u5207\u6362\u4E3B\u529B\u6A21\u578B",
|
|
848
|
+
"\u8F93\u5165 @recent \u5FEB\u901F\u63D0\u53D6\u6700\u8FD1\u53D8\u52A8\u7684\u9879\u76EE\u6838\u5FC3\u6E90\u6587\u4EF6\u5217\u8868",
|
|
849
|
+
"\u8F93\u5165 /monk cn \u968F\u65F6\u5207\u6362\u4E2D\u6587\u5DE5\u7A0B\u7CBE\u70BC\u6A21\u5F0F\uFF08\u96F6\u5BA2\u5957\xB7\u884C\u52A8\u4F18\u5148\uFF09",
|
|
850
|
+
"\u7EC8\u7AEF\u8F93\u5165 monk-pi -r \u53EF\u89C6\u5316\u6062\u590D\u4EE5\u5F80\u4EFB\u610F\u5386\u53F2\u4EFB\u52A1\u65AD\u70B9\u7EED\u5199"
|
|
851
|
+
];
|
|
852
|
+
|
|
853
|
+
// src/commands/run.ts
|
|
854
|
+
async function runCommand(passthroughArgs) {
|
|
855
|
+
const piCheck = detectPi();
|
|
856
|
+
if (!piCheck.installed) {
|
|
857
|
+
const shouldInstall = await promptInstallPi();
|
|
858
|
+
if (shouldInstall) {
|
|
859
|
+
const installed = await installPi();
|
|
860
|
+
if (!installed) {
|
|
861
|
+
logError("\u65E0\u6CD5\u81EA\u52A8\u5B89\u88C5 Pi\uFF0C\u8BF7\u624B\u52A8\u8FD0\u884C `npm install -g @earendil-works/pi-coding-agent` \u540E\u91CD\u8BD5\u3002");
|
|
862
|
+
return 1;
|
|
863
|
+
}
|
|
864
|
+
} else {
|
|
865
|
+
logWarn("\u5DF2\u53D6\u6D88\u8FD0\u884C\u3002Monk Harness \u9700\u8981 Pi \u4F5C\u4E3A\u8FD0\u884C\u5E95\u5EA7\u3002");
|
|
866
|
+
return 1;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
let { key } = resolveApiKey();
|
|
870
|
+
if (!key) {
|
|
871
|
+
logWarn("\u672A\u68C0\u6D4B\u5230 Monk API Key\uFF0C\u6B63\u5728\u4E3A\u60A8\u542F\u52A8\u9996\u6B21\u914D\u7F6E\u5F15\u5BFC...");
|
|
872
|
+
const ok = await loginCommand();
|
|
873
|
+
if (!ok) {
|
|
874
|
+
return 1;
|
|
875
|
+
}
|
|
876
|
+
const resolved = resolveApiKey();
|
|
877
|
+
key = resolved.key;
|
|
878
|
+
}
|
|
879
|
+
if (!key) {
|
|
880
|
+
logError("\u672A\u627E\u5230\u6709\u6548\u7684 Monk API Key\uFF0C\u9000\u51FA\u8FD0\u884C\u3002");
|
|
881
|
+
return 1;
|
|
882
|
+
}
|
|
883
|
+
syncPiModelsJson(key);
|
|
884
|
+
syncPiExtension();
|
|
885
|
+
const defaultModel = getDefaultModel();
|
|
886
|
+
if (!passthroughArgs.includes("-p") && !passthroughArgs.includes("--print")) {
|
|
887
|
+
const tip = PRO_TIPS[Math.floor(Math.random() * PRO_TIPS.length)];
|
|
888
|
+
console.log(` ${pc6.yellow("\u{1F4A1} \u6781\u5BA2\u5C0F\u8D34\u58EB:")} ${pc6.dim(tip)}`);
|
|
889
|
+
console.log();
|
|
890
|
+
}
|
|
891
|
+
return launchPi({
|
|
892
|
+
apiKey: key,
|
|
893
|
+
defaultModel,
|
|
894
|
+
passthroughArgs
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// src/commands/status.ts
|
|
899
|
+
import pc7 from "picocolors";
|
|
900
|
+
async function statusCommand() {
|
|
901
|
+
printBanner();
|
|
902
|
+
console.log(` ${pc7.bold("\u3010\u670D\u52A1\u4E0E\u73AF\u5883\u72B6\u6001\u68C0\u6D4B\u3011")}`);
|
|
903
|
+
console.log();
|
|
904
|
+
const piDetect = detectPi();
|
|
905
|
+
if (piDetect.installed) {
|
|
906
|
+
logSuccess(
|
|
907
|
+
`Pi \u8FD0\u884C\u73AF\u5883: ${pc7.bold("\u5DF2\u5C31\u7EEA")} (v${piDetect.version}) \xB7 ${pc7.dim(`[\u6765\u6E90: ${piDetect.description}]`)}`
|
|
908
|
+
);
|
|
909
|
+
} else {
|
|
910
|
+
logWarn(`Pi \u8FD0\u884C\u73AF\u5883: ${pc7.red("\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u8FD0\u884C\u65F6")}`);
|
|
911
|
+
console.log(` ${pc7.dim("\u8BF7\u8FD0\u884C npm install -g @earendil-works/pi-coding-agent")}`);
|
|
912
|
+
}
|
|
913
|
+
const { key, source } = resolveApiKey();
|
|
914
|
+
const defaultModel = getDefaultModel();
|
|
915
|
+
if (!key) {
|
|
916
|
+
logError(`Monk API Key: ${pc7.red("\u672A\u914D\u7F6E")}`);
|
|
917
|
+
console.log(` ${pc7.dim("\u8BF7\u8FD0\u884C `monk-pi login` \u8F93\u5165\u60A8\u7684 Key")}`);
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
const sourceLabels = {
|
|
921
|
+
env: "\u73AF\u5883\u53D8\u91CF ($MONK_API_KEY)",
|
|
922
|
+
local: `\u672C\u5730\u914D\u7F6E (${getMonkConfigFile()})`,
|
|
923
|
+
pi: `Pi \u914D\u7F6E\u6587\u4EF6 (${getPiModelsFile()})`,
|
|
924
|
+
none: "\u65E0"
|
|
925
|
+
};
|
|
926
|
+
logSuccess(`Monk API Key: ${pc7.bold(maskKey(key))} ${pc7.dim(`[\u6765\u6E90: ${sourceLabels[source]}]`)}`);
|
|
927
|
+
logInfo(`\u5F53\u524D\u9ED8\u8BA4\u4E3B\u529B\u6A21\u578B: ${pc7.yellow(defaultModel)}`);
|
|
928
|
+
logInfo(`Monk \u57FA\u7840\u5730\u5740: ${pc7.dim(MONK_BASE_URL)}`);
|
|
929
|
+
process.stdout.write(` ${pc7.dim("\u23F3 \u6B63\u5728\u6D4B\u8BD5 Monk API \u8FDE\u63A5\u4E0E\u8BA4\u8BC1...")} `);
|
|
930
|
+
const valResult = await validateApiKey(key);
|
|
931
|
+
if (valResult.valid) {
|
|
932
|
+
process.stdout.write("\r" + " ".repeat(50) + "\r");
|
|
933
|
+
logSuccess(
|
|
934
|
+
`Monk API \u8FDE\u63A5\u6B63\u5E38 ${pc7.dim("\xB7")} \u8BA4\u8BC1\u6709\u6548 ${pc7.dim("\xB7")} \u5EF6\u8FDF: ${pc7.green(`${valResult.latencyMs}ms`)}`
|
|
935
|
+
);
|
|
936
|
+
if (valResult.models.length > 0) {
|
|
937
|
+
logInfo(`\u652F\u6301\u7684\u6A21\u578B\u7AEF\u70B9: ${pc7.dim(valResult.models.join(" \xB7 "))}`);
|
|
938
|
+
}
|
|
939
|
+
} else {
|
|
940
|
+
process.stdout.write("\r" + " ".repeat(50) + "\r");
|
|
941
|
+
logError(`Monk API \u9A8C\u8BC1\u5F02\u5E38: ${valResult.error}`);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
process.stdout.write(` ${pc7.dim(`\u23F3 \u6B63\u5728\u5BF9 ${defaultModel} \u53D1\u8D77\u6781\u7B80\u63E1\u624B\u63A8\u6F14...`)} `);
|
|
945
|
+
const testRes = await testChatCompletion(key, defaultModel);
|
|
946
|
+
if (testRes.success) {
|
|
947
|
+
process.stdout.write("\r" + " ".repeat(50) + "\r");
|
|
948
|
+
logSuccess(
|
|
949
|
+
`\u63A8\u7406\u901A\u9053\u63E1\u624B\u6210\u529F ${pc7.dim("\xB7")} \u54CD\u5E94\u5EF6\u8FDF: ${pc7.green(`${testRes.latencyMs}ms`)}`
|
|
950
|
+
);
|
|
951
|
+
} else {
|
|
952
|
+
process.stdout.write("\r" + " ".repeat(50) + "\r");
|
|
953
|
+
logWarn(`\u63A8\u7406\u901A\u9053\u63E1\u624B\u8F7B\u5FAE\u544A\u8B66: ${testRes.error || "\u672A\u8FD4\u56DE\u5E38\u89C4\u5185\u5BB9"}`);
|
|
954
|
+
}
|
|
955
|
+
console.log();
|
|
956
|
+
console.log(pc7.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
957
|
+
console.log(` ${pc7.dim("\u5B98\u65B9\u7F51\u7AD9:")} ${pc7.cyan(MONK_WEBSITE)}`);
|
|
958
|
+
console.log(` ${pc7.dim("\u7528\u91CF\u4E0E\u5230\u671F\u67E5\u8BE2:")} ${pc7.cyan(MONK_ACCOUNT_URL)}`);
|
|
959
|
+
console.log();
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
export {
|
|
963
|
+
MONK_BASE_URL,
|
|
964
|
+
MONK_WEBSITE,
|
|
965
|
+
MONK_ACCOUNT_URL,
|
|
966
|
+
MONK_MODELS,
|
|
967
|
+
DEFAULT_MONK_MODEL,
|
|
968
|
+
getMonkHomeDir,
|
|
969
|
+
getMonkConfigFile,
|
|
970
|
+
getPiHomeDir,
|
|
971
|
+
getPiModelsFile,
|
|
972
|
+
getPiSettingsFile,
|
|
973
|
+
getPiExtensionsDir,
|
|
974
|
+
getPiMonkExtensionFile,
|
|
975
|
+
loadMonkConfig,
|
|
976
|
+
saveMonkConfig,
|
|
977
|
+
resolveApiKey,
|
|
978
|
+
syncPiModelsJson,
|
|
979
|
+
getMonkExtensionRaw,
|
|
980
|
+
syncPiExtension,
|
|
981
|
+
getDefaultModel,
|
|
982
|
+
validateApiKey,
|
|
983
|
+
testChatCompletion,
|
|
984
|
+
openBrowser,
|
|
985
|
+
printBanner,
|
|
986
|
+
logSuccess,
|
|
987
|
+
logInfo,
|
|
988
|
+
logWarn,
|
|
989
|
+
logError,
|
|
990
|
+
logStep,
|
|
991
|
+
promptForApiKey,
|
|
992
|
+
promptSelectModel,
|
|
993
|
+
promptInstallPi,
|
|
994
|
+
maskKey,
|
|
995
|
+
resolvePiBinary,
|
|
996
|
+
detectPi,
|
|
997
|
+
detectPackageManager,
|
|
998
|
+
installPi,
|
|
999
|
+
launchPi,
|
|
1000
|
+
doctorCommand,
|
|
1001
|
+
loginCommand,
|
|
1002
|
+
modelCommand,
|
|
1003
|
+
runCommand,
|
|
1004
|
+
statusCommand
|
|
1005
|
+
};
|