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,216 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { runSetup, buildInviteUrl } from './wizard.js';
6
+ import { ConfigStore } from '../core/config.js';
7
+ // Zero-entropy fixtures: deliberately NOT secret-shaped so no scanner treats them as
8
+ // real credentials. The wizard never inspects the token's shape, so a plain token is
9
+ // a faithful stand-in.
10
+ const FIXTURE_TOKEN = 'test-token-value';
11
+ const FIXTURE_CLIENT_ID = '100000000000000001';
12
+ // A scripted prompt double: pops one answer per prompt call, in order. Neither role
13
+ // tiers NOR defaults are prompted anymore (they move to Discord `/config`), so the
14
+ // wizard now calls only:
15
+ // password(token) → input(clientId) → confirm(intent).
16
+ function scriptedPrompts(answers) {
17
+ const passwords = [...answers.passwords];
18
+ const inputs = [...answers.inputs];
19
+ const confirms = [...answers.confirms];
20
+ const passwordMessages = [];
21
+ const inputMessages = [];
22
+ const prompts = {
23
+ async password(config) {
24
+ passwordMessages.push(config.message);
25
+ const v = passwords.shift();
26
+ if (v === undefined)
27
+ throw new Error('no scripted password answer left');
28
+ return v;
29
+ },
30
+ async input(config) {
31
+ inputMessages.push(config.message);
32
+ const v = inputs.shift();
33
+ return v ?? config.default ?? '';
34
+ },
35
+ async confirm(config) {
36
+ const v = confirms.shift();
37
+ return v ?? config.default ?? false;
38
+ },
39
+ };
40
+ return { prompts, passwordMessages, inputMessages };
41
+ }
42
+ // A logger double that records every message + meta it is handed, so a test can
43
+ // assert the token never reaches the operational log.
44
+ function recordingLogger() {
45
+ const entries = [];
46
+ const push = (message, meta) => {
47
+ entries.push(message + ' ' + JSON.stringify(meta));
48
+ };
49
+ const logger = {
50
+ debug: (m, ...meta) => push(m, meta),
51
+ info: (m, ...meta) => push(m, meta),
52
+ warn: (m, ...meta) => push(m, meta),
53
+ error: (m, ...meta) => push(m, meta),
54
+ };
55
+ return { logger, entries };
56
+ }
57
+ let dir;
58
+ let store;
59
+ beforeEach(() => {
60
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'dab-setup-'));
61
+ store = new ConfigStore(dir);
62
+ });
63
+ afterEach(() => {
64
+ fs.rmSync(dir, { recursive: true, force: true });
65
+ });
66
+ describe('buildInviteUrl', () => {
67
+ it('contains the client id, both scopes, and a non-zero permission bitfield', () => {
68
+ const url = buildInviteUrl(FIXTURE_CLIENT_ID);
69
+ const parsed = new URL(url);
70
+ expect(parsed.searchParams.get('client_id')).toBe(FIXTURE_CLIENT_ID);
71
+ // scope carries both `bot` and `applications.commands`.
72
+ const scope = parsed.searchParams.get('scope');
73
+ expect(scope).toContain('bot');
74
+ expect(scope).toContain('applications.commands');
75
+ // permissions is a positive integer bitfield.
76
+ const perms = parsed.searchParams.get('permissions');
77
+ expect(perms).toBeTruthy();
78
+ expect(BigInt(perms) > 0n).toBe(true);
79
+ });
80
+ });
81
+ describe('runSetup', () => {
82
+ it('writes a config with the entered token + clientId and CONFIG_DEFAULTS defaults', async () => {
83
+ const { prompts } = scriptedPrompts({
84
+ passwords: [FIXTURE_TOKEN],
85
+ // ONLY the clientId is prompted now — model/codexHome/locale are NOT.
86
+ inputs: [FIXTURE_CLIENT_ID],
87
+ confirms: [true],
88
+ });
89
+ const opened = [];
90
+ await runSetup({
91
+ prompts,
92
+ store,
93
+ open: async (target) => {
94
+ opened.push(target);
95
+ },
96
+ log: () => { },
97
+ });
98
+ const config = store.load();
99
+ expect(config.discord.token).toBe(FIXTURE_TOKEN);
100
+ expect(config.discord.clientId).toBe(FIXTURE_CLIENT_ID);
101
+ // Every default comes straight from CONFIG_DEFAULTS (set later in `/config`).
102
+ expect(config.defaults.mode).toBe('claude');
103
+ expect(config.defaults.claudeModel).toBe('opus');
104
+ expect(config.defaults.codexHome).toBe('~/.codex');
105
+ expect(config.defaults.permissionMode).toBe('default');
106
+ expect(config.locale).toBe('ko');
107
+ // The invite URL was opened, carrying the client id + both scopes + non-zero perms.
108
+ expect(opened).toHaveLength(1);
109
+ const parsed = new URL(opened[0]);
110
+ expect(parsed.searchParams.get('client_id')).toBe(FIXTURE_CLIENT_ID);
111
+ expect(parsed.searchParams.get('scope')).toContain('bot');
112
+ expect(parsed.searchParams.get('scope')).toContain('applications.commands');
113
+ expect(BigInt(parsed.searchParams.get('permissions')) > 0n).toBe(true);
114
+ });
115
+ it('no longer prompts for model, codexHome, locale, or permission mode', async () => {
116
+ const { prompts, inputMessages } = scriptedPrompts({
117
+ passwords: [FIXTURE_TOKEN],
118
+ inputs: [FIXTURE_CLIENT_ID],
119
+ confirms: [true],
120
+ });
121
+ await runSetup({ prompts, store, open: async () => { }, log: () => { } });
122
+ // Exactly ONE input prompt (the Client ID); no default/role prompts remain.
123
+ expect(inputMessages).toHaveLength(1);
124
+ for (const msg of inputMessages) {
125
+ // No prompt mentions role tiers, models, Codex path, language, or permissions.
126
+ expect(msg).not.toMatch(/역할|role/i);
127
+ expect(msg).not.toMatch(/모델|model/i);
128
+ expect(msg).not.toMatch(/codex|경로/i);
129
+ expect(msg).not.toMatch(/locale|언어/i);
130
+ expect(msg).not.toMatch(/권한|permission/i);
131
+ }
132
+ });
133
+ it('writes EMPTY role allowlists (deny-by-default) from CONFIG_DEFAULTS', async () => {
134
+ const { prompts } = scriptedPrompts({
135
+ passwords: [FIXTURE_TOKEN],
136
+ inputs: [FIXTURE_CLIENT_ID],
137
+ confirms: [true],
138
+ });
139
+ await runSetup({ prompts, store, open: async () => { }, log: () => { } });
140
+ const config = store.load();
141
+ expect(config.auth.adminRoleIds).toEqual([]);
142
+ expect(config.auth.executeRoleIds).toEqual([]);
143
+ expect(config.auth.readOnlyRoleIds).toEqual([]);
144
+ });
145
+ it('prints the `/config` guidance for roles AND defaults (model/language/permissions)', async () => {
146
+ const { prompts } = scriptedPrompts({
147
+ passwords: [FIXTURE_TOKEN],
148
+ inputs: [FIXTURE_CLIENT_ID],
149
+ confirms: [true],
150
+ });
151
+ const logs = [];
152
+ await runSetup({ prompts, store, open: async () => { }, log: (m) => logs.push(m) });
153
+ // Roles → Discord `/config`.
154
+ expect(logs.some((l) => l.includes('/config') && l.includes('Discord'))).toBe(true);
155
+ // Defaults (model/language/permissions) → Discord `/config`.
156
+ expect(logs.some((l) => l.includes('/config') && /모델|언어|권한/.test(l))).toBe(true);
157
+ });
158
+ it('writes a 0600 config file', async () => {
159
+ const { prompts } = scriptedPrompts({
160
+ passwords: [FIXTURE_TOKEN],
161
+ inputs: [FIXTURE_CLIENT_ID],
162
+ confirms: [true],
163
+ });
164
+ await runSetup({ prompts, store, open: async () => { }, log: () => { } });
165
+ const config = store.load();
166
+ expect(config.auth.executeRoleIds).toEqual([]);
167
+ expect(config.defaults.claudeModel).toBe('opus');
168
+ expect(config.defaults.codexHome).toBe('~/.codex');
169
+ expect(config.locale).toBe('ko');
170
+ if (process.platform !== 'win32') {
171
+ const mode = fs.statSync(store.configPath).mode & 0o777;
172
+ expect(mode).toBe(0o600);
173
+ }
174
+ });
175
+ it('never leaks the token to the operational logger or user output', async () => {
176
+ const { prompts } = scriptedPrompts({
177
+ passwords: [FIXTURE_TOKEN],
178
+ inputs: [FIXTURE_CLIENT_ID],
179
+ confirms: [true],
180
+ });
181
+ const { logger, entries } = recordingLogger();
182
+ const userOutput = [];
183
+ await runSetup({
184
+ prompts,
185
+ store,
186
+ logger,
187
+ open: async () => { },
188
+ log: (m) => userOutput.push(m),
189
+ });
190
+ // Token must never appear in any logged line or any user-facing output line.
191
+ for (const line of [...entries, ...userOutput]) {
192
+ expect(line).not.toContain(FIXTURE_TOKEN);
193
+ }
194
+ // But it WAS written to the (0600) config file.
195
+ expect(store.load().discord.token).toBe(FIXTURE_TOKEN);
196
+ });
197
+ it('proceeds even if opening the browser throws', async () => {
198
+ const { prompts } = scriptedPrompts({
199
+ passwords: [FIXTURE_TOKEN],
200
+ inputs: [FIXTURE_CLIENT_ID],
201
+ confirms: [true],
202
+ });
203
+ await runSetup({
204
+ prompts,
205
+ store,
206
+ open: async () => {
207
+ throw new Error('no browser here');
208
+ },
209
+ log: () => { },
210
+ });
211
+ // A failed open() does not abort the wizard — the config is still written.
212
+ expect(store.exists()).toBe(true);
213
+ expect(store.load().discord.clientId).toBe(FIXTURE_CLIENT_ID);
214
+ });
215
+ });
216
+ //# sourceMappingURL=wizard.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.test.js","sourceRoot":"","sources":["../../src/setup/wizard.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { startBot } from './app.js';
6
+ import { ConfigStore } from './core/config.js';
7
+ import { CONFIG_DEFAULTS, CONFIG_VERSION } from './core/configSchema.js';
8
+ // startBot's first-run guardrails (§ friendly startup errors): a config-less or
9
+ // token-less boot must print a short, actionable "run --setup" message and set a
10
+ // non-zero exit code — NOT throw a raw stack trace. Genuine errors (a corrupt
11
+ // config) still propagate. Every case uses a temp DAB home so the real ~/.config
12
+ // is never touched, and no real Discord login happens (we bail before createApp).
13
+ function makeConfig(overrides = {}) {
14
+ return {
15
+ ...CONFIG_DEFAULTS,
16
+ version: CONFIG_VERSION,
17
+ discord: { token: 'fake-token-value', clientId: 'client-id-000' },
18
+ ...overrides,
19
+ };
20
+ }
21
+ describe('startBot — first-run guardrails', () => {
22
+ let dir;
23
+ let errSpy;
24
+ let prevExitCode;
25
+ beforeEach(() => {
26
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'dab-boot-'));
27
+ errSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
28
+ prevExitCode = process.exitCode;
29
+ process.exitCode = undefined;
30
+ });
31
+ afterEach(() => {
32
+ errSpy.mockRestore();
33
+ process.exitCode = prevExitCode;
34
+ fs.rmSync(dir, { recursive: true, force: true });
35
+ });
36
+ it('no config file → friendly "run --setup" message + non-zero exit, no throw', async () => {
37
+ // Empty temp dir: no config.json exists.
38
+ expect(new ConfigStore(dir).exists()).toBe(false);
39
+ const app = await startBot({ baseDir: dir });
40
+ expect(app).toBeUndefined();
41
+ expect(process.exitCode).toBe(1);
42
+ expect(errSpy).toHaveBeenCalledTimes(1);
43
+ const msg = String(errSpy.mock.calls[0]?.[0]);
44
+ expect(msg).toContain('--setup');
45
+ // Friendly text, not an Error/stack trace.
46
+ expect(msg).not.toMatch(/\bError\b|\bat \S+:\d+/);
47
+ });
48
+ it('config present but empty token → friendly token message + non-zero exit, no throw', async () => {
49
+ const store = new ConfigStore(dir);
50
+ store.save(makeConfig({ discord: { token: '', clientId: 'client-id-000' } }));
51
+ const app = await startBot({ baseDir: dir });
52
+ expect(app).toBeUndefined();
53
+ expect(process.exitCode).toBe(1);
54
+ expect(errSpy).toHaveBeenCalledTimes(1);
55
+ const msg = String(errSpy.mock.calls[0]?.[0]);
56
+ // Korean default token guidance mentions --setup and does not leak a stack.
57
+ expect(msg).toContain('--setup');
58
+ expect(msg).not.toMatch(/\bError\b|\bat \S+:\d+/);
59
+ });
60
+ it('a whitespace-only token is treated as missing (friendly path, non-zero exit)', async () => {
61
+ const store = new ConfigStore(dir);
62
+ store.save(makeConfig({ discord: { token: ' ', clientId: 'client-id-000' } }));
63
+ const app = await startBot({ baseDir: dir });
64
+ expect(app).toBeUndefined();
65
+ expect(process.exitCode).toBe(1);
66
+ expect(errSpy).toHaveBeenCalledTimes(1);
67
+ });
68
+ it('a present-but-invalid config still THROWS (real bug, not the friendly path)', async () => {
69
+ const store = new ConfigStore(dir);
70
+ fs.mkdirSync(dir, { recursive: true });
71
+ // Missing the required discord section → zod rejects on load.
72
+ fs.writeFileSync(store.configPath, JSON.stringify({ locale: 'ko' }), 'utf-8');
73
+ await expect(startBot({ baseDir: dir })).rejects.toThrow();
74
+ // Not swallowed into the friendly exit path.
75
+ expect(process.exitCode).toBeUndefined();
76
+ });
77
+ });
78
+ //# sourceMappingURL=startBot.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startBot.test.js","sourceRoot":"","sources":["../src/startBot.test.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "discord-agent-bridge",
3
+ "version": "0.1.0",
4
+ "description": "Self-hosted Discord bot that runs AI coding agents — Claude Code, Codex, and more — per channel. Role-based access, multi-server, extensible.",
5
+ "type": "module",
6
+ "bin": {
7
+ "discord-agent-bridge": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsx watch src/cli.ts",
16
+ "start": "node dist/cli.js",
17
+ "typecheck": "tsc --noEmit",
18
+ "test": "vitest run",
19
+ "lint": "eslint src/"
20
+ },
21
+ "keywords": [
22
+ "discord",
23
+ "claude",
24
+ "claude-code",
25
+ "codex",
26
+ "agent",
27
+ "bot"
28
+ ],
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/rsupport/discord-agent-bridge.git"
33
+ },
34
+ "homepage": "https://github.com/rsupport/discord-agent-bridge#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/rsupport/discord-agent-bridge/issues"
37
+ },
38
+ "engines": {
39
+ "node": ">=20.0.0"
40
+ },
41
+ "dependencies": {
42
+ "discord.js": "^14.18.0",
43
+ "@anthropic-ai/claude-agent-sdk": "^0.2.0",
44
+ "@discordjs/rest": "^2.4.0",
45
+ "@inquirer/prompts": "^8.0.0",
46
+ "open": "^11.0.0",
47
+ "zod": "^4.4.3",
48
+ "sql.js": "^1.14.1"
49
+ },
50
+ "devDependencies": {
51
+ "typescript": "~5.7.0",
52
+ "tsx": "^4.0.0",
53
+ "vitest": "^3.0.0",
54
+ "eslint": "^9.0.0",
55
+ "@types/node": "^20.0.0",
56
+ "@types/sql.js": "^1.4.11"
57
+ }
58
+ }