Skip to content

Commit 7dfb42d

Browse files
authored
refactor: standardize agent inbox config loading (#33)
* refactor: standardize agent inbox config loading * refactor: reuse loaded relay config
1 parent 47c0d2d commit 7dfb42d

43 files changed

Lines changed: 1625 additions & 788 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 0 additions & 20 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ dist/
55
data/
66
.agent-inbox/
77
.worktrees/
8-
.DS_Store
8+
.DS_Store

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ A Discord bot that lets users interact with Codex directly in Discord threads.
2828
3. Tool usage (file reads, edits, bash commands) shown as formatted blocks
2929
4. Support `/ask` for quick questions without file system tools
3030
5. Error handling: timeouts, rate limits, graceful shutdown
31-
6. Use environment variables for all secrets (dotenv)
31+
6. Store secrets and runtime config in `~/.agent-inbox/config.jsonl`
3232

3333
## Code Style
3434
- ESM modules
@@ -41,5 +41,5 @@ A Discord bot that lets users interact with Codex directly in Discord threads.
4141
## Setup
4242
- pnpm init, install deps
4343
- tsconfig.json with strict mode, ESM
44-
- .env.example with required vars
45-
- .gitignore for node_modules, .env, dist
44+
- `~/.agent-inbox/config.jsonl` with required records
45+
- .gitignore for node_modules, dist

CLAUDE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ A Discord bot that lets users interact with Claude Code directly in Discord thre
2828
3. Tool usage (file reads, edits, bash commands) shown as formatted blocks
2929
4. Support `/ask` for quick questions without file system tools
3030
5. Error handling: timeouts, rate limits, graceful shutdown
31-
6. Use environment variables for all secrets (dotenv)
31+
6. Store secrets and runtime config in `~/.agent-inbox/config.jsonl`
3232

3333
## Code Style
3434
- ESM modules
@@ -41,5 +41,5 @@ A Discord bot that lets users interact with Claude Code directly in Discord thre
4141
## Setup
4242
- pnpm init, install deps
4343
- tsconfig.json with strict mode, ESM
44-
- .env.example with required vars
45-
- .gitignore for node_modules, .env, dist
44+
- `~/.agent-inbox/config.jsonl` with required records
45+
- .gitignore for node_modules, dist

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ Configuration is stored in `~/.agent-inbox/config.jsonl`. Example:
4141
{"type":"meta","version":1}
4242
{"type":"im","id":"discord","enabled":true,"config":{"token":"your-bot-token","clientId":"your-client-id"}}
4343
{"type":"im","id":"feishu","enabled":false,"config":{"appId":"","appSecret":""}}
44-
{"type":"runtime","config":{"agentTimeoutMs":600000}}
44+
{"type":"im","id":"slack","enabled":false,"config":{"botToken":"","appToken":"","signingSecret":"","socketMode":true}}
45+
{"type":"runtime","config":{"agentTimeoutMs":600000,"claudeBin":"claude","codexBin":"codex","opencodeBin":"opencode"}}
4546
```
4647

48+
Standalone adapter runs use the same `~/.agent-inbox/config.jsonl` file. There is no repo-local `.env` bootstrap path.
49+
4750
### Step 3: Start
4851

4952
```bash
@@ -139,9 +142,10 @@ pnpm start
139142
# Development mode (run adapters independently)
140143
pnpm dev:discord
141144
pnpm dev:feishu
145+
pnpm dev:slack
142146
```
143147

144-
Use the repo root `.env` file for local environment variables during development. See `.env.example` for reference.
148+
All adapter development commands load configuration from `~/.agent-inbox/config.jsonl`.
145149

146150
### Build Outputs
147151

apps/agent-inbox/src/__tests__/config.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ describe('app config', () => {
77
const parsed = parseConfigJsonl([
88
'{"type":"meta","version":1}',
99
'{"type":"im","id":"discord","enabled":true,"note":"discord","config":{"token":"abc","clientId":"123"}}',
10+
'{"type":"im","id":"slack","enabled":true,"config":{"botToken":"xoxb","appToken":"xapp","signingSecret":"secret"}}',
1011
'{"type":"im","id":"feishu","enabled":true,"config":{"appId":"app-1"}}',
1112
'{"type":"runtime","config":{"agentTimeoutMs":1200}}',
1213
].join('\n'));
1314

14-
expect(parsed.availableIms).toHaveLength(1);
15+
expect(parsed.availableIms).toHaveLength(2);
1516
expect(parsed.availableIms[0]?.id).toBe('discord');
17+
expect(parsed.availableIms[1]?.id).toBe('slack');
1618
expect(parsed.runtime.agentTimeoutMs).toBe(1200);
1719
});
1820

@@ -30,14 +32,24 @@ describe('app config', () => {
3032
it('ignores invalid last used platform preference values', () => {
3133
const parsed = parseConfigJsonl([
3234
'{"type":"meta","version":1}',
33-
'{"type":"local-preferences","lastUsedPlatform":"slack"}',
35+
'{"type":"local-preferences","lastUsedPlatform":"teams"}',
3436
'{"type":"im","id":"discord","enabled":true,"config":{"token":"abc","clientId":"123"}}',
3537
].join('\n'));
3638

3739
expect((parsed as { lastUsedPlatform?: string }).lastUsedPlatform).toBeUndefined();
3840
expect(parsed.errors).toHaveLength(0);
3941
});
4042

43+
it('accepts Slack as a valid last used platform', () => {
44+
const parsed = parseConfigJsonl([
45+
'{"type":"meta","version":1}',
46+
'{"type":"local-preferences","lastUsedPlatform":"slack"}',
47+
'{"type":"im","id":"slack","enabled":true,"config":{"botToken":"xoxb","appToken":"xapp","signingSecret":"secret"}}',
48+
].join('\n'));
49+
50+
expect((parsed as { lastUsedPlatform?: string }).lastUsedPlatform).toBe('slack');
51+
});
52+
4153
it('reports malformed lines without crashing the whole file', () => {
4254
const parsed = parseConfigJsonl('{"type":"meta","version":1}\nnope');
4355

apps/agent-inbox/src/__tests__/runtime.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,31 @@ describe('runtime dispatch', () => {
2727
expect(process.env['DISCORD_TOKEN']).toBe('discord-token');
2828
expect(process.env['AGENT_TIMEOUT_MS']).toBe('1234');
2929
});
30+
31+
it('dispatches to the Slack runtime and applies Slack env vars', async () => {
32+
const startSlackRuntime = vi.fn(async () => {});
33+
const selectedIm: AvailableIm = {
34+
id: 'slack',
35+
config: {
36+
botToken: 'xoxb-test-token',
37+
appToken: 'xapp-test-token',
38+
signingSecret: 'test-signing-secret',
39+
socketMode: false,
40+
},
41+
};
42+
43+
await startSelectedIm(
44+
selectedIm,
45+
{ agentTimeoutMs: 4321 },
46+
resolveRelayPaths('/tmp/runtime-dispatch-slack'),
47+
{
48+
slack: async () => ({ startSlackRuntime }),
49+
},
50+
);
51+
52+
expect(startSlackRuntime).toHaveBeenCalledOnce();
53+
expect(process.env['SLACK_BOT_TOKEN']).toBe('xoxb-test-token');
54+
expect(process.env['SLACK_SOCKET_MODE']).toBe('false');
55+
expect(process.env['AGENT_TIMEOUT_MS']).toBe('4321');
56+
});
3057
});

apps/agent-inbox/src/__tests__/setup.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,28 @@ describe('setup flow', () => {
123123
expect.objectContaining({ message: 'Encrypt key (optional)' }),
124124
);
125125
});
126+
127+
it('writes a slack IM record through the interactive setup flow', async () => {
128+
const tempHome = await mkdtemp(join('/tmp', 'agent-inbox-setup-'));
129+
const paths = resolveRelayPaths(tempHome);
130+
131+
(prompts as any).__setResponses([
132+
'slack',
133+
'xoxb-test-token',
134+
'xapp-test-token',
135+
'test-signing-secret',
136+
true,
137+
]);
138+
139+
const loaded = await runSetup(paths, ['discord', 'feishu', 'slack']);
140+
141+
expect(loaded.availableIms).toEqual(
142+
expect.arrayContaining([
143+
expect.objectContaining({ id: 'slack' }),
144+
]),
145+
);
146+
147+
const saved = await readFile(paths.configFile, 'utf-8');
148+
expect(saved).toContain('"id":"slack"');
149+
});
126150
});

0 commit comments

Comments
 (0)