laohuang 0.8.2 → 0.8.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/README.md +9 -2
- package/dist/bin.js +89 -51
- package/dist/bin.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,8 +29,15 @@ Google Vertex, OAuth-only providers, and OpenAI Codex. Use `/providers` to see
|
|
|
29
29
|
available, configured, and verified status independently.
|
|
30
30
|
|
|
31
31
|
`/login <provider>` stores API-key credentials, `/logout <provider>` removes
|
|
32
|
-
them, `/model
|
|
33
|
-
|
|
32
|
+
them, and `/model` opens a searchable list of all available models from
|
|
33
|
+
configured providers, including credentials supplied through environment variables.
|
|
34
|
+
Search by provider ID, model ID, or model name; scroll to browse the full list.
|
|
35
|
+
If no models are available, the CLI points to `/login`.
|
|
36
|
+
`/model <provider>` narrows the list, `/model <provider> <model>` switches
|
|
37
|
+
directly, and `/apikey` remains a compatibility alias. Switching models affects
|
|
38
|
+
only the current session, not the default profile.
|
|
39
|
+
|
|
40
|
+
`verified` means an explicitly authorized live native
|
|
34
41
|
tool-call/tool-result E2E was recorded; no providers are checked in as verified
|
|
35
42
|
by default.
|
|
36
43
|
|
package/dist/bin.js
CHANGED
|
@@ -10022,7 +10022,7 @@ function renderMarkdownStyledLines(text, width) {
|
|
|
10022
10022
|
const layoutWidth = Math.max(12, width);
|
|
10023
10023
|
const lines2 = [];
|
|
10024
10024
|
let previous = null;
|
|
10025
|
-
for (const block of renderBlocks(clean, layoutWidth)) {
|
|
10025
|
+
for (const block of renderBlocks(clean, layoutWidth, Math.max(1, width))) {
|
|
10026
10026
|
const leadingBlank = previous === null ? block.kind === "list" || block.kind === "table" || block.kind === "quote" : previous !== "hr";
|
|
10027
10027
|
if (leadingBlank) {
|
|
10028
10028
|
lines2.push(line());
|
|
@@ -10046,7 +10046,7 @@ function styleKey(style) {
|
|
|
10046
10046
|
style.background ?? ""
|
|
10047
10047
|
].join("|");
|
|
10048
10048
|
}
|
|
10049
|
-
function renderBlocks(text, layoutWidth) {
|
|
10049
|
+
function renderBlocks(text, layoutWidth, tableWidth) {
|
|
10050
10050
|
const lines2 = text.replace(/\r\n/g, "\n").split("\n");
|
|
10051
10051
|
const blocks = [];
|
|
10052
10052
|
let paragraph = [];
|
|
@@ -10094,6 +10094,7 @@ function renderBlocks(text, layoutWidth) {
|
|
|
10094
10094
|
const delimiter = splitTableRow(lines2[index + 1].trim());
|
|
10095
10095
|
if (header !== null && delimiter !== null && delimiter.length === header.length && delimiter.every((cell) => /^:?-+:?$/.test(cell))) {
|
|
10096
10096
|
flushParagraph();
|
|
10097
|
+
const tableStart = index;
|
|
10097
10098
|
index += 2;
|
|
10098
10099
|
const rows = [];
|
|
10099
10100
|
while (index < lines2.length) {
|
|
@@ -10110,7 +10111,7 @@ function renderBlocks(text, layoutWidth) {
|
|
|
10110
10111
|
}
|
|
10111
10112
|
blocks.push({
|
|
10112
10113
|
kind: "table",
|
|
10113
|
-
lines: renderTable(header, rows,
|
|
10114
|
+
lines: renderTable(header, rows, tableWidth, lines2.slice(tableStart, index))
|
|
10114
10115
|
});
|
|
10115
10116
|
continue;
|
|
10116
10117
|
}
|
|
@@ -10249,7 +10250,7 @@ function segmentsWidth(segments) {
|
|
|
10249
10250
|
}
|
|
10250
10251
|
return width;
|
|
10251
10252
|
}
|
|
10252
|
-
function renderTable(header, rows, layoutWidth) {
|
|
10253
|
+
function renderTable(header, rows, layoutWidth, rawLines) {
|
|
10253
10254
|
const columnCount = header.length;
|
|
10254
10255
|
const borderStyle = {
|
|
10255
10256
|
foreground: "border_muted"
|
|
@@ -10261,12 +10262,26 @@ function renderTable(header, rows, layoutWidth) {
|
|
|
10261
10262
|
const normalize = (cells) => Array.from({ length: columnCount }, (_, i) => cells[i] ?? "");
|
|
10262
10263
|
const headerCells = normalize(header).map((cell) => parseInline(cell, headerStyle));
|
|
10263
10264
|
const bodyCells = rows.map((row) => normalize(row).map((cell) => parseInline(cell, {})));
|
|
10265
|
+
const minWidths = Array(columnCount).fill(1);
|
|
10266
|
+
for (const row of [headerCells, ...bodyCells]) {
|
|
10267
|
+
for (let i = 0; i < columnCount; i += 1) {
|
|
10268
|
+
for (const segment of row[i]) {
|
|
10269
|
+
for (const cluster of graphemeClusters(segment.text)) {
|
|
10270
|
+
minWidths[i] = Math.max(minWidths[i], clusterWidth(cluster));
|
|
10271
|
+
}
|
|
10272
|
+
}
|
|
10273
|
+
}
|
|
10274
|
+
}
|
|
10275
|
+
const spacingWidth = 2 * columnCount;
|
|
10276
|
+
if (minWidths.reduce((total, width) => total + width, spacingWidth) > layoutWidth) {
|
|
10277
|
+
return rawLines.flatMap((text) => wrapSegments([{ text, style: {} }], layoutWidth));
|
|
10278
|
+
}
|
|
10264
10279
|
const widths = Array.from({ length: columnCount }, (_, i) => Math.max(1, segmentsWidth(headerCells[i]), ...bodyCells.map((row) => segmentsWidth(row[i]))));
|
|
10265
10280
|
const totalWidth = () => widths.reduce((total, w) => total + w, 0) + 2 * (columnCount - 1) + 2;
|
|
10266
|
-
while (totalWidth() > layoutWidth
|
|
10267
|
-
let widest =
|
|
10268
|
-
for (let i =
|
|
10269
|
-
if (widths[i] > widths[widest]) {
|
|
10281
|
+
while (totalWidth() > layoutWidth) {
|
|
10282
|
+
let widest = -1;
|
|
10283
|
+
for (let i = 0; i < widths.length; i += 1) {
|
|
10284
|
+
if (widths[i] > minWidths[i] && (widest === -1 || widths[i] > widths[widest])) {
|
|
10270
10285
|
widest = i;
|
|
10271
10286
|
}
|
|
10272
10287
|
}
|
|
@@ -10296,7 +10311,7 @@ function renderTableRows(cells, widths, borderStyle, padStyle) {
|
|
|
10296
10311
|
if (i > 0) {
|
|
10297
10312
|
line2.push({ style: borderStyle, text: " " });
|
|
10298
10313
|
}
|
|
10299
|
-
const cellLine = wrappedCells[i][row];
|
|
10314
|
+
const cellLine = wrappedCells[i][row] ?? [];
|
|
10300
10315
|
line2.push(...cellLine);
|
|
10301
10316
|
const pad = widths[i] - segmentsWidth(cellLine);
|
|
10302
10317
|
if (pad > 0) {
|
|
@@ -14737,7 +14752,7 @@ var SessionCommands = class {
|
|
|
14737
14752
|
this.registry = new CommandRegistry([
|
|
14738
14753
|
{
|
|
14739
14754
|
name: "/model",
|
|
14740
|
-
description: "\u9009\u62E9\
|
|
14755
|
+
description: "\u641C\u7D22\u5E76\u9009\u62E9\u5DF2\u914D\u7F6E\u4F9B\u5E94\u5546\u7684\u6A21\u578B",
|
|
14741
14756
|
usage: "/model [provider|model] [model]",
|
|
14742
14757
|
handler: (args) => this.handleModel(args),
|
|
14743
14758
|
allowedStates: IDLE_ONLY,
|
|
@@ -15124,16 +15139,10 @@ ${sessionDisplayDescription(session, {
|
|
|
15124
15139
|
}
|
|
15125
15140
|
let provider;
|
|
15126
15141
|
let modelName;
|
|
15127
|
-
if (args.length ===
|
|
15128
|
-
const selectedProvider = await this.selectModelProvider();
|
|
15129
|
-
if (selectedProvider === null) {
|
|
15130
|
-
return true;
|
|
15131
|
-
}
|
|
15132
|
-
provider = selectedProvider;
|
|
15133
|
-
} else if (args.length === 2) {
|
|
15142
|
+
if (args.length === 2) {
|
|
15134
15143
|
provider = args[0];
|
|
15135
15144
|
modelName = args[1];
|
|
15136
|
-
} else {
|
|
15145
|
+
} else if (args.length === 1) {
|
|
15137
15146
|
const argument = args[0];
|
|
15138
15147
|
if (this.#catalog.getProvider(argument) !== void 0) {
|
|
15139
15148
|
provider = argument;
|
|
@@ -15144,9 +15153,24 @@ ${sessionDisplayDescription(session, {
|
|
|
15144
15153
|
}
|
|
15145
15154
|
if (modelName === void 0) {
|
|
15146
15155
|
try {
|
|
15147
|
-
|
|
15156
|
+
let models;
|
|
15157
|
+
if (provider === void 0) {
|
|
15158
|
+
const available = await this.#selector.listConfiguredModels();
|
|
15159
|
+
models = available.models;
|
|
15160
|
+
for (const failure of available.errors) {
|
|
15161
|
+
this.notice(
|
|
15162
|
+
`Could not list models for ${failure.provider}: ${errorMessage10(failure.error)}`,
|
|
15163
|
+
"warning"
|
|
15164
|
+
);
|
|
15165
|
+
}
|
|
15166
|
+
} else {
|
|
15167
|
+
models = await this.#selector.listModels(provider, "");
|
|
15168
|
+
}
|
|
15148
15169
|
if (models.length === 0) {
|
|
15149
|
-
this.notice(
|
|
15170
|
+
this.notice(
|
|
15171
|
+
provider === void 0 ? "No models available from configured providers. Use /login to configure a provider." : `No models available for provider: ${provider}. Use /login ${provider} to configure credentials.`,
|
|
15172
|
+
"warning"
|
|
15173
|
+
);
|
|
15150
15174
|
return true;
|
|
15151
15175
|
}
|
|
15152
15176
|
if (this.#presenter === null) {
|
|
@@ -15155,26 +15179,34 @@ ${sessionDisplayDescription(session, {
|
|
|
15155
15179
|
}
|
|
15156
15180
|
const selected = await this.#presenter.select({
|
|
15157
15181
|
id: "model-name",
|
|
15158
|
-
title: `Select model for ${provider}`,
|
|
15159
|
-
items: models.map((
|
|
15160
|
-
value: `${provider}/${
|
|
15161
|
-
label:
|
|
15162
|
-
description: provider
|
|
15182
|
+
title: provider === void 0 ? "Select model from configured providers" : `Select model for ${provider}`,
|
|
15183
|
+
items: models.map((model2) => ({
|
|
15184
|
+
value: `${model2.provider}/${model2.id}`,
|
|
15185
|
+
label: model2.name,
|
|
15186
|
+
description: model2.provider
|
|
15163
15187
|
})),
|
|
15164
|
-
currentValue: this.#currentConfig.provider
|
|
15188
|
+
currentValue: `${this.#currentConfig.provider}/${this.#currentConfig.model}`,
|
|
15165
15189
|
searchable: true,
|
|
15166
|
-
maxVisible:
|
|
15190
|
+
maxVisible: 10
|
|
15167
15191
|
});
|
|
15168
15192
|
if (selected === null) {
|
|
15169
15193
|
return true;
|
|
15170
15194
|
}
|
|
15171
|
-
const
|
|
15172
|
-
|
|
15195
|
+
const model = models.find((candidate) => `${candidate.provider}/${candidate.id}` === selected);
|
|
15196
|
+
if (model === void 0) {
|
|
15197
|
+
this.notice("Selected model is no longer available. Run /model to refresh the list.", "error");
|
|
15198
|
+
return true;
|
|
15199
|
+
}
|
|
15200
|
+
provider = model.provider;
|
|
15201
|
+
modelName = model.id;
|
|
15173
15202
|
} catch (error) {
|
|
15174
15203
|
this.notice(`Could not list models: ${errorMessage10(error)}`, "error");
|
|
15175
15204
|
return true;
|
|
15176
15205
|
}
|
|
15177
15206
|
}
|
|
15207
|
+
if (provider === void 0) {
|
|
15208
|
+
return true;
|
|
15209
|
+
}
|
|
15178
15210
|
let selection;
|
|
15179
15211
|
try {
|
|
15180
15212
|
selection = await this.#selector.selectExact({
|
|
@@ -15187,6 +15219,7 @@ ${sessionDisplayDescription(session, {
|
|
|
15187
15219
|
return true;
|
|
15188
15220
|
}
|
|
15189
15221
|
if (selection === null) {
|
|
15222
|
+
this.notice(`Use /login ${provider} to configure credentials before switching models.`, "warning");
|
|
15190
15223
|
return true;
|
|
15191
15224
|
}
|
|
15192
15225
|
const previousProvider = this.#currentConfig.provider;
|
|
@@ -15445,23 +15478,6 @@ ${sessionDisplayDescription(session, {
|
|
|
15445
15478
|
)
|
|
15446
15479
|
};
|
|
15447
15480
|
}
|
|
15448
|
-
async selectModelProvider() {
|
|
15449
|
-
if (this.#presenter === null) {
|
|
15450
|
-
this.notice("Model provider selection is unavailable.", "error");
|
|
15451
|
-
return null;
|
|
15452
|
-
}
|
|
15453
|
-
const selected = await this.#presenter.select({
|
|
15454
|
-
id: "model-provider",
|
|
15455
|
-
title: "Select model provider",
|
|
15456
|
-
items: this.#selector.listProviders().map((provider) => ({
|
|
15457
|
-
value: provider.id,
|
|
15458
|
-
label: provider.name,
|
|
15459
|
-
description: provider.id
|
|
15460
|
-
})),
|
|
15461
|
-
currentValue: this.#currentConfig.provider
|
|
15462
|
-
});
|
|
15463
|
-
return selected;
|
|
15464
|
-
}
|
|
15465
15481
|
*modelCompletions(args) {
|
|
15466
15482
|
if (args.length === 0) {
|
|
15467
15483
|
yield ["current", "\u663E\u793A\u5F53\u524D\u6A21\u578B"];
|
|
@@ -15578,12 +15594,30 @@ var ModelSelector = class {
|
|
|
15578
15594
|
return this.#catalog.listProviders();
|
|
15579
15595
|
}
|
|
15580
15596
|
async listModels(provider, query) {
|
|
15597
|
+
if (!await this.#providerAuth.ensureConfigured(provider, { promptIfMissing: false })) {
|
|
15598
|
+
return [];
|
|
15599
|
+
}
|
|
15581
15600
|
await this.#catalog.refresh(provider);
|
|
15582
15601
|
return filterModels(
|
|
15583
15602
|
await this.#catalog.listAvailableModels(provider),
|
|
15584
|
-
query
|
|
15585
|
-
|
|
15603
|
+
query
|
|
15604
|
+
);
|
|
15605
|
+
}
|
|
15606
|
+
async listConfiguredModels() {
|
|
15607
|
+
const providers = this.#catalog.listProviders();
|
|
15608
|
+
const results = await Promise.allSettled(
|
|
15609
|
+
providers.map((provider) => this.listModels(provider.id, ""))
|
|
15586
15610
|
);
|
|
15611
|
+
const models = [];
|
|
15612
|
+
const errors = [];
|
|
15613
|
+
for (const [index, result] of results.entries()) {
|
|
15614
|
+
if (result.status === "fulfilled") {
|
|
15615
|
+
models.push(...result.value);
|
|
15616
|
+
} else {
|
|
15617
|
+
errors.push({ provider: providers[index].id, error: result.reason });
|
|
15618
|
+
}
|
|
15619
|
+
}
|
|
15620
|
+
return { models: filterModels(models, ""), errors };
|
|
15587
15621
|
}
|
|
15588
15622
|
async selectExact(options) {
|
|
15589
15623
|
const provider = this.#catalog.getProvider(options.providerName);
|
|
@@ -15615,7 +15649,7 @@ var ModelSelector = class {
|
|
|
15615
15649
|
};
|
|
15616
15650
|
}
|
|
15617
15651
|
};
|
|
15618
|
-
function filterModels(models, query
|
|
15652
|
+
function filterModels(models, query) {
|
|
15619
15653
|
const normalized = query.toLowerCase().trim();
|
|
15620
15654
|
const terms = normalized.split(/\s+/).filter((term) => term.length > 0);
|
|
15621
15655
|
const matched = models.filter((model) => {
|
|
@@ -15639,9 +15673,9 @@ function filterModels(models, query, limit = 20) {
|
|
|
15639
15673
|
if (leftPrefix !== rightPrefix) {
|
|
15640
15674
|
return leftPrefix ? -1 : 1;
|
|
15641
15675
|
}
|
|
15642
|
-
return left.id.localeCompare(right.id);
|
|
15676
|
+
return left.provider.localeCompare(right.provider) || left.id.localeCompare(right.id);
|
|
15643
15677
|
});
|
|
15644
|
-
return matched
|
|
15678
|
+
return matched;
|
|
15645
15679
|
}
|
|
15646
15680
|
|
|
15647
15681
|
// src/plain-command-presenter.ts
|
|
@@ -17323,6 +17357,10 @@ async function main(argv, options = {}) {
|
|
|
17323
17357
|
await sessionRecorder.close();
|
|
17324
17358
|
await sessionController.close();
|
|
17325
17359
|
}
|
|
17360
|
+
const renderError = terminalUi?.renderError ?? null;
|
|
17361
|
+
if (renderError !== null) {
|
|
17362
|
+
throw new Error(`Terminal rendering failed: ${errorMessage11(renderError)}`, { cause: renderError });
|
|
17363
|
+
}
|
|
17326
17364
|
return cleanShutdown ? 0 : 1;
|
|
17327
17365
|
}
|
|
17328
17366
|
function defaultSessionsRoot(environ) {
|