opencode-catpaw-auth 1.1.0 → 1.2.2
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +38 -0
- package/dist/src/plugin.d.ts +14 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +123 -0
- package/dist/src/request.d.ts +12 -0
- package/dist/src/request.d.ts.map +1 -0
- package/dist/src/request.js +35 -0
- package/dist/src/types.d.ts +78 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/package.json +25 -10
- package/index.ts +0 -1
- package/src/config.ts +0 -43
- package/src/plugin.ts +0 -116
- package/src/request.ts +0 -47
- package/src/types.ts +0 -85
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从 mcopilot-cli 配置文件中加载 API key
|
|
3
|
+
* 配置文件路径: ~/.config/mcopilot-cli/.config.yaml
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadApiKeyFromConfig(): Promise<string | null>;
|
|
6
|
+
/**
|
|
7
|
+
* 获取配置文件路径(用于调试)
|
|
8
|
+
*/
|
|
9
|
+
export declare function getConfigPath(): string;
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBnE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import yaml from "js-yaml";
|
|
5
|
+
const CONFIG_PATH = join(homedir(), ".config", "mcopilot-cli", ".config.yaml");
|
|
6
|
+
/**
|
|
7
|
+
* 从 mcopilot-cli 配置文件中加载 API key
|
|
8
|
+
* 配置文件路径: ~/.config/mcopilot-cli/.config.yaml
|
|
9
|
+
*/
|
|
10
|
+
export async function loadApiKeyFromConfig() {
|
|
11
|
+
try {
|
|
12
|
+
// 检查配置文件是否存在
|
|
13
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
14
|
+
console.error(`CatPaw config file not found: ${CONFIG_PATH}`);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// 读取并解析 YAML
|
|
18
|
+
const content = readFileSync(CONFIG_PATH, "utf-8");
|
|
19
|
+
const config = yaml.load(content);
|
|
20
|
+
// 获取 AUTHORIZATION 字段
|
|
21
|
+
const apiKey = config?.AUTHORIZATION;
|
|
22
|
+
if (typeof apiKey !== "string" || !apiKey) {
|
|
23
|
+
console.error("AUTHORIZATION not found in config file");
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return apiKey;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error("Failed to load CatPaw API key:", error);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 获取配置文件路径(用于调试)
|
|
35
|
+
*/
|
|
36
|
+
export function getConfigPath() {
|
|
37
|
+
return CONFIG_PATH;
|
|
38
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
export declare const CATPAW_PROVIDER_ID = "catpaw";
|
|
3
|
+
/**
|
|
4
|
+
* CatPaw AI Provider Plugin for OpenCode
|
|
5
|
+
*
|
|
6
|
+
* This plugin automatically:
|
|
7
|
+
* 1. Loads API key from ~/.config/mcopilot-cli/.config.yaml
|
|
8
|
+
* 2. Injects required headers (x-api-key, x-working-dir)
|
|
9
|
+
* 3. Supports multiple models: LongCat-Flash-Chat, kimi-k2.5, glm-5, MiniMax-M2.5, claude-sonnet-4.5
|
|
10
|
+
*/
|
|
11
|
+
declare const plugin: Plugin;
|
|
12
|
+
export default plugin;
|
|
13
|
+
export { plugin as CatPawAuthPlugin };
|
|
14
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,qBAAqB,CAAC;AAKhF,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,QAAA,MAAM,MAAM,EAAE,MAsIb,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { loadApiKeyFromConfig } from "./config";
|
|
2
|
+
import { isCatPawRequest, prepareCatPawRequest } from "./request";
|
|
3
|
+
export const CATPAW_PROVIDER_ID = "catpaw";
|
|
4
|
+
/**
|
|
5
|
+
* CatPaw AI Provider Plugin for OpenCode
|
|
6
|
+
*
|
|
7
|
+
* This plugin automatically:
|
|
8
|
+
* 1. Loads API key from ~/.config/mcopilot-cli/.config.yaml
|
|
9
|
+
* 2. Injects required headers (x-api-key, x-working-dir)
|
|
10
|
+
* 3. Supports multiple models: LongCat-Flash-Chat, kimi-k2.5, glm-5, MiniMax-M2.5, claude-sonnet-4.5
|
|
11
|
+
*/
|
|
12
|
+
const plugin = async ({ client, }) => {
|
|
13
|
+
return {
|
|
14
|
+
config: async (config) => {
|
|
15
|
+
// 配置 CatPaw provider
|
|
16
|
+
config.provider = config.provider || {};
|
|
17
|
+
config.provider[CATPAW_PROVIDER_ID] = {
|
|
18
|
+
npm: "@ai-sdk/openai-compatible",
|
|
19
|
+
name: "CatPaw AI",
|
|
20
|
+
options: {
|
|
21
|
+
baseURL: "https://mcli.sankuai.com/v1",
|
|
22
|
+
},
|
|
23
|
+
models: {
|
|
24
|
+
"LongCat-Flash-Chat": {
|
|
25
|
+
name: "LongCat Flash Chat",
|
|
26
|
+
limit: {
|
|
27
|
+
context: 256000,
|
|
28
|
+
output: 8192,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
"kimi-k2.5": {
|
|
32
|
+
name: "Kimi K2.5",
|
|
33
|
+
limit: {
|
|
34
|
+
context: 256000,
|
|
35
|
+
output: 8192,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
"glm-5": {
|
|
39
|
+
name: "GLM-5",
|
|
40
|
+
limit: {
|
|
41
|
+
context: 200000,
|
|
42
|
+
output: 8192,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
"MiniMax-M2.5": {
|
|
46
|
+
name: "MiniMax M2.5",
|
|
47
|
+
limit: {
|
|
48
|
+
context: 200000,
|
|
49
|
+
output: 8192,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
"claude-sonnet-4.5": {
|
|
53
|
+
name: "Claude Sonnet 4.5",
|
|
54
|
+
limit: {
|
|
55
|
+
context: 200000,
|
|
56
|
+
output: 8192,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
auth: {
|
|
63
|
+
provider: CATPAW_PROVIDER_ID,
|
|
64
|
+
loader: async (getAuth, provider) => {
|
|
65
|
+
// 从配置文件加载 API key
|
|
66
|
+
const apiKey = await loadApiKeyFromConfig();
|
|
67
|
+
if (!apiKey) {
|
|
68
|
+
client.app.log({
|
|
69
|
+
body: {
|
|
70
|
+
service: "catpaw-auth",
|
|
71
|
+
level: "error",
|
|
72
|
+
message: "Failed to load API key from ~/.config/mcopilot-cli/.config.yaml",
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
const workingDir = process.env.HOME || process.env.USERPROFILE || "/";
|
|
78
|
+
client.app.log({
|
|
79
|
+
body: {
|
|
80
|
+
service: "catpaw-auth",
|
|
81
|
+
level: "info",
|
|
82
|
+
message: "CatPaw auth loaded successfully",
|
|
83
|
+
extra: { workingDir },
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
apiKey: "", // 使用自定义 fetch,不需要标准 apiKey
|
|
88
|
+
async fetch(input, init) {
|
|
89
|
+
// 只处理 CatPaw 相关的请求
|
|
90
|
+
if (!isCatPawRequest(input)) {
|
|
91
|
+
return fetch(input, init);
|
|
92
|
+
}
|
|
93
|
+
// 准备请求,注入必要的 headers
|
|
94
|
+
const { request, init: requestInit } = prepareCatPawRequest(input, init, apiKey, workingDir);
|
|
95
|
+
// 发送请求
|
|
96
|
+
return fetch(request, requestInit);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
methods: [
|
|
101
|
+
{
|
|
102
|
+
type: "api",
|
|
103
|
+
label: "Auto-config from mcopilot-cli",
|
|
104
|
+
authorize: async () => {
|
|
105
|
+
// 从 mcopilot-cli 配置文件加载 API key
|
|
106
|
+
const apiKey = await loadApiKeyFromConfig();
|
|
107
|
+
if (!apiKey) {
|
|
108
|
+
return { type: "failed" };
|
|
109
|
+
}
|
|
110
|
+
// 返回成功,使用 apiKey 作为 key
|
|
111
|
+
return {
|
|
112
|
+
type: "success",
|
|
113
|
+
key: apiKey,
|
|
114
|
+
provider: CATPAW_PROVIDER_ID,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
export default plugin;
|
|
123
|
+
export { plugin as CatPawAuthPlugin };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查请求是否是 CatPaw API 请求
|
|
3
|
+
*/
|
|
4
|
+
export declare function isCatPawRequest(input: RequestInfo | URL | string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 准备 CatPaw 请求,注入必要的 headers
|
|
7
|
+
*/
|
|
8
|
+
export declare function prepareCatPawRequest(input: RequestInfo | URL | string, init: RequestInit | undefined, apiKey: string, workingDir: string): {
|
|
9
|
+
request: RequestInfo | URL | string;
|
|
10
|
+
init: RequestInit;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,GAAG,OAAO,CAG1E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,EACjC,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB;IAAE,OAAO,EAAE,WAAW,GAAG,GAAG,GAAG,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CA8B5D"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查请求是否是 CatPaw API 请求
|
|
3
|
+
*/
|
|
4
|
+
export function isCatPawRequest(input) {
|
|
5
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
6
|
+
return url.includes("mcli.sankuai.com");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 准备 CatPaw 请求,注入必要的 headers
|
|
10
|
+
*/
|
|
11
|
+
export function prepareCatPawRequest(input, init, apiKey, workingDir) {
|
|
12
|
+
// 解析原始 URL
|
|
13
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
14
|
+
// 准备 headers
|
|
15
|
+
const headers = new Headers(init?.headers);
|
|
16
|
+
// 移除可能冲突的 headers
|
|
17
|
+
headers.delete("host");
|
|
18
|
+
headers.delete("authorization");
|
|
19
|
+
// 注入 CatPaw 必需的 headers
|
|
20
|
+
headers.set("x-api-key", apiKey);
|
|
21
|
+
headers.set("x-working-dir", workingDir);
|
|
22
|
+
// 确保 Content-Type 存在
|
|
23
|
+
if (!headers.has("Content-Type") && !headers.has("content-type")) {
|
|
24
|
+
headers.set("Content-Type", "application/json");
|
|
25
|
+
}
|
|
26
|
+
// 创建新的请求配置
|
|
27
|
+
const requestInit = {
|
|
28
|
+
...init,
|
|
29
|
+
headers,
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
request: input,
|
|
33
|
+
init: requestInit,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode Plugin Types
|
|
3
|
+
* 这些类型定义基于 @opencode-ai/plugin
|
|
4
|
+
*/
|
|
5
|
+
export interface PluginContext {
|
|
6
|
+
project: {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
directory: string;
|
|
10
|
+
};
|
|
11
|
+
directory: string;
|
|
12
|
+
worktree: string;
|
|
13
|
+
client: PluginClient;
|
|
14
|
+
}
|
|
15
|
+
export interface PluginClient {
|
|
16
|
+
app: {
|
|
17
|
+
log: (params: {
|
|
18
|
+
body: {
|
|
19
|
+
service: string;
|
|
20
|
+
level: "debug" | "info" | "warn" | "error";
|
|
21
|
+
message: string;
|
|
22
|
+
extra?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
}) => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface PluginResult {
|
|
28
|
+
config?: (config: Config) => Promise<void> | void;
|
|
29
|
+
auth?: {
|
|
30
|
+
provider: string;
|
|
31
|
+
loader: (getAuth: GetAuth, provider: Provider) => Promise<LoaderResult | null>;
|
|
32
|
+
methods: AuthMethod[];
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface Config {
|
|
36
|
+
provider?: Record<string, ProviderConfig>;
|
|
37
|
+
command?: Record<string, CommandConfig>;
|
|
38
|
+
}
|
|
39
|
+
export interface ProviderConfig {
|
|
40
|
+
npm?: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
options?: Record<string, unknown>;
|
|
43
|
+
models?: Record<string, ModelConfig>;
|
|
44
|
+
}
|
|
45
|
+
export interface ModelConfig {
|
|
46
|
+
name?: string;
|
|
47
|
+
limit?: {
|
|
48
|
+
context?: number;
|
|
49
|
+
output?: number;
|
|
50
|
+
};
|
|
51
|
+
options?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
export interface CommandConfig {
|
|
54
|
+
description: string;
|
|
55
|
+
template: string;
|
|
56
|
+
}
|
|
57
|
+
export interface Provider {
|
|
58
|
+
options?: Record<string, unknown>;
|
|
59
|
+
models?: Record<string, ModelConfig>;
|
|
60
|
+
}
|
|
61
|
+
export interface AuthMethod {
|
|
62
|
+
provider?: string;
|
|
63
|
+
label: string;
|
|
64
|
+
type: "oauth" | "api" | "token";
|
|
65
|
+
authorize?: (inputs?: Record<string, string>) => Promise<{
|
|
66
|
+
type: "success";
|
|
67
|
+
key: string;
|
|
68
|
+
provider?: string;
|
|
69
|
+
} | {
|
|
70
|
+
type: "failed";
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
export type GetAuth = () => Promise<unknown>;
|
|
74
|
+
export interface LoaderResult {
|
|
75
|
+
apiKey: string;
|
|
76
|
+
fetch: (input: RequestInfo | URL | string, init?: RequestInit) => Promise<Response>;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-catpaw-auth",
|
|
3
|
-
"
|
|
4
|
-
"version": "1.1.0",
|
|
3
|
+
"version": "1.2.2",
|
|
5
4
|
"description": "CatPaw AI provider plugin for OpenCode - Auto-auth from mcopilot-cli config",
|
|
6
5
|
"author": "zu1k",
|
|
7
6
|
"repository": {
|
|
@@ -19,26 +18,42 @@
|
|
|
19
18
|
"ai",
|
|
20
19
|
"provider"
|
|
21
20
|
],
|
|
22
|
-
"files": [
|
|
23
|
-
"index.ts",
|
|
24
|
-
"src"
|
|
25
|
-
],
|
|
26
21
|
"license": "MIT",
|
|
27
22
|
"type": "module",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"module": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
28
37
|
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
29
39
|
"dev": "bun run --watch index.ts",
|
|
30
40
|
"check": "tsc --noEmit",
|
|
31
|
-
"clean": "rm -rf node_modules bun.lock"
|
|
41
|
+
"clean": "rm -rf dist node_modules bun.lock",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
32
43
|
},
|
|
33
44
|
"devDependencies": {
|
|
34
45
|
"@types/bun": "latest",
|
|
35
|
-
"@types/js-yaml": "^4.0.9"
|
|
36
|
-
|
|
37
|
-
"peerDependencies": {
|
|
46
|
+
"@types/js-yaml": "^4.0.9",
|
|
47
|
+
"@types/node": "^22.13.9",
|
|
38
48
|
"typescript": "^5.9.3"
|
|
39
49
|
},
|
|
40
50
|
"dependencies": {
|
|
41
51
|
"@opencode-ai/plugin": "^1.2.10",
|
|
52
|
+
"@opencode-ai/sdk": "^1.2.10",
|
|
42
53
|
"js-yaml": "^4.1.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@opencode-ai/plugin": "^1.2.0",
|
|
57
|
+
"@opencode-ai/sdk": "^1.2.0"
|
|
43
58
|
}
|
|
44
59
|
}
|
package/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { CatPawAuthPlugin } from "./src/plugin";
|
package/src/config.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from "fs";
|
|
2
|
-
import { join, homedir } from "path";
|
|
3
|
-
import yaml from "js-yaml";
|
|
4
|
-
|
|
5
|
-
const CONFIG_PATH = join(homedir(), ".config", "mcopilot-cli", ".config.yaml");
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 从 mcopilot-cli 配置文件中加载 API key
|
|
9
|
-
* 配置文件路径: ~/.config/mcopilot-cli/.config.yaml
|
|
10
|
-
*/
|
|
11
|
-
export async function loadApiKeyFromConfig(): Promise<string | null> {
|
|
12
|
-
try {
|
|
13
|
-
// 检查配置文件是否存在
|
|
14
|
-
if (!existsSync(CONFIG_PATH)) {
|
|
15
|
-
console.error(`CatPaw config file not found: ${CONFIG_PATH}`);
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// 读取并解析 YAML
|
|
20
|
-
const content = readFileSync(CONFIG_PATH, "utf-8");
|
|
21
|
-
const config = yaml.load(content) as Record<string, unknown>;
|
|
22
|
-
|
|
23
|
-
// 获取 AUTHORIZATION 字段
|
|
24
|
-
const apiKey = config?.AUTHORIZATION;
|
|
25
|
-
|
|
26
|
-
if (typeof apiKey !== "string" || !apiKey) {
|
|
27
|
-
console.error("AUTHORIZATION not found in config file");
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return apiKey;
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error("Failed to load CatPaw API key:", error);
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 获取配置文件路径(用于调试)
|
|
40
|
-
*/
|
|
41
|
-
export function getConfigPath(): string {
|
|
42
|
-
return CONFIG_PATH;
|
|
43
|
-
}
|
package/src/plugin.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import type { PluginContext, PluginResult, Provider } from "./types";
|
|
2
|
-
import { loadApiKeyFromConfig } from "./config";
|
|
3
|
-
import { isCatPawRequest, prepareCatPawRequest } from "./request";
|
|
4
|
-
|
|
5
|
-
export const CATPAW_PROVIDER_ID = "catpaw";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* CatPaw AI Provider Plugin for OpenCode
|
|
9
|
-
*
|
|
10
|
-
* This plugin automatically:
|
|
11
|
-
* 1. Loads API key from ~/.config/mcopilot-cli/.config.yaml
|
|
12
|
-
* 2. Injects required headers (x-api-key, x-working-dir)
|
|
13
|
-
* 3. Supports multiple models: LongCat-Flash-Chat, kimi-k2.5, glm-5, MiniMax-M2.5, claude-sonnet-4.5
|
|
14
|
-
*/
|
|
15
|
-
export const CatPawAuthPlugin = async ({ client }: PluginContext): Promise<PluginResult> => ({
|
|
16
|
-
config: async (config) => {
|
|
17
|
-
// 配置 CatPaw provider
|
|
18
|
-
config.provider = config.provider || {};
|
|
19
|
-
config.provider[CATPAW_PROVIDER_ID] = {
|
|
20
|
-
npm: "@ai-sdk/openai-compatible",
|
|
21
|
-
name: "CatPaw AI",
|
|
22
|
-
options: {
|
|
23
|
-
baseURL: "https://mcli.sankuai.com/v1",
|
|
24
|
-
},
|
|
25
|
-
models: {
|
|
26
|
-
"LongCat-Flash-Chat": {
|
|
27
|
-
name: "LongCat Flash Chat",
|
|
28
|
-
limit: {
|
|
29
|
-
context: 256000,
|
|
30
|
-
output: 8192,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
"kimi-k2.5": {
|
|
34
|
-
name: "Kimi K2.5",
|
|
35
|
-
limit: {
|
|
36
|
-
context: 256000,
|
|
37
|
-
output: 8192,
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
"glm-5": {
|
|
41
|
-
name: "GLM-5",
|
|
42
|
-
limit: {
|
|
43
|
-
context: 200000,
|
|
44
|
-
output: 8192,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
"MiniMax-M2.5": {
|
|
48
|
-
name: "MiniMax M2.5",
|
|
49
|
-
limit: {
|
|
50
|
-
context: 200000,
|
|
51
|
-
output: 8192,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
"claude-sonnet-4.5": {
|
|
55
|
-
name: "Claude Sonnet 4.5",
|
|
56
|
-
limit: {
|
|
57
|
-
context: 200000,
|
|
58
|
-
output: 8192,
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
auth: {
|
|
65
|
-
provider: CATPAW_PROVIDER_ID,
|
|
66
|
-
loader: async (getAuth, provider: Provider) => {
|
|
67
|
-
// 从配置文件加载 API key
|
|
68
|
-
const apiKey = await loadApiKeyFromConfig();
|
|
69
|
-
|
|
70
|
-
if (!apiKey) {
|
|
71
|
-
client.app.log({
|
|
72
|
-
body: {
|
|
73
|
-
service: "catpaw-auth",
|
|
74
|
-
level: "error",
|
|
75
|
-
message: "Failed to load API key from ~/.config/mcopilot-cli/.config.yaml",
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const workingDir = process.env.HOME || process.env.USERPROFILE || "/";
|
|
82
|
-
|
|
83
|
-
client.app.log({
|
|
84
|
-
body: {
|
|
85
|
-
service: "catpaw-auth",
|
|
86
|
-
level: "info",
|
|
87
|
-
message: "CatPaw auth loaded successfully",
|
|
88
|
-
extra: { workingDir },
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
apiKey: "", // 使用自定义 fetch,不需要标准 apiKey
|
|
94
|
-
async fetch(input, init) {
|
|
95
|
-
// 只处理 CatPaw 相关的请求
|
|
96
|
-
if (!isCatPawRequest(input)) {
|
|
97
|
-
return fetch(input, init);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 准备请求,注入必要的 headers
|
|
101
|
-
const { request, init: requestInit } = prepareCatPawRequest(input, init, apiKey, workingDir);
|
|
102
|
-
|
|
103
|
-
// 发送请求
|
|
104
|
-
return fetch(request, requestInit);
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
},
|
|
108
|
-
methods: [
|
|
109
|
-
{
|
|
110
|
-
provider: CATPAW_PROVIDER_ID,
|
|
111
|
-
label: "Auto-config from mcopilot-cli",
|
|
112
|
-
type: "api",
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
},
|
|
116
|
-
});
|
package/src/request.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 检查请求是否是 CatPaw API 请求
|
|
3
|
-
*/
|
|
4
|
-
export function isCatPawRequest(input: RequestInfo): boolean {
|
|
5
|
-
const url = typeof input === "string" ? input : input.url;
|
|
6
|
-
return url.includes("mcli.sankuai.com");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 准备 CatPaw 请求,注入必要的 headers
|
|
11
|
-
*/
|
|
12
|
-
export function prepareCatPawRequest(
|
|
13
|
-
input: RequestInfo,
|
|
14
|
-
init: RequestInit | undefined,
|
|
15
|
-
apiKey: string,
|
|
16
|
-
workingDir: string
|
|
17
|
-
): { request: RequestInfo; init: RequestInit } {
|
|
18
|
-
// 解析原始 URL
|
|
19
|
-
const url = typeof input === "string" ? input : input.url;
|
|
20
|
-
|
|
21
|
-
// 准备 headers
|
|
22
|
-
const headers = new Headers(init?.headers);
|
|
23
|
-
|
|
24
|
-
// 移除可能冲突的 headers
|
|
25
|
-
headers.delete("host");
|
|
26
|
-
headers.delete("authorization");
|
|
27
|
-
|
|
28
|
-
// 注入 CatPaw 必需的 headers
|
|
29
|
-
headers.set("x-api-key", apiKey);
|
|
30
|
-
headers.set("x-working-dir", workingDir);
|
|
31
|
-
|
|
32
|
-
// 确保 Content-Type 存在
|
|
33
|
-
if (!headers.has("Content-Type") && !headers.has("content-type")) {
|
|
34
|
-
headers.set("Content-Type", "application/json");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 创建新的请求配置
|
|
38
|
-
const requestInit: RequestInit = {
|
|
39
|
-
...init,
|
|
40
|
-
headers,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
request: input,
|
|
45
|
-
init: requestInit,
|
|
46
|
-
};
|
|
47
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenCode Plugin Types
|
|
3
|
-
* 这些类型定义基于 @opencode-ai/plugin
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface PluginContext {
|
|
7
|
-
project: {
|
|
8
|
-
id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
directory: string;
|
|
11
|
-
};
|
|
12
|
-
directory: string;
|
|
13
|
-
worktree: string;
|
|
14
|
-
client: PluginClient;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface PluginClient {
|
|
18
|
-
app: {
|
|
19
|
-
log: (params: {
|
|
20
|
-
body: {
|
|
21
|
-
service: string;
|
|
22
|
-
level: "debug" | "info" | "warn" | "error";
|
|
23
|
-
message: string;
|
|
24
|
-
extra?: Record<string, unknown>;
|
|
25
|
-
};
|
|
26
|
-
}) => Promise<void>;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface PluginResult {
|
|
31
|
-
config?: (config: Config) => Promise<void> | void;
|
|
32
|
-
auth?: {
|
|
33
|
-
provider: string;
|
|
34
|
-
loader: (
|
|
35
|
-
getAuth: GetAuth,
|
|
36
|
-
provider: Provider
|
|
37
|
-
) => Promise<LoaderResult | null>;
|
|
38
|
-
methods: AuthMethod[];
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface Config {
|
|
43
|
-
provider?: Record<string, ProviderConfig>;
|
|
44
|
-
command?: Record<string, CommandConfig>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface ProviderConfig {
|
|
48
|
-
npm?: string;
|
|
49
|
-
name?: string;
|
|
50
|
-
options?: Record<string, unknown>;
|
|
51
|
-
models?: Record<string, ModelConfig>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface ModelConfig {
|
|
55
|
-
name?: string;
|
|
56
|
-
limit?: {
|
|
57
|
-
context?: number;
|
|
58
|
-
output?: number;
|
|
59
|
-
};
|
|
60
|
-
options?: Record<string, unknown>;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface CommandConfig {
|
|
64
|
-
description: string;
|
|
65
|
-
template: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface Provider {
|
|
69
|
-
options?: Record<string, unknown>;
|
|
70
|
-
models?: Record<string, ModelConfig>;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface AuthMethod {
|
|
74
|
-
provider: string;
|
|
75
|
-
label: string;
|
|
76
|
-
type: "oauth" | "api" | "token";
|
|
77
|
-
authorize?: () => Promise<unknown>;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export type GetAuth = () => Promise<unknown>;
|
|
81
|
-
|
|
82
|
-
export interface LoaderResult {
|
|
83
|
-
apiKey: string;
|
|
84
|
-
fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
85
|
-
}
|