Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minimax-cli",
"version": "0.1.0",
"version": "0.3.1",
"private": true,
"description": "CLI for the MiniMax API Platform (Token Plan)",
"type": "module",
Expand Down
9 changes: 7 additions & 2 deletions src/client/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ export interface RequestOpts {
authStyle?: 'bearer' | 'x-api-key';
}

// Printed once per process invocation to avoid repeating on every request.
let statusBarPrinted = false;

export async function request(
config: Config,
opts: RequestOpts,
): Promise<Response> {
const isFormData =
typeof FormData !== 'undefined' && opts.body instanceof FormData;

const version = process.env.CLI_VERSION ?? '0.3.1';
const headers: Record<string, string> = {
'User-Agent': 'minimax-cli/0.1.0',
'User-Agent': `minimax-cli/${version}`,
...opts.headers,
};

Expand All @@ -47,7 +51,8 @@ export async function request(
}

// ANSI 真彩色 (24-bit) 与基础排版
if (!config.quiet && process.stderr.isTTY) {
if (!config.quiet && !statusBarPrinted && process.stderr.isTTY) {
statusBarPrinted = true;
const reset = '\x1b[0m';
const dim = '\x1b[2m';
const bold = '\x1b[1m'; // 新增加粗效果
Expand Down
2 changes: 0 additions & 2 deletions src/commands/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export default defineCommand({
'minimax auth login --method api-key --api-key sk-xxxxx',
],
async run(config: Config, flags: GlobalFlags) {
// --- Phase 4: env key detection ---
const envKey = process.env.MINIMAX_API_KEY;
if (envKey) {
const maskedEnvKey = envKey.length > 8 ? `${envKey.slice(0, 4)}...${envKey.slice(-4)}` : '***';
Expand All @@ -48,7 +47,6 @@ export default defineCommand({
process.stderr.write(`Warning: MINIMAX_API_KEY is already set in environment.\n`);
}
}
// --- Phase 4 end ---

const method = flags.apiKey ? 'api-key' : (flags.method as string) || 'oauth';

Expand Down
18 changes: 12 additions & 6 deletions src/commands/quota/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ export default defineCommand({
const url = quotaEndpoint(config.baseUrl);
const response = await requestJson<QuotaApiResponse>(config, { url });
const models = response.model_remains || [];
const format = detectOutputFormat(config.output);
// Only honour explicit --output flag; ignore config-file output setting so the
// rich HUD is shown by default in TTY even when the user has output: json globally.
const format = detectOutputFormat(flags.output as string | undefined);

// Step 1: Non-text formats pass through as-is
if (format !== 'text') {
Expand All @@ -208,9 +210,12 @@ export default defineCommand({
const maxNameLen = models.length > 0
? Math.max(...models.map(m => m.model_name.length))
: 16;
// Layout per row: name + 2 + usage(15) + 2 + bar(BAR_WIDTH) + 1 + pct(4) = name + BAR_WIDTH + 24
// Box inner W = content + 2 (for "│ " and " │" padding)
const W = Math.max(68, maxNameLen + BAR_WIDTH + 26);
// color bar: BAR_WIDTH spaces + ' ' + pct(4) = BAR_WIDTH + 5 visible cols
// no-color bar: '[' + BAR_WIDTH chars + '] ' + pct(4) = BAR_WIDTH + 7 visible cols
const barVisLen = useColor ? BAR_WIDTH + 5 : BAR_WIDTH + 7;
// line1 content = name(maxNameLen) + ' '(2) + usage(15) + ' '(2) + bar(barVisLen)
// W must be content + 2 so boxRow borders ('| ' + ' |') have room
const W = Math.max(68, maxNameLen + 2 + 15 + 2 + barVisLen + 2);

// ── Header row ──
const weekRange = models.length > 0
Expand Down Expand Up @@ -264,8 +269,9 @@ export default defineCommand({
const usageFrac = `${used.toLocaleString()} / ${limit.toLocaleString()}`;
const bar = renderBar(usedPct, useColor);

// Visible columns: name(padded) + gap(2) + usage(15) + gap(2) + bar(BAR_WIDTH) + gap(1) + pct(4)
const line1VisLen = maxNameLen + 2 + 15 + 2 + BAR_WIDTH + 1 + 4;
// color bar: BAR_WIDTH spaces + gap(1) + pct(4) = BAR_WIDTH + 5
// no-color bar: '[' + BAR_WIDTH chars + '] ' + pct(4) = BAR_WIDTH + 7
const line1VisLen = maxNameLen + 2 + 15 + 2 + barVisLen;

let line1Styled: string;
if (useColor) {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/text/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function extractText(content: ContentBlock[]): string {

export default defineCommand({
name: 'text chat',
description: 'Send a chat completion (Anthropic Messages API)',
description: 'Send a chat completion (MiniMax Messages API)',
usage: 'minimax text chat --message <text> [flags]',
options: [
{ flag: '--model <model>', description: 'Model ID (default: MiniMax-M2.7)' },
Expand Down
6 changes: 3 additions & 3 deletions src/errors/handler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { CLIError } from './base';
import { ExitCode } from './codes';
import { detectOutputFormat } from '../output/formatter';

export function handleError(err: unknown): never {
if (err instanceof CLIError) {
const isJson = process.env.MINIMAX_OUTPUT === 'json' ||
(typeof process.stdout?.isTTY !== 'undefined' && !process.stdout.isTTY);
const format = detectOutputFormat(process.env.MINIMAX_OUTPUT);

if (isJson) {
if (format === 'json') {
process.stderr.write(JSON.stringify(err.toJSON(), null, 2) + '\n');
} else {
process.stderr.write(`\nError: ${err.message}\n`);
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { detectRegion, saveDetectedRegion } from './config/detect-region';
import { REGIONS } from './config/schema';
import { checkForUpdate, getPendingUpdateNotification } from './update/checker';

const CLI_VERSION = process.env.CLI_VERSION ?? '0.1.0';
const CLI_VERSION = process.env.CLI_VERSION ?? '0.3.1';

async function main() {
const args = process.argv.slice(2);
Expand Down
21 changes: 13 additions & 8 deletions src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import quotaShow from './commands/quota/show';
import configShow from './commands/config/show';
import configSet from './commands/config/set';
import configExportSchema from './commands/config/export-schema';
// ❄️ 暂时雪藏 File API (等待接口权限开放)
// File API temporarily disabled (pending permission grant)
// import fileUpload from './commands/file/upload';
// import fileList from './commands/file/list';
// import fileDelete from './commands/file/delete';
Expand Down Expand Up @@ -205,13 +205,18 @@ Getting Help:
}

private printChildren(node: CommandNode, prefix: string, out: NodeJS.WriteStream): void {
for (const [name, child] of node.children) {
if (child.command) {
out.write(` ${prefix} ${name.padEnd(12)} ${child.command.description}\n`);
}
if (child.children.size > 0) {
this.printChildren(child, `${prefix} ${name}`, out);
// Collect all leaf entries first so we can align the description column.
const entries: Array<{ fullName: string; description: string }> = [];
const collect = (n: CommandNode, p: string) => {
for (const [name, child] of n.children) {
if (child.command) entries.push({ fullName: `${p} ${name}`, description: child.command.description });
if (child.children.size > 0) collect(child, `${p} ${name}`);
}
};
collect(node, prefix);
const maxLen = Math.max(...entries.map(e => e.fullName.length));
for (const { fullName, description } of entries) {
out.write(` ${fullName.padEnd(maxLen)} ${description}\n`);
}
}
}
Expand All @@ -236,7 +241,7 @@ export const registry = new CommandRegistry({
'config set': configSet,
'config export-schema': configExportSchema,

// ❄️ 暂时雪藏 File API
// File API temporarily disabled (pending permission grant)
// 'file upload': fileUpload,
// 'file list': fileList,
// 'file delete': fileDelete,
Expand Down
Loading