discord-agent-bridge 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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/app.js +210 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/app.test.js +117 -0
  6. package/dist/app.test.js.map +1 -0
  7. package/dist/cli.js +63 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/cli.test.js +91 -0
  10. package/dist/cli.test.js.map +1 -0
  11. package/dist/core/auditLog.js +65 -0
  12. package/dist/core/auditLog.js.map +1 -0
  13. package/dist/core/auditLog.test.js +124 -0
  14. package/dist/core/auditLog.test.js.map +1 -0
  15. package/dist/core/auth.js +106 -0
  16. package/dist/core/auth.js.map +1 -0
  17. package/dist/core/auth.test.js +216 -0
  18. package/dist/core/auth.test.js.map +1 -0
  19. package/dist/core/channelRegistry.js +119 -0
  20. package/dist/core/channelRegistry.js.map +1 -0
  21. package/dist/core/channelRegistry.test.js +114 -0
  22. package/dist/core/channelRegistry.test.js.map +1 -0
  23. package/dist/core/commandPolicy.js +6 -0
  24. package/dist/core/commandPolicy.js.map +1 -0
  25. package/dist/core/commandRouter.js +9 -0
  26. package/dist/core/commandRouter.js.map +1 -0
  27. package/dist/core/config.js +141 -0
  28. package/dist/core/config.js.map +1 -0
  29. package/dist/core/config.test.js +149 -0
  30. package/dist/core/config.test.js.map +1 -0
  31. package/dist/core/configResolver.js +90 -0
  32. package/dist/core/configResolver.js.map +1 -0
  33. package/dist/core/configResolver.test.js +138 -0
  34. package/dist/core/configResolver.test.js.map +1 -0
  35. package/dist/core/configSchema.js +164 -0
  36. package/dist/core/configSchema.js.map +1 -0
  37. package/dist/core/contracts.js +5 -0
  38. package/dist/core/contracts.js.map +1 -0
  39. package/dist/core/eventBus.js +42 -0
  40. package/dist/core/eventBus.js.map +1 -0
  41. package/dist/core/eventBus.test.js +72 -0
  42. package/dist/core/eventBus.test.js.map +1 -0
  43. package/dist/core/hookBridge.js +11 -0
  44. package/dist/core/hookBridge.js.map +1 -0
  45. package/dist/core/logger.js +116 -0
  46. package/dist/core/logger.js.map +1 -0
  47. package/dist/core/logger.test.js +88 -0
  48. package/dist/core/logger.test.js.map +1 -0
  49. package/dist/core/modeRegistry.js +33 -0
  50. package/dist/core/modeRegistry.js.map +1 -0
  51. package/dist/core/permissionResolver.js +43 -0
  52. package/dist/core/permissionResolver.js.map +1 -0
  53. package/dist/core/permissionResolver.test.js +136 -0
  54. package/dist/core/permissionResolver.test.js.map +1 -0
  55. package/dist/core/providerCatalog.js +240 -0
  56. package/dist/core/providerCatalog.js.map +1 -0
  57. package/dist/core/providerCatalog.test.js +230 -0
  58. package/dist/core/providerCatalog.test.js.map +1 -0
  59. package/dist/core/sessionOrchestrator.js +463 -0
  60. package/dist/core/sessionOrchestrator.js.map +1 -0
  61. package/dist/core/sessionOrchestrator.test.js +344 -0
  62. package/dist/core/sessionOrchestrator.test.js.map +1 -0
  63. package/dist/core/state/schema.js +49 -0
  64. package/dist/core/state/schema.js.map +1 -0
  65. package/dist/core/state/store.js +86 -0
  66. package/dist/core/state/store.js.map +1 -0
  67. package/dist/core/state/store.test.js +99 -0
  68. package/dist/core/state/store.test.js.map +1 -0
  69. package/dist/core/usageService.js +310 -0
  70. package/dist/core/usageService.js.map +1 -0
  71. package/dist/core/usageService.test.js +234 -0
  72. package/dist/core/usageService.test.js.map +1 -0
  73. package/dist/discord/alwaysAllow.test.js +181 -0
  74. package/dist/discord/alwaysAllow.test.js.map +1 -0
  75. package/dist/discord/client.js +666 -0
  76. package/dist/discord/client.js.map +1 -0
  77. package/dist/discord/client.test.js +256 -0
  78. package/dist/discord/client.test.js.map +1 -0
  79. package/dist/discord/configPanel.js +270 -0
  80. package/dist/discord/configPanel.js.map +1 -0
  81. package/dist/discord/configPanel.test.js +332 -0
  82. package/dist/discord/configPanel.test.js.map +1 -0
  83. package/dist/discord/directoryBrowser.js +151 -0
  84. package/dist/discord/directoryBrowser.js.map +1 -0
  85. package/dist/discord/directoryBrowser.test.js +163 -0
  86. package/dist/discord/directoryBrowser.test.js.map +1 -0
  87. package/dist/discord/favorites.js +10 -0
  88. package/dist/discord/favorites.js.map +1 -0
  89. package/dist/discord/fileDownload.js +94 -0
  90. package/dist/discord/fileDownload.js.map +1 -0
  91. package/dist/discord/fileDownload.test.js +59 -0
  92. package/dist/discord/fileDownload.test.js.map +1 -0
  93. package/dist/discord/format.js +104 -0
  94. package/dist/discord/format.js.map +1 -0
  95. package/dist/discord/format.test.js +40 -0
  96. package/dist/discord/format.test.js.map +1 -0
  97. package/dist/discord/guildChannels.js +97 -0
  98. package/dist/discord/guildChannels.js.map +1 -0
  99. package/dist/discord/guildChannels.test.js +231 -0
  100. package/dist/discord/guildChannels.test.js.map +1 -0
  101. package/dist/discord/i18n.js +207 -0
  102. package/dist/discord/i18n.js.map +1 -0
  103. package/dist/discord/i18n.test.js +31 -0
  104. package/dist/discord/i18n.test.js.map +1 -0
  105. package/dist/discord/interactionRouter.js +954 -0
  106. package/dist/discord/interactionRouter.js.map +1 -0
  107. package/dist/discord/interactionRouter.test.js +1245 -0
  108. package/dist/discord/interactionRouter.test.js.map +1 -0
  109. package/dist/discord/messageRouter.js +221 -0
  110. package/dist/discord/messageRouter.js.map +1 -0
  111. package/dist/discord/messageRouter.test.js +360 -0
  112. package/dist/discord/messageRouter.test.js.map +1 -0
  113. package/dist/discord/ports.js +12 -0
  114. package/dist/discord/ports.js.map +1 -0
  115. package/dist/discord/renderers/defaultSet.test.js +97 -0
  116. package/dist/discord/renderers/defaultSet.test.js.map +1 -0
  117. package/dist/discord/renderers/diffView.js +73 -0
  118. package/dist/discord/renderers/diffView.js.map +1 -0
  119. package/dist/discord/renderers/diffView.test.js +54 -0
  120. package/dist/discord/renderers/diffView.test.js.map +1 -0
  121. package/dist/discord/renderers/index.js +143 -0
  122. package/dist/discord/renderers/index.js.map +1 -0
  123. package/dist/discord/renderers/index.test.js +124 -0
  124. package/dist/discord/renderers/index.test.js.map +1 -0
  125. package/dist/discord/renderers/mentionOnComplete.js +19 -0
  126. package/dist/discord/renderers/mentionOnComplete.js.map +1 -0
  127. package/dist/discord/renderers/mentionOnComplete.test.js +35 -0
  128. package/dist/discord/renderers/mentionOnComplete.test.js.map +1 -0
  129. package/dist/discord/renderers/permissionButtons.js +150 -0
  130. package/dist/discord/renderers/permissionButtons.js.map +1 -0
  131. package/dist/discord/renderers/permissionButtons.test.js +108 -0
  132. package/dist/discord/renderers/permissionButtons.test.js.map +1 -0
  133. package/dist/discord/renderers/resultLine.js +25 -0
  134. package/dist/discord/renderers/resultLine.js.map +1 -0
  135. package/dist/discord/renderers/statusEmbed.js +20 -0
  136. package/dist/discord/renderers/statusEmbed.js.map +1 -0
  137. package/dist/discord/renderers/statusEmbed.test.js +32 -0
  138. package/dist/discord/renderers/statusEmbed.test.js.map +1 -0
  139. package/dist/discord/renderers/streamEmbed.js +134 -0
  140. package/dist/discord/renderers/streamEmbed.js.map +1 -0
  141. package/dist/discord/renderers/streamEmbed.test.js +97 -0
  142. package/dist/discord/renderers/streamEmbed.test.js.map +1 -0
  143. package/dist/discord/renderers/toolThread.js +65 -0
  144. package/dist/discord/renderers/toolThread.js.map +1 -0
  145. package/dist/discord/renderers/toolThread.test.js +54 -0
  146. package/dist/discord/renderers/toolThread.test.js.map +1 -0
  147. package/dist/discord/renderers/transcriptFeed.js +33 -0
  148. package/dist/discord/renderers/transcriptFeed.js.map +1 -0
  149. package/dist/discord/renderers/usageEmbed.js +78 -0
  150. package/dist/discord/renderers/usageEmbed.js.map +1 -0
  151. package/dist/discord/renderers/usageEmbed.test.js +42 -0
  152. package/dist/discord/renderers/usageEmbed.test.js.map +1 -0
  153. package/dist/discord/wiring.js +214 -0
  154. package/dist/discord/wiring.js.map +1 -0
  155. package/dist/discord/wiring.test.js +252 -0
  156. package/dist/discord/wiring.test.js.map +1 -0
  157. package/dist/discord/wizard/channelWizard.js +305 -0
  158. package/dist/discord/wizard/channelWizard.js.map +1 -0
  159. package/dist/discord/wizard/channelWizard.test.js +298 -0
  160. package/dist/discord/wizard/channelWizard.test.js.map +1 -0
  161. package/dist/discord/wizard/resumeWizard.js +123 -0
  162. package/dist/discord/wizard/resumeWizard.js.map +1 -0
  163. package/dist/modes/claude/index.js +80 -0
  164. package/dist/modes/claude/index.js.map +1 -0
  165. package/dist/modes/claude/listResumable.test.js +72 -0
  166. package/dist/modes/claude/listResumable.test.js.map +1 -0
  167. package/dist/modes/claude/mcpFileTool.js +82 -0
  168. package/dist/modes/claude/mcpFileTool.js.map +1 -0
  169. package/dist/modes/claude/permissions.js +35 -0
  170. package/dist/modes/claude/permissions.js.map +1 -0
  171. package/dist/modes/claude/plugins.js +56 -0
  172. package/dist/modes/claude/plugins.js.map +1 -0
  173. package/dist/modes/claude/session.js +324 -0
  174. package/dist/modes/claude/session.js.map +1 -0
  175. package/dist/modes/claude/session.test.js +415 -0
  176. package/dist/modes/claude/session.test.js.map +1 -0
  177. package/dist/modes/codex/discovery.js +221 -0
  178. package/dist/modes/codex/discovery.js.map +1 -0
  179. package/dist/modes/codex/discovery.test.js +213 -0
  180. package/dist/modes/codex/discovery.test.js.map +1 -0
  181. package/dist/modes/codex/eventMapper.js +262 -0
  182. package/dist/modes/codex/eventMapper.js.map +1 -0
  183. package/dist/modes/codex/index.js +132 -0
  184. package/dist/modes/codex/index.js.map +1 -0
  185. package/dist/modes/codex/index.test.js +170 -0
  186. package/dist/modes/codex/index.test.js.map +1 -0
  187. package/dist/modes/codex/runner.js +207 -0
  188. package/dist/modes/codex/runner.js.map +1 -0
  189. package/dist/modes/codex/runner.test.js +587 -0
  190. package/dist/modes/codex/runner.test.js.map +1 -0
  191. package/dist/modes/codex/sqliteReader.js +171 -0
  192. package/dist/modes/codex/sqliteReader.js.map +1 -0
  193. package/dist/modes/codex/sqliteReader.test.js +137 -0
  194. package/dist/modes/codex/sqliteReader.test.js.map +1 -0
  195. package/dist/setup/wizard.js +115 -0
  196. package/dist/setup/wizard.js.map +1 -0
  197. package/dist/setup/wizard.test.js +216 -0
  198. package/dist/setup/wizard.test.js.map +1 -0
  199. package/dist/startBot.test.js +78 -0
  200. package/dist/startBot.test.js.map +1 -0
  201. package/package.json +58 -0
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { DiffViewHandler } from './diffView.js';
3
+ function fakeChannel() {
4
+ const sent = [];
5
+ const channel = {
6
+ async send(message) {
7
+ sent.push(message);
8
+ const em = { id: 'm1', async edit() { } };
9
+ return em;
10
+ },
11
+ async startThread() {
12
+ throw new Error('not used');
13
+ },
14
+ };
15
+ return { channel, sent };
16
+ }
17
+ const use = (e) => e;
18
+ const result = (e) => e;
19
+ describe('DiffViewHandler', () => {
20
+ it('renders an old→new diff for a successful Edit', async () => {
21
+ const { channel, sent } = fakeChannel();
22
+ const h = new DiffViewHandler({ channel });
23
+ h.noteToolUse(use({ kind: 'tool_use', id: 't1', name: 'Edit', input: { file_path: '/ws/a.ts', old_string: 'a', new_string: 'b' } }));
24
+ await h.handleResult(result({ kind: 'tool_result', id: 't1', ok: true, content: 'ok' }));
25
+ expect(sent).toHaveLength(1);
26
+ const body = sent[0].content ?? '';
27
+ expect(body).toContain('```diff');
28
+ expect(body).toContain('- a');
29
+ expect(body).toContain('+ b');
30
+ });
31
+ it('renders additions-only for a Write with content', async () => {
32
+ const { channel, sent } = fakeChannel();
33
+ const h = new DiffViewHandler({ channel });
34
+ h.noteToolUse(use({ kind: 'tool_use', id: 't2', name: 'Write', input: { file_path: '/ws/n.ts', content: 'line1\nline2' } }));
35
+ await h.handleResult(result({ kind: 'tool_result', id: 't2', ok: true, content: 'ok' }));
36
+ expect(sent[0].content).toContain('+ line1');
37
+ expect(sent[0].content).toContain('+ line2');
38
+ });
39
+ it('renders nothing for a non-edit tool', async () => {
40
+ const { channel, sent } = fakeChannel();
41
+ const h = new DiffViewHandler({ channel });
42
+ h.noteToolUse(use({ kind: 'tool_use', id: 't3', name: 'Bash', input: { command: 'ls' } }));
43
+ await h.handleResult(result({ kind: 'tool_result', id: 't3', ok: true, content: 'files' }));
44
+ expect(sent).toHaveLength(0);
45
+ });
46
+ it('renders nothing for a failed edit result', async () => {
47
+ const { channel, sent } = fakeChannel();
48
+ const h = new DiffViewHandler({ channel });
49
+ h.noteToolUse(use({ kind: 'tool_use', id: 't4', name: 'Edit', input: { file_path: '/ws/a.ts', old_string: 'a', new_string: 'b' } }));
50
+ await h.handleResult(result({ kind: 'tool_result', id: 't4', ok: false, content: 'error' }));
51
+ expect(sent).toHaveLength(0);
52
+ });
53
+ });
54
+ //# sourceMappingURL=diffView.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diffView.test.js","sourceRoot":"","sources":["../../../src/discord/renderers/diffView.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import { StreamEmbedHandler } from './streamEmbed.js';
2
+ import { ToolThreadHandler } from './toolThread.js';
3
+ import { PermissionButtonsHandler } from './permissionButtons.js';
4
+ import { DiffViewHandler } from './diffView.js';
5
+ import { TranscriptFeedHandler } from './transcriptFeed.js';
6
+ import { MentionOnCompleteHandler } from './mentionOnComplete.js';
7
+ import { buildResultLine } from './resultLine.js';
8
+ import { buildUsageEmbed } from './usageEmbed.js';
9
+ export class RendererDispatcher {
10
+ renderers;
11
+ capabilities;
12
+ constructor(renderers, capabilities) {
13
+ this.renderers = renderers;
14
+ this.capabilities = capabilities;
15
+ }
16
+ // Subscribe this dispatcher to a channel's event stream. Returns the unsubscribe.
17
+ subscribe(bus, guildId, channelId) {
18
+ return bus.on(guildId, channelId, (ev) => this.dispatch(ev));
19
+ }
20
+ // Capability-gated dispatch. This is the ONE place capabilities decide which
21
+ // renderer fires. A backend that lacks a capability simply has that path skipped;
22
+ // for text specifically, a non-streaming backend routes the final text to a plain
23
+ // message and progress to the transcript feed (Codex degraded UX, §5c).
24
+ dispatch(ev) {
25
+ const caps = this.capabilities;
26
+ switch (ev.kind) {
27
+ case 'text':
28
+ if (caps.streaming)
29
+ this.renderers.stream(ev);
30
+ else
31
+ this.renderers.plainText(ev);
32
+ break;
33
+ case 'thinking':
34
+ if (caps.thinking)
35
+ this.renderers.stream(ev);
36
+ break;
37
+ case 'tool_use':
38
+ case 'tool_result':
39
+ if (caps.toolThreads)
40
+ this.renderers.toolThread(ev);
41
+ if (caps.fileDiff)
42
+ this.renderers.diff(ev);
43
+ break;
44
+ case 'permission_request':
45
+ if (caps.permissionPrompts)
46
+ this.renderers.permission(ev);
47
+ break;
48
+ case 'progress':
49
+ if (caps.progress || caps.transcript)
50
+ this.renderers.transcript(ev);
51
+ break;
52
+ case 'result':
53
+ // Non-streaming/transcript backends post their final text via the feed.
54
+ if (!caps.streaming && (caps.transcript || caps.progress))
55
+ this.renderers.transcript(ev);
56
+ this.renderers.result(ev);
57
+ this.renderers.mention(ev);
58
+ break;
59
+ case 'context_usage':
60
+ if (caps.usagePanel)
61
+ this.renderers.usage(ev);
62
+ break;
63
+ case 'error':
64
+ this.renderers.error(ev);
65
+ break;
66
+ }
67
+ }
68
+ }
69
+ // Wire the concrete handlers over one channel. Async handler work is fire-and-forget
70
+ // with a swallowed rejection so a rendering hiccup never breaks the event stream —
71
+ // the orchestrator's error events remain the user-visible failure signal.
72
+ export function createDefaultRendererSet(options) {
73
+ const { channel, ownerId } = options;
74
+ const textStream = new StreamEmbedHandler({ channel, kind: 'text' });
75
+ const thinkingStream = new StreamEmbedHandler({ channel, kind: 'thinking' });
76
+ const toolThread = new ToolThreadHandler({ channel });
77
+ const permission = new PermissionButtonsHandler({ channel });
78
+ const diff = new DiffViewHandler({ channel });
79
+ const transcript = new TranscriptFeedHandler({ channel });
80
+ const mention = new MentionOnCompleteHandler({ channel, ownerId });
81
+ let lastCtxUsage = null;
82
+ const swallow = (p) => {
83
+ void p.catch(() => { });
84
+ };
85
+ return {
86
+ stream(ev) {
87
+ if (ev.kind === 'thinking')
88
+ thinkingStream.push(ev);
89
+ else
90
+ textStream.push(ev);
91
+ },
92
+ plainText(ev) {
93
+ swallow(channel.send({ content: ev.text }));
94
+ },
95
+ toolThread(ev) {
96
+ swallow(toolThread.handle(ev));
97
+ },
98
+ diff(ev) {
99
+ if (ev.kind === 'tool_use')
100
+ diff.noteToolUse(ev);
101
+ else
102
+ swallow(diff.handleResult(ev));
103
+ },
104
+ permission(ev) {
105
+ // The dispatcher path posts the buttons; the returned promise is resolved by
106
+ // the orchestrator's requestPermission hookup (7b). Here we just surface them.
107
+ swallow(permission.request(ev));
108
+ },
109
+ transcript(ev) {
110
+ swallow(transcript.handle(ev));
111
+ },
112
+ result(ev) {
113
+ // Finalize any open text stream before the done-line, so the answer lands first.
114
+ swallow(textStream.finalize().then(() => thinkingStream.finalize()));
115
+ const line = buildResultLine(ev);
116
+ if (line)
117
+ swallow(channel.send({ content: line }));
118
+ },
119
+ usage(ev) {
120
+ lastCtxUsage = ev;
121
+ const usage = options.getUsage?.() ?? null;
122
+ const embed = buildUsageEmbed(usage, lastCtxUsage);
123
+ if (embed)
124
+ swallow(channel.send({ embeds: [embed] }));
125
+ },
126
+ mention(ev) {
127
+ swallow(mention.handle(ev));
128
+ },
129
+ error(ev) {
130
+ swallow(channel.send({ content: `⚠️ ${ev.message}` }));
131
+ },
132
+ dispose() {
133
+ // Cancel the streaming/thinking debounce timers so a detach mid-stream cannot
134
+ // fire a late edit/send against a channel that is being torn down.
135
+ textStream.cancel();
136
+ thinkingStream.cancel();
137
+ },
138
+ };
139
+ }
140
+ // Re-export the permission handler for 7b to wire orchestrator.requestPermission
141
+ // and button-interaction resolution (the request/resolve round-trip lives there).
142
+ export { PermissionButtonsHandler } from './permissionButtons.js';
143
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/discord/renderers/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { RendererDispatcher } from './index.js';
3
+ // A spy renderer set: every action is a vi.fn() so a test asserts exactly which
4
+ // renderer fired for a given event × capability combination.
5
+ function spySet() {
6
+ return {
7
+ stream: vi.fn(),
8
+ plainText: vi.fn(),
9
+ toolThread: vi.fn(),
10
+ diff: vi.fn(),
11
+ permission: vi.fn(),
12
+ transcript: vi.fn(),
13
+ result: vi.fn(),
14
+ usage: vi.fn(),
15
+ mention: vi.fn(),
16
+ error: vi.fn(),
17
+ };
18
+ }
19
+ const claudeCaps = {
20
+ streaming: true,
21
+ thinking: true,
22
+ toolThreads: true,
23
+ permissionPrompts: true,
24
+ progress: false,
25
+ transcript: false,
26
+ sessionResume: true,
27
+ fileAttach: true,
28
+ fileDiff: true,
29
+ usagePanel: true,
30
+ permissionModes: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
31
+ };
32
+ const codexCaps = {
33
+ streaming: false,
34
+ thinking: false,
35
+ toolThreads: false,
36
+ permissionPrompts: false,
37
+ progress: true,
38
+ transcript: true,
39
+ sessionResume: true,
40
+ fileAttach: false,
41
+ fileDiff: false,
42
+ usagePanel: false,
43
+ permissionModes: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
44
+ };
45
+ const toolUse = { kind: 'tool_use', id: 't1', name: 'Edit', input: { file_path: '/ws/a' } };
46
+ const permReq = { kind: 'permission_request', id: 'p1', toolName: 'Bash', input: {} };
47
+ const textEv = { kind: 'text', text: 'hello', delta: true };
48
+ const progressEv = { kind: 'progress', label: 'editing' };
49
+ const ctxUsage = { kind: 'context_usage', totalTokens: 10, maxTokens: 100, percentage: 10 };
50
+ describe('RendererDispatcher capability dispatch', () => {
51
+ it('fires toolThread for tool_use only when toolThreads is set', () => {
52
+ const set = spySet();
53
+ new RendererDispatcher(set, claudeCaps).dispatch(toolUse);
54
+ expect(set.toolThread).toHaveBeenCalledWith(toolUse);
55
+ const set2 = spySet();
56
+ new RendererDispatcher(set2, codexCaps).dispatch(toolUse);
57
+ expect(set2.toolThread).not.toHaveBeenCalled();
58
+ });
59
+ it('fires the diff renderer for tool_use only when fileDiff is set', () => {
60
+ const set = spySet();
61
+ new RendererDispatcher(set, claudeCaps).dispatch(toolUse);
62
+ expect(set.diff).toHaveBeenCalledWith(toolUse);
63
+ const set2 = spySet();
64
+ new RendererDispatcher(set2, codexCaps).dispatch(toolUse);
65
+ expect(set2.diff).not.toHaveBeenCalled();
66
+ });
67
+ it('fires permission buttons for permission_request only when permissionPrompts is set', () => {
68
+ const set = spySet();
69
+ new RendererDispatcher(set, claudeCaps).dispatch(permReq);
70
+ expect(set.permission).toHaveBeenCalledWith(permReq);
71
+ const set2 = spySet();
72
+ new RendererDispatcher(set2, codexCaps).dispatch(permReq);
73
+ expect(set2.permission).not.toHaveBeenCalled();
74
+ });
75
+ it('routes text to the stream embed when streaming is set', () => {
76
+ const set = spySet();
77
+ new RendererDispatcher(set, claudeCaps).dispatch(textEv);
78
+ expect(set.stream).toHaveBeenCalledWith(textEv);
79
+ expect(set.plainText).not.toHaveBeenCalled();
80
+ });
81
+ it('routes text to a plain message when streaming is NOT set (Codex-like)', () => {
82
+ const set = spySet();
83
+ new RendererDispatcher(set, codexCaps).dispatch(textEv);
84
+ expect(set.plainText).toHaveBeenCalledWith(textEv);
85
+ expect(set.stream).not.toHaveBeenCalled();
86
+ });
87
+ it('routes progress to the transcript feed for a transcript/progress backend', () => {
88
+ const set = spySet();
89
+ new RendererDispatcher(set, codexCaps).dispatch(progressEv);
90
+ expect(set.transcript).toHaveBeenCalledWith(progressEv);
91
+ // Claude (no progress/transcript) skips it.
92
+ const set2 = spySet();
93
+ new RendererDispatcher(set2, claudeCaps).dispatch(progressEv);
94
+ expect(set2.transcript).not.toHaveBeenCalled();
95
+ });
96
+ it('fires the usage panel for context_usage only when usagePanel is set', () => {
97
+ const set = spySet();
98
+ new RendererDispatcher(set, claudeCaps).dispatch(ctxUsage);
99
+ expect(set.usage).toHaveBeenCalledWith(ctxUsage);
100
+ const set2 = spySet();
101
+ new RendererDispatcher(set2, codexCaps).dispatch(ctxUsage);
102
+ expect(set2.usage).not.toHaveBeenCalled();
103
+ });
104
+ it('always fires result + mention on result; Codex additionally feeds final text to transcript', () => {
105
+ const resultEv = { kind: 'result', text: 'final', costUsd: 0.01 };
106
+ const claude = spySet();
107
+ new RendererDispatcher(claude, claudeCaps).dispatch(resultEv);
108
+ expect(claude.result).toHaveBeenCalledWith(resultEv);
109
+ expect(claude.mention).toHaveBeenCalledWith(resultEv);
110
+ expect(claude.transcript).not.toHaveBeenCalled();
111
+ const codex = spySet();
112
+ new RendererDispatcher(codex, codexCaps).dispatch(resultEv);
113
+ expect(codex.result).toHaveBeenCalledWith(resultEv);
114
+ expect(codex.mention).toHaveBeenCalledWith(resultEv);
115
+ expect(codex.transcript).toHaveBeenCalledWith(resultEv);
116
+ });
117
+ it('always surfaces errors regardless of capabilities', () => {
118
+ const errEv = { kind: 'error', message: 'boom', retryable: false };
119
+ const set = spySet();
120
+ new RendererDispatcher(set, codexCaps).dispatch(errEv);
121
+ expect(set.error).toHaveBeenCalledWith(errEv);
122
+ });
123
+ });
124
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/discord/renderers/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export class MentionOnCompleteHandler {
2
+ channel;
3
+ ownerId;
4
+ constructor(deps) {
5
+ this.channel = deps.channel;
6
+ this.ownerId = deps.ownerId;
7
+ }
8
+ async handle(_ev) {
9
+ // No owner bound (e.g. a resumed binding missing its ownerId) → skip the mention
10
+ // rather than post a broken `<@>` that pings no one.
11
+ if (!this.ownerId)
12
+ return;
13
+ await this.channel.send({
14
+ content: `<@${this.ownerId}>`,
15
+ mentionUserIds: [this.ownerId],
16
+ });
17
+ }
18
+ }
19
+ //# sourceMappingURL=mentionOnComplete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentionOnComplete.js","sourceRoot":"","sources":["../../../src/discord/renderers/mentionOnComplete.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,wBAAwB;IAClB,OAAO,CAAiB;IACxB,OAAO,CAAS;IAEjC,YAAY,IAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAA4C;QACvD,iFAAiF;QACjF,qDAAqD;QACrD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YACtB,OAAO,EAAE,KAAK,IAAI,CAAC,OAAO,GAAG;YAC7B,cAAc,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { MentionOnCompleteHandler } from './mentionOnComplete.js';
3
+ // A fake channel recording every sent message.
4
+ function fakeChannel() {
5
+ const sent = [];
6
+ const channel = {
7
+ async send(message) {
8
+ sent.push(message);
9
+ const em = { id: `m${sent.length}`, async edit() { } };
10
+ return em;
11
+ },
12
+ async startThread() {
13
+ throw new Error('not used');
14
+ },
15
+ };
16
+ return { channel, sent };
17
+ }
18
+ const resultEv = { kind: 'result', text: 'done' };
19
+ describe('MentionOnCompleteHandler', () => {
20
+ it('mentions the owner on completion when an ownerId is bound', async () => {
21
+ const { channel, sent } = fakeChannel();
22
+ const handler = new MentionOnCompleteHandler({ channel, ownerId: 'owner-9' });
23
+ await handler.handle(resultEv);
24
+ expect(sent).toHaveLength(1);
25
+ expect(sent[0].content).toBe('<@owner-9>');
26
+ expect(sent[0].mentionUserIds).toEqual(['owner-9']);
27
+ });
28
+ it('posts NO message when the ownerId is empty (no broken <@> ping)', async () => {
29
+ const { channel, sent } = fakeChannel();
30
+ const handler = new MentionOnCompleteHandler({ channel, ownerId: '' });
31
+ await handler.handle(resultEv);
32
+ expect(sent).toHaveLength(0);
33
+ });
34
+ });
35
+ //# sourceMappingURL=mentionOnComplete.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentionOnComplete.test.js","sourceRoot":"","sources":["../../../src/discord/renderers/mentionOnComplete.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAIlE,+CAA+C;AAC/C,SAAS,WAAW;IAClB,MAAM,IAAI,GAAsB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAmB;QAC9B,KAAK,CAAC,IAAI,CAAC,OAAO;YAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,MAAM,EAAE,GAAoB,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,KAAI,CAAC,EAAE,CAAC;YACvE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,KAAK,CAAC,WAAW;YACf,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,QAAQ,GAA4C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAE3F,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,wBAAwB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9E,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,wBAAwB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,150 @@
1
+ import { COLORS, truncate } from '../format.js';
2
+ import { t } from '../i18n.js';
3
+ // Permission buttons (§6, §5a): a permission_request posts Allow / Always-Allow /
4
+ // Deny buttons; the button interaction resolves the pending PermissionDecision.
5
+ // custom_id scheme: `perm:<reqId>:<action>` where action ∈ allow|always|deny.
6
+ //
7
+ // This handler owns the pending map keyed by reqId. 7b wires two directions:
8
+ // - orchestrator.requestPermission → request(reqId, toolName, input) posts the
9
+ // buttons and returns a Promise<PermissionDecision> that resolves when the user
10
+ // clicks; the awaiting orchestrator turn is unblocked by that resolution.
11
+ // - a button interaction → resolve(customId) settles the matching pending promise.
12
+ // No discord.js here: the sink is the MessageChannel port; interactions are parsed
13
+ // by 7b and handed to resolve() as the raw custom_id string.
14
+ const CUSTOM_ID_PREFIX = 'perm';
15
+ export function buildCustomId(reqId, action) {
16
+ return `${CUSTOM_ID_PREFIX}:${reqId}:${action}`;
17
+ }
18
+ // Parse a `perm:<reqId>:<action>` custom_id. Returns null for a non-permission id
19
+ // or an unknown action, so a foreign interaction is safely ignored by the caller.
20
+ export function parseCustomId(customId) {
21
+ const parts = customId.split(':');
22
+ if (parts.length !== 3 || parts[0] !== CUSTOM_ID_PREFIX)
23
+ return null;
24
+ const [, reqId, action] = parts;
25
+ if (action !== 'allow' && action !== 'always' && action !== 'deny')
26
+ return null;
27
+ if (!reqId)
28
+ return null;
29
+ return { reqId, action };
30
+ }
31
+ export class PermissionButtonsHandler {
32
+ channel;
33
+ pending = new Map();
34
+ constructor(deps) {
35
+ this.channel = deps.channel;
36
+ }
37
+ // The tool name of a still-pending request, or null once it has resolved/expired.
38
+ // Lets the wiring layer read the tool for an always-allow persistence decision
39
+ // before resolve() removes the pending entry.
40
+ peekToolName(reqId) {
41
+ return this.pending.get(reqId)?.toolName ?? null;
42
+ }
43
+ // The approver bound to a still-pending request, or null when unbound/unknown.
44
+ peekApproverId(reqId) {
45
+ return this.pending.get(reqId)?.approverId ?? null;
46
+ }
47
+ // Post the buttons for a permission_request and return a promise that settles when
48
+ // the user decides. The pending resolver is registered SYNCHRONOUSLY (before the
49
+ // send completes) so a decision that races the post still resolves; the message
50
+ // handle used to disable the buttons is filled in once send resolves. `ev.id` is
51
+ // the AgentEvent id (stable across the round-trip). `approverId` binds the prompt
52
+ // to the one actor allowed to resolve it (the session owner/driver); when omitted
53
+ // the prompt is unbound (resolve() enforces no actor).
54
+ request(ev, approverId) {
55
+ const entry = {
56
+ resolve: () => { },
57
+ message: null,
58
+ toolName: ev.toolName,
59
+ approverId: approverId ?? null,
60
+ };
61
+ const decision = new Promise((resolve) => {
62
+ entry.resolve = resolve;
63
+ });
64
+ this.pending.set(ev.id, entry);
65
+ const embed = {
66
+ title: t('perm.request.title'),
67
+ description: t('perm.request.body', {
68
+ tool: ev.toolName,
69
+ input: truncate(formatInput(ev.input), 3000),
70
+ }),
71
+ color: COLORS.permission,
72
+ };
73
+ const buttons = [
74
+ { type: 'button', customId: buildCustomId(ev.id, 'allow'), label: t('perm.button.allow'), style: 'success' },
75
+ { type: 'button', customId: buildCustomId(ev.id, 'always'), label: t('perm.button.always'), style: 'primary' },
76
+ { type: 'button', customId: buildCustomId(ev.id, 'deny'), label: t('perm.button.deny'), style: 'danger' },
77
+ ];
78
+ void this.channel
79
+ .send({ embeds: [embed], components: [{ components: buttons }] })
80
+ .then((message) => {
81
+ // If the user already decided (entry removed), leave the message as-is.
82
+ if (this.pending.get(ev.id) === entry)
83
+ entry.message = message;
84
+ })
85
+ .catch(() => { });
86
+ return decision;
87
+ }
88
+ // Settle a pending request from a button custom_id. Returns the decision applied,
89
+ // or null if the id is unknown/foreign/already-resolved (idempotent, safe to call
90
+ // on any interaction). When the prompt is bound to an approver and `actorId` is
91
+ // supplied, an actor other than the approver is IGNORED (returns null, prompt stays
92
+ // pending) — a bystander cannot resolve another driver's prompt (§7.1/§7.5).
93
+ // Disables the buttons and marks the outcome on resolve.
94
+ async resolve(customId, actorId) {
95
+ const parsed = parseCustomId(customId);
96
+ if (!parsed)
97
+ return null;
98
+ const entry = this.pending.get(parsed.reqId);
99
+ if (!entry)
100
+ return null;
101
+ // Enforce the approver binding: if the prompt is bound and the caller passed an
102
+ // actor id, only that actor may resolve it. Leave the entry pending otherwise.
103
+ if (entry.approverId !== null && actorId !== undefined && actorId !== entry.approverId) {
104
+ return null;
105
+ }
106
+ this.pending.delete(parsed.reqId);
107
+ const decision = parsed.action === 'deny'
108
+ ? { behavior: 'deny', message: 'User denied via Discord' }
109
+ : { behavior: 'allow' };
110
+ const decidedKey = parsed.action === 'deny'
111
+ ? 'perm.decided.deny'
112
+ : parsed.action === 'always'
113
+ ? 'perm.decided.always'
114
+ : 'perm.decided.allow';
115
+ // Collapse the prompt: disable buttons and note the outcome so the record is
116
+ // clear and the buttons cannot be re-clicked. If the buttons message has not
117
+ // finished posting yet (a decision that raced the send), skip the edit — the
118
+ // decision still resolves below.
119
+ if (entry.message) {
120
+ await entry.message.edit({
121
+ embeds: [
122
+ {
123
+ title: `${t('perm.request.title')} — ${t(decidedKey)}`,
124
+ description: t('perm.request.body', {
125
+ tool: entry.toolName,
126
+ input: t(decidedKey),
127
+ }),
128
+ color: parsed.action === 'deny' ? COLORS.stopped : COLORS.idle,
129
+ },
130
+ ],
131
+ components: [],
132
+ });
133
+ }
134
+ entry.resolve(decision);
135
+ // `always` is surfaced as allow here; 7b/8 persists the always-allow set into
136
+ // the resolved tool allowlist (config-driven auto-allow, §7A) — not this layer's job.
137
+ return decision;
138
+ }
139
+ }
140
+ function formatInput(input) {
141
+ if (typeof input === 'string')
142
+ return input;
143
+ try {
144
+ return '```json\n' + JSON.stringify(input, null, 2) + '\n```';
145
+ }
146
+ catch {
147
+ return String(input);
148
+ }
149
+ }
150
+ //# sourceMappingURL=permissionButtons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionButtons.js","sourceRoot":"","sources":["../../../src/discord/renderers/permissionButtons.ts"],"names":[],"mappings":"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"}