@addozhang/dsh-discord 0.1.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.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -0
  3. package/cordis.patch.yml +14 -0
  4. package/lib/client/DiscordSettingsCard.d.ts +6 -0
  5. package/lib/client/PluginCard.d.ts +43 -0
  6. package/lib/client/card-controller.d.ts +22 -0
  7. package/lib/client/card-form.d.ts +111 -0
  8. package/lib/client/fields.d.ts +50 -0
  9. package/lib/client/index.d.ts +12 -0
  10. package/lib/client/nav-icon.d.ts +21 -0
  11. package/lib/client/settings-model.d.ts +49 -0
  12. package/lib/client/slot-contract.d.ts +57 -0
  13. package/lib/client/snapshot-store.d.ts +9 -0
  14. package/lib/client.js +1622 -0
  15. package/lib/compose.d.ts +158 -0
  16. package/lib/compose.js +227 -0
  17. package/lib/credential.d.ts +20 -0
  18. package/lib/credential.js +24 -0
  19. package/lib/discord/commands.d.ts +45 -0
  20. package/lib/discord/commands.js +87 -0
  21. package/lib/discord/components.d.ts +29 -0
  22. package/lib/discord/components.js +57 -0
  23. package/lib/discord/delivery.d.ts +21 -0
  24. package/lib/discord/delivery.js +31 -0
  25. package/lib/discord/interaction-lifecycle.d.ts +42 -0
  26. package/lib/discord/interaction-lifecycle.js +78 -0
  27. package/lib/discord/rest.d.ts +74 -0
  28. package/lib/discord/rest.js +149 -0
  29. package/lib/discord/selector.d.ts +39 -0
  30. package/lib/discord/selector.js +70 -0
  31. package/lib/discord/thread-port.d.ts +37 -0
  32. package/lib/discord/thread-port.js +58 -0
  33. package/lib/dsh/api-proxy-face.d.ts +253 -0
  34. package/lib/dsh/api-proxy-face.js +370 -0
  35. package/lib/features/adapter-status.d.ts +111 -0
  36. package/lib/features/adapter-status.js +103 -0
  37. package/lib/features/approval-expiry.d.ts +27 -0
  38. package/lib/features/approval-expiry.js +36 -0
  39. package/lib/features/approval-routing.d.ts +50 -0
  40. package/lib/features/approval-routing.js +57 -0
  41. package/lib/features/approval-store.d.ts +86 -0
  42. package/lib/features/approval-store.js +119 -0
  43. package/lib/features/approval-view.d.ts +47 -0
  44. package/lib/features/approval-view.js +48 -0
  45. package/lib/features/ask-wiring.d.ts +74 -0
  46. package/lib/features/ask-wiring.js +151 -0
  47. package/lib/features/host-status.d.ts +41 -0
  48. package/lib/features/host-status.js +24 -0
  49. package/lib/features/image-collection.d.ts +56 -0
  50. package/lib/features/image-collection.js +79 -0
  51. package/lib/features/image-download.d.ts +48 -0
  52. package/lib/features/image-download.js +77 -0
  53. package/lib/features/image-submission.d.ts +67 -0
  54. package/lib/features/image-submission.js +57 -0
  55. package/lib/features/interaction-router.d.ts +84 -0
  56. package/lib/features/interaction-router.js +655 -0
  57. package/lib/features/model-control.d.ts +79 -0
  58. package/lib/features/model-control.js +51 -0
  59. package/lib/features/preset-control.d.ts +84 -0
  60. package/lib/features/preset-control.js +43 -0
  61. package/lib/features/project-bind.d.ts +69 -0
  62. package/lib/features/project-bind.js +57 -0
  63. package/lib/features/project-info.d.ts +25 -0
  64. package/lib/features/project-info.js +22 -0
  65. package/lib/features/project-list.d.ts +79 -0
  66. package/lib/features/project-list.js +93 -0
  67. package/lib/features/prompt-submission.d.ts +53 -0
  68. package/lib/features/prompt-submission.js +47 -0
  69. package/lib/features/question-expiry.d.ts +53 -0
  70. package/lib/features/question-expiry.js +56 -0
  71. package/lib/features/question-routing.d.ts +108 -0
  72. package/lib/features/question-routing.js +162 -0
  73. package/lib/features/question-store.d.ts +124 -0
  74. package/lib/features/question-store.js +186 -0
  75. package/lib/features/question-view.d.ts +58 -0
  76. package/lib/features/question-view.js +81 -0
  77. package/lib/features/queue-control.d.ts +63 -0
  78. package/lib/features/queue-control.js +31 -0
  79. package/lib/features/reconcile-bindings.d.ts +75 -0
  80. package/lib/features/reconcile-bindings.js +54 -0
  81. package/lib/features/reconcile-deliveries.d.ts +29 -0
  82. package/lib/features/reconcile-deliveries.js +28 -0
  83. package/lib/features/reconcile-events.d.ts +49 -0
  84. package/lib/features/reconcile-events.js +50 -0
  85. package/lib/features/reconcile-intents.d.ts +32 -0
  86. package/lib/features/reconcile-intents.js +32 -0
  87. package/lib/features/reconcile-interactions.d.ts +59 -0
  88. package/lib/features/reconcile-interactions.js +54 -0
  89. package/lib/features/session-adopt.d.ts +89 -0
  90. package/lib/features/session-adopt.js +77 -0
  91. package/lib/features/session-creation.d.ts +49 -0
  92. package/lib/features/session-creation.js +43 -0
  93. package/lib/features/session-mainline.d.ts +75 -0
  94. package/lib/features/session-mainline.js +96 -0
  95. package/lib/features/session-resume.d.ts +44 -0
  96. package/lib/features/session-resume.js +40 -0
  97. package/lib/features/skill-run.d.ts +48 -0
  98. package/lib/features/skill-run.js +25 -0
  99. package/lib/features/steer-control.d.ts +37 -0
  100. package/lib/features/steer-control.js +28 -0
  101. package/lib/features/stop-control.d.ts +38 -0
  102. package/lib/features/stop-control.js +31 -0
  103. package/lib/features/task-admission.d.ts +29 -0
  104. package/lib/features/task-admission.js +21 -0
  105. package/lib/features/thread-continuation.d.ts +36 -0
  106. package/lib/features/thread-continuation.js +18 -0
  107. package/lib/features/thread-creation.d.ts +81 -0
  108. package/lib/features/thread-creation.js +81 -0
  109. package/lib/features/thread-routing.d.ts +49 -0
  110. package/lib/features/thread-routing.js +34 -0
  111. package/lib/features/turn-ownership.d.ts +39 -0
  112. package/lib/features/turn-ownership.js +40 -0
  113. package/lib/features/unbound-mention.d.ts +49 -0
  114. package/lib/features/unbound-mention.js +31 -0
  115. package/lib/features/workspace-channel.d.ts +41 -0
  116. package/lib/features/workspace-channel.js +47 -0
  117. package/lib/gateway/gateway.d.ts +50 -0
  118. package/lib/gateway/gateway.js +229 -0
  119. package/lib/gateway/inbound.d.ts +85 -0
  120. package/lib/gateway/inbound.js +186 -0
  121. package/lib/gateway/ingress.d.ts +15 -0
  122. package/lib/gateway/ingress.js +22 -0
  123. package/lib/i18n.d.ts +92 -0
  124. package/lib/i18n.js +180 -0
  125. package/lib/index.d.ts +17 -0
  126. package/lib/index.js +869 -0
  127. package/lib/lifecycle.d.ts +44 -0
  128. package/lib/lifecycle.js +84 -0
  129. package/lib/policy/authorization.d.ts +41 -0
  130. package/lib/policy/authorization.js +64 -0
  131. package/lib/policy/disclosure.d.ts +93 -0
  132. package/lib/policy/disclosure.js +153 -0
  133. package/lib/policy/guard.d.ts +31 -0
  134. package/lib/policy/guard.js +46 -0
  135. package/lib/policy/suppress.d.ts +13 -0
  136. package/lib/policy/suppress.js +20 -0
  137. package/lib/settings-namespace.d.ts +7 -0
  138. package/lib/settings-namespace.js +6 -0
  139. package/lib/settings.d.ts +37 -0
  140. package/lib/settings.js +102 -0
  141. package/lib/startup.d.ts +16 -0
  142. package/lib/startup.js +60 -0
  143. package/lib/state/bindings.d.ts +46 -0
  144. package/lib/state/bindings.js +55 -0
  145. package/lib/state/channel-bindings.d.ts +37 -0
  146. package/lib/state/channel-bindings.js +43 -0
  147. package/lib/state/domain.d.ts +82 -0
  148. package/lib/state/domain.js +86 -0
  149. package/lib/state/effect-machine.d.ts +37 -0
  150. package/lib/state/effect-machine.js +52 -0
  151. package/lib/state/fail-closed.d.ts +44 -0
  152. package/lib/state/fail-closed.js +57 -0
  153. package/lib/state/intents.d.ts +51 -0
  154. package/lib/state/intents.js +73 -0
  155. package/lib/state/records.d.ts +37 -0
  156. package/lib/state/records.js +30 -0
  157. package/lib/state/retention.d.ts +74 -0
  158. package/lib/state/retention.js +68 -0
  159. package/lib/state/session-owners.d.ts +50 -0
  160. package/lib/state/session-owners.js +50 -0
  161. package/lib/stream/finalizer.d.ts +49 -0
  162. package/lib/stream/finalizer.js +67 -0
  163. package/lib/stream/icons.d.ts +15 -0
  164. package/lib/stream/icons.js +36 -0
  165. package/lib/stream/live.d.ts +140 -0
  166. package/lib/stream/live.js +515 -0
  167. package/lib/stream/markdown.d.ts +24 -0
  168. package/lib/stream/markdown.js +95 -0
  169. package/lib/stream/outbound.d.ts +27 -0
  170. package/lib/stream/outbound.js +25 -0
  171. package/lib/stream/render-fence.d.ts +27 -0
  172. package/lib/stream/render-fence.js +37 -0
  173. package/lib/stream/render-model.d.ts +48 -0
  174. package/lib/stream/render-model.js +68 -0
  175. package/lib/stream/splitter.d.ts +8 -0
  176. package/lib/stream/splitter.js +58 -0
  177. package/lib/stream/tool-view.d.ts +40 -0
  178. package/lib/stream/tool-view.js +39 -0
  179. package/lib/stream/typing.d.ts +22 -0
  180. package/lib/stream/typing.js +58 -0
  181. package/lib/stream/update-scheduler.d.ts +20 -0
  182. package/lib/stream/update-scheduler.js +65 -0
  183. package/package.json +86 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Image submission through `session.prompt` (design.md §12, task 12.3).
3
+ * Mixed text/images encode into ordered prompt parts; the model's modality
4
+ * is checked BEFORE any DSH call; and the request id claims an intent so a
5
+ * duplicate Discord delivery never resubmits. Host outcomes map to values
6
+ * with the intent state kept honest (failed on rejection, unknown preserved
7
+ * for reconciliation).
8
+ */
9
+ import { hashPayload } from '../state/intents.js';
10
+ /** Encode text plus images into ordered prompt parts. */
11
+ export function encodePromptParts(text, images) {
12
+ const parts = [];
13
+ const trimmed = text.trim();
14
+ if (trimmed !== '')
15
+ parts.push({ type: 'text', text: trimmed });
16
+ for (const image of images) {
17
+ parts.push({ type: 'image', mediaType: image.mediaType, data: image.base64 });
18
+ }
19
+ return parts;
20
+ }
21
+ export function createImageSubmissionFlow(deps) {
22
+ return {
23
+ async submit(request) {
24
+ const parts = encodePromptParts(request.text, request.images);
25
+ // Modality gate: refuse BEFORE the intent claim so an explicit user
26
+ // retry with a text-only message is a clean new attempt.
27
+ if (request.images.length > 0 && !deps.modality()) {
28
+ return { outcome: 'refused', reason: 'unsupported-modality' };
29
+ }
30
+ const contentHash = await hashPayload({ sessionId: request.sessionId, parts });
31
+ const claim = await deps.intents.claim({
32
+ messageId: request.requestId,
33
+ contentHash,
34
+ claimedAtMs: deps.nowMs(),
35
+ });
36
+ if (claim.outcome === 'conflict')
37
+ return { outcome: 'conflict' };
38
+ if (claim.outcome === 'duplicate')
39
+ return { outcome: 'already-submitted' };
40
+ const submitted = await deps.prompts.submit({
41
+ requestId: request.requestId,
42
+ sessionId: request.sessionId,
43
+ parts,
44
+ });
45
+ if (submitted.outcome === 'accepted') {
46
+ await deps.intents.resolve(request.requestId, 'succeeded', deps.nowMs());
47
+ return { outcome: 'accepted' };
48
+ }
49
+ if (submitted.outcome === 'rejected') {
50
+ await deps.intents.resolve(request.requestId, 'failed', deps.nowMs());
51
+ return { outcome: 'rejected' };
52
+ }
53
+ await deps.intents.resolve(request.requestId, 'unknown', deps.nowMs());
54
+ return { outcome: 'unknown' };
55
+ },
56
+ };
57
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The interaction router (extracted from the Host composition root so the
3
+ * whole command/component surface is testable against the Discord API twin).
4
+ * Every path re-checks authorization where the event alone cannot prove it
5
+ * (workspace-administrator level, catalog freshness), answers interactions
6
+ * through the deferred-ack + ephemeral-followup pattern, and maps every DSH
7
+ * outcome onto caller-facing copy without ever retrying.
8
+ */
9
+ import type { ComponentRegistry } from '../discord/components.js';
10
+ import type { SharedRestClient } from '../discord/rest.js';
11
+ import { type PolicyTable } from '../policy/authorization.js';
12
+ import { type ProjectListPort } from './project-list.js';
13
+ import type { WorkspaceResolver } from './project-bind.js';
14
+ import type { CancelOutcome, PromptOutcome, QueueRemoveOutcome, WorkspaceDetailOutcome } from '../dsh/api-proxy-face.js';
15
+ import type { TurnTracker } from './turn-ownership.js';
16
+ import { type DshApprovalRespondPort } from './approval-routing.js';
17
+ import type { QuestionInteractionOutcome } from './question-routing.js';
18
+ import type { ApprovalStore } from './approval-store.js';
19
+ import type { ChannelBinding } from '../state/records.js';
20
+ import type { NormalizedInteraction } from '../gateway/inbound.js';
21
+ import type { CopyTable } from '../i18n.js';
22
+ /** The DSH faces the control commands submit through (apiProxy-backed). */
23
+ export interface InteractionDshFace {
24
+ cancel(sessionId: string): Promise<CancelOutcome>;
25
+ steer(sessionId: string, prompt: string): Promise<PromptOutcome>;
26
+ removeQueueItem(sessionId: string, itemId: string): Promise<QueueRemoveOutcome>;
27
+ readWorkspaceDetail(reference: string): Promise<WorkspaceDetailOutcome>;
28
+ }
29
+ export interface InteractionRouterDeps {
30
+ policy: () => PolicyTable;
31
+ applicationId: () => string;
32
+ /** The shared component registry (render + click routing use one instance). */
33
+ registry: ComponentRegistry;
34
+ /** Discord-visible copy, resolved per access (language can change live). */
35
+ copy: CopyTable;
36
+ approvals: ApprovalStore;
37
+ approvalRespondPort: DshApprovalRespondPort;
38
+ turnTracker: TurnTracker;
39
+ /** Latest mux queue snapshots per session — the /queue surface's source. */
40
+ queueSnapshots: Map<string, Array<{
41
+ id: string;
42
+ summary: string;
43
+ }>>;
44
+ dsh: InteractionDshFace;
45
+ catalogPort: ProjectListPort;
46
+ resolver: WorkspaceResolver;
47
+ channelBinding: (guildId: string, channelId: string) => ChannelBinding | undefined;
48
+ findBoundChannelFor: (guildId: string, workspaceId: string) => string | undefined;
49
+ sessionForThread: (guildId: string, threadId: string) => string | undefined;
50
+ ensureWorkspaceChannel: (options: {
51
+ guildId: string;
52
+ workspaceId: string;
53
+ title: string;
54
+ actorId: string;
55
+ }) => Promise<{
56
+ channelId: string;
57
+ created: boolean;
58
+ } | undefined>;
59
+ /** Delete every adapter-owned record for one guild (DSH untouched). */
60
+ forgetGuild: (guildId: string) => Promise<void>;
61
+ /** Ephemeral failure/guidance followup on a component interaction. */
62
+ componentFollowUp: (interactionId: string, interactionToken: string, content: string) => Promise<void>;
63
+ /** Retire a rendered control (remove its components on the source message). */
64
+ disableControl: (key: string) => Promise<void>;
65
+ /** Question select/submit clicks and modal submits (module-tested routing). */
66
+ handleQuestionComponent: (input: {
67
+ customId: string;
68
+ userId: string;
69
+ threadId: string;
70
+ values: string[];
71
+ }) => Promise<QuestionInteractionOutcome>;
72
+ handleQuestionModal: (input: {
73
+ customId: string;
74
+ userId: string;
75
+ threadId: string;
76
+ text: string;
77
+ }) => QuestionInteractionOutcome;
78
+ rest: () => Promise<SharedRestClient | undefined>;
79
+ log: (event: string, detail?: unknown) => void;
80
+ warn: (event: string, detail?: unknown) => void;
81
+ }
82
+ export declare function createInteractionRouter(deps: InteractionRouterDeps): {
83
+ route(event: NormalizedInteraction, interactionToken?: string): Promise<void>;
84
+ };