@addozhang/dsh-discord 0.6.3-rc.1 → 0.6.4-rc.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 +2 -0
- package/README.zh.md +2 -0
- package/lib/client.js +4 -3
- package/lib/discord/commands.js +1 -0
- package/lib/features/interaction-router.d.ts +4 -0
- package/lib/features/interaction-router.js +4 -0
- package/lib/i18n.d.ts +1 -0
- package/lib/i18n.js +4 -2
- package/lib/index.js +6 -0
- package/lib/version.d.ts +2 -0
- package/lib/version.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ No extra process: the adapter is a DSH plugin that mounts straight onto your `ds
|
|
|
23
23
|
- **Approvals & questions** — DSH asks become buttons, select menus, and a free-text modal. Ownership is enforced (the asker — or the thread owner on later turns — clicks), expiry sweeps fail closed, and settled controls grey out in place.
|
|
24
24
|
- **Session control** — `/steer`, `/stop`, and `/queue list|remove` with turn-ownership checks; `/project bind|list|info` and `/session resume` for guild↔workspace binding and history; `/guild forget` for operator cleanup.
|
|
25
25
|
- **Model selection** — `/model show` reads the session's live model directory; `/model select` walks an interactive provider → model → reasoning cascade, or applies a typed `provider/model` directly. Open to any authorized member by default; restrictable to Host operators.
|
|
26
|
+
- **Adapter status** — `/info` shows the adapter version, connection state, and project links (feedback, docs). Works in any channel.
|
|
26
27
|
- **Permission switching** — `/permission show` / `set` read and switch the session's permission preset (bundled sandbox + approval tiers) through the Host's own `/permission` command path, inheriting its journal audit pair; `danger-full-access` requires a button confirmation.
|
|
27
28
|
- **Settings card, bilingual out of the box** — token onboarding and connect/disconnect (stored in the Host credential service, never in settings or logs), guild allowlist, auto-archive, and language. Every Discord-visible string ships in Chinese and English; the bot follows the DSH language preference or a pinned choice.
|
|
28
29
|
- **Hardened by design** — deny-first authorization inside an explicit guild allowlist. Mentions are suppressed twice: `allowed_mentions` on every request, plus byte-level neutralization of the wire body. DSH submission is at-most-once with unknown-preserving reconciliation — an ambiguous delivery is never blindly resent. Bindings survive restarts, and the READY sweep rebuilds deleted category/control channels while treating a deleted workspace channel as user intent (the mapping retires; the workspace stays bindable).
|
|
@@ -122,6 +123,7 @@ The settings card exposes the three high-frequency fields (guild allowlist, auto
|
|
|
122
123
|
| `/project list` / `info` | any channel | list workspaces / inspect this channel's binding |
|
|
123
124
|
| `/queue list`, `/queue remove` | session thread | inspect and trim the pending queue |
|
|
124
125
|
| `/steer`, `/stop` | session thread | steer or cancel the running turn — any member of the thread may act on the current turn (the thread is a deliberately shared surface: single-user and small-team deployments; approvals/questions stay stricter — asker or thread owner only) |
|
|
126
|
+
| `/info` | any channel | show the adapter version, connection state, and project links |
|
|
125
127
|
| `/model show` / `select` | session thread | show the live model directory; `select` without arguments walks the interactive provider → model → reasoning cascade (any authorized member by default) |
|
|
126
128
|
| `/session resume` | project channel | pick one of this workspace's past sessions (autocomplete: title and age, newest first) and resume it into a new thread of this channel; blank, already-bound, subagent, and archived sessions are never offered. The thread renders the session's history — answers and tool summaries plus the user's inputs as quoted echo lines (plugin/system injections are never echoed). After an adapter restart, threads catch up only what they missed: a persisted render watermark suppresses already-delivered history, and bound sessions re-subscribe on reconnect so turns prompted from the web UI still land in their thread |
|
|
127
129
|
| `/guild forget` | any channel | operator-only removal of adapter records |
|
package/README.zh.md
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
- **审批与提问** — DSH 的 ask 渲染为按钮、下拉菜单与自由文本弹窗。所有权强制校验(提问者——或后续 Turn 的线程属主——才能点击),超时清扫 fail-closed,结算后的控件原地置灰。
|
|
24
24
|
- **会话控制** — `/steer`、`/stop`、`/queue list|remove` 带运行所有权校验;`/project bind|list|info` 与 `/session resume` 管理 Guild↔工作区绑定与历史会话;`/guild forget` 供操作员清理。
|
|
25
25
|
- **模型切换** — `/model show` 读取会话的实时模型目录;`/model select` 走交互式 provider → 模型 → 推理强度级联,也可直接填写 `provider/model` 应用。默认对所有授权成员开放,可收紧为仅 Host 操作员。
|
|
26
|
+
- **适配器状态** — `/info` 显示适配器版本、连接状态与项目链接(反馈/文档)。任意频道可用。
|
|
26
27
|
- **权限切换** — `/permission show` / `set` 读写会话权限预设(沙箱 + 审批捆绑档位),走宿主自己的 `/permission` 命令路径,journal 自动记审计;`danger-full-access` 需按钮二次确认。
|
|
27
28
|
- **设置卡片,开箱双语** — Token 引导与连接/断开(存入 Host 凭据服务,绝不写入设置或日志)、服务器白名单、自动归档与语言。所有 Discord 可见文案提供中英双语;Bot 默认跟随 DSH 语言偏好,也可从卡片固定。
|
|
28
29
|
- **安全设计** — 显式服务器白名单内的 deny-first 授权。提及抑制双保险:每条请求携带 `allowed_mentions`,外加 wire body 的字节级提及中和。DSH 提交至多一次,并做保留 unknown 的对账——结果不明的投递绝不盲目重发。绑定重启后持久;READY 扫描会重建被删除的 category/控制频道,而把被删除的工作区频道视为用户意图(解除映射,workspace 保持可重新绑定)。
|
|
@@ -122,6 +123,7 @@ dsh-discord:
|
|
|
122
123
|
| `/project list` / `info` | 任意频道 | 列出工作区 / 查看当前频道绑定 |
|
|
123
124
|
| `/queue list`, `/queue remove` | 会话线程 | 查看与移除待处理队列 |
|
|
124
125
|
| `/steer`, `/stop` | 会话线程 | 插话或取消运行中的 Turn——线程内任意成员可操作当前 Turn(有意为之的共享驾驶舱模型,面向单人与小团队场景;审批/提问保持更严的提问人-or-线程主人规则) |
|
|
126
|
+
| `/info` | 任意频道 | 显示适配器版本、连接状态与项目链接 |
|
|
125
127
|
| `/model show` / `select` | 会话线程 | 查看实时模型目录;`select` 不带参数时走交互式 provider → 模型 → 推理强度级联(默认对所有授权成员开放) |
|
|
126
128
|
| `/session resume` | 项目频道 | 自动补全选择本工作区的历史会话(显示标题与时间,最新优先),恢复为当前频道的新线程;空白、已挂线程、subagent、已归档的会话不会出现。线程会渲染会话历史——回答与工具摘要之外,用户输入以引用行回显(插件/系统注入永不回显)。适配器重启后线程只补齐错过部分:持久化的渲染水位抑制已投递过的历史,已绑定会话在重连时自动重订阅,因此从 web UI 发起的回合也会落进对应线程 |
|
|
127
129
|
| `/guild forget` | 任意频道 | 仅操作员:移除适配器记录 |
|
package/lib/client.js
CHANGED
|
@@ -1374,7 +1374,7 @@ function DiscordSettingsCard(props) {
|
|
|
1374
1374
|
{ value: "auto", label: t("discordLanguageAuto") },
|
|
1375
1375
|
...LANGUAGE_CHOICES
|
|
1376
1376
|
];
|
|
1377
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1378
1378
|
PluginCard,
|
|
1379
1379
|
{
|
|
1380
1380
|
copy,
|
|
@@ -1471,10 +1471,11 @@ function DiscordSettingsCard(props) {
|
|
|
1471
1471
|
props.resetField(LANGUAGE_FIELD);
|
|
1472
1472
|
}
|
|
1473
1473
|
}
|
|
1474
|
-
)
|
|
1474
|
+
),
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { "data-dsh-discord-card-footer-link": "", style: { margin: "6px 2px 0", fontSize: 12, opacity: 0.6 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://github.com/addozhang/dsh-discord", target: "_blank", rel: "noopener noreferrer", children: "\u2B50 Feedback & docs" }) })
|
|
1475
1476
|
]
|
|
1476
1477
|
}
|
|
1477
|
-
);
|
|
1478
|
+
) });
|
|
1478
1479
|
}
|
|
1479
1480
|
|
|
1480
1481
|
// src/client/index.ts
|
package/lib/discord/commands.js
CHANGED
|
@@ -27,6 +27,7 @@ export const MILESTONE_ONE_COMMANDS = [
|
|
|
27
27
|
{ name: 'list' },
|
|
28
28
|
{ name: 'remove', options: [{ name: 'item', required: true }] },
|
|
29
29
|
]),
|
|
30
|
+
leaf('info', 'Show the adapter version, connection state, and project links'),
|
|
30
31
|
leaf('steer', 'Steer the running turn of this thread', [{ name: 'prompt', required: true }]),
|
|
31
32
|
leaf('stop', 'Cancel the running turn of this thread'),
|
|
32
33
|
grouped('model', 'Show or select the session model', [
|
|
@@ -60,6 +60,10 @@ export interface InteractionRouterDeps {
|
|
|
60
60
|
} | undefined>;
|
|
61
61
|
/** Delete every adapter-owned record for one guild (DSH untouched). */
|
|
62
62
|
forgetGuild: (guildId: string) => Promise<void>;
|
|
63
|
+
/** The adapter's own package version (from package.json at load). */
|
|
64
|
+
adapterVersion: () => string;
|
|
65
|
+
/** One-word connection condition for /info. */
|
|
66
|
+
adapterStatus: () => string;
|
|
63
67
|
/** Ephemeral failure/guidance followup on a component interaction. */
|
|
64
68
|
componentFollowUp: (interactionId: string, interactionToken: string, content: string) => Promise<void>;
|
|
65
69
|
/** Retire a rendered control (remove its components on the source message). */
|
|
@@ -469,6 +469,10 @@ export function createInteractionRouter(deps) {
|
|
|
469
469
|
}]);
|
|
470
470
|
return;
|
|
471
471
|
}
|
|
472
|
+
if (event.commandName === 'info') {
|
|
473
|
+
await followUp(deps.copy.infoLine(deps.adapterVersion(), deps.adapterStatus()));
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
472
476
|
if (event.commandName === 'model') {
|
|
473
477
|
const options = event.data['options'];
|
|
474
478
|
const subcommand = Array.isArray(options) ? options[0] : undefined;
|
package/lib/i18n.d.ts
CHANGED
package/lib/i18n.js
CHANGED
|
@@ -34,7 +34,7 @@ const zh = {
|
|
|
34
34
|
infoUnavailable: '⚠️ 无法读取工作区目录,请稍后重试。',
|
|
35
35
|
infoRevision: (revision, binder) => `修订 ${revision}(由 <@${binder}> 绑定)`,
|
|
36
36
|
infoPath: (path) => `路径:\`${path}\``,
|
|
37
|
-
unknownSubcommand: '💡
|
|
37
|
+
unknownSubcommand: '💡 未知子命令。反馈与文档: https://github.com/addozhang/dsh-discord',
|
|
38
38
|
// ── /stop /steer /queue ──────────────────────────────────────────────
|
|
39
39
|
stopNotSessionThread: '⚠️ 此频道不是适配器拥有的会话线程。',
|
|
40
40
|
stopNothingRunning: '此线程当前没有可停止的运行中任务。',
|
|
@@ -64,6 +64,7 @@ const zh = {
|
|
|
64
64
|
forgetConfirmPrompt: '⚠️ 将删除本 Guild 的全部适配器记录(绑定/意图;DSH 工作区与 Session 不受影响)。确认?',
|
|
65
65
|
forgetConfirmButton: '确认忘记',
|
|
66
66
|
forgetDone: '💡 已忘记本 Guild:适配器记录(绑定/意图)已删除;DSH 工作区与 Session 未受影响。',
|
|
67
|
+
infoLine: (version, connection) => `📡 dsh-discord v${version} · ${connection}\n⭐ 反馈与文档: https://github.com/addozhang/dsh-discord`,
|
|
67
68
|
// ── interaction failures / denials ───────────────────────────────────
|
|
68
69
|
commandFailed: '⚠️ 命令处理失败,请稍后重试。',
|
|
69
70
|
confirmNotOwner: '⚠️ 此确认不属于你。',
|
|
@@ -194,7 +195,7 @@ const en = {
|
|
|
194
195
|
infoUnavailable: '⚠️ The workspace directory is temporarily unavailable; try again later.',
|
|
195
196
|
infoRevision: (revision, binder) => `Revision ${revision} (bound by <@${binder}>)`,
|
|
196
197
|
infoPath: path => `Path: \`${path}\``,
|
|
197
|
-
unknownSubcommand: '💡 Unknown subcommand.',
|
|
198
|
+
unknownSubcommand: '💡 Unknown subcommand. Feedback & docs: https://github.com/addozhang/dsh-discord',
|
|
198
199
|
stopNotSessionThread: '⚠️ This channel is not an adapter-owned session thread.',
|
|
199
200
|
stopNothingRunning: 'This thread has no running task to stop.',
|
|
200
201
|
stopNotOwner: '⚠️ The running task was not submitted from this thread and cannot be stopped here.',
|
|
@@ -222,6 +223,7 @@ const en = {
|
|
|
222
223
|
forgetConfirmPrompt: '⚠️ This deletes every adapter-owned record for this Guild (bindings/intents; DSH workspaces and sessions are untouched). Continue?',
|
|
223
224
|
forgetConfirmButton: 'Confirm forget',
|
|
224
225
|
forgetDone: '💡 Guild forgotten: adapter records (bindings/intents) are deleted; DSH workspaces and sessions are untouched.',
|
|
226
|
+
infoLine: (version, connection) => `📡 dsh-discord v${version} · ${connection}\n⭐ Feedback & docs: https://github.com/addozhang/dsh-discord`,
|
|
225
227
|
commandFailed: '⚠️ Command handling failed; try again later.',
|
|
226
228
|
confirmNotOwner: '⚠️ This confirmation is not yours.',
|
|
227
229
|
submittedAck: '💡 Your choice has been submitted.',
|
package/lib/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { sweepExpiredApprovals } from './features/approval-expiry.js';
|
|
|
16
16
|
import { sweepExpiredQuestions } from './features/question-expiry.js';
|
|
17
17
|
import { createQuestionStore } from './features/question-store.js';
|
|
18
18
|
import { createTrailingSingleFlight } from './features/single-flight.js';
|
|
19
|
+
import { ADAPTER_VERSION } from './version.js';
|
|
19
20
|
import { handleSelectInput, handleModalSubmit } from './features/question-routing.js';
|
|
20
21
|
import { createCopy, permissionPresetLabel } from './i18n.js';
|
|
21
22
|
import { createInteractionRouter } from './features/interaction-router.js';
|
|
@@ -900,6 +901,11 @@ export function apply(ctx, config = DEFAULT_DISCORD_SETTINGS) {
|
|
|
900
901
|
turnTracker,
|
|
901
902
|
queueSnapshots,
|
|
902
903
|
forgetGuild,
|
|
904
|
+
adapterVersion: () => ADAPTER_VERSION,
|
|
905
|
+
adapterStatus: () => {
|
|
906
|
+
const g = statusTracker.project().connection;
|
|
907
|
+
return g === 'connected' ? 'connected' : g === 'connecting' ? 'connecting' : 'disconnected';
|
|
908
|
+
},
|
|
903
909
|
componentFollowUp,
|
|
904
910
|
disableControl: key => askWiring.disableControl(key),
|
|
905
911
|
handleQuestionComponent: input => handleSelectInput(questionRoutingDeps, input),
|
package/lib/version.d.ts
ADDED
package/lib/version.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adapter's own package version, read at load time from the
|
|
3
|
+
* package.json that always sits next to lib/ in the installed tree.
|
|
4
|
+
* Surfaced by /info and the settings-card RPC for support and discovery.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '../package.json');
|
|
10
|
+
export const ADAPTER_VERSION = JSON.parse(readFileSync(pkgPath, 'utf8')).version;
|
|
11
|
+
export const REPO_URL = 'https://github.com/addozhang/dsh-discord';
|