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 apps/kimi-code/src/tui/kimi-tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,7 @@
isCompacting: this.state.appState.isCompacting,
});

switch (intent.kind) {

Check warning on line 1342 in apps/kimi-code/src/tui/kimi-tui.ts

View workflow job for this annotation

GitHub Actions / lint

typescript-eslint(switch-exhaustiveness-check)

Switch is not exhaustive. Cases not matched: "invalid"
case 'not-command':
return;
case 'blocked':
Expand Down Expand Up @@ -5224,7 +5224,7 @@
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;
}
}
Expand Down
58 changes: 44 additions & 14 deletions apps/kimi-code/src/tui/utils/connect-catalog.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -17,30 +14,63 @@ 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 (explicitUrl !== undefined) {
if (trimmed === '') {
return {
kind: 'ok',
request: {
url: explicitUrl,
preferBuiltIn: false,
allowBuiltInFallback: false,
url: DEFAULT_CATALOG_URL,
preferBuiltIn: true,
allowBuiltInFallback: true,
},
};
}

if (URL_FLAG_PRESENT_RE.test(trimmed)) {
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:
'--url requires an http(s) URL value, e.g. /connect --url=https://example.com/catalog.json',
message: `Unknown argument "${token}". Usage: /connect [url] [refresh]`,
};
}

if (explicitUrl !== undefined) {
return {
kind: 'ok',
request: {
url: explicitUrl,
preferBuiltIn: false,
allowBuiltInFallback: false,
},
};
}

const refreshRequested = REFRESH_FLAG_RE.test(trimmed);
return {
kind: 'ok',
request: {
Expand Down
76 changes: 30 additions & 46 deletions apps/kimi-code/test/tui/utils/connect-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,18 @@ 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,
preferBuiltIn: false,
allowBuiltInFallback: true,
},
});
expect(resolveConnectCatalogRequest(' --refresh ')).toEqual({
expect(resolveConnectCatalogRequest(' refresh ')).toEqual({
kind: 'ok',
request: {
url: DEFAULT_CATALOG_URL,
Expand All @@ -49,24 +41,18 @@ 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({
it('treats explicit catalog URLs as authoritative and ignores refresh on them', () => {
expect(resolveConnectCatalogRequest('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')).toEqual({
expect(
resolveConnectCatalogRequest('refresh https://internal.example/catalog.json'),
).toEqual({
kind: 'ok',
request: {
url: 'https://internal.example/catalog.json',
Expand All @@ -75,7 +61,7 @@ describe('resolveConnectCatalogRequest', () => {
},
});
expect(
resolveConnectCatalogRequest('--refresh --url=https://internal.example/catalog.json'),
resolveConnectCatalogRequest('https://internal.example/catalog.json refresh'),
).toEqual({
kind: 'ok',
request: {
Expand All @@ -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({
kind: 'error',
message: expectedMessage,
});
expect(resolveConnectCatalogRequest('--url=')).toEqual({
kind: 'error',
message: expectedMessage,
});
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('--refresh --url')).toEqual({
expect(resolveConnectCatalogRequest('--url=https://internal.example/catalog.json')).toEqual({
kind: 'error',
message: expectedMessage,
message: flagMessage('--url=https://internal.example/catalog.json'),
});
// Flag-like tokens after --url must not be swallowed as the URL value.
expect(resolveConnectCatalogRequest('--url --refresh')).toEqual({
expect(resolveConnectCatalogRequest('--url https://internal.example/catalog.json')).toEqual({
kind: 'error',
message: expectedMessage,
message: flagMessage('--url'),
});
// Plain non-URL tokens must also be rejected, not silently used.
expect(resolveConnectCatalogRequest('--url not-a-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]',
});
expect(resolveConnectCatalogRequest('--url=ftp://example.com/x')).toEqual({
});

it('rejects multiple URLs', () => {
expect(
resolveConnectCatalogRequest('https://a.com/x.json https://b.com/y.json'),
).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".',
});
});
});
Expand Down
Loading