monk-pi 0.2.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.
@@ -55,207 +55,8 @@ function getPiMonkExtensionFile() {
55
55
 
56
56
  // src/config.ts
57
57
  import fs from "fs";
58
-
59
- // src/extension/code.ts
60
- var MONK_EXTENSION_CODE = `// @monk-managed-pi-extension
61
- // Monk \xD7 Pi Native Extension
62
- // Features: Footer status, /monk slash command, and context overflow auto-compaction
63
-
64
- const MONK_MODELS = [
65
- { id: "monk-coding", label: "monk-coding (\u4EE3\u7801\u4E3B\u529B - \u63A8\u8350 \xB7 \u6DF1\u5EA6\u5DE5\u5177\u8C03\u7528)" },
66
- { id: "monk-fast", label: "monk-fast (\u6781\u901F\u63A8\u7406 \xB7 \u5FEB\u901F\u95EE\u7B54\u4E0E\u8F7B\u91CF\u4EFB\u52A1)" },
67
- { id: "monk", label: "monk (\u878D\u5408\u65D7\u8230 \xB7 \u8D28\u91CF\u4F18\u5148\u4E0E\u7EFC\u5408\u63A8\u7406)" },
68
- ];
69
-
70
- const OVERFLOW_PATTERNS = [
71
- /context.*length/i,
72
- /maximum.*tokens/i,
73
- /token.*limit/i,
74
- /too many tokens/i,
75
- /prompt.*too long/i,
76
- /request.*too large/i,
77
- /context_window_exceeded/i,
78
- /exceed.*context/i,
79
- ];
80
-
81
- export default function monkExtension(pi) {
82
- let turnCount = 0;
83
-
84
- function updateStatus(ctx) {
85
- if (!ctx.ui) return;
86
- const model = ctx.model;
87
- const isMonk = model && model.provider === "monk";
88
-
89
- if (!isMonk) {
90
- ctx.ui.setStatus("monk", undefined);
91
- return;
92
- }
93
-
94
- const theme = ctx.ui.theme;
95
- const indicator = theme.fg("success", "\u25CF");
96
- const label = theme.fg("accent", \`Monk: \${model.id}\`);
97
- const meta = theme.fg("dim", " (1M ctx)");
98
- ctx.ui.setStatus("monk", \`\${indicator} \${label}\${meta}\`);
99
- }
100
-
101
- // 1. Lifecycle Events: update footer status
102
- pi.on("session_start", async (_event, ctx) => {
103
- updateStatus(ctx);
104
- });
105
-
106
- pi.on("model_select", async (_event, ctx) => {
107
- updateStatus(ctx);
108
- });
109
-
110
- pi.on("turn_start", async (_event, ctx) => {
111
- turnCount++;
112
- if (!ctx.ui) return;
113
- const model = ctx.model;
114
- if (model && model.provider === "monk") {
115
- const theme = ctx.ui.theme;
116
- const spinner = theme.fg("warning", "\u25B2");
117
- const label = theme.fg("accent", \`Monk: \${model.id}\`);
118
- const text = theme.fg("dim", \` [Turn \${turnCount}]\`);
119
- ctx.ui.setStatus("monk", \`\${spinner} \${label}\${text}\`);
120
- }
121
- });
122
-
123
- pi.on("turn_end", async (_event, ctx) => {
124
- updateStatus(ctx);
125
- });
126
-
127
- // 2. Intelligent Context Overflow & Compaction Recovery
128
- pi.on("message_end", async (event, ctx) => {
129
- const message = event.message;
130
- if (!message || message.role !== "assistant") return;
131
- if (message.stopReason !== "error") return;
132
-
133
- const isMonk = message.provider === "monk" || (ctx.model && ctx.model.provider === "monk");
134
- if (!isMonk) return;
135
-
136
- const errorMsg = message.errorMessage || "";
137
- if (errorMsg.includes("context_length_exceeded")) return;
138
-
139
- const isOverflow = OVERFLOW_PATTERNS.some((p) => p.test(errorMsg));
140
- if (isOverflow) {
141
- ctx.ui && ctx.ui.notify(
142
- "Monk: \u68C0\u6D4B\u5230\u4E0A\u4E0B\u6587\u8D85\u957F\uFF0C\u5DF2\u81EA\u52A8\u91CD\u5199\u9519\u8BEF\u5E76\u89E6\u53D1\u667A\u80FD\u538B\u7F29 (Compaction) \u91CD\u8BD5...",
143
- "warning"
144
- );
145
- return {
146
- message: {
147
- ...message,
148
- errorMessage: \`context_length_exceeded: \${errorMsg}\`,
149
- },
150
- };
151
- }
152
- });
153
-
154
- // 3. Custom Slash Command: /monk
155
- pi.registerCommand("monk", {
156
- description: "Monk \u4E13\u5C5E\u63A7\u5236\u53F0 (/monk [model|ping|status|account])",
157
- handler: async (args, ctx) => {
158
- const sub = (args || "").trim().toLowerCase();
159
-
160
- if (sub === "model" || sub === "switch") {
161
- await handleModelSwitch(pi, ctx);
162
- return;
163
- }
164
-
165
- if (sub === "ping" || sub === "status") {
166
- await handlePing(ctx);
167
- return;
168
- }
169
-
170
- if (sub === "account" || sub === "quota") {
171
- ctx.ui && ctx.ui.notify("Monk \u7528\u91CF\u4E0E\u5230\u671F\u67E5\u8BE2: https://monk.party/account/", "info");
172
- return;
173
- }
174
-
175
- // Default: interactive menu
176
- await handleMenu(pi, ctx);
177
- },
178
- });
179
- }
180
-
181
- async function handleModelSwitch(pi, ctx) {
182
- if (!ctx.ui) return;
183
-
184
- const choices = MONK_MODELS.map((m) => m.label);
185
- const selectedLabel = await ctx.ui.select("\u9009\u62E9\u5F53\u524D\u4F1A\u8BDD\u7684 Monk \u6A21\u578B:", choices);
186
-
187
- if (!selectedLabel) return;
188
-
189
- const matched = MONK_MODELS.find((m) => m.label === selectedLabel);
190
- if (!matched) return;
191
-
192
- const model = ctx.modelRegistry.find("monk", matched.id);
193
- if (!model) {
194
- ctx.ui.notify(\`\u672A\u5728\u914D\u7F6E\u4E2D\u627E\u5230\u6A21\u578B: monk/\${matched.id}\`, "error");
195
- return;
196
- }
197
-
198
- const success = await pi.setModel(model);
199
- if (success) {
200
- ctx.ui.notify(\`\u4E3B\u529B\u6A21\u578B\u5DF2\u5207\u6362\u81F3: \${matched.id}\`, "info");
201
- } else {
202
- ctx.ui.notify(\`\u5207\u6362\u5931\u8D25\uFF0C\u672A\u80FD\u8BBE\u7F6E\u6A21\u578B: \${matched.id}\`, "error");
203
- }
204
- }
205
-
206
- async function handlePing(ctx) {
207
- if (!ctx.ui) return;
208
-
209
- const startTime = Date.now();
210
- const apiKey = process.env.MONK_API_KEY || "";
211
-
212
- try {
213
- const controller = new AbortController();
214
- const timeout = setTimeout(() => controller.abort(), 6000);
215
-
216
- const res = await fetch("https://monk.party/v1/models", {
217
- headers: { Authorization: \`Bearer \${apiKey}\` },
218
- signal: controller.signal,
219
- });
220
-
221
- clearTimeout(timeout);
222
- const latency = Date.now() - startTime;
223
-
224
- if (res.ok) {
225
- ctx.ui.notify(\`Monk API \u8FDE\u901A\u6B63\u5E38 \xB7 \u5EF6\u8FDF \${latency}ms\`, "info");
226
- } else {
227
- ctx.ui.notify(\`Monk API \u54CD\u5E94\u5F02\u5E38 (HTTP \${res.status})\`, "warning");
228
- }
229
- } catch (err) {
230
- ctx.ui.notify(
231
- \`Monk API \u8FDE\u63A5\u5931\u8D25: \${err instanceof Error ? err.message : String(err)}\`,
232
- "error"
233
- );
234
- }
235
- }
236
-
237
- async function handleMenu(pi, ctx) {
238
- if (!ctx.ui) return;
239
-
240
- const choice = await ctx.ui.select("Monk API \u63A7\u5236\u53F0", [
241
- "1. \u5207\u6362\u4F1A\u8BDD\u6A21\u578B (Switch Model)",
242
- "2. \u63A2\u6D4B\u7F51\u7EDC\u5EF6\u8FDF (Ping API)",
243
- "3. \u67E5\u8BE2\u7528\u91CF\u4E0E\u5230\u671F\u65F6\u95F4 (Account Info)",
244
- ]);
245
-
246
- if (!choice) return;
247
-
248
- if (choice.startsWith("1")) {
249
- await handleModelSwitch(pi, ctx);
250
- } else if (choice.startsWith("2")) {
251
- await handlePing(ctx);
252
- } else if (choice.startsWith("3")) {
253
- ctx.ui.notify("\u8BF7\u5728\u6D4F\u89C8\u5668\u6253\u5F00 https://monk.party/account/ \u67E5\u770B\u7528\u91CF\u4E0E\u5269\u4F59\u5929\u6570", "info");
254
- }
255
- }
256
- `;
257
-
258
- // src/config.ts
58
+ import path2 from "path";
59
+ import { fileURLToPath } from "url";
259
60
  function loadMonkConfig() {
260
61
  const configFile = getMonkConfigFile();
261
62
  try {
@@ -354,19 +155,59 @@ function syncPiModelsJson(apiKey) {
354
155
  };
355
156
  }
356
157
  }
357
- function syncPiExtension() {
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) {
358
183
  const extDir = getPiExtensionsDir();
359
184
  const extFile = getPiMonkExtensionFile();
360
185
  try {
361
186
  if (!fs.existsSync(extDir)) {
362
187
  fs.mkdirSync(extDir, { recursive: true });
363
188
  }
364
- fs.writeFileSync(extFile, MONK_EXTENSION_CODE.trim() + "\n", "utf-8");
365
- return { success: true, path: extFile };
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 };
366
206
  } catch (err) {
367
207
  return {
368
208
  success: false,
369
209
  path: extFile,
210
+ updated: false,
370
211
  error: err instanceof Error ? err.message : String(err)
371
212
  };
372
213
  }
@@ -443,12 +284,27 @@ async function validateApiKey(apiKey, baseUrl = MONK_BASE_URL) {
443
284
  };
444
285
  }
445
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
+ }
446
302
  async function testChatCompletion(apiKey, model = "monk-fast", baseUrl = MONK_BASE_URL) {
447
303
  const endpoint = `${baseUrl.replace(/\/+$/, "")}/chat/completions`;
448
304
  const startTime = Date.now();
449
305
  try {
450
306
  const controller = new AbortController();
451
- const timeoutId = setTimeout(() => controller.abort(), 12e3);
307
+ const timeoutId = setTimeout(() => controller.abort(), 3e4);
452
308
  const response = await fetch(endpoint, {
453
309
  method: "POST",
454
310
  headers: {
@@ -465,16 +321,15 @@ async function testChatCompletion(apiKey, model = "monk-fast", baseUrl = MONK_BA
465
321
  });
466
322
  clearTimeout(timeoutId);
467
323
  const latencyMs = Date.now() - startTime;
324
+ const payload = extractFirstJson(await response.text());
468
325
  if (!response.ok) {
469
- const errJson = await response.json().catch(() => ({}));
470
326
  return {
471
327
  success: false,
472
328
  latencyMs,
473
- error: errJson.error?.message || `HTTP ${response.status}`
329
+ error: payload.error?.message || `HTTP ${response.status}`
474
330
  };
475
331
  }
476
- const json = await response.json().catch(() => ({}));
477
- const reply = json.choices?.[0]?.message?.content?.trim() || "";
332
+ const reply = (payload.choices?.[0]?.message?.content ?? "").trim();
478
333
  return {
479
334
  success: true,
480
335
  latencyMs,
@@ -491,8 +346,25 @@ async function testChatCompletion(apiKey, model = "monk-fast", baseUrl = MONK_BA
491
346
  }
492
347
 
493
348
  // src/ui.ts
349
+ import spawn from "cross-spawn";
494
350
  import pc from "picocolors";
495
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
+ }
496
368
  function printBanner() {
497
369
  const line = pc.dim("\u2500".repeat(54));
498
370
  console.log();
@@ -526,11 +398,62 @@ function logStep(step, total, msg) {
526
398
  async function promptForApiKey(currentKey) {
527
399
  console.log();
528
400
  console.log(` ${pc.bold("\u6B22\u8FCE\u4F7F\u7528 Monk \xD7 Pi \u7F16\u7801\u4F34\u4FA3\uFF01")}`);
529
- console.log(` ${pc.dim("Monk \u4E13\u4E3A Agent \u63D0\u4F9B\u9AD8\u5E76\u53D1\u6781\u901F\u878D\u5408\u6A21\u578B\u3002\u8BF7\u914D\u7F6E\u60A8\u7684 API Key\u3002")}`);
530
- console.log(` ${pc.dim("\u8FD8\u6CA1\u6709 Key\uFF1F\u53EF\u4EE5\u5728")} ${pc.underline(pc.yellow(MONK_WEBSITE))} ${pc.dim("\u8BA2\u9605\u6708\u5361 (\xA530/\u6708)")}`);
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
+ );
531
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
+ }
532
455
  const key = await password({
533
- message: currentKey ? `\u8BF7\u8F93\u5165 Monk API Key (\u76F4\u63A5\u56DE\u8F66\u4FDD\u6301\u5F53\u524D: ${maskKey(currentKey)}):` : "\u8BF7\u8F93\u5165 Monk API Key (\u683C\u5F0F sk-monk-...):",
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-...):",
534
457
  mask: "*",
535
458
  validate: (val) => {
536
459
  const trimmed = val.trim();
@@ -574,13 +497,13 @@ function maskKey(key) {
574
497
 
575
498
  // src/pi-runner.ts
576
499
  import fs2 from "fs";
577
- import path2 from "path";
578
- import { fileURLToPath } from "url";
579
- import spawn from "cross-spawn";
500
+ import path3 from "path";
501
+ import { fileURLToPath as fileURLToPath2 } from "url";
502
+ import spawn2 from "cross-spawn";
580
503
  import pc2 from "picocolors";
581
504
  function resolvePiBinary() {
582
505
  try {
583
- const globalCheck = spawn.sync("pi", ["--version"], {
506
+ const globalCheck = spawn2.sync("pi", ["--version"], {
584
507
  encoding: "utf-8",
585
508
  stdio: ["ignore", "pipe", "ignore"]
586
509
  });
@@ -596,13 +519,13 @@ function resolvePiBinary() {
596
519
  } catch {
597
520
  }
598
521
  const candidateBinDirs = [
599
- path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "../node_modules/.bin/pi"),
600
- path2.resolve(process.cwd(), "node_modules/.bin/pi")
522
+ path3.resolve(path3.dirname(fileURLToPath2(import.meta.url)), "../node_modules/.bin/pi"),
523
+ path3.resolve(process.cwd(), "node_modules/.bin/pi")
601
524
  ];
602
525
  for (const binPath of candidateBinDirs) {
603
526
  if (fs2.existsSync(binPath)) {
604
527
  try {
605
- const localCheck = spawn.sync(binPath, ["--version"], {
528
+ const localCheck = spawn2.sync(binPath, ["--version"], {
606
529
  encoding: "utf-8",
607
530
  stdio: ["ignore", "pipe", "ignore"]
608
531
  });
@@ -612,7 +535,7 @@ function resolvePiBinary() {
612
535
  command: binPath,
613
536
  argsPrefix: [],
614
537
  version: localCheck.stdout.trim(),
615
- sourceDescription: `\u672C\u5730\u4F9D\u8D56 (${path2.basename(path2.dirname(binPath))})`
538
+ sourceDescription: `\u672C\u5730\u4F9D\u8D56 (${path3.basename(path3.dirname(binPath))})`
616
539
  };
617
540
  }
618
541
  } catch {
@@ -620,10 +543,10 @@ function resolvePiBinary() {
620
543
  }
621
544
  }
622
545
  try {
623
- const mainEntry = fileURLToPath(import.meta.resolve("@earendil-works/pi-coding-agent"));
624
- const cliEntry = path2.join(path2.dirname(mainEntry), "bundle", "cli.js");
546
+ const mainEntry = fileURLToPath2(import.meta.resolve("@earendil-works/pi-coding-agent"));
547
+ const cliEntry = path3.join(path3.dirname(mainEntry), "bundle", "cli.js");
625
548
  if (fs2.existsSync(cliEntry)) {
626
- const moduleCheck = spawn.sync(process.execPath, [cliEntry, "--version"], {
549
+ const moduleCheck = spawn2.sync(process.execPath, [cliEntry, "--version"], {
627
550
  encoding: "utf-8",
628
551
  stdio: ["ignore", "pipe", "ignore"]
629
552
  });
@@ -657,12 +580,12 @@ function detectPi() {
657
580
  }
658
581
  function detectPackageManager() {
659
582
  try {
660
- const bunCheck = spawn.sync("bun", ["--version"], { stdio: "ignore" });
583
+ const bunCheck = spawn2.sync("bun", ["--version"], { stdio: "ignore" });
661
584
  if (bunCheck.status === 0) return "bun";
662
585
  } catch {
663
586
  }
664
587
  try {
665
- const pnpmCheck = spawn.sync("pnpm", ["--version"], { stdio: "ignore" });
588
+ const pnpmCheck = spawn2.sync("pnpm", ["--version"], { stdio: "ignore" });
666
589
  if (pnpmCheck.status === 0) return "pnpm";
667
590
  } catch {
668
591
  }
@@ -681,7 +604,7 @@ async function installPi() {
681
604
  }
682
605
  logInfo(`\u68C0\u6D4B\u5230\u5305\u7BA1\u7406\u5668: ${pc2.bold(pm)}\uFF0C\u6B63\u5728\u6267\u884C: ${pc2.yellow(`${cmd} ${args.join(" ")}`)} ...`);
683
606
  try {
684
- const child = spawn.sync(cmd, args, {
607
+ const child = spawn2.sync(cmd, args, {
685
608
  stdio: "inherit"
686
609
  });
687
610
  if (child.status === 0) {
@@ -720,7 +643,7 @@ function launchPi(options) {
720
643
  ...process.env,
721
644
  MONK_API_KEY: apiKey
722
645
  };
723
- const child = spawn(resolved.command, fullArgs, {
646
+ const child = spawn2(resolved.command, fullArgs, {
724
647
  stdio: "inherit",
725
648
  env
726
649
  });
@@ -807,17 +730,19 @@ async function doctorCommand() {
807
730
  syncPiModelsJson(key);
808
731
  logSuccess(`Pi \u914D\u7F6E\u6587\u4EF6: \u521B\u5EFA\u5B8C\u6210`);
809
732
  }
810
- const extFile = getPiMonkExtensionFile();
811
- if (fs3.existsSync(extFile)) {
812
- logSuccess(`Pi \u539F\u751F\u6269\u5C55: ${pc3.bold("\u5DF2\u5B89\u88C5")} (/monk \u6307\u4EE4\u3001\u72B6\u6001\u680F\u4E0E\u6EA2\u51FA\u81EA\u52A8\u91CD\u8BD5\u5C31\u7EEA)`);
813
- } else {
814
- logWarn(`Pi \u539F\u751F\u6269\u5C55: \u672A\u5B89\u88C5\uFF0C\u6B63\u5728\u4E3A\u60A8\u81EA\u52A8\u90E8\u7F72...`);
815
- const extRes = syncPiExtension();
816
- if (extRes.success) {
817
- logSuccess(`Pi \u539F\u751F\u6269\u5C55: \u90E8\u7F72\u5B8C\u6210`);
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
+ );
818
739
  } else {
819
- logError(`Pi \u539F\u751F\u6269\u5C55\u90E8\u7F72\u5931\u8D25: ${extRes.error}`);
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
+ );
820
743
  }
744
+ } else {
745
+ logError(`Pi \u539F\u751F\u6269\u5C55\u90E8\u7F72\u5931\u8D25: ${extRes.error}`);
821
746
  }
822
747
  if (key) {
823
748
  process.stdout.write(` ${pc3.dim("\u23F3 \u6B63\u5728\u63A2\u6D4B\u4E0E monk.party \u63A5\u53E3\u7684\u8FDE\u901A\u6027...")} `);
@@ -908,6 +833,23 @@ async function modelCommand(targetModel) {
908
833
  console.log();
909
834
  }
910
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
+
911
853
  // src/commands/run.ts
912
854
  async function runCommand(passthroughArgs) {
913
855
  const piCheck = detectPi();
@@ -941,6 +883,11 @@ async function runCommand(passthroughArgs) {
941
883
  syncPiModelsJson(key);
942
884
  syncPiExtension();
943
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
+ }
944
891
  return launchPi({
945
892
  apiKey: key,
946
893
  defaultModel,
@@ -949,25 +896,25 @@ async function runCommand(passthroughArgs) {
949
896
  }
950
897
 
951
898
  // src/commands/status.ts
952
- import pc6 from "picocolors";
899
+ import pc7 from "picocolors";
953
900
  async function statusCommand() {
954
901
  printBanner();
955
- console.log(` ${pc6.bold("\u3010\u670D\u52A1\u4E0E\u73AF\u5883\u72B6\u6001\u68C0\u6D4B\u3011")}`);
902
+ console.log(` ${pc7.bold("\u3010\u670D\u52A1\u4E0E\u73AF\u5883\u72B6\u6001\u68C0\u6D4B\u3011")}`);
956
903
  console.log();
957
904
  const piDetect = detectPi();
958
905
  if (piDetect.installed) {
959
906
  logSuccess(
960
- `Pi \u8FD0\u884C\u73AF\u5883: ${pc6.bold("\u5DF2\u5C31\u7EEA")} (v${piDetect.version}) \xB7 ${pc6.dim(`[\u6765\u6E90: ${piDetect.description}]`)}`
907
+ `Pi \u8FD0\u884C\u73AF\u5883: ${pc7.bold("\u5DF2\u5C31\u7EEA")} (v${piDetect.version}) \xB7 ${pc7.dim(`[\u6765\u6E90: ${piDetect.description}]`)}`
961
908
  );
962
909
  } else {
963
- logWarn(`Pi \u8FD0\u884C\u73AF\u5883: ${pc6.red("\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u8FD0\u884C\u65F6")}`);
964
- console.log(` ${pc6.dim("\u8BF7\u8FD0\u884C npm install -g @earendil-works/pi-coding-agent")}`);
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")}`);
965
912
  }
966
913
  const { key, source } = resolveApiKey();
967
914
  const defaultModel = getDefaultModel();
968
915
  if (!key) {
969
- logError(`Monk API Key: ${pc6.red("\u672A\u914D\u7F6E")}`);
970
- console.log(` ${pc6.dim("\u8BF7\u8FD0\u884C `monk-pi login` \u8F93\u5165\u60A8\u7684 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")}`);
971
918
  return;
972
919
  }
973
920
  const sourceLabels = {
@@ -976,39 +923,39 @@ async function statusCommand() {
976
923
  pi: `Pi \u914D\u7F6E\u6587\u4EF6 (${getPiModelsFile()})`,
977
924
  none: "\u65E0"
978
925
  };
979
- logSuccess(`Monk API Key: ${pc6.bold(maskKey(key))} ${pc6.dim(`[\u6765\u6E90: ${sourceLabels[source]}]`)}`);
980
- logInfo(`\u5F53\u524D\u9ED8\u8BA4\u4E3B\u529B\u6A21\u578B: ${pc6.yellow(defaultModel)}`);
981
- logInfo(`Monk \u57FA\u7840\u5730\u5740: ${pc6.dim(MONK_BASE_URL)}`);
982
- process.stdout.write(` ${pc6.dim("\u23F3 \u6B63\u5728\u6D4B\u8BD5 Monk API \u8FDE\u63A5\u4E0E\u8BA4\u8BC1...")} `);
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...")} `);
983
930
  const valResult = await validateApiKey(key);
984
931
  if (valResult.valid) {
985
932
  process.stdout.write("\r" + " ".repeat(50) + "\r");
986
933
  logSuccess(
987
- `Monk API \u8FDE\u63A5\u6B63\u5E38 ${pc6.dim("\xB7")} \u8BA4\u8BC1\u6709\u6548 ${pc6.dim("\xB7")} \u5EF6\u8FDF: ${pc6.green(`${valResult.latencyMs}ms`)}`
934
+ `Monk API \u8FDE\u63A5\u6B63\u5E38 ${pc7.dim("\xB7")} \u8BA4\u8BC1\u6709\u6548 ${pc7.dim("\xB7")} \u5EF6\u8FDF: ${pc7.green(`${valResult.latencyMs}ms`)}`
988
935
  );
989
936
  if (valResult.models.length > 0) {
990
- logInfo(`\u652F\u6301\u7684\u6A21\u578B\u7AEF\u70B9: ${pc6.dim(valResult.models.join(" \xB7 "))}`);
937
+ logInfo(`\u652F\u6301\u7684\u6A21\u578B\u7AEF\u70B9: ${pc7.dim(valResult.models.join(" \xB7 "))}`);
991
938
  }
992
939
  } else {
993
940
  process.stdout.write("\r" + " ".repeat(50) + "\r");
994
941
  logError(`Monk API \u9A8C\u8BC1\u5F02\u5E38: ${valResult.error}`);
995
942
  return;
996
943
  }
997
- process.stdout.write(` ${pc6.dim(`\u23F3 \u6B63\u5728\u5BF9 ${defaultModel} \u53D1\u8D77\u6781\u7B80\u63E1\u624B\u63A8\u6F14...`)} `);
944
+ process.stdout.write(` ${pc7.dim(`\u23F3 \u6B63\u5728\u5BF9 ${defaultModel} \u53D1\u8D77\u6781\u7B80\u63E1\u624B\u63A8\u6F14...`)} `);
998
945
  const testRes = await testChatCompletion(key, defaultModel);
999
946
  if (testRes.success) {
1000
947
  process.stdout.write("\r" + " ".repeat(50) + "\r");
1001
948
  logSuccess(
1002
- `\u63A8\u7406\u901A\u9053\u63E1\u624B\u6210\u529F ${pc6.dim("\xB7")} \u54CD\u5E94\u5EF6\u8FDF: ${pc6.green(`${testRes.latencyMs}ms`)}`
949
+ `\u63A8\u7406\u901A\u9053\u63E1\u624B\u6210\u529F ${pc7.dim("\xB7")} \u54CD\u5E94\u5EF6\u8FDF: ${pc7.green(`${testRes.latencyMs}ms`)}`
1003
950
  );
1004
951
  } else {
1005
952
  process.stdout.write("\r" + " ".repeat(50) + "\r");
1006
953
  logWarn(`\u63A8\u7406\u901A\u9053\u63E1\u624B\u8F7B\u5FAE\u544A\u8B66: ${testRes.error || "\u672A\u8FD4\u56DE\u5E38\u89C4\u5185\u5BB9"}`);
1007
954
  }
1008
955
  console.log();
1009
- console.log(pc6.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"));
1010
- console.log(` ${pc6.dim("\u5B98\u65B9\u7F51\u7AD9:")} ${pc6.cyan(MONK_WEBSITE)}`);
1011
- console.log(` ${pc6.dim("\u7528\u91CF\u4E0E\u5230\u671F\u67E5\u8BE2:")} ${pc6.cyan(MONK_ACCOUNT_URL)}`);
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)}`);
1012
959
  console.log();
1013
960
  }
1014
961
 
@@ -1029,10 +976,12 @@ export {
1029
976
  saveMonkConfig,
1030
977
  resolveApiKey,
1031
978
  syncPiModelsJson,
979
+ getMonkExtensionRaw,
1032
980
  syncPiExtension,
1033
981
  getDefaultModel,
1034
982
  validateApiKey,
1035
983
  testChatCompletion,
984
+ openBrowser,
1036
985
  printBanner,
1037
986
  logSuccess,
1038
987
  logInfo,