@fanchaozz/provider-manager 0.2.1 → 0.2.3
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/commands.ts +6 -4
- package/package.json +47 -47
- package/ui.ts +18 -10
package/commands.ts
CHANGED
|
@@ -259,7 +259,8 @@ async function testCommand(ctx: ExtensionCommandContext, arg: string): Promise<v
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
const result = await testModel({ ctx: ctx as any, provider, model, mode: "full" });
|
|
262
|
-
|
|
262
|
+
// 同步 dashboard:测试结果统一 info(showStatus 可覆盖),失败语义靠文本 ✗ fail 前缀表达
|
|
263
|
+
ctx.ui.notify(formatTestResult(result), "info");
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
/** 批量测某 provider 全部 model;无参数时取第一个 provider。 */
|
|
@@ -295,7 +296,8 @@ async function testAllCommand(ctx: ExtensionCommandContext, providerId: string |
|
|
|
295
296
|
mode: "full",
|
|
296
297
|
concurrency: 3,
|
|
297
298
|
});
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
299
|
+
// 批量结果拼成一条 notify:逐条 notify 会被 showStatus 原地覆盖,只残留最后一条
|
|
300
|
+
const okCount = results.filter((r) => r.ok).length;
|
|
301
|
+
const summary = results.map((r) => formatTestResult(r)).join("\n\n") + `\n${provider}: ${okCount}/${results.length} ok`;
|
|
302
|
+
ctx.ui.notify(summary, "info");
|
|
301
303
|
}
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fanchaozz/provider-manager",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "A pi extension that manages custom providers and models in ~/.pi/agent/models.json via a TUI dashboard, /providers slash command, and remote model sync.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "index.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"*.ts",
|
|
9
|
-
"README.md",
|
|
10
|
-
"README_EN.md"
|
|
11
|
-
],
|
|
12
|
-
"keywords": [
|
|
13
|
-
"pi-package",
|
|
14
|
-
"pi-extension",
|
|
15
|
-
"provider",
|
|
16
|
-
"model",
|
|
17
|
-
"ai"
|
|
18
|
-
],
|
|
19
|
-
"pi": {
|
|
20
|
-
"extensions": [
|
|
21
|
-
"./"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
"license": "MIT",
|
|
25
|
-
"author": "fanchaozz <fanchaozz@users.noreply.github.com>",
|
|
26
|
-
"homepage": "https://github.com/fanchaozz/provider-manager#readme",
|
|
27
|
-
"repository": {
|
|
28
|
-
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/fanchaozz/provider-manager.git"
|
|
30
|
-
},
|
|
31
|
-
"bugs": {
|
|
32
|
-
"url": "https://github.com/fanchaozz/provider-manager/issues"
|
|
33
|
-
},
|
|
34
|
-
"engines": {
|
|
35
|
-
"node": ">=20"
|
|
36
|
-
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"test": "for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done",
|
|
42
|
-
"ci:test": "npm install --no-save @earendil-works/pi-coding-agent && for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done"
|
|
43
|
-
},
|
|
44
|
-
"publishConfig": {
|
|
45
|
-
"access": "public"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fanchaozz/provider-manager",
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "A pi extension that manages custom providers and models in ~/.pi/agent/models.json via a TUI dashboard, /providers slash command, and remote model sync.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"*.ts",
|
|
9
|
+
"README.md",
|
|
10
|
+
"README_EN.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"pi-package",
|
|
14
|
+
"pi-extension",
|
|
15
|
+
"provider",
|
|
16
|
+
"model",
|
|
17
|
+
"ai"
|
|
18
|
+
],
|
|
19
|
+
"pi": {
|
|
20
|
+
"extensions": [
|
|
21
|
+
"./"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "fanchaozz <fanchaozz@users.noreply.github.com>",
|
|
26
|
+
"homepage": "https://github.com/fanchaozz/provider-manager#readme",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/fanchaozz/provider-manager.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/fanchaozz/provider-manager/issues"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"test": "for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done",
|
|
42
|
+
"ci:test": "npm install --no-save @earendil-works/pi-coding-agent && for f in _test_*.mts; do node --experimental-strip-types --no-warnings \"$f\" 2>&1 | tail -3; done"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/ui.ts
CHANGED
|
@@ -291,6 +291,16 @@ class Dashboard {
|
|
|
291
291
|
this.invalidate();
|
|
292
292
|
return;
|
|
293
293
|
}
|
|
294
|
+
// 空列表下"新增 provider"是唯一可执行动作,必须在导航块之前判定。
|
|
295
|
+
// 否则 n 会落到 else if 链外的 if (items.length === 0) 分支被吞掉。
|
|
296
|
+
if (data === "n") {
|
|
297
|
+
if (this.pane === "provider") {
|
|
298
|
+
void this.runForm(addProviderFlow);
|
|
299
|
+
} else {
|
|
300
|
+
this.ctx.ui.notify("model 不能直接新增,请用 sync(按 y)", "info");
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
294
304
|
// 导航(循环:第 1 个按 ↑ 跳最后,最后按 ↓ 跳第 1 个)
|
|
295
305
|
const items = this.pane === "provider" ? this.providers : (this.providers[this.providerIndex]?.models ?? []);
|
|
296
306
|
if (items.length === 0) {
|
|
@@ -313,13 +323,6 @@ class Dashboard {
|
|
|
313
323
|
const m = prov?.models[this.modelIndex];
|
|
314
324
|
if (prov && m) void this.runForm(editModelFlow, prov.id, m.id);
|
|
315
325
|
}
|
|
316
|
-
} else if (data === "n") {
|
|
317
|
-
// n: 新增 provider。仅 provider 面板支持;model 面板的 n 跳到 sync 提示。
|
|
318
|
-
if (this.pane === "provider") {
|
|
319
|
-
void this.runForm(addProviderFlow);
|
|
320
|
-
} else {
|
|
321
|
-
this.ctx.ui.notify("model 不能直接新增,请用 sync(按 y)", "info");
|
|
322
|
-
}
|
|
323
326
|
} else if (data === "d") {
|
|
324
327
|
const prov = this.providers[this.providerIndex];
|
|
325
328
|
if (this.pane === "provider" && prov) {
|
|
@@ -416,9 +419,10 @@ class Dashboard {
|
|
|
416
419
|
let okCount = 0;
|
|
417
420
|
for (const r of results) {
|
|
418
421
|
if (r.ok) okCount++;
|
|
419
|
-
ctx.ui.notify(formatTestResult(r), r.ok ? "info" : "warning");
|
|
420
422
|
}
|
|
421
|
-
|
|
423
|
+
// 批量结果拼成一条 notify:逐条 notify 会被 showStatus 原地覆盖,只残留汇总行
|
|
424
|
+
const summary = results.map((r) => formatTestResult(r)).join("\n\n") + `\n${provider.id}: ${okCount}/${results.length} ok`;
|
|
425
|
+
ctx.ui.notify(summary, "info");
|
|
422
426
|
} else {
|
|
423
427
|
// t: 测当前 pane 的 model(provider pane 测第一个 model;model pane 测当前 model)
|
|
424
428
|
let modelId: string | undefined;
|
|
@@ -430,7 +434,8 @@ class Dashboard {
|
|
|
430
434
|
if (!modelId) { ctx.ui.notify(`${provider.id} 无 model`, "warning"); return; }
|
|
431
435
|
ctx.ui.notify(`testing ${provider.id}/${modelId}...`, "info");
|
|
432
436
|
const r = await testModel({ ctx, provider: provider.id, model: modelId, mode: "full" });
|
|
433
|
-
|
|
437
|
+
// 同上:统一 info 避免滞留
|
|
438
|
+
ctx.ui.notify(formatTestResult(r), "info");
|
|
434
439
|
}
|
|
435
440
|
this.invalidate();
|
|
436
441
|
}
|
|
@@ -476,6 +481,9 @@ class Dashboard {
|
|
|
476
481
|
lines.push(th.fg("borderMuted", "─".repeat(width)));
|
|
477
482
|
if (this.help) {
|
|
478
483
|
lines.push(...this.renderHelp(width, th));
|
|
484
|
+
} else if (this.providers.length === 0) {
|
|
485
|
+
// 空态:导航/编辑/同步/删除 均无意义,只保留有效动作
|
|
486
|
+
lines.push(th.fg("dim", " n add first provider · ? help · q close"));
|
|
479
487
|
} else {
|
|
480
488
|
const parts = ["↑↓/jk nav", "←→ pane"];
|
|
481
489
|
if (this.pane === "provider") parts.push("n new", "Enter edit", "y sync");
|