saycoder 0.1.1 → 0.1.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/README.md CHANGED
@@ -6,7 +6,7 @@ A small CLI that configures OpenCode to use SayCoder as the model layer, plus pr
6
6
 
7
7
  1. Checks whether `opencode` is installed.
8
8
  2. If missing, asks whether to install it with `npm install -g opencode-ai --foreground-scripts`.
9
- 3. Optionally enables China mirror optimization, measures available mirrors, and lets the user choose with arrow keys.
9
+ 3. Optionally enables China mirror optimization, measures available mirrors, and lets the user choose with arrow keys or number input on Windows.
10
10
  4. Installs OpenCode and verifies `opencode --version` before continuing.
11
11
  5. Prompts the user for a SayCoder API key.
12
12
  6. Validates the key with `GET https://jstapi.xinbai.icu/v1/models`.
package/bin/saycoder.js CHANGED
@@ -200,13 +200,32 @@ function renderMirrorChoices(mirrors, selected) {
200
200
  });
201
201
  }
202
202
 
203
+ async function selectMirrorByNumber(mirrors) {
204
+ console.log(color.blue("选择 npm 镜像源"));
205
+ console.log(color.dim("输入序号并回车。\n"));
206
+
207
+ mirrors.forEach((mirror, index) => {
208
+ const latency = mirror.ok ? color.green(formatLatency(mirror.latency)) : color.red("不可用");
209
+ console.log(`${index + 1}. ${mirror.name} ${latency} ${color.dim(mirror.url)}`);
210
+ });
211
+
212
+ while (true) {
213
+ const answer = await prompt("请选择镜像序号: ");
214
+ const selected = Number.parseInt(answer, 10) - 1;
215
+ if (mirrors[selected]?.ok) return mirrors[selected];
216
+ warn("请输入可用镜像的序号。");
217
+ }
218
+ }
219
+
203
220
  async function selectMirror(mirrors) {
204
221
  const available = mirrors.filter((mirror) => mirror.ok);
205
222
  if (available.length === 0) throw new Error("No npm mirror is reachable. Please retry later or use the default npm registry.");
206
223
  if (!input.isTTY || !output.isTTY) return available[0];
224
+ if (process.platform === "win32" || typeof input.setRawMode !== "function") return await selectMirrorByNumber(available);
207
225
 
208
226
  let selected = 0;
209
227
  emitKeypressEvents(input);
228
+ input.resume();
210
229
  input.setRawMode(true);
211
230
  renderMirrorChoices(available, selected);
212
231
 
@@ -216,12 +235,14 @@ async function selectMirror(mirrors) {
216
235
  else if (key.name === "down") selected = (selected + 1) % available.length;
217
236
  else if (key.name === "return") {
218
237
  input.setRawMode(false);
238
+ input.pause();
219
239
  input.off("keypress", onKeypress);
220
240
  console.log(`\nSelected: ${available[selected].name} (${available[selected].url})`);
221
241
  resolve(available[selected]);
222
242
  return;
223
243
  } else if (key.ctrl && key.name === "c") {
224
244
  input.setRawMode(false);
245
+ input.pause();
225
246
  process.exit(130);
226
247
  }
227
248
  renderMirrorChoices(available, selected);
@@ -529,12 +550,13 @@ async function setup(flags) {
529
550
  console.log(color.green("\n模型选择中意模型,即可开始编程了!\n"));
530
551
  }
531
552
 
532
- const flags = parseArgs(process.argv.slice(2));
533
-
534
- try {
553
+ async function main() {
554
+ const flags = parseArgs(process.argv.slice(2));
535
555
  if (flags.command === "setup") await setup(flags);
536
556
  else usage();
537
- } catch (error) {
557
+ }
558
+
559
+ main().catch((error) => {
538
560
  console.error(color.red(`saycoder: ${error.message}`));
539
561
  process.exitCode = 1;
540
- }
562
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saycoder",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "SayCoder setup helper for OpenCode models, MCP servers, and skills.",
5
5
  "type": "module",
6
6
  "bin": {