@shgroup/dsh-serenity-hooks 1.30.14 → 1.30.15
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/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.15",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——10 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.2-rc.1(deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/ccc.d.ts
CHANGED
|
@@ -178,6 +178,15 @@ export interface WeixinRouteConfig {
|
|
|
178
178
|
export interface SkiffRoleConfig {
|
|
179
179
|
/** 角色模型(provider/model;CCC 直接指定,无白名单校验——用户拍板) */
|
|
180
180
|
model?: string;
|
|
181
|
+
/**
|
|
182
|
+
* 角色类型(v1.30.15,S142 用户拍板"skiff 应该区分的类型是临时和长期"):
|
|
183
|
+
* - `temporary`:临时 skiff——不绑定 trajectory(无 SESSION.md 工作台),
|
|
184
|
+
* 提示词按创建时快照注入("注入发生一次")。
|
|
185
|
+
* - `persistent`:长期 skiff——绑定 trajectory(自动建/恢复 SESSION.md 工作台),
|
|
186
|
+
* 提示词**每轮动态重读文件**(改 `systemPromptFile` 即生效,无需重启)。
|
|
187
|
+
* 缺省(未写)= 隐式推断:调用方传入稳定 sessionId → persistent,否则 temporary。
|
|
188
|
+
*/
|
|
189
|
+
kind?: 'temporary' | 'persistent';
|
|
181
190
|
/** MSM 白名单(独立):该角色可 exec 的 MSM 名列表;缺省空 = 无 MSM 通道 */
|
|
182
191
|
msms?: string[];
|
|
183
192
|
/** 非 MSM 工具白名单(独立):平台/ACC 工具名列表;缺省空 = 仅 MSM 通道 */
|
|
@@ -191,7 +200,8 @@ export interface SkiffRoleConfig {
|
|
|
191
200
|
/** 角色系统提示词(CCC 完整定义:人格/认知边界/回答风格) */
|
|
192
201
|
systemPrompt?: string;
|
|
193
202
|
/** 角色系统提示词文件(推荐:相对 CCC 根引用 md 文件——超长提示词在 JSON 内嵌不可读;
|
|
194
|
-
* 优先于 systemPrompt;文件缺失/逃逸 → resolveRoleSystemPrompt
|
|
203
|
+
* 优先于 systemPrompt;文件缺失/逃逸 → resolveRoleSystemPrompt 抛错。
|
|
204
|
+
* persistent 型每轮重读(mtime 缓存),改文件即生效) */
|
|
195
205
|
systemPromptFile?: string;
|
|
196
206
|
}
|
|
197
207
|
/**
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { a as findSerenityRoot, c as matchBlacklist, d as readCccName$2, f as readHandymanConfig, i as findGitRoot, l as pathInside, m as resolveInside, n as SAFE_MODE_MARKER, o as isSafeModeOn, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-DAsSHsub.js";
|
|
3
|
-
import { a as
|
|
4
|
-
import { A as skiffRoleFor, C as listActiveHandymen, D as splitModel, E as requireWhitelistedModel, O as writeFailedStatus, S as handymanProgressPaths, T as readProgress, _ as unregisterSkiffSession, a as startSkiffDebugServer, b as HANDYMAN_GUIDE, c as askSkiff, d as ensureWorkspacePromptSection, f as getSkiffAgent, g as skiffTrajectoryEnabled, h as skiffSessionSnapshot, k as writeProgress, l as createSkiffAgent, m as skiffSessionInfo, n as jscSafeJsonText, o as stopSkiffDebugServer, p as skiffMsmGate, r as renderSkiffMarkdown, s as stripThink, t as discoverCccs, u as ensureSkiffSession, v as workspaceTrajectoryLine, w as newStopToken, x as buildRoundPrompt, y as waitAgentIdle } from "./skiff-debug-
|
|
3
|
+
import { a as readSkiffRoles, d as systemPromptSource, i as isSkiffSessionId, l as roleToolWhitelist, o as resolveRoleSystemPrompt } from "./skiff-role-BYvNnwv1.js";
|
|
4
|
+
import { A as skiffRoleFor, C as listActiveHandymen, D as splitModel, E as requireWhitelistedModel, O as writeFailedStatus, S as handymanProgressPaths, T as readProgress, _ as unregisterSkiffSession, a as startSkiffDebugServer, b as HANDYMAN_GUIDE, c as askSkiff, d as ensureWorkspacePromptSection, f as getSkiffAgent, g as skiffTrajectoryEnabled, h as skiffSessionSnapshot, k as writeProgress, l as createSkiffAgent, m as skiffSessionInfo, n as jscSafeJsonText, o as stopSkiffDebugServer, p as skiffMsmGate, r as renderSkiffMarkdown, s as stripThink, t as discoverCccs, u as ensureSkiffSession, v as workspaceTrajectoryLine, w as newStopToken, x as buildRoundPrompt, y as waitAgentIdle } from "./skiff-debug-C5ulZKCa.js";
|
|
5
5
|
import { i as hostSessions, n as hostInjected, o as hostWeb, r as hostService, s as hostWebServer, t as hostAgents } from "./access-dU_vG1q8.js";
|
|
6
6
|
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, h as runLocalStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-BD_yYAZz.js";
|
|
7
7
|
import { C as useSession, S as summarize, _ as resolveSessionByTitle, a as archiveSessions, b as setActiveSessionInfo, c as createSession, d as getActiveSessionInfo, f as healthCheck, g as readActiveSessionMd, h as qaCheck, i as SESSION_ACTIONS, l as extractSessionMdPathFromText, m as parseSessionContextFromEvents, n as readLastBound, o as clearActiveSessionInfo, p as listSessions, r as DEFAULT_SESSION_SCOPE, s as closeSession, t as appendBound, u as findSession, v as sessionEvents, x as showSession, y as sessionsRoot } from "./session-bound-BpTayaIS.js";
|
|
@@ -6478,7 +6478,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
6478
6478
|
workspace: url.searchParams.get("workspace") ?? void 0
|
|
6479
6479
|
});
|
|
6480
6480
|
const root = findSerenityRoot(workspace) ?? "";
|
|
6481
|
-
const { discoverCccs } = await import("./skiff-debug-
|
|
6481
|
+
const { discoverCccs } = await import("./skiff-debug-C5ulZKCa.js").then((n) => n.i);
|
|
6482
6482
|
sendJson$2(res, 200, { cccs: await discoverCccs(ctx, root) });
|
|
6483
6483
|
} catch (err) {
|
|
6484
6484
|
sendJson$2(res, 400, { error: err.message ?? String(err) });
|
|
@@ -6675,7 +6675,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
6675
6675
|
return;
|
|
6676
6676
|
}
|
|
6677
6677
|
const { saveWeixinRoutes } = await import("./weixin-route-BD_yYAZz.js").then((n) => n.u);
|
|
6678
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
6678
|
+
const { readSkiffRoles } = await import("./skiff-role-BYvNnwv1.js").then((n) => n.u);
|
|
6679
6679
|
const roles = readSkiffRoles(root);
|
|
6680
6680
|
for (const r of routes) if (!roles.has(r.role)) {
|
|
6681
6681
|
sendJson$2(res, 400, { error: `unknown role: ${r.role} (not in ${root} skiff.roles)` });
|
|
@@ -9897,7 +9897,7 @@ function matchCcc(input, candidates) {
|
|
|
9897
9897
|
}
|
|
9898
9898
|
/** 组装候选列表(discoverCccs 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
|
|
9899
9899
|
async function collectCandidates(ctx) {
|
|
9900
|
-
const { discoverCccs } = await import("./skiff-debug-
|
|
9900
|
+
const { discoverCccs } = await import("./skiff-debug-C5ulZKCa.js").then((n) => n.i);
|
|
9901
9901
|
const entries = await discoverCccs(ctx, process.cwd());
|
|
9902
9902
|
const seen = /* @__PURE__ */ new Set();
|
|
9903
9903
|
const out = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { a as findSerenityRoot, f as readHandymanConfig } from "./ccc-DAsSHsub.js";
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as readSkiffRoles, c as roleMsmWhitelist, f as trajectorySubset, i as isSkiffSessionId, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-BYvNnwv1.js";
|
|
4
4
|
import { i as hostSessions, r as hostService, t as hostAgents } from "./access-dU_vG1q8.js";
|
|
5
5
|
import { b as setActiveSessionInfo, c as createSession, d as getActiveSessionInfo, n as readLastBound, t as appendBound } from "./session-bound-BpTayaIS.js";
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
@@ -458,15 +458,20 @@ async function createSkiffAgent(ctx, root, roleName, role, defaultModel, session
|
|
|
458
458
|
};
|
|
459
459
|
const handle = await createOrResumeAgent(ctx, id, root, model, setup, sessionId !== void 0);
|
|
460
460
|
const agent = handle.agent;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
461
|
+
const kind = resolveSkiffKind(role, sessionId !== void 0);
|
|
462
|
+
const rolePrompt = kind === "persistent" ? createRolePromptReader(root, role) : (() => {
|
|
463
|
+
let snapshot = "";
|
|
464
|
+
try {
|
|
465
|
+
snapshot = resolveRoleSystemPrompt(root, role);
|
|
466
|
+
} catch (err) {
|
|
467
|
+
console.warn(`[serenity-hooks] skiff 角色 "${roleName}" 系统提示词解析失败(回退仅基础段): ${String(err?.message ?? err)}`);
|
|
468
|
+
}
|
|
469
|
+
return () => snapshot;
|
|
470
|
+
})();
|
|
471
|
+
rolePrompt();
|
|
467
472
|
let workspaceMdPath = null;
|
|
468
473
|
try {
|
|
469
|
-
workspaceMdPath = ensureSkiffSession(root, agent, roleName, role,
|
|
474
|
+
workspaceMdPath = ensureSkiffSession(root, agent, roleName, role, kind === "persistent");
|
|
470
475
|
} catch (err) {
|
|
471
476
|
console.warn(`[serenity-hooks] skiff 角色 "${roleName}" 专属 SESSION 处理失败(不影响 agent 创建): ${String(err?.message ?? err)}`);
|
|
472
477
|
}
|
|
@@ -474,7 +479,7 @@ async function createSkiffAgent(ctx, root, roleName, role, defaultModel, session
|
|
|
474
479
|
agent.ctx.systemPrompt.section({
|
|
475
480
|
name: "serenity-skiff",
|
|
476
481
|
order: -60,
|
|
477
|
-
text: () => [buildSkiffBasePrompt(roleName, role),
|
|
482
|
+
text: () => [buildSkiffBasePrompt(roleName, role), rolePrompt()].filter(Boolean).join("\n")
|
|
478
483
|
});
|
|
479
484
|
} catch (err) {
|
|
480
485
|
console.warn(`[serenity-hooks] skiff 系统提示词注册失败: ${String(err?.message ?? err)}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { m as resolveInside, p as readUtf8, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS } from "./ccc-DAsSHsub.js";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
//#region src/skiff-role.ts
|
|
5
5
|
/**
|
|
6
6
|
* skiff-role.ts — Skiff(F4,v1.25.0 实验性)角色层纯逻辑(零 DSH 依赖,可独立单测)
|
|
@@ -15,9 +15,11 @@ import { existsSync } from "node:fs";
|
|
|
15
15
|
var skiff_role_exports = /* @__PURE__ */ __exportAll({
|
|
16
16
|
SKIFF_SESSION_PREFIX: () => SKIFF_SESSION_PREFIX,
|
|
17
17
|
buildSkiffBasePrompt: () => buildSkiffBasePrompt,
|
|
18
|
+
createRolePromptReader: () => createRolePromptReader,
|
|
18
19
|
isSkiffSessionId: () => isSkiffSessionId,
|
|
19
20
|
readSkiffRoles: () => readSkiffRoles,
|
|
20
21
|
resolveRoleSystemPrompt: () => resolveRoleSystemPrompt,
|
|
22
|
+
resolveSkiffKind: () => resolveSkiffKind,
|
|
21
23
|
roleMsmWhitelist: () => roleMsmWhitelist,
|
|
22
24
|
roleToolWhitelist: () => roleToolWhitelist,
|
|
23
25
|
systemPromptSource: () => systemPromptSource,
|
|
@@ -43,6 +45,7 @@ function readSkiffRoles(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
|
43
45
|
if (name.trim() === "") continue;
|
|
44
46
|
out.set(name.trim(), {
|
|
45
47
|
model: typeof role.model === "string" ? role.model : void 0,
|
|
48
|
+
kind: role.kind === "temporary" || role.kind === "persistent" ? role.kind : void 0,
|
|
46
49
|
msms: Array.isArray(role.msms) ? role.msms.filter((m) => typeof m === "string") : void 0,
|
|
47
50
|
tools: Array.isArray(role.tools) ? role.tools.filter((t) => typeof t === "string") : void 0,
|
|
48
51
|
trajectory: role.trajectory && typeof role.trajectory === "object" ? {
|
|
@@ -103,6 +106,65 @@ function systemPromptSource(role) {
|
|
|
103
106
|
if (role?.systemPrompt?.trim()) return "inline";
|
|
104
107
|
return "none";
|
|
105
108
|
}
|
|
109
|
+
function resolveSkiffKind(role, hasStableId) {
|
|
110
|
+
const k = role?.kind;
|
|
111
|
+
if (k === "temporary" || k === "persistent") return k;
|
|
112
|
+
return hasStableId ? "persistent" : "temporary";
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 角色提示词**读取器**(v1.30.15,方案 A:长期型热更新)。
|
|
116
|
+
*
|
|
117
|
+
* 为什么是函数而不是字符串(R↓):旧实现 `createSkiffAgent` 在创建时把
|
|
118
|
+
* `resolveRoleSystemPrompt(...)` 的结果**快照**进系统提示词段闭包 → CCC 改了
|
|
119
|
+
* `zhaocai.md` 必须重启 dsh web 才生效(本轮实证:改完 18KB 提示词,live agent 仍用旧文本)。
|
|
120
|
+
* 现形态返回一个读取函数,由系统提示词段的 `text()` **每轮调用**:
|
|
121
|
+
* - `systemPromptFile`:按 **mtime + size** 缓存重读(命中缓存零 IO;未变不解析)
|
|
122
|
+
* → 改文件即生效,**无需重启**;变更时打一行 info 日志(可观测,便于确认热更生效)
|
|
123
|
+
* - 内嵌 `systemPrompt`:静态(JSON 配置改动仍需重启/重载配置)
|
|
124
|
+
* - 读取失败:返回**上次成功内容**(绝不返回空——空提示词会让角色失去人格与纪律),
|
|
125
|
+
* 并按标签去重告警一次
|
|
126
|
+
* @param root CCC 根
|
|
127
|
+
* @param role 角色配置
|
|
128
|
+
*/
|
|
129
|
+
function createRolePromptReader(root, role) {
|
|
130
|
+
const file = role?.systemPromptFile?.trim();
|
|
131
|
+
if (!file) {
|
|
132
|
+
const inline = role?.systemPrompt ?? "";
|
|
133
|
+
return () => inline;
|
|
134
|
+
}
|
|
135
|
+
let abs = null;
|
|
136
|
+
try {
|
|
137
|
+
abs = resolveInside(root, file);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.warn(`[serenity-hooks] ✗ skiff 角色提示词路径非法(${file}): ${String(err?.message ?? err)}`);
|
|
140
|
+
}
|
|
141
|
+
if (abs === null) return () => "";
|
|
142
|
+
const absPath = abs;
|
|
143
|
+
let cachedMtime = -1;
|
|
144
|
+
let cachedSize = -1;
|
|
145
|
+
let cachedText = "";
|
|
146
|
+
let warned = false;
|
|
147
|
+
return () => {
|
|
148
|
+
try {
|
|
149
|
+
const st = statSync(absPath);
|
|
150
|
+
if (st.mtimeMs === cachedMtime && st.size === cachedSize) return cachedText;
|
|
151
|
+
const text = readUtf8(absPath).trim();
|
|
152
|
+
const isReload = cachedMtime !== -1;
|
|
153
|
+
cachedMtime = st.mtimeMs;
|
|
154
|
+
cachedSize = st.size;
|
|
155
|
+
cachedText = text;
|
|
156
|
+
warned = false;
|
|
157
|
+
if (isReload) console.info(`[serenity-hooks] ↻ skiff 角色提示词已热重载(${file},${text.length} 字符)`);
|
|
158
|
+
return text;
|
|
159
|
+
} catch (err) {
|
|
160
|
+
if (!warned) {
|
|
161
|
+
warned = true;
|
|
162
|
+
console.warn(`[serenity-hooks] ✗ skiff 角色提示词读取失败(${file})——沿用上次成功内容: ${String(err?.message ?? err)}`);
|
|
163
|
+
}
|
|
164
|
+
return cachedText;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
106
168
|
/**
|
|
107
169
|
* Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接):
|
|
108
170
|
* 身份 + 可用 MSM/工具清单 + 调用协议 + 边界声明。动态生成(清单来自角色白名单)。
|
|
@@ -125,4 +187,4 @@ function buildSkiffBasePrompt(roleName, role) {
|
|
|
125
187
|
return lines.join("\n");
|
|
126
188
|
}
|
|
127
189
|
//#endregion
|
|
128
|
-
export {
|
|
190
|
+
export { readSkiffRoles as a, roleMsmWhitelist as c, systemPromptSource as d, trajectorySubset as f, isSkiffSessionId as i, roleToolWhitelist as l, buildSkiffBasePrompt as n, resolveRoleSystemPrompt as o, createRolePromptReader as r, resolveSkiffKind as s, SKIFF_SESSION_PREFIX as t, skiff_role_exports as u };
|
package/lib/skiff-role.d.ts
CHANGED
|
@@ -43,6 +43,30 @@ export declare function roleMsmWhitelist(role: SkiffRoleConfig | undefined): Set
|
|
|
43
43
|
export declare function resolveRoleSystemPrompt(root: string, role: SkiffRoleConfig | undefined): string;
|
|
44
44
|
/** 角色系统提示词来源(validate/list 展示用) */
|
|
45
45
|
export declare function systemPromptSource(role: SkiffRoleConfig | undefined): 'file' | 'inline' | 'none';
|
|
46
|
+
/**
|
|
47
|
+
* 角色类型(v1.30.15,S142 用户拍板):
|
|
48
|
+
* - 显式 `role.kind` 优先(`temporary` / `persistent`)
|
|
49
|
+
* - 缺省 = 隐式推断:调用方给出**稳定 sessionId** → persistent;否则 temporary
|
|
50
|
+
* (存量配置零迁移;微信桥传固定会话 id → persistent,ACP/调试页随机 id → temporary)
|
|
51
|
+
*/
|
|
52
|
+
export type SkiffKind = 'temporary' | 'persistent';
|
|
53
|
+
export declare function resolveSkiffKind(role: SkiffRoleConfig | undefined, hasStableId: boolean): SkiffKind;
|
|
54
|
+
/**
|
|
55
|
+
* 角色提示词**读取器**(v1.30.15,方案 A:长期型热更新)。
|
|
56
|
+
*
|
|
57
|
+
* 为什么是函数而不是字符串(R↓):旧实现 `createSkiffAgent` 在创建时把
|
|
58
|
+
* `resolveRoleSystemPrompt(...)` 的结果**快照**进系统提示词段闭包 → CCC 改了
|
|
59
|
+
* `zhaocai.md` 必须重启 dsh web 才生效(本轮实证:改完 18KB 提示词,live agent 仍用旧文本)。
|
|
60
|
+
* 现形态返回一个读取函数,由系统提示词段的 `text()` **每轮调用**:
|
|
61
|
+
* - `systemPromptFile`:按 **mtime + size** 缓存重读(命中缓存零 IO;未变不解析)
|
|
62
|
+
* → 改文件即生效,**无需重启**;变更时打一行 info 日志(可观测,便于确认热更生效)
|
|
63
|
+
* - 内嵌 `systemPrompt`:静态(JSON 配置改动仍需重启/重载配置)
|
|
64
|
+
* - 读取失败:返回**上次成功内容**(绝不返回空——空提示词会让角色失去人格与纪律),
|
|
65
|
+
* 并按标签去重告警一次
|
|
66
|
+
* @param root CCC 根
|
|
67
|
+
* @param role 角色配置
|
|
68
|
+
*/
|
|
69
|
+
export declare function createRolePromptReader(root: string, role: SkiffRoleConfig | undefined): () => string;
|
|
46
70
|
/**
|
|
47
71
|
* Skiff 基础提示词(dsp 只给这部分;CCC 的 systemPrompt 段由调用方拼接):
|
|
48
72
|
* 身份 + 可用 MSM/工具清单 + 调用协议 + 边界声明。动态生成(清单来自角色白名单)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.15",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:10 个工具(container_fs/logbook/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/autopilot-trajectory)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/自主巡航。适配 DSH 0.1.2-rc.1。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|