@zhin.js/adapter 1.1.0 → 1.1.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/README.md +12 -0
- package/lib/adapter-index.d.ts +6 -1
- package/lib/adapter-index.js +9 -1
- package/lib/definition.d.ts +40 -0
- package/lib/definition.js +42 -0
- package/lib/endpoint-commands.d.ts +127 -0
- package/lib/endpoint-commands.js +385 -0
- package/lib/endpoint-lifecycle.d.ts +68 -0
- package/lib/endpoint-lifecycle.js +333 -0
- package/lib/endpoint-management.d.ts +4 -2
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/provider.js +1 -0
- package/package.json +6 -4
- package/src/adapter-index.ts +13 -1
- package/src/definition.ts +104 -0
- package/src/endpoint-commands.ts +559 -0
- package/src/endpoint-lifecycle.ts +422 -0
- package/src/endpoint-management.ts +4 -2
- package/src/index.ts +4 -0
- package/src/provider.ts +1 -0
package/README.md
CHANGED
|
@@ -16,6 +16,18 @@ export default defineAdapter({
|
|
|
16
16
|
本包只依赖 Kernel 与 Feature Kit,不包含具体平台 SDK。生产 manifest 指向
|
|
17
17
|
`lib/provider.js`;开发时可通过 conditional export 读取源码。
|
|
18
18
|
|
|
19
|
+
单文件插件可用 `setup({ addAdapter })` 注册 `defineAdapter(...)`;Endpoint 仍由同一个
|
|
20
|
+
AdapterIndex 和 generation handoff 管理。
|
|
21
|
+
|
|
22
|
+
## Endpoint 生命周期基座(createEndpointLifecycle)
|
|
23
|
+
|
|
24
|
+
WS/SSE 类端点的 start/stop/重连/心跳统一走 `createEndpointLifecycle`
|
|
25
|
+
(`src/endpoint-lifecycle.ts`),不要手写 `#started`/`#scheduleReconnect` 状态机——
|
|
26
|
+
napcat/milky/onebot11/onebot12/satori 已迁移(各自曾独立犯过同一个 start 失败竞态)。
|
|
27
|
+
基座内置:start 失败复位不武装重连、仅曾 open 才按退避重连(指数+jitter 可配)、
|
|
28
|
+
stop 主动断开不重连、心跳 PONG 看门狗、定时器集中清理、陈旧 socket 事件防叠套。
|
|
29
|
+
迁移指引见该文件 JSDoc。
|
|
30
|
+
|
|
19
31
|
## Adapter ↔ Endpoint:固定 1 对多
|
|
20
32
|
|
|
21
33
|
一个 adapter 插件实例固定对应一到多个 endpoint:
|
package/lib/adapter-index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CapabilityId, type CapabilitySlot, type PluginId, type RuntimeSnapshot } from '@zhin.js/plugin-runtime';
|
|
2
|
-
import type { AdapterCapability, AdapterDefinition, EndpointInstance, EndpointSendRequest } from './definition.js';
|
|
2
|
+
import type { AdapterCapability, AdapterDefinition, AdapterSegmentPolicy, EndpointInstance, EndpointSendRequest } from './definition.js';
|
|
3
3
|
import { type EndpointManagementCapability } from './endpoint-management.js';
|
|
4
4
|
export interface AdapterDescriptor {
|
|
5
5
|
readonly id: CapabilityId;
|
|
@@ -37,6 +37,11 @@ export declare class AdapterIndex {
|
|
|
37
37
|
*/
|
|
38
38
|
instance(adapter: string, endpointId: string): EndpointInstance | undefined;
|
|
39
39
|
owner(id: CapabilityId): PluginId;
|
|
40
|
+
/**
|
|
41
|
+
* Endpoint 的消息段能力声明(出站协商降级依据);
|
|
42
|
+
* 未声明或未知 id 返回 undefined(调用方按历史行为处理)。
|
|
43
|
+
*/
|
|
44
|
+
segmentPolicy(id: CapabilityId): AdapterSegmentPolicy | undefined;
|
|
40
45
|
start(): Promise<void>;
|
|
41
46
|
open(): void;
|
|
42
47
|
close(): Promise<void>;
|
package/lib/adapter-index.js
CHANGED
|
@@ -37,6 +37,7 @@ export class AdapterIndex {
|
|
|
37
37
|
source: slot.source,
|
|
38
38
|
capabilities: slot.definition.capabilities,
|
|
39
39
|
endpoint: endpoint.instance,
|
|
40
|
+
...(slot.definition.segments ? { segments: slot.definition.segments } : {}),
|
|
40
41
|
unconfigured: endpoint.unconfigured,
|
|
41
42
|
started: false,
|
|
42
43
|
open: false,
|
|
@@ -62,7 +63,7 @@ export class AdapterIndex {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
list() {
|
|
65
|
-
return this.#order.map(({ endpoint: _endpoint, unconfigured: _unconfigured, started: _started, open: _open, stopped: _stopped, failed: _failed, startAttempted: _startAttempted, ...descriptor }) => Object.freeze(descriptor));
|
|
66
|
+
return this.#order.map(({ endpoint: _endpoint, unconfigured: _unconfigured, started: _started, open: _open, stopped: _stopped, failed: _failed, startAttempted: _startAttempted, segments: _segments, ...descriptor }) => Object.freeze(descriptor));
|
|
66
67
|
}
|
|
67
68
|
/** Endpoint rows for Console `endpoint.list` / `endpoint.info`. */
|
|
68
69
|
describe() {
|
|
@@ -108,6 +109,13 @@ export class AdapterIndex {
|
|
|
108
109
|
throw new Error(`Unknown Adapter Endpoint: ${id}`);
|
|
109
110
|
return record.owner;
|
|
110
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Endpoint 的消息段能力声明(出站协商降级依据);
|
|
114
|
+
* 未声明或未知 id 返回 undefined(调用方按历史行为处理)。
|
|
115
|
+
*/
|
|
116
|
+
segmentPolicy(id) {
|
|
117
|
+
return this.#records.get(id)?.segments;
|
|
118
|
+
}
|
|
111
119
|
async start() {
|
|
112
120
|
// Soft-start in parallel with a short wait so kitchen-sink Roots do not
|
|
113
121
|
// stall generation. Configured platforms that need longer (QQ auth, Slack
|
package/lib/definition.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ import type { CapabilityContext } from '@zhin.js/feature-kit';
|
|
|
3
3
|
import type { EndpointManagement } from './endpoint-management.js';
|
|
4
4
|
declare const adapterBrand: "zhin.adapter/1";
|
|
5
5
|
export type AdapterCapability = 'inbound' | 'outbound';
|
|
6
|
+
/** 端点可消费的出站媒体来源形式。 */
|
|
7
|
+
export type AdapterOutboundMedia = 'url' | 'path' | 'base64' | 'upload';
|
|
8
|
+
/** 交互段(卡片/按钮等富交互)的端点消费方式。 */
|
|
9
|
+
export type AdapterInteractiveMode = 'native' | 'text';
|
|
6
10
|
export interface EndpointSendRequest {
|
|
7
11
|
readonly target: string;
|
|
8
12
|
readonly payload: unknown;
|
|
@@ -29,11 +33,47 @@ export interface AdapterContext<TConfig = unknown> extends CapabilityContext<TCo
|
|
|
29
33
|
readonly id: CapabilityId;
|
|
30
34
|
readonly name: string;
|
|
31
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* html 段出站策略:
|
|
38
|
+
* - `direct`:端点直接消费 html 段(Console UI 类端点),核心不做任何转换;
|
|
39
|
+
* - `image`:经 html-renderer 渲染成 image 段,无渲染器时降级 text(缺省);
|
|
40
|
+
* - `text`:直接降级为 text 段。
|
|
41
|
+
*/
|
|
42
|
+
export type HtmlOutboundMode = 'direct' | 'image' | 'text';
|
|
43
|
+
/**
|
|
44
|
+
* 端点消息段能力声明(出站协商降级的依据)。
|
|
45
|
+
* 缺省(未声明 `segments`)保持历史行为:仅 html 段按 image/text 处理,
|
|
46
|
+
* 其余段原样透传给端点。
|
|
47
|
+
*/
|
|
48
|
+
export interface AdapterSegmentPolicy {
|
|
49
|
+
/**
|
|
50
|
+
* 端点原生可消费的 wire 段类型(如 `['text', 'image', 'at']`)。
|
|
51
|
+
* 声明后,未列出的段由核心按 `formatSegmentPreview` 降级为 text 段;
|
|
52
|
+
* 不声明则不过滤(全部透传)。
|
|
53
|
+
*/
|
|
54
|
+
readonly supported?: readonly string[];
|
|
55
|
+
/** html 段处理策略,缺省 `image`。 */
|
|
56
|
+
readonly html?: HtmlOutboundMode;
|
|
57
|
+
/** 端点可消费的媒体来源形式;缺省表示不做媒体来源协商。 */
|
|
58
|
+
readonly outboundMedia?: readonly AdapterOutboundMedia[];
|
|
59
|
+
/**
|
|
60
|
+
* 交互段(卡片/按钮等富交互)消费方式:`native` 原生渲染 / `text` 降级纯文本。
|
|
61
|
+
* 目前仅为声明(供出站协商与门禁消费),`text` 的降级执行随 Wave 2 落地。
|
|
62
|
+
*/
|
|
63
|
+
readonly interactive?: AdapterInteractiveMode;
|
|
64
|
+
}
|
|
32
65
|
export interface AdapterDefinition<TConfig = unknown, TResult = unknown> {
|
|
33
66
|
readonly $feature: typeof adapterBrand;
|
|
34
67
|
readonly capabilities: readonly AdapterCapability[];
|
|
68
|
+
/** 可选:端点消息段能力声明(出站协商降级挂载点)。 */
|
|
69
|
+
readonly segments?: AdapterSegmentPolicy;
|
|
35
70
|
create(context: AdapterContext<TConfig>): EndpointInstance<TResult> | Promise<EndpointInstance<TResult>>;
|
|
36
71
|
}
|
|
72
|
+
declare module '@zhin.js/plugin-runtime' {
|
|
73
|
+
interface PluginSetupContext<TConfig> {
|
|
74
|
+
addAdapter<TResult = unknown>(localName: string, definition: AdapterDefinition<TConfig, TResult>): void;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
37
77
|
export declare function defineAdapter<TConfig = unknown, TResult = unknown>(definition: Omit<AdapterDefinition<TConfig, TResult>, '$feature'>): Readonly<AdapterDefinition<TConfig, TResult>>;
|
|
38
78
|
export declare function parseAdapterDefinition(value: unknown): AdapterDefinition;
|
|
39
79
|
export {};
|
package/lib/definition.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
const adapterBrand = 'zhin.adapter/1';
|
|
2
|
+
const HTML_OUTBOUND_MODES = ['direct', 'image', 'text'];
|
|
3
|
+
const OUTBOUND_MEDIA_FORMS = [
|
|
4
|
+
'url', 'path', 'base64', 'upload',
|
|
5
|
+
];
|
|
2
6
|
export function defineAdapter(definition) {
|
|
3
7
|
if (typeof definition.create !== 'function') {
|
|
4
8
|
throw new TypeError('Adapter create must be a function');
|
|
@@ -8,10 +12,46 @@ export function defineAdapter(definition) {
|
|
|
8
12
|
|| capabilities.some((value) => value !== 'inbound' && value !== 'outbound')) {
|
|
9
13
|
throw new TypeError('Adapter capabilities must contain inbound and/or outbound');
|
|
10
14
|
}
|
|
15
|
+
const segments = normalizeSegmentPolicy(definition.segments);
|
|
11
16
|
return Object.freeze({
|
|
12
17
|
...definition,
|
|
13
18
|
$feature: adapterBrand,
|
|
14
19
|
capabilities: Object.freeze(capabilities),
|
|
20
|
+
...(segments ? { segments } : {}),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function normalizeSegmentPolicy(policy) {
|
|
24
|
+
if (policy === undefined)
|
|
25
|
+
return undefined;
|
|
26
|
+
if (!policy || typeof policy !== 'object') {
|
|
27
|
+
throw new TypeError('Adapter segments policy must be an object');
|
|
28
|
+
}
|
|
29
|
+
if (policy.supported !== undefined
|
|
30
|
+
&& (!Array.isArray(policy.supported)
|
|
31
|
+
|| policy.supported.some((type) => typeof type !== 'string' || !type))) {
|
|
32
|
+
throw new TypeError('Adapter segments.supported must be an array of segment type names');
|
|
33
|
+
}
|
|
34
|
+
if (policy.html !== undefined && !HTML_OUTBOUND_MODES.includes(policy.html)) {
|
|
35
|
+
throw new TypeError('Adapter segments.html must be direct, image or text');
|
|
36
|
+
}
|
|
37
|
+
if (policy.outboundMedia !== undefined
|
|
38
|
+
&& (!Array.isArray(policy.outboundMedia)
|
|
39
|
+
|| policy.outboundMedia.length === 0
|
|
40
|
+
|| policy.outboundMedia.some((form) => !OUTBOUND_MEDIA_FORMS.includes(form)))) {
|
|
41
|
+
throw new TypeError("Adapter segments.outboundMedia must be a non-empty array of 'url' | 'path' | 'base64' | 'upload'");
|
|
42
|
+
}
|
|
43
|
+
if (policy.interactive !== undefined
|
|
44
|
+
&& policy.interactive !== 'native'
|
|
45
|
+
&& policy.interactive !== 'text') {
|
|
46
|
+
throw new TypeError("Adapter segments.interactive must be 'native' or 'text'");
|
|
47
|
+
}
|
|
48
|
+
return Object.freeze({
|
|
49
|
+
...(policy.supported ? { supported: Object.freeze([...new Set(policy.supported)]) } : {}),
|
|
50
|
+
...(policy.html ? { html: policy.html } : {}),
|
|
51
|
+
...(policy.outboundMedia
|
|
52
|
+
? { outboundMedia: Object.freeze([...new Set(policy.outboundMedia)]) }
|
|
53
|
+
: {}),
|
|
54
|
+
...(policy.interactive ? { interactive: policy.interactive } : {}),
|
|
15
55
|
});
|
|
16
56
|
}
|
|
17
57
|
export function parseAdapterDefinition(value) {
|
|
@@ -24,6 +64,8 @@ export function parseAdapterDefinition(value) {
|
|
|
24
64
|
|| definition.capabilities.length === 0
|
|
25
65
|
|| definition.capabilities.some((capability) => capability !== 'inbound' && capability !== 'outbound'))
|
|
26
66
|
throw invalidAdapter();
|
|
67
|
+
// defineAdapter 已校验过形状;外部手工构造的 definition 也在此兜底
|
|
68
|
+
normalizeSegmentPolicy(definition.segments);
|
|
27
69
|
return definition;
|
|
28
70
|
}
|
|
29
71
|
function invalidAdapter() {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { type Token } from '@zhin.js/plugin-runtime';
|
|
2
|
+
/**
|
|
3
|
+
* endpoint 管理命令的操作者校验:实例配置声明了 master(顶层或任一端点项)时
|
|
4
|
+
* 仅 master 可执行管理命令;未配置则放行。
|
|
5
|
+
*/
|
|
6
|
+
export declare function isEndpointOperator(config: unknown, input: unknown): boolean;
|
|
7
|
+
/** add/remove 的拒绝文案(list 只读,不校验)。 */
|
|
8
|
+
export declare function endpointCommandForbidden(adapterDisplayName: string): string;
|
|
9
|
+
export type EndpointCommandReply = (text: string) => Promise<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* 从命令 input(Runtime Message)提取 $reply;非消息来源(如 Host API 调用)降级为 no-op。
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractEndpointCommandReply(input: unknown): EndpointCommandReply;
|
|
14
|
+
export interface EndpointRunningInfo {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/** 连接模式(ws / wss / polling / socket-mode …),仅用于 list 展示。 */
|
|
17
|
+
readonly mode?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface EndpointRuntimeState {
|
|
20
|
+
/** 当前 generation 已成功创建的 endpoint(name → 描述) */
|
|
21
|
+
readonly endpoints: Map<string, EndpointRunningInfo>;
|
|
22
|
+
}
|
|
23
|
+
export declare function createEndpointRuntimeState(): EndpointRuntimeState;
|
|
24
|
+
/** 每个适配器在模块顶层调用一次,创建自己的 runtime state token。 */
|
|
25
|
+
export declare function defineEndpointRuntimeStateToken(adapterKey: string): Token<EndpointRuntimeState>;
|
|
26
|
+
/** 项目根:ZHIN_PROJECT_ROOT 优先,缺省 process.cwd()(替代 legacy runtimeCwd) */
|
|
27
|
+
export declare function resolveProjectRoot(): string;
|
|
28
|
+
/** 派生 endpoint 凭据的 env 键:`${ADAPTER}_${NAME}_${FIELD}`(如 `TELEGRAM_MY_BOT_TOKEN`) */
|
|
29
|
+
export declare function buildEndpointEnvKey(adapterKey: string, endpointName: string, fieldKey: string): string;
|
|
30
|
+
/** 写入或更新 `.env` 中的键值,并同步到当前进程 `process.env` */
|
|
31
|
+
export declare function persistEndpointEnvValues(values: Readonly<Record<string, string>>, projectRoot?: string): void;
|
|
32
|
+
export interface ConfiguredEndpointEntry {
|
|
33
|
+
name: string;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** 定位项目配置文件:ZHIN_CONFIG 指定优先,否则发现 zhin.config.yml/.yaml,都没有则默认新建 zhin.config.yml */
|
|
37
|
+
export declare function findEndpointConfigFile(adapterKey: string, projectRoot?: string): string;
|
|
38
|
+
/** 读取 plugins.<adapterKey>.endpoints(plain JS);plugins/<adapterKey> 缺失或形态不符时返回 [] */
|
|
39
|
+
export declare function listConfiguredEndpoints(adapterKey: string, projectRoot?: string): ConfiguredEndpointEntry[];
|
|
40
|
+
/** 追加 endpoint 到 plugins.<adapterKey>.endpoints;name 已存在时报错 */
|
|
41
|
+
export declare function addEndpointToConfig(adapterKey: string, entry: ConfiguredEndpointEntry, projectRoot?: string): string;
|
|
42
|
+
/** 按 name 移除 plugins.<adapterKey>.endpoints 项;不存在返回 false */
|
|
43
|
+
export declare function removeEndpointFromConfig(adapterKey: string, name: string, projectRoot?: string): {
|
|
44
|
+
removed: boolean;
|
|
45
|
+
filePath: string;
|
|
46
|
+
};
|
|
47
|
+
/** add 命令可录入的字段描述(与 schema.json 的 endpoints.items.properties 对齐)。 */
|
|
48
|
+
export interface EndpointFieldSpec {
|
|
49
|
+
/** 配置字段 key(如 token / access_token / url / baseUrl) */
|
|
50
|
+
readonly key: string;
|
|
51
|
+
/** add 时必填(schema 中 required 的凭据/连接字段) */
|
|
52
|
+
readonly required?: boolean;
|
|
53
|
+
/** 凭据类字段:值写入 .env,yaml 保存 ${REF} 引用;否则内联写入 yaml */
|
|
54
|
+
readonly env?: boolean;
|
|
55
|
+
/** 字段说明(用于用法提示) */
|
|
56
|
+
readonly description?: string;
|
|
57
|
+
}
|
|
58
|
+
export type EndpointCommandUse = <T>(token: Token<T>) => T;
|
|
59
|
+
/** bindFlow 钩子上下文:接管 add 命令的自定义绑定流程(如 QQ 扫码)。 */
|
|
60
|
+
export interface EndpointBindFlowContext {
|
|
61
|
+
/** 命令参数 name(未指定时为 undefined,流程可自行决定终名) */
|
|
62
|
+
readonly name?: string;
|
|
63
|
+
/** 向当前会话推送后续状态(二维码刷新 / 成功 / 失败) */
|
|
64
|
+
readonly reply: EndpointCommandReply;
|
|
65
|
+
readonly config: unknown;
|
|
66
|
+
readonly input: unknown;
|
|
67
|
+
readonly use: EndpointCommandUse;
|
|
68
|
+
}
|
|
69
|
+
export interface EndpointCommandsSpec {
|
|
70
|
+
/** 实例 key(zhin.config.yml 的 plugins.<key>,如 telegram / napcat) */
|
|
71
|
+
readonly adapterKey: string;
|
|
72
|
+
/** 展示名(QQ / Telegram / NapCat …),用于权限与列表文案 */
|
|
73
|
+
readonly adapterDisplayName: string;
|
|
74
|
+
/** add 命令可录入字段(bindFlow 接管 add 时仅用于展示) */
|
|
75
|
+
readonly fields?: readonly EndpointFieldSpec[];
|
|
76
|
+
/** 运行中 endpoints 数据源(可选):通常读 adapter create 注册的 runtime state */
|
|
77
|
+
readonly running?: (use: EndpointCommandUse) => Iterable<EndpointRunningInfo>;
|
|
78
|
+
/** list 中配置项的附加描述(如 entry => `appid: ${entry.appid}`) */
|
|
79
|
+
readonly describeEntry?: (entry: ConfiguredEndpointEntry) => string;
|
|
80
|
+
/** list 末尾的附加行(如 QQ 的进行中扫码提示);返回 undefined 不加行 */
|
|
81
|
+
readonly listFooter?: (use: EndpointCommandUse) => string | undefined;
|
|
82
|
+
/** 自定义 add 流程(扫码绑定等);提供时 add 命令忽略 kv 参数,交给钩子 */
|
|
83
|
+
readonly bindFlow?: (context: EndpointBindFlowContext) => Promise<string> | string;
|
|
84
|
+
/** add 命令描述覆盖 */
|
|
85
|
+
readonly addDescription?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 命令定义的最小结构(与 @zhin.js/command 的 CommandDefinition 结构兼容)。
|
|
89
|
+
* provider 层不允许 import @zhin.js/command,故 defineCommand 由调用方注入,
|
|
90
|
+
* 这里只描述结构;适配器侧传入 defineCommand 后 TCommand 即 Readonly<CommandDefinition>。
|
|
91
|
+
*
|
|
92
|
+
* `params` 值域须与 CommandParameterValue 对齐(含 null / 结构化对象),
|
|
93
|
+
* 否则注入的 defineCommand 会因 TS 逆变检查失败(TS2345)。
|
|
94
|
+
*/
|
|
95
|
+
export interface EndpointCommandContext {
|
|
96
|
+
readonly config: unknown;
|
|
97
|
+
/**
|
|
98
|
+
* 与 `@zhin.js/command` 的 `CommandContext.input` 对齐:IM 命中时有值,
|
|
99
|
+
* Host / 无消息路径可为 `undefined`。须保持可选,否则注入 `defineCommand` 会因
|
|
100
|
+
* execute 参数逆变检查失败(TS2345)。
|
|
101
|
+
*/
|
|
102
|
+
readonly input?: unknown;
|
|
103
|
+
readonly args: readonly string[];
|
|
104
|
+
readonly params: Readonly<Record<string, string | number | boolean | Readonly<Record<string, unknown>> | null>>;
|
|
105
|
+
readonly use: EndpointCommandUse;
|
|
106
|
+
}
|
|
107
|
+
export interface EndpointCommandDefinition {
|
|
108
|
+
readonly description?: string;
|
|
109
|
+
execute(context: EndpointCommandContext): unknown;
|
|
110
|
+
}
|
|
111
|
+
export interface EndpointCommands<TCommand = EndpointCommandDefinition> {
|
|
112
|
+
readonly list: TCommand;
|
|
113
|
+
readonly add: TCommand;
|
|
114
|
+
readonly remove: TCommand;
|
|
115
|
+
}
|
|
116
|
+
/** list 文案:运行中 + 配置中两段,footer 可选。 */
|
|
117
|
+
export declare function formatEndpointList(spec: Pick<EndpointCommandsSpec, 'adapterKey' | 'adapterDisplayName' | 'describeEntry'>, source: {
|
|
118
|
+
readonly running: Iterable<EndpointRunningInfo>;
|
|
119
|
+
readonly configured: readonly ConfiguredEndpointEntry[];
|
|
120
|
+
readonly footer?: string;
|
|
121
|
+
}): string;
|
|
122
|
+
/** add(kv 模式)的完整业务逻辑:解析 kv → 凭据写 .env → 追加 yaml;返回回复文本。 */
|
|
123
|
+
export declare function addEndpointFromKeyValues(spec: EndpointCommandsSpec, name: string, args: readonly string[], projectRoot?: string): string;
|
|
124
|
+
/** remove 的完整业务逻辑:从 yaml 移除;返回回复文本。 */
|
|
125
|
+
export declare function removeEndpointByName(spec: Pick<EndpointCommandsSpec, 'adapterKey'>, name: string, projectRoot?: string): string;
|
|
126
|
+
/** 生成 `<adapter> endpoint` 的 list / add / remove 三个命令定义(见文件头接入步骤)。 */
|
|
127
|
+
export declare function createEndpointCommands<TCommand>(spec: EndpointCommandsSpec, defineCommand: (definition: EndpointCommandDefinition) => TCommand): EndpointCommands<TCommand>;
|