@double-coding/dsh-connectors 0.0.0-stage → 0.1.0-test.0
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/CONTRIBUTING.md +173 -0
- package/LICENSE +21 -0
- package/README.en.md +156 -0
- package/README.md +153 -2
- package/assets/readme/architecture.webp +0 -0
- package/assets/readme/hero-en.svg +62 -0
- package/assets/readme/hero.svg +62 -0
- package/assets/readme/panel.webp +0 -0
- package/cordis.patch.yml +8 -0
- package/dist/client.js +5385 -0
- package/dist/client.js.map +7 -0
- package/dist/host/catalog.d.ts +7 -0
- package/dist/host/catalog.js +15 -0
- package/dist/host/catalog.js.map +1 -0
- package/dist/host/cli/adapters.d.ts +69 -0
- package/dist/host/cli/adapters.js +577 -0
- package/dist/host/cli/adapters.js.map +1 -0
- package/dist/host/cli/exec.d.ts +34 -0
- package/dist/host/cli/exec.js +186 -0
- package/dist/host/cli/exec.js.map +1 -0
- package/dist/host/cli/service.d.ts +44 -0
- package/dist/host/cli/service.js +711 -0
- package/dist/host/cli/service.js.map +1 -0
- package/dist/host/cli/version.d.ts +1 -0
- package/dist/host/cli/version.js +16 -0
- package/dist/host/cli/version.js.map +1 -0
- package/dist/host/connections.d.ts +106 -0
- package/dist/host/connections.js +1207 -0
- package/dist/host/connections.js.map +1 -0
- package/dist/host/errors.d.ts +4 -0
- package/dist/host/errors.js +8 -0
- package/dist/host/errors.js.map +1 -0
- package/dist/host/instanceUrl.d.ts +1 -0
- package/dist/host/instanceUrl.js +27 -0
- package/dist/host/instanceUrl.js.map +1 -0
- package/dist/host/mcpServers.d.ts +19 -0
- package/dist/host/mcpServers.js +243 -0
- package/dist/host/mcpServers.js.map +1 -0
- package/dist/host/oauth.d.ts +49 -0
- package/dist/host/oauth.js +215 -0
- package/dist/host/oauth.js.map +1 -0
- package/dist/host/openExternal.d.ts +1 -0
- package/dist/host/openExternal.js +45 -0
- package/dist/host/openExternal.js.map +1 -0
- package/dist/host/providers.d.ts +105 -0
- package/dist/host/providers.js +199 -0
- package/dist/host/providers.js.map +1 -0
- package/dist/host/routes.d.ts +18 -0
- package/dist/host/routes.js +514 -0
- package/dist/host/routes.js.map +1 -0
- package/dist/host/sse-bridge.d.ts +1 -0
- package/dist/host/sse-bridge.js +168 -0
- package/dist/host/sse-bridge.js.map +1 -0
- package/dist/host/store.d.ts +184 -0
- package/dist/host/store.js +98 -0
- package/dist/host/store.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/categories.d.ts +12 -0
- package/dist/shared/categories.js +59 -0
- package/dist/shared/categories.js.map +1 -0
- package/dist/shared/customConfig.d.ts +1 -0
- package/dist/shared/customConfig.js +2 -0
- package/dist/shared/customConfig.js.map +1 -0
- package/dist/shared/types.d.ts +222 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +96 -4
- package/providers/README.md +44 -0
- package/providers/amap/icon.png +0 -0
- package/providers/amap/provider.json +34 -0
- package/providers/baidu-netdisk/icon.png +0 -0
- package/providers/baidu-netdisk/provider.json +36 -0
- package/providers/circleci/icon.svg +1 -0
- package/providers/circleci/provider.json +29 -0
- package/providers/cloudflare-docs/icon.svg +1 -0
- package/providers/cloudflare-docs/provider.json +26 -0
- package/providers/context7/icon.png +0 -0
- package/providers/context7/provider.json +25 -0
- package/providers/deepwiki/icon.svg +5 -0
- package/providers/deepwiki/provider.json +26 -0
- package/providers/firecrawl/icon.png +0 -0
- package/providers/firecrawl/provider.json +40 -0
- package/providers/gitee/icon.svg +1 -0
- package/providers/gitee/provider.json +32 -0
- package/providers/github/icon.svg +1 -0
- package/providers/github/provider.json +33 -0
- package/providers/gitlab/icon.svg +1 -0
- package/providers/gitlab/provider.json +31 -0
- package/providers/gitlab-self-hosted/icon.svg +1 -0
- package/providers/gitlab-self-hosted/provider.json +39 -0
- package/providers/grafana/icon.svg +1 -0
- package/providers/grafana/provider.json +32 -0
- package/providers/linear/icon.svg +1 -0
- package/providers/linear/provider.json +41 -0
- package/providers/microsoft-learn/icon.svg +6 -0
- package/providers/microsoft-learn/provider.json +26 -0
- package/providers/neon/icon.svg +1 -0
- package/providers/neon/provider.json +41 -0
- package/providers/notion/icon.svg +1 -0
- package/providers/notion/provider.json +29 -0
- package/providers/posthog/icon.svg +1 -0
- package/providers/posthog/provider.json +38 -0
- package/providers/postman/icon.svg +1 -0
- package/providers/postman/provider.json +29 -0
- package/providers/qcc/icon.png +0 -0
- package/providers/qcc/provider.json +50 -0
- package/providers/sentry/icon.svg +1 -0
- package/providers/sentry/provider.json +30 -0
- package/providers/sourcegraph/icon.png +0 -0
- package/providers/sourcegraph/provider.json +32 -0
- package/providers/supabase/icon.svg +1 -0
- package/providers/supabase/provider.json +52 -0
- package/providers/tavily/icon.svg +4 -0
- package/providers/tavily/provider.json +41 -0
- package/providers/tencent-docs/icon.png +0 -0
- package/providers/tencent-docs/provider.json +34 -0
- package/providers/tencent-yuanbao-search/icon.png +0 -0
- package/providers/tencent-yuanbao-search/provider.json +32 -0
- package/providers/tianyancha/icon.png +0 -0
- package/providers/tianyancha/provider.json +34 -0
- package/providers/yunxiao/icon.svg +1 -0
- package/providers/yunxiao/provider.json +30 -0
- package/schema/provider.schema.json +325 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { loadProviders } from './providers.js';
|
|
3
|
+
const PROVIDERS_DIR = fileURLToPath(new URL('../../providers/', import.meta.url));
|
|
4
|
+
let cached;
|
|
5
|
+
export function loadBuiltinCatalog() {
|
|
6
|
+
if (cached !== undefined)
|
|
7
|
+
return cached;
|
|
8
|
+
const { cards, issues } = loadProviders(PROVIDERS_DIR);
|
|
9
|
+
for (const issue of issues) {
|
|
10
|
+
console.warn(`[dsh-connectors] provider 配置错误 ${issue.file}: ${issue.message}`);
|
|
11
|
+
}
|
|
12
|
+
cached = { version: 3, cards };
|
|
13
|
+
return cached;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/host/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAO9C,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAEjF,IAAI,MAAkC,CAAA;AAEtC,MAAM,UAAU,kBAAkB;IAChC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IAEvC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,CAAC,aAAa,CAAC,CAAA;IACtD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,kCAAkC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,MAAM,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAA;IAC9B,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { CliCapabilitiesView } from '../../shared/types.js';
|
|
2
|
+
export type CliConnectorId = 'dingtalk' | 'feishu' | 'tmeet' | 'wecom' | 'hf' | 'agent-mail';
|
|
3
|
+
export interface CliAuthStatus {
|
|
4
|
+
authenticated: boolean;
|
|
5
|
+
account?: {
|
|
6
|
+
name?: string;
|
|
7
|
+
email?: string;
|
|
8
|
+
org?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface CliLoginHint {
|
|
12
|
+
link?: string;
|
|
13
|
+
code?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CliCommand {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface CliInstallStep {
|
|
20
|
+
label: string;
|
|
21
|
+
command: string;
|
|
22
|
+
args: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface CliCapabilitySpec {
|
|
25
|
+
args: string[];
|
|
26
|
+
parse(raw: string): CliCapabilitiesView;
|
|
27
|
+
}
|
|
28
|
+
export interface CliAdapter {
|
|
29
|
+
id: CliConnectorId;
|
|
30
|
+
name: string;
|
|
31
|
+
vendor: string;
|
|
32
|
+
description: string;
|
|
33
|
+
category: string;
|
|
34
|
+
examples: string[];
|
|
35
|
+
docsUrl: string;
|
|
36
|
+
bin: string;
|
|
37
|
+
/** 优先使用的可执行文件路径(例如 uv 装到 ~/.local/bin,而 PATH 上可能有旧版) */
|
|
38
|
+
binCandidates?: string[];
|
|
39
|
+
versionArgs: string[];
|
|
40
|
+
/** 官方要求的最低版本;低于时界面提示更新 */
|
|
41
|
+
minVersion?: string;
|
|
42
|
+
/** 登录等待上限,缺省 120s;个别 CLI 的设备码有效期更长 */
|
|
43
|
+
loginTimeoutMs?: number;
|
|
44
|
+
capabilities?: CliCapabilitySpec;
|
|
45
|
+
unsetEnv?: string[];
|
|
46
|
+
install: CliInstallStep[];
|
|
47
|
+
uninstall: CliInstallStep[];
|
|
48
|
+
skills: {
|
|
49
|
+
expectedPrefix: string;
|
|
50
|
+
expected: string[];
|
|
51
|
+
};
|
|
52
|
+
auth: {
|
|
53
|
+
prepare?: CliCommand;
|
|
54
|
+
login: CliCommand;
|
|
55
|
+
status: CliCommand;
|
|
56
|
+
logout?: CliCommand;
|
|
57
|
+
};
|
|
58
|
+
/** CLI 没有 logout 子命令时,用删除本地凭据文件实现解绑 */
|
|
59
|
+
logoutFiles?: {
|
|
60
|
+
dir: string;
|
|
61
|
+
envDir?: string;
|
|
62
|
+
files: string[];
|
|
63
|
+
};
|
|
64
|
+
parseStatus(raw: string): CliAuthStatus;
|
|
65
|
+
parseLoginHint(raw: string): CliLoginHint;
|
|
66
|
+
}
|
|
67
|
+
export declare const CLI_ADAPTERS: Record<CliConnectorId, CliAdapter>;
|
|
68
|
+
export declare function getAdapter(id: string): CliAdapter | undefined;
|
|
69
|
+
export declare function listAdapters(): CliAdapter[];
|
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { resolveNpmCommand, resolveNpxCommand } from './exec.js';
|
|
4
|
+
const URL_PATTERN = /https?:\/\/[^\s"'<>))】]+/i;
|
|
5
|
+
const DEVICE_CODE_PATTERN = /\b([A-Z0-9]{4,8}(?:-[A-Z0-9]{4,8})?)\b/g;
|
|
6
|
+
function firstUrl(raw) {
|
|
7
|
+
const match = URL_PATTERN.exec(raw);
|
|
8
|
+
return match?.[0];
|
|
9
|
+
}
|
|
10
|
+
function textStatus(raw) {
|
|
11
|
+
const trimmed = raw.trim();
|
|
12
|
+
if (trimmed === '')
|
|
13
|
+
return { authenticated: false };
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(trimmed);
|
|
16
|
+
const pick = (...keys) => {
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
const value = parsed[key];
|
|
19
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
20
|
+
return value.trim();
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
};
|
|
24
|
+
const identities = parsed.identities;
|
|
25
|
+
if (typeof identities === 'object' && identities !== null) {
|
|
26
|
+
const user = identities.user;
|
|
27
|
+
if (typeof user === 'object' && user !== null) {
|
|
28
|
+
const record = user;
|
|
29
|
+
const ready = record.status === 'ready'
|
|
30
|
+
|| record.available === true
|
|
31
|
+
|| record.tokenStatus === 'valid'
|
|
32
|
+
|| record.authenticated === true;
|
|
33
|
+
if (ready) {
|
|
34
|
+
const read = (...keys) => {
|
|
35
|
+
for (const key of keys) {
|
|
36
|
+
const value = record[key];
|
|
37
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
38
|
+
return value.trim();
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
};
|
|
42
|
+
const name = read('userName', 'user_name', 'nickName', 'nick_name', 'name');
|
|
43
|
+
const email = read('email', 'mail');
|
|
44
|
+
const org = read('tenantName', 'tenant_name', 'corpName', 'corp_name', 'org', 'orgName', 'org_name');
|
|
45
|
+
return {
|
|
46
|
+
authenticated: true,
|
|
47
|
+
account: {
|
|
48
|
+
...(name === undefined ? {} : { name }),
|
|
49
|
+
...(email === undefined ? {} : { email }),
|
|
50
|
+
...(org === undefined ? {} : { org }),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (record.status === 'expired' || record.status === 'invalid' || record.available === false) {
|
|
55
|
+
return { authenticated: false };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const flag = parsed.authenticated ?? parsed.loggedIn ?? parsed.logged_in ?? parsed.isLogin ?? parsed.is_login;
|
|
60
|
+
const authenticated = flag === true || flag === 'true' || flag === 1
|
|
61
|
+
|| (typeof flag === 'undefined'
|
|
62
|
+
&& pick('userName', 'user_name', 'nickName', 'nick_name', 'email', 'userId', 'user_id', 'unionId') !== undefined);
|
|
63
|
+
const accountName = pick('userName', 'user_name', 'nickName', 'nick_name', 'nick', 'name');
|
|
64
|
+
const accountEmail = pick('email', 'mail');
|
|
65
|
+
const accountOrg = pick('corpName', 'corp_name', 'orgName', 'org_name', 'tenantName', 'tenant_name', 'teamName', 'team_name');
|
|
66
|
+
return {
|
|
67
|
+
authenticated,
|
|
68
|
+
...(authenticated
|
|
69
|
+
? {
|
|
70
|
+
account: {
|
|
71
|
+
...(accountName === undefined ? {} : { name: accountName }),
|
|
72
|
+
...(accountEmail === undefined ? {} : { email: accountEmail }),
|
|
73
|
+
...(accountOrg === undefined ? {} : { org: accountOrg }),
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
const negative = /(未登录|not logged|logged out|no account|not login|未授权|unauthenticated)/i.test(trimmed);
|
|
81
|
+
if (negative)
|
|
82
|
+
return { authenticated: false };
|
|
83
|
+
const positive = /(已登录|logged in|login success|已授权|authenticated)/i.test(trimmed);
|
|
84
|
+
if (!positive)
|
|
85
|
+
return { authenticated: false };
|
|
86
|
+
const name = /(?:用户|账号|account|user|name)[::\s]+([^\s,,;;]+)/i.exec(trimmed)?.[1];
|
|
87
|
+
const email = /[\w.+-]+@[\w-]+\.[\w.-]+/.exec(trimmed)?.[0];
|
|
88
|
+
return { authenticated: true, account: { ...(name === undefined ? {} : { name }), ...(email === undefined ? {} : { email }) } };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function textLoginHint(raw) {
|
|
92
|
+
const link = firstUrl(raw);
|
|
93
|
+
const labelled = /(?:code|代码|设备码|verification)[^\w]{0,8}([A-Z0-9]{4,8}(?:-[A-Z0-9]{4,8})?)/i.exec(raw)?.[1];
|
|
94
|
+
const candidates = [...raw.matchAll(DEVICE_CODE_PATTERN)]
|
|
95
|
+
.map(match => match[1])
|
|
96
|
+
.filter((code) => code !== undefined && !/^(HTTP|HTTPS|JSON|TRUE|FALSE)$/i.test(code));
|
|
97
|
+
const code = labelled ?? candidates[candidates.length - 1];
|
|
98
|
+
return {
|
|
99
|
+
...(link === undefined ? {} : { link }),
|
|
100
|
+
...(code === undefined ? {} : { code }),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function parseJsonObject(raw) {
|
|
104
|
+
const trimmed = raw.trim();
|
|
105
|
+
const candidates = [trimmed];
|
|
106
|
+
const start = trimmed.indexOf('{');
|
|
107
|
+
const end = trimmed.lastIndexOf('}');
|
|
108
|
+
if (start >= 0 && end > start)
|
|
109
|
+
candidates.push(trimmed.slice(start, end + 1));
|
|
110
|
+
for (const candidate of candidates) {
|
|
111
|
+
try {
|
|
112
|
+
const parsed = JSON.parse(candidate);
|
|
113
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// try next candidate
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
function parseDwsCapabilities(raw) {
|
|
124
|
+
const parsed = parseJsonObject(raw);
|
|
125
|
+
const products = Array.isArray(parsed?.products) ? parsed.products : [];
|
|
126
|
+
const items = products.flatMap(product => {
|
|
127
|
+
if (typeof product !== 'object' || product === null)
|
|
128
|
+
return [];
|
|
129
|
+
const record = product;
|
|
130
|
+
if (typeof record.id !== 'string' || record.id.trim() === '')
|
|
131
|
+
return [];
|
|
132
|
+
return [{
|
|
133
|
+
id: record.id.trim(),
|
|
134
|
+
name: record.id.trim(),
|
|
135
|
+
...(typeof record.agent_summary === 'string' && record.agent_summary.trim() !== ''
|
|
136
|
+
? { description: record.agent_summary.trim() }
|
|
137
|
+
: {}),
|
|
138
|
+
...(typeof record.tool_count === 'number' ? { count: record.tool_count } : {}),
|
|
139
|
+
}];
|
|
140
|
+
});
|
|
141
|
+
const metadata = parsed?.agent_metadata;
|
|
142
|
+
const surfaceTools = typeof metadata === 'object' && metadata !== null
|
|
143
|
+
? metadata.surface_tools
|
|
144
|
+
: undefined;
|
|
145
|
+
const total = typeof surfaceTools === 'number'
|
|
146
|
+
? surfaceTools
|
|
147
|
+
: items.reduce((sum, item) => sum + (item.count ?? 0), 0);
|
|
148
|
+
return { kind: 'products', total, items };
|
|
149
|
+
}
|
|
150
|
+
function parseLarkCapabilities(raw) {
|
|
151
|
+
const parsed = parseJsonObject(raw);
|
|
152
|
+
const skills = Array.isArray(parsed?.skills) ? parsed.skills : [];
|
|
153
|
+
const items = skills.flatMap(skill => {
|
|
154
|
+
if (typeof skill !== 'object' || skill === null)
|
|
155
|
+
return [];
|
|
156
|
+
const record = skill;
|
|
157
|
+
if (typeof record.name !== 'string' || record.name.trim() === '')
|
|
158
|
+
return [];
|
|
159
|
+
return [{
|
|
160
|
+
id: record.name.trim(),
|
|
161
|
+
name: record.name.trim(),
|
|
162
|
+
...(typeof record.description === 'string' && record.description.trim() !== ''
|
|
163
|
+
? { description: record.description.trim() }
|
|
164
|
+
: {}),
|
|
165
|
+
}];
|
|
166
|
+
});
|
|
167
|
+
return { kind: 'skills', total: items.length, items };
|
|
168
|
+
}
|
|
169
|
+
const TMEET_GROUPS = {
|
|
170
|
+
app: '应用开通与授权配置',
|
|
171
|
+
auth: '登录与授权状态',
|
|
172
|
+
contact: '企业通讯录',
|
|
173
|
+
control: '会中控制(成员、静音、共享)',
|
|
174
|
+
event: '实时事件订阅',
|
|
175
|
+
meeting: '会议预约、查询与邀请人',
|
|
176
|
+
minutes: '智能纪要',
|
|
177
|
+
record: '录制与转写',
|
|
178
|
+
report: '会议报告',
|
|
179
|
+
tshoot: '故障排查',
|
|
180
|
+
};
|
|
181
|
+
function parseTmeetCapabilities(raw) {
|
|
182
|
+
const lines = raw.split(/\r?\n/);
|
|
183
|
+
const start = lines.findIndex(line => line.trim() === 'Available Commands:');
|
|
184
|
+
const items = [];
|
|
185
|
+
if (start >= 0) {
|
|
186
|
+
for (const line of lines.slice(start + 1)) {
|
|
187
|
+
const trimmed = line.trim();
|
|
188
|
+
if (trimmed === '' || trimmed.startsWith('Flags:'))
|
|
189
|
+
break;
|
|
190
|
+
const match = /^([a-z][a-z0-9-]*)\s*(.*)$/.exec(trimmed);
|
|
191
|
+
if (match === null)
|
|
192
|
+
continue;
|
|
193
|
+
const id = match[1];
|
|
194
|
+
const summary = (match[2] ?? '').trim();
|
|
195
|
+
if (id === 'help' || id === 'completion')
|
|
196
|
+
continue;
|
|
197
|
+
items.push({
|
|
198
|
+
id,
|
|
199
|
+
name: id,
|
|
200
|
+
...(TMEET_GROUPS[id] === undefined && summary === '' ? {} : { description: TMEET_GROUPS[id] ?? summary }),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { kind: 'groups', total: items.length, items };
|
|
205
|
+
}
|
|
206
|
+
const WECOM_SKIP_COMMANDS = new Set(['auth', 'help']);
|
|
207
|
+
function parseWecomCapabilities(raw) {
|
|
208
|
+
const lines = raw.split(/\r?\n/);
|
|
209
|
+
const start = lines.findIndex(line => line.trim() === 'Commands:');
|
|
210
|
+
const items = [];
|
|
211
|
+
if (start >= 0) {
|
|
212
|
+
for (const line of lines.slice(start + 1)) {
|
|
213
|
+
const trimmed = line.trim();
|
|
214
|
+
if (trimmed === '' || trimmed.startsWith('Options:'))
|
|
215
|
+
break;
|
|
216
|
+
const match = /^([a-z][a-z0-9-]*)\s+(.+)$/.exec(trimmed);
|
|
217
|
+
if (match === null)
|
|
218
|
+
continue;
|
|
219
|
+
const id = match[1];
|
|
220
|
+
if (WECOM_SKIP_COMMANDS.has(id))
|
|
221
|
+
continue;
|
|
222
|
+
items.push({ id, name: id, description: match[2].trim() });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return { kind: 'groups', total: items.length, items };
|
|
226
|
+
}
|
|
227
|
+
function parseWecomStatus(raw) {
|
|
228
|
+
const text = raw.trim();
|
|
229
|
+
const lower = text.toLowerCase();
|
|
230
|
+
if (!/status\s*:\s*authorized/.test(lower))
|
|
231
|
+
return { authenticated: false };
|
|
232
|
+
const line = (pattern) => pattern.exec(text)?.[1]?.trim();
|
|
233
|
+
// auth show 只给 Bot ID,没有机器人名称或用户名,不把 ID 当账号名展示
|
|
234
|
+
const name = line(/(?:机器人名称|Bot\s*Name)[^\n::]*[::]\s*(\S+)/i);
|
|
235
|
+
const org = line(/(?:企业名称|团队名称|Corp\s*Name)[^\n::]*[::]\s*([^\n]+)/i);
|
|
236
|
+
return {
|
|
237
|
+
authenticated: true,
|
|
238
|
+
...(name === undefined && org === undefined
|
|
239
|
+
? {}
|
|
240
|
+
: { account: { ...(name === undefined ? {} : { name }), ...(org === undefined ? {} : { org }) } }),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const HF_SKIP_COMMANDS = new Set(['auth', 'skills']);
|
|
244
|
+
function parseHfCapabilities(raw) {
|
|
245
|
+
const lines = raw.split(/\r?\n/);
|
|
246
|
+
const start = lines.findIndex(line => line.trim() === 'Main commands:');
|
|
247
|
+
const items = [];
|
|
248
|
+
if (start >= 0) {
|
|
249
|
+
for (const line of lines.slice(start + 1)) {
|
|
250
|
+
const trimmed = line.trim();
|
|
251
|
+
if (trimmed === '' || trimmed.startsWith('Help commands:'))
|
|
252
|
+
break;
|
|
253
|
+
const match = /^([a-z][a-z0-9-]*)\s{2,}(.+)$/.exec(trimmed);
|
|
254
|
+
if (match === null)
|
|
255
|
+
continue;
|
|
256
|
+
const id = match[1];
|
|
257
|
+
if (HF_SKIP_COMMANDS.has(id))
|
|
258
|
+
continue;
|
|
259
|
+
items.push({ id, name: id, description: match[2].trim() });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return { kind: 'groups', total: items.length, items };
|
|
263
|
+
}
|
|
264
|
+
function parseHfStatus(raw) {
|
|
265
|
+
const text = raw.trim();
|
|
266
|
+
if (/(not logged in|no token|invalid token|unauthorized)/i.test(text))
|
|
267
|
+
return { authenticated: false };
|
|
268
|
+
try {
|
|
269
|
+
const parsed = JSON.parse(text);
|
|
270
|
+
const read = (...keys) => {
|
|
271
|
+
for (const key of keys) {
|
|
272
|
+
const value = parsed[key];
|
|
273
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
274
|
+
return value.trim();
|
|
275
|
+
if (typeof value === 'object' && value !== null) {
|
|
276
|
+
const nested = value.name;
|
|
277
|
+
if (typeof nested === 'string' && nested.trim() !== '')
|
|
278
|
+
return nested.trim();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
};
|
|
283
|
+
const name = read('name', 'user', 'username', 'fullname');
|
|
284
|
+
const email = read('email');
|
|
285
|
+
const org = read('org', 'orgs', 'orgName');
|
|
286
|
+
return {
|
|
287
|
+
authenticated: true,
|
|
288
|
+
...(name === undefined && email === undefined && org === undefined
|
|
289
|
+
? {}
|
|
290
|
+
: { account: { ...(name === undefined ? {} : { name }), ...(email === undefined ? {} : { email }), ...(org === undefined ? {} : { org }) } }),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
const name = /(?:user(?:name)?|account)\s*[::]\s*(\S+)/i.exec(text)?.[1];
|
|
295
|
+
return { authenticated: text !== '', ...(name === undefined ? {} : { account: { name } }) };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const HF_BIN = join(homedir(), '.local', 'bin', process.platform === 'win32' ? 'hf.exe' : 'hf');
|
|
299
|
+
const AGENT_MAIL_SKIP_COMMANDS = new Set(['auth', 'help']);
|
|
300
|
+
const AGENT_MAIL_GROUPS = {
|
|
301
|
+
'+me': '当前账号与别名',
|
|
302
|
+
attachment: '附件上传与下载',
|
|
303
|
+
message: '邮件列表、读取、搜索、监听、发送、回复、转发、垃圾箱与删除',
|
|
304
|
+
};
|
|
305
|
+
function parseAgentMailCapabilities(raw) {
|
|
306
|
+
const lines = raw.split(/\r?\n/);
|
|
307
|
+
const start = lines.findIndex(line => line.trim() === 'Available Commands:');
|
|
308
|
+
const items = [];
|
|
309
|
+
if (start >= 0) {
|
|
310
|
+
for (const line of lines.slice(start + 1)) {
|
|
311
|
+
const trimmed = line.trim();
|
|
312
|
+
if (trimmed === '' || trimmed.startsWith('Flags:'))
|
|
313
|
+
break;
|
|
314
|
+
const match = /^(\+?[a-z][a-z0-9-]*)\s{2,}(.+)$/.exec(trimmed);
|
|
315
|
+
if (match === null)
|
|
316
|
+
continue;
|
|
317
|
+
const id = match[1];
|
|
318
|
+
if (AGENT_MAIL_SKIP_COMMANDS.has(id))
|
|
319
|
+
continue;
|
|
320
|
+
items.push({ id: id.startsWith('+') ? id.slice(1) : id, name: id, description: AGENT_MAIL_GROUPS[id] ?? match[2].trim() });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return { kind: 'groups', total: items.length, items };
|
|
324
|
+
}
|
|
325
|
+
function parseAgentMailStatus(raw) {
|
|
326
|
+
const text = raw.trim();
|
|
327
|
+
try {
|
|
328
|
+
const parsed = JSON.parse(text);
|
|
329
|
+
const data = typeof parsed.data === 'object' && parsed.data !== null
|
|
330
|
+
? parsed.data
|
|
331
|
+
: parsed;
|
|
332
|
+
const loggedIn = data.logged_in === true || data.status === 'logged_in' || data.logged_in === 'true';
|
|
333
|
+
if (!loggedIn)
|
|
334
|
+
return { authenticated: false };
|
|
335
|
+
const read = (...keys) => {
|
|
336
|
+
for (const key of keys) {
|
|
337
|
+
const value = data[key];
|
|
338
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
339
|
+
return value.trim();
|
|
340
|
+
}
|
|
341
|
+
return undefined;
|
|
342
|
+
};
|
|
343
|
+
const name = read('email', 'mail', 'address', 'alias', 'user');
|
|
344
|
+
return { authenticated: true, ...(name === undefined ? {} : { account: { name } }) };
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return { authenticated: /"logged_in"\s*:\s*true/.test(text) };
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
export const CLI_ADAPTERS = {
|
|
351
|
+
dingtalk: {
|
|
352
|
+
id: 'dingtalk',
|
|
353
|
+
name: '钉钉',
|
|
354
|
+
vendor: '钉钉',
|
|
355
|
+
description: '通过官方 dws CLI 管理钉钉全产品能力:AI 表格、考勤、日历、群聊与机器人、通讯录、DING、文档、云盘、AI 听记、邮箱、OA 审批、日志、待办。',
|
|
356
|
+
category: '办公协作',
|
|
357
|
+
examples: [
|
|
358
|
+
'在钉钉群【产品周会】里用机器人发通知:今天 15:00 在 3 楼会议室开周会,带上上周进展材料',
|
|
359
|
+
'查我下周的钉钉日程,列出与【客户对接】相关的会议,并找出三人都空闲的时段约同步会',
|
|
360
|
+
'在钉钉 AI 表格【任务跟踪】新增一行:标题=Q2 上线评审、负责人=张三、截止=2026-05-20、状态=进行中',
|
|
361
|
+
'用 dws 搜索我钉钉邮箱里最近一周来自财务部、主题含【报销】的邮件',
|
|
362
|
+
],
|
|
363
|
+
docsUrl: 'https://open.dingtalk.com/document/development/dingtalk-dws-cli-install-guide',
|
|
364
|
+
bin: 'dws',
|
|
365
|
+
versionArgs: ['--version'],
|
|
366
|
+
capabilities: { args: ['schema', '-f', 'json'], parse: parseDwsCapabilities },
|
|
367
|
+
install: [
|
|
368
|
+
{ label: '安装 dws CLI', command: resolveNpmCommand(), args: ['install', '-g', 'dingtalk-workspace-cli'] },
|
|
369
|
+
],
|
|
370
|
+
uninstall: [
|
|
371
|
+
{ label: '卸载 dws CLI', command: resolveNpmCommand(), args: ['uninstall', '-g', 'dingtalk-workspace-cli'] },
|
|
372
|
+
],
|
|
373
|
+
skills: {
|
|
374
|
+
expectedPrefix: 'dingtalk-',
|
|
375
|
+
expected: ['dingtalk-aitable', 'dingtalk-calendar', 'dingtalk-chat', 'dingtalk-contact', 'dingtalk-doc', 'dingtalk-drive', 'dingtalk-todo', 'dingtalk-wiki'],
|
|
376
|
+
},
|
|
377
|
+
auth: {
|
|
378
|
+
login: { command: 'dws', args: ['auth', 'login', '--device', '--recommend'] },
|
|
379
|
+
status: { command: 'dws', args: ['auth', 'status', '--format', 'json'] },
|
|
380
|
+
logout: { command: 'dws', args: ['auth', 'logout'] },
|
|
381
|
+
},
|
|
382
|
+
parseStatus: textStatus,
|
|
383
|
+
parseLoginHint: textLoginHint,
|
|
384
|
+
},
|
|
385
|
+
feishu: {
|
|
386
|
+
id: 'feishu',
|
|
387
|
+
name: '飞书',
|
|
388
|
+
vendor: '飞书',
|
|
389
|
+
description: '通过官方 lark-cli 管理飞书:消息、文档、多维表格、电子表格、幻灯片、日历、邮箱、任务、会议等。',
|
|
390
|
+
category: '办公协作',
|
|
391
|
+
examples: [
|
|
392
|
+
'在飞书群里发一条消息,汇总本周项目进展并 @ 相关负责人',
|
|
393
|
+
'查我下周的飞书日历,列出与【客户对接】相关的会议并找出空闲时段',
|
|
394
|
+
'在飞书多维表格【任务跟踪】新增一条记录:标题=Q2 上线评审、负责人=张三、截止=2026-05-20',
|
|
395
|
+
'搜索我飞书邮箱里最近一周来自财务部、主题含【报销】的邮件',
|
|
396
|
+
],
|
|
397
|
+
docsUrl: 'https://open.feishu.cn/document/mcp_open_tools/feishu-cli-let-ai-actually-do-your-work-in-feishu',
|
|
398
|
+
bin: 'lark-cli',
|
|
399
|
+
versionArgs: ['--version'],
|
|
400
|
+
capabilities: { args: ['skills', 'list'], parse: parseLarkCapabilities },
|
|
401
|
+
unsetEnv: ['HERMES_HOME', 'OPENCLAW_HOME'],
|
|
402
|
+
install: [
|
|
403
|
+
{ label: '安装 lark-cli', command: resolveNpmCommand(), args: ['install', '-g', '@larksuite/cli'] },
|
|
404
|
+
{ label: '安装飞书 Skills', command: resolveNpxCommand(), args: ['skills', 'add', 'larksuite/cli', '-y', '-g'] },
|
|
405
|
+
],
|
|
406
|
+
uninstall: [
|
|
407
|
+
{ label: '卸载 lark-cli', command: resolveNpmCommand(), args: ['uninstall', '-g', '@larksuite/cli'] },
|
|
408
|
+
],
|
|
409
|
+
skills: {
|
|
410
|
+
expectedPrefix: 'lark-',
|
|
411
|
+
expected: ['lark-shared', 'lark-calendar', 'lark-im', 'lark-doc', 'lark-drive', 'lark-sheets', 'lark-base', 'lark-task', 'lark-mail', 'lark-contact', 'lark-wiki'],
|
|
412
|
+
},
|
|
413
|
+
auth: {
|
|
414
|
+
prepare: { command: 'lark-cli', args: ['config', 'init', '--new'] },
|
|
415
|
+
login: { command: 'lark-cli', args: ['auth', 'login', '--recommend'] },
|
|
416
|
+
status: { command: 'lark-cli', args: ['auth', 'status'] },
|
|
417
|
+
logout: { command: 'lark-cli', args: ['auth', 'logout'] },
|
|
418
|
+
},
|
|
419
|
+
parseStatus: textStatus,
|
|
420
|
+
parseLoginHint: textLoginHint,
|
|
421
|
+
},
|
|
422
|
+
tmeet: {
|
|
423
|
+
id: 'tmeet',
|
|
424
|
+
name: '腾讯会议',
|
|
425
|
+
vendor: '腾讯',
|
|
426
|
+
description: '通过官方 tmeet CLI 管理腾讯会议:预约/查询会议、邀请人、录制与转写、智能纪要、会议报告、会中控制。',
|
|
427
|
+
category: '办公协作',
|
|
428
|
+
examples: [
|
|
429
|
+
'帮我约下周三 15:00 的腾讯会议,主题【Q3 方案评审】,邀请张三和李四',
|
|
430
|
+
'查我下周的腾讯会议,按时间列出来',
|
|
431
|
+
'把昨天那场会的智能纪要整理成待办',
|
|
432
|
+
'找上周那场会的录制链接和参会报告',
|
|
433
|
+
],
|
|
434
|
+
docsUrl: 'https://meeting.tencent.com/support/topic/2236/index.html',
|
|
435
|
+
bin: 'tmeet',
|
|
436
|
+
versionArgs: ['--version'],
|
|
437
|
+
capabilities: { args: ['--help'], parse: parseTmeetCapabilities },
|
|
438
|
+
install: [
|
|
439
|
+
{ label: '安装 tmeet CLI', command: resolveNpmCommand(), args: ['install', '-g', '@tencentcloud/tmeet'] },
|
|
440
|
+
{ label: '安装腾讯会议 Skills', command: resolveNpxCommand(), args: ['skills', 'add', 'TencentCloud/tencentmeeting-cli', '-y', '-g'] },
|
|
441
|
+
],
|
|
442
|
+
uninstall: [
|
|
443
|
+
{ label: '卸载 tmeet CLI', command: resolveNpmCommand(), args: ['uninstall', '-g', '@tencentcloud/tmeet'] },
|
|
444
|
+
],
|
|
445
|
+
skills: {
|
|
446
|
+
expectedPrefix: 'tmeet',
|
|
447
|
+
expected: ['tmeet-skill'],
|
|
448
|
+
},
|
|
449
|
+
auth: {
|
|
450
|
+
login: { command: 'tmeet', args: ['auth', 'login', '--no-browser'] },
|
|
451
|
+
status: { command: 'tmeet', args: ['auth', 'status', '--format', 'json'] },
|
|
452
|
+
logout: { command: 'tmeet', args: ['auth', 'logout'] },
|
|
453
|
+
},
|
|
454
|
+
parseStatus: textStatus,
|
|
455
|
+
parseLoginHint: textLoginHint,
|
|
456
|
+
},
|
|
457
|
+
wecom: {
|
|
458
|
+
id: 'wecom',
|
|
459
|
+
name: '企业微信',
|
|
460
|
+
vendor: '企业微信',
|
|
461
|
+
description: '通过官方 wecom-cli 操作企业微信:消息、邮件、文档、表格、智能表格、智能文档、待办、日程、会议、微盘、通讯录。',
|
|
462
|
+
category: '办公协作',
|
|
463
|
+
examples: [
|
|
464
|
+
'在企业微信里给张三发一条消息,说明今天的发布已推迟到 18 点',
|
|
465
|
+
'搜一下我这周的邮件,把需要今天回复的列出来',
|
|
466
|
+
'在智能表格【任务跟踪】新增一行:标题=Q3 复盘、负责人=张三、截止=2026-11-05',
|
|
467
|
+
'查我明天的日程,把和客户相关的会议整理成一页待办',
|
|
468
|
+
],
|
|
469
|
+
docsUrl: 'https://developer.work.weixin.qq.com/document/path/101750',
|
|
470
|
+
bin: 'wecom-cli',
|
|
471
|
+
versionArgs: ['--version'],
|
|
472
|
+
minVersion: '1.2.1',
|
|
473
|
+
capabilities: { args: ['--help'], parse: parseWecomCapabilities },
|
|
474
|
+
install: [
|
|
475
|
+
{ label: '安装 wecom-cli', command: resolveNpmCommand(), args: ['install', '-g', '@wecom/cli'] },
|
|
476
|
+
{ label: '安装企业微信 Skills', command: resolveNpxCommand(), args: ['skills', 'add', 'WeComTeam/wecom-cli', '-y', '-g'] },
|
|
477
|
+
],
|
|
478
|
+
uninstall: [
|
|
479
|
+
{ label: '卸载 wecom-cli', command: resolveNpmCommand(), args: ['uninstall', '-g', '@wecom/cli'] },
|
|
480
|
+
],
|
|
481
|
+
skills: {
|
|
482
|
+
expectedPrefix: 'wecomcli',
|
|
483
|
+
expected: ['wecomcli-shared', 'wecomcli-message', 'wecomcli-doc', 'wecomcli-sheet', 'wecomcli-smartsheet', 'wecomcli-todo', 'wecomcli-calendar', 'wecomcli-meeting'],
|
|
484
|
+
},
|
|
485
|
+
auth: {
|
|
486
|
+
login: { command: 'wecom-cli', args: ['auth', 'init', '--noninteractive', '--no-browser'] },
|
|
487
|
+
status: { command: 'wecom-cli', args: ['auth', 'show'] },
|
|
488
|
+
},
|
|
489
|
+
logoutFiles: {
|
|
490
|
+
dir: '~/.config/wecom',
|
|
491
|
+
envDir: 'WECOM_CLI_CONFIG_DIR',
|
|
492
|
+
files: ['bot.enc', 'token.enc', 'credentials.enc', 'config.json'],
|
|
493
|
+
},
|
|
494
|
+
parseStatus: parseWecomStatus,
|
|
495
|
+
parseLoginHint: textLoginHint,
|
|
496
|
+
},
|
|
497
|
+
hf: {
|
|
498
|
+
id: 'hf',
|
|
499
|
+
name: 'Hugging Face',
|
|
500
|
+
vendor: 'Hugging Face',
|
|
501
|
+
description: '通过官方 hf CLI 管理 Hugging Face:搜索与下载模型/数据集、上传文件、管理仓库、Spaces、Buckets、Jobs 与 Webhooks。',
|
|
502
|
+
category: '知识检索',
|
|
503
|
+
examples: [
|
|
504
|
+
'搜一下 Hugging Face 上 Qwen 的量化模型,按下载量排序',
|
|
505
|
+
'下载 meta-llama/Llama-3.2-1B-Instruct 到本地缓存',
|
|
506
|
+
'把本地 ./model 目录上传到我账号下新建的模型仓库',
|
|
507
|
+
'看看我昨天的 Jobs 跑完没有,失败的把日志摘要给我',
|
|
508
|
+
],
|
|
509
|
+
docsUrl: 'https://huggingface.co/docs/hub/agents-cli',
|
|
510
|
+
bin: 'hf',
|
|
511
|
+
binCandidates: [HF_BIN],
|
|
512
|
+
versionArgs: ['version', '--format', 'json'],
|
|
513
|
+
loginTimeoutMs: 300_000,
|
|
514
|
+
capabilities: { args: ['--help'], parse: parseHfCapabilities },
|
|
515
|
+
install: [
|
|
516
|
+
{ label: '安装 hf CLI', command: 'uv', args: ['tool', 'install', 'huggingface_hub'] },
|
|
517
|
+
{ label: '安装 Hugging Face Skills', command: HF_BIN, args: ['skills', 'add', '-g'] },
|
|
518
|
+
],
|
|
519
|
+
uninstall: [
|
|
520
|
+
{ label: '卸载 hf CLI', command: 'uv', args: ['tool', 'uninstall', 'huggingface-hub'] },
|
|
521
|
+
],
|
|
522
|
+
skills: {
|
|
523
|
+
expectedPrefix: 'hf-cli',
|
|
524
|
+
expected: ['hf-cli'],
|
|
525
|
+
},
|
|
526
|
+
auth: {
|
|
527
|
+
login: { command: 'hf', args: ['auth', 'login', '--format', 'agent'] },
|
|
528
|
+
status: { command: 'hf', args: ['auth', 'whoami', '--format', 'json'] },
|
|
529
|
+
logout: { command: 'hf', args: ['auth', 'logout'] },
|
|
530
|
+
},
|
|
531
|
+
parseStatus: parseHfStatus,
|
|
532
|
+
parseLoginHint: textLoginHint,
|
|
533
|
+
},
|
|
534
|
+
'agent-mail': {
|
|
535
|
+
id: 'agent-mail',
|
|
536
|
+
name: 'Agent Mail',
|
|
537
|
+
vendor: 'QQ 邮箱',
|
|
538
|
+
description: '通过官方 agently-cli 操作 Agent Mail(QQ 邮箱为 Agent 打造的专属邮箱):收发、回复、转发、搜索、附件与垃圾箱管理。',
|
|
539
|
+
category: '办公协作',
|
|
540
|
+
examples: [
|
|
541
|
+
'给 alice@example.com 发一封邮件,主题【周会纪要】,正文用我给的要点',
|
|
542
|
+
'看看我最近 10 封邮件,把需要今天回复的挑出来',
|
|
543
|
+
'搜索最近一个月带【发票】的邮件,把附件下载到本地',
|
|
544
|
+
'回复 msg_001,说明会议改到周四下午',
|
|
545
|
+
],
|
|
546
|
+
docsUrl: 'https://agent.qq.com/doc/cli-setup.md',
|
|
547
|
+
bin: 'agently-cli',
|
|
548
|
+
versionArgs: ['--version'],
|
|
549
|
+
loginTimeoutMs: 300_000,
|
|
550
|
+
capabilities: { args: ['--help'], parse: parseAgentMailCapabilities },
|
|
551
|
+
install: [
|
|
552
|
+
{ label: '安装 agently-cli', command: resolveNpmCommand(), args: ['install', '-g', '@tencent-qqmail/agently-cli'] },
|
|
553
|
+
{ label: '安装 Agent Mail Skills', command: resolveNpxCommand(), args: ['skills', 'add', 'https://agent.qq.com', '--skill', '-g', '-y'] },
|
|
554
|
+
],
|
|
555
|
+
uninstall: [
|
|
556
|
+
{ label: '卸载 agently-cli', command: resolveNpmCommand(), args: ['uninstall', '-g', '@tencent-qqmail/agently-cli'] },
|
|
557
|
+
],
|
|
558
|
+
skills: {
|
|
559
|
+
expectedPrefix: 'agently-mail',
|
|
560
|
+
expected: ['agently-mail'],
|
|
561
|
+
},
|
|
562
|
+
auth: {
|
|
563
|
+
login: { command: 'agently-cli', args: ['auth', 'login'] },
|
|
564
|
+
status: { command: 'agently-cli', args: ['auth', 'status'] },
|
|
565
|
+
logout: { command: 'agently-cli', args: ['auth', 'logout'] },
|
|
566
|
+
},
|
|
567
|
+
parseStatus: parseAgentMailStatus,
|
|
568
|
+
parseLoginHint: textLoginHint,
|
|
569
|
+
},
|
|
570
|
+
};
|
|
571
|
+
export function getAdapter(id) {
|
|
572
|
+
return CLI_ADAPTERS[id];
|
|
573
|
+
}
|
|
574
|
+
export function listAdapters() {
|
|
575
|
+
return Object.values(CLI_ADAPTERS);
|
|
576
|
+
}
|
|
577
|
+
//# sourceMappingURL=adapters.js.map
|