@addozhang/dsh-discord 0.2.0 → 0.2.1
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 +0 -1
- package/README.zh.md +0 -1
- package/lib/features/ask-wiring.d.ts +9 -0
- package/lib/features/ask-wiring.js +16 -6
- package/lib/index.js +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,7 +98,6 @@ The settings card exposes the three high-frequency fields (guild allowlist, auto
|
|
|
98
98
|
| `/steer`, `/stop` | session thread | steer or cancel the running turn (owner only) |
|
|
99
99
|
| `/guild forget` | any channel | operator-only removal of adapter records |
|
|
100
100
|
|
|
101
|
-
`/model` remains registered ahead of its interactive provider → model → thinking/reasoning cascade (next milestone); `/preset`, `/skill`, and `/host` are deregistered until the router wires them — see Known limitations.
|
|
102
101
|
|
|
103
102
|
## Design notes
|
|
104
103
|
|
package/README.zh.md
CHANGED
|
@@ -55,6 +55,15 @@ export interface AskWiringDeps {
|
|
|
55
55
|
reason?: string;
|
|
56
56
|
messageId?: string;
|
|
57
57
|
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Edit an already-posted control message (PATCH). Retirement greys the
|
|
60
|
+
* controls out on the ORIGINAL message — a POST would only add a new,
|
|
61
|
+
* empty message while the live buttons stayed behind (16.41).
|
|
62
|
+
*/
|
|
63
|
+
editMessage(channelId: string, messageId: string, payload: unknown): Promise<{
|
|
64
|
+
stored: boolean;
|
|
65
|
+
reason?: string;
|
|
66
|
+
}>;
|
|
58
67
|
}
|
|
59
68
|
export declare function createAskWiring(deps: AskWiringDeps): {
|
|
60
69
|
/** Retire a rendered control (clear components) once the ask is settled. */
|
|
@@ -14,8 +14,16 @@ import { renderQuestionControls } from './question-view.js';
|
|
|
14
14
|
import { abandonUnrenderableQuestion } from './question-expiry.js';
|
|
15
15
|
import { handleRemoteResolution } from './question-routing.js';
|
|
16
16
|
export function createAskWiring(deps) {
|
|
17
|
-
/** Discord message refs
|
|
17
|
+
/** Discord message refs + rendered rows for controls, keyed by ask id. */
|
|
18
18
|
const controlMessages = new Map();
|
|
19
|
+
function disabledComponents(components) {
|
|
20
|
+
if (!Array.isArray(components))
|
|
21
|
+
return [];
|
|
22
|
+
return components.map(row => ({
|
|
23
|
+
...row,
|
|
24
|
+
components: (row.components ?? []).map(control => ({ ...control, disabled: true })),
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
19
27
|
const disableControl = async (key) => {
|
|
20
28
|
const target = controlMessages.get(key);
|
|
21
29
|
if (target === undefined)
|
|
@@ -24,9 +32,11 @@ export function createAskWiring(deps) {
|
|
|
24
32
|
// Retirement is best-effort: a failed disable must never fail the ask's
|
|
25
33
|
// settled outcome — the registry TTL keeps stray clicks answerable.
|
|
26
34
|
try {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
const patched = await deps.editMessage(target.channelId, target.messageId, {
|
|
36
|
+
components: disabledComponents(target.components),
|
|
37
|
+
});
|
|
38
|
+
if (!patched.stored)
|
|
39
|
+
deps.log('discord_control_disable_failed', { key, reason: patched.reason });
|
|
30
40
|
}
|
|
31
41
|
catch (cause) {
|
|
32
42
|
deps.log('discord_control_disable_failed', { key, cause: String(cause) });
|
|
@@ -77,7 +87,7 @@ export function createAskWiring(deps) {
|
|
|
77
87
|
void deps.postMessage(input.threadId, payload)
|
|
78
88
|
.then(sent => {
|
|
79
89
|
if (sent.stored && sent.messageId !== undefined) {
|
|
80
|
-
controlMessages.set(input.approvalId, { channelId: input.threadId, messageId: sent.messageId });
|
|
90
|
+
controlMessages.set(input.approvalId, { channelId: input.threadId, messageId: sent.messageId, components: payload.components });
|
|
81
91
|
}
|
|
82
92
|
})
|
|
83
93
|
.catch((cause) => { deps.log('discord_approval_render_failed', String(cause)); });
|
|
@@ -136,7 +146,7 @@ export function createAskWiring(deps) {
|
|
|
136
146
|
abandonQuestion(sent.reason ?? 'post rejected');
|
|
137
147
|
return;
|
|
138
148
|
}
|
|
139
|
-
controlMessages.set(input.rpcId, { channelId: input.threadId, messageId: sent.messageId });
|
|
149
|
+
controlMessages.set(input.rpcId, { channelId: input.threadId, messageId: sent.messageId, components: payload.components });
|
|
140
150
|
})
|
|
141
151
|
.catch((cause) => { abandonQuestion(String(cause)); });
|
|
142
152
|
},
|
package/lib/index.js
CHANGED
|
@@ -225,6 +225,21 @@ export function apply(ctx, config = DEFAULT_DISCORD_SETTINGS) {
|
|
|
225
225
|
return { stored: false, reason: `HTTP ${String(sent.status)}: response missing message id` };
|
|
226
226
|
return { stored: true, messageId: sent.body.id };
|
|
227
227
|
},
|
|
228
|
+
editMessage: async (channelId, messageId, payload) => {
|
|
229
|
+
const rest = await sharedRest();
|
|
230
|
+
if (rest === undefined)
|
|
231
|
+
return { stored: false, reason: 'rest unavailable' };
|
|
232
|
+
const patched = await rest.request('PATCH', `/channels/${channelId}/messages/${messageId}`, payload);
|
|
233
|
+
if (patched.outcome !== 'completed') {
|
|
234
|
+
return {
|
|
235
|
+
stored: false,
|
|
236
|
+
reason: patched.outcome === 'rejected'
|
|
237
|
+
? `HTTP ${String(patched.status)} ${patched.error.message}`
|
|
238
|
+
: patched.reason,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return { stored: true };
|
|
242
|
+
},
|
|
228
243
|
});
|
|
229
244
|
const componentFollowUp = async (_interactionId, interactionToken, content) => {
|
|
230
245
|
const rest = await sharedRest();
|