mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-10 01:39:25 +00:00
feat(kimi-code): use positional args and bare keywords for /connect (#50)
Replace the --flag style (/connect --url=..., /connect --refresh) with positional arguments and bare keywords: - /connect https://example.com/catalog.json - /connect refresh - /connect (no args, default behavior) This aligns the slash-command UX with peer CLI tools (claude-code, pi, opencode) where slash commands use bare words rather than CLI-style flags. Closes #30 follow-up
This commit is contained in:
parent
cf5270ce6a
commit
c473823a4b
3 changed files with 82 additions and 68 deletions
|
|
@ -5224,7 +5224,7 @@ export class KimiTUI {
|
|||
if (preferBuiltIn) {
|
||||
const builtIn = loadBuiltInCatalog(BUILT_IN_CATALOG_JSON);
|
||||
if (builtIn !== undefined) {
|
||||
this.showStatus('Loaded built-in catalog. Run /connect --refresh for the latest.');
|
||||
this.showStatus('Loaded built-in catalog. Run /connect refresh for the latest.');
|
||||
catalog = builtIn;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { DEFAULT_CATALOG_URL } from '@moonshot-ai/kimi-code-sdk';
|
||||
|
||||
const CATALOG_URL_FLAG_RE = /--url(?:=|\s+)(https?:\/\/\S+)/;
|
||||
const URL_FLAG_PRESENT_RE = /(?:^|\s)--url(?=\s|=|$)/;
|
||||
const REFRESH_FLAG_RE = /(?:^|\s)--refresh(?=\s|$)/;
|
||||
const BARE_HTTP_URL_RE = /^https?:\/\/\S+$/;
|
||||
|
||||
export interface ConnectCatalogRequest {
|
||||
|
|
@ -17,9 +14,51 @@ export type ConnectCatalogResolution =
|
|||
|
||||
export function resolveConnectCatalogRequest(args: string): ConnectCatalogResolution {
|
||||
const trimmed = args.trim();
|
||||
const urlMatch = CATALOG_URL_FLAG_RE.exec(trimmed);
|
||||
const bareUrl = BARE_HTTP_URL_RE.test(trimmed) ? trimmed : undefined;
|
||||
const explicitUrl = urlMatch?.[1] ?? bareUrl;
|
||||
|
||||
if (trimmed === '') {
|
||||
return {
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: DEFAULT_CATALOG_URL,
|
||||
preferBuiltIn: true,
|
||||
allowBuiltInFallback: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const tokens = trimmed.split(/\s+/).filter(Boolean);
|
||||
let explicitUrl: string | undefined;
|
||||
let refreshRequested = false;
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token.toLowerCase() === 'refresh') {
|
||||
refreshRequested = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BARE_HTTP_URL_RE.test(token)) {
|
||||
if (explicitUrl !== undefined) {
|
||||
return {
|
||||
kind: 'error',
|
||||
message: `Only one catalog URL can be provided. Got "${explicitUrl}" and "${token}".`,
|
||||
};
|
||||
}
|
||||
explicitUrl = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.startsWith('--')) {
|
||||
return {
|
||||
kind: 'error',
|
||||
message: `Unexpected flag "${token}". Use /connect [url] [refresh] instead.`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'error',
|
||||
message: `Unknown argument "${token}". Usage: /connect [url] [refresh]`,
|
||||
};
|
||||
}
|
||||
|
||||
if (explicitUrl !== undefined) {
|
||||
return {
|
||||
|
|
@ -32,15 +71,6 @@ export function resolveConnectCatalogRequest(args: string): ConnectCatalogResolu
|
|||
};
|
||||
}
|
||||
|
||||
if (URL_FLAG_PRESENT_RE.test(trimmed)) {
|
||||
return {
|
||||
kind: 'error',
|
||||
message:
|
||||
'--url requires an http(s) URL value, e.g. /connect --url=https://example.com/catalog.json',
|
||||
};
|
||||
}
|
||||
|
||||
const refreshRequested = REFRESH_FLAG_RE.test(trimmed);
|
||||
return {
|
||||
kind: 'ok',
|
||||
request: {
|
||||
|
|
|
|||
|
|
@ -20,18 +20,10 @@ describe('resolveConnectCatalogRequest', () => {
|
|||
allowBuiltInFallback: true,
|
||||
},
|
||||
});
|
||||
expect(resolveConnectCatalogRequest('ignored text')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: DEFAULT_CATALOG_URL,
|
||||
preferBuiltIn: true,
|
||||
allowBuiltInFallback: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('forces an online fetch when --refresh is requested', () => {
|
||||
expect(resolveConnectCatalogRequest('--refresh')).toEqual({
|
||||
it('forces an online fetch when refresh is requested', () => {
|
||||
expect(resolveConnectCatalogRequest('refresh')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: DEFAULT_CATALOG_URL,
|
||||
|
|
@ -39,7 +31,7 @@ describe('resolveConnectCatalogRequest', () => {
|
|||
allowBuiltInFallback: true,
|
||||
},
|
||||
});
|
||||
expect(resolveConnectCatalogRequest(' --refresh ')).toEqual({
|
||||
expect(resolveConnectCatalogRequest(' refresh ')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: DEFAULT_CATALOG_URL,
|
||||
|
|
@ -49,23 +41,7 @@ describe('resolveConnectCatalogRequest', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('treats explicit catalog URLs as authoritative and ignores --refresh on them', () => {
|
||||
expect(resolveConnectCatalogRequest('--url=https://internal.example/catalog.json')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: 'https://internal.example/catalog.json',
|
||||
preferBuiltIn: false,
|
||||
allowBuiltInFallback: false,
|
||||
},
|
||||
});
|
||||
expect(resolveConnectCatalogRequest('--url https://internal.example/catalog.json')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: 'https://internal.example/catalog.json',
|
||||
preferBuiltIn: false,
|
||||
allowBuiltInFallback: false,
|
||||
},
|
||||
});
|
||||
it('treats explicit catalog URLs as authoritative and ignores refresh on them', () => {
|
||||
expect(resolveConnectCatalogRequest('https://internal.example/catalog.json')).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
|
|
@ -75,7 +51,17 @@ describe('resolveConnectCatalogRequest', () => {
|
|||
},
|
||||
});
|
||||
expect(
|
||||
resolveConnectCatalogRequest('--refresh --url=https://internal.example/catalog.json'),
|
||||
resolveConnectCatalogRequest('refresh https://internal.example/catalog.json'),
|
||||
).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
url: 'https://internal.example/catalog.json',
|
||||
preferBuiltIn: false,
|
||||
allowBuiltInFallback: false,
|
||||
},
|
||||
});
|
||||
expect(
|
||||
resolveConnectCatalogRequest('https://internal.example/catalog.json refresh'),
|
||||
).toEqual({
|
||||
kind: 'ok',
|
||||
request: {
|
||||
|
|
@ -86,38 +72,36 @@ describe('resolveConnectCatalogRequest', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('rejects --url when no value or a non-URL value is provided', () => {
|
||||
const expectedMessage =
|
||||
'--url requires an http(s) URL value, e.g. /connect --url=https://example.com/catalog.json';
|
||||
expect(resolveConnectCatalogRequest('--url')).toEqual({
|
||||
it('rejects unsupported flags', () => {
|
||||
const flagMessage = (flag: string) =>
|
||||
`Unexpected flag "${flag}". Use /connect [url] [refresh] instead.`;
|
||||
expect(resolveConnectCatalogRequest('--refresh')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
message: flagMessage('--refresh'),
|
||||
});
|
||||
expect(resolveConnectCatalogRequest('--url=')).toEqual({
|
||||
expect(resolveConnectCatalogRequest('--url=https://internal.example/catalog.json')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
message: flagMessage('--url=https://internal.example/catalog.json'),
|
||||
});
|
||||
expect(resolveConnectCatalogRequest(' --url ')).toEqual({
|
||||
expect(resolveConnectCatalogRequest('--url https://internal.example/catalog.json')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
message: flagMessage('--url'),
|
||||
});
|
||||
expect(resolveConnectCatalogRequest('--refresh --url')).toEqual({
|
||||
});
|
||||
|
||||
it('rejects non-URL bare tokens', () => {
|
||||
expect(resolveConnectCatalogRequest('ignored text')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
message: 'Unknown argument "ignored". Usage: /connect [url] [refresh]',
|
||||
});
|
||||
// Flag-like tokens after --url must not be swallowed as the URL value.
|
||||
expect(resolveConnectCatalogRequest('--url --refresh')).toEqual({
|
||||
});
|
||||
|
||||
it('rejects multiple URLs', () => {
|
||||
expect(
|
||||
resolveConnectCatalogRequest('https://a.com/x.json https://b.com/y.json'),
|
||||
).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
});
|
||||
// Plain non-URL tokens must also be rejected, not silently used.
|
||||
expect(resolveConnectCatalogRequest('--url not-a-url')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
});
|
||||
expect(resolveConnectCatalogRequest('--url=ftp://example.com/x')).toEqual({
|
||||
kind: 'error',
|
||||
message: expectedMessage,
|
||||
message: 'Only one catalog URL can be provided. Got "https://a.com/x.json" and "https://b.com/y.json".',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue