oh-my-codex 0.3.8 → 0.3.10
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/dist/cli/__tests__/doctor-team.test.js +58 -0
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +3 -3
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +2 -0
- package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +1 -0
- package/dist/cli/__tests__/lifecycle-notifications.test.js +48 -0
- package/dist/cli/__tests__/lifecycle-notifications.test.js.map +1 -0
- package/dist/cli/doctor.js +28 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +41 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config/__tests__/models.test.d.ts +2 -0
- package/dist/config/__tests__/models.test.d.ts.map +1 -0
- package/dist/config/__tests__/models.test.js +69 -0
- package/dist/config/__tests__/models.test.js.map +1 -0
- package/dist/config/models.d.ts +24 -0
- package/dist/config/models.d.ts.map +1 -0
- package/dist/config/models.js +53 -0
- package/dist/config/models.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +221 -36
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +21 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server-team-tools.test.js +53 -1
- package/dist/mcp/__tests__/state-server-team-tools.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +1 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +34 -1
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +46 -11
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/notifications/__tests__/config.test.d.ts +2 -0
- package/dist/notifications/__tests__/config.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/config.test.js +186 -0
- package/dist/notifications/__tests__/config.test.js.map +1 -0
- package/dist/notifications/__tests__/dispatcher.test.d.ts +2 -0
- package/dist/notifications/__tests__/dispatcher.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/dispatcher.test.js +202 -0
- package/dist/notifications/__tests__/dispatcher.test.js.map +1 -0
- package/dist/notifications/__tests__/formatter.test.d.ts +2 -0
- package/dist/notifications/__tests__/formatter.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/formatter.test.js +103 -0
- package/dist/notifications/__tests__/formatter.test.js.map +1 -0
- package/dist/notifications/__tests__/notifier.test.d.ts +2 -0
- package/dist/notifications/__tests__/notifier.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/notifier.test.js +104 -0
- package/dist/notifications/__tests__/notifier.test.js.map +1 -0
- package/dist/notifications/__tests__/profiles.test.d.ts +2 -0
- package/dist/notifications/__tests__/profiles.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/profiles.test.js +404 -0
- package/dist/notifications/__tests__/profiles.test.js.map +1 -0
- package/dist/notifications/__tests__/reply-listener.test.d.ts +2 -0
- package/dist/notifications/__tests__/reply-listener.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/reply-listener.test.js +58 -0
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -0
- package/dist/notifications/__tests__/session-registry.test.d.ts +2 -0
- package/dist/notifications/__tests__/session-registry.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/session-registry.test.js +147 -0
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -0
- package/dist/notifications/__tests__/tmux-detector.test.d.ts +2 -0
- package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/tmux-detector.test.js +77 -0
- package/dist/notifications/__tests__/tmux-detector.test.js.map +1 -0
- package/dist/notifications/__tests__/tmux.test.d.ts +2 -0
- package/dist/notifications/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/tmux.test.js +86 -0
- package/dist/notifications/__tests__/tmux.test.js.map +1 -0
- package/dist/notifications/config.d.ts +44 -0
- package/dist/notifications/config.d.ts.map +1 -0
- package/dist/notifications/config.js +407 -0
- package/dist/notifications/config.js.map +1 -0
- package/dist/notifications/dispatcher.d.ts +15 -0
- package/dist/notifications/dispatcher.d.ts.map +1 -0
- package/dist/notifications/dispatcher.js +410 -0
- package/dist/notifications/dispatcher.js.map +1 -0
- package/dist/notifications/formatter.d.ts +14 -0
- package/dist/notifications/formatter.d.ts.map +1 -0
- package/dist/notifications/formatter.js +134 -0
- package/dist/notifications/formatter.js.map +1 -0
- package/dist/notifications/index.d.ts +32 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +93 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/reply-listener.d.ts +47 -0
- package/dist/notifications/reply-listener.d.ts.map +1 -0
- package/dist/notifications/reply-listener.js +656 -0
- package/dist/notifications/reply-listener.js.map +1 -0
- package/dist/notifications/session-registry.d.ts +26 -0
- package/dist/notifications/session-registry.d.ts.map +1 -0
- package/dist/notifications/session-registry.js +275 -0
- package/dist/notifications/session-registry.js.map +1 -0
- package/dist/notifications/tmux-detector.d.ts +17 -0
- package/dist/notifications/tmux-detector.d.ts.map +1 -0
- package/dist/notifications/tmux-detector.js +77 -0
- package/dist/notifications/tmux-detector.js.map +1 -0
- package/dist/notifications/tmux.d.ts +28 -0
- package/dist/notifications/tmux.d.ts.map +1 -0
- package/dist/notifications/tmux.js +203 -0
- package/dist/notifications/tmux.js.map +1 -0
- package/dist/notifications/types.d.ts +181 -0
- package/dist/notifications/types.d.ts.map +1 -0
- package/dist/notifications/types.js +9 -0
- package/dist/notifications/types.js.map +1 -0
- package/dist/team/__tests__/runtime.test.js +54 -2
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +30 -0
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +59 -1
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/runtime.d.ts +2 -2
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +50 -23
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/state.d.ts +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +5 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +53 -10
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +12 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +37 -0
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/package.json +1 -1
- package/prompts/planner.md +3 -3
- package/scripts/notify-hook.js +137 -7
- package/skills/team/SKILL.md +3 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
/**
|
|
4
|
+
* Notification Profiles Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests named notification profiles: resolution priority, default fallback,
|
|
7
|
+
* env var selection, backward compatibility with flat config, and edge cases.
|
|
8
|
+
*
|
|
9
|
+
* Config is read from disk via readRawConfig(), so we mock the fs module
|
|
10
|
+
* to inject test configs without touching the filesystem.
|
|
11
|
+
*/
|
|
12
|
+
// We need to mock fs before importing config, so we use dynamic imports
|
|
13
|
+
// after setting up mocks per test.
|
|
14
|
+
const PROFILE_ENV_KEY = "OMX_NOTIFY_PROFILE";
|
|
15
|
+
function clearProfileEnv() {
|
|
16
|
+
delete process.env[PROFILE_ENV_KEY];
|
|
17
|
+
delete process.env.OMX_DISCORD_NOTIFIER_BOT_TOKEN;
|
|
18
|
+
delete process.env.OMX_DISCORD_NOTIFIER_CHANNEL;
|
|
19
|
+
delete process.env.OMX_DISCORD_WEBHOOK_URL;
|
|
20
|
+
delete process.env.OMX_DISCORD_MENTION;
|
|
21
|
+
delete process.env.OMX_TELEGRAM_BOT_TOKEN;
|
|
22
|
+
delete process.env.OMX_TELEGRAM_CHAT_ID;
|
|
23
|
+
delete process.env.OMX_SLACK_WEBHOOK_URL;
|
|
24
|
+
}
|
|
25
|
+
// ---------- resolveProfileConfig (pure function, no fs needed) ----------
|
|
26
|
+
describe("resolveProfileConfig", () => {
|
|
27
|
+
let resolveProfileConfig;
|
|
28
|
+
beforeEach(async () => {
|
|
29
|
+
clearProfileEnv();
|
|
30
|
+
const mod = await import("../config.js");
|
|
31
|
+
resolveProfileConfig = mod.resolveProfileConfig;
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
clearProfileEnv();
|
|
35
|
+
});
|
|
36
|
+
it("returns null when no profiles defined", () => {
|
|
37
|
+
const result = resolveProfileConfig({
|
|
38
|
+
enabled: true,
|
|
39
|
+
telegram: { enabled: true, botToken: "t", chatId: "c" },
|
|
40
|
+
});
|
|
41
|
+
assert.equal(result, null);
|
|
42
|
+
});
|
|
43
|
+
it("returns null when profiles object is empty", () => {
|
|
44
|
+
const result = resolveProfileConfig({
|
|
45
|
+
enabled: true,
|
|
46
|
+
profiles: {},
|
|
47
|
+
});
|
|
48
|
+
assert.equal(result, null);
|
|
49
|
+
});
|
|
50
|
+
it("resolves explicit profileName argument", () => {
|
|
51
|
+
const workProfile = {
|
|
52
|
+
enabled: true,
|
|
53
|
+
telegram: { enabled: true, botToken: "work-token", chatId: "work-chat" },
|
|
54
|
+
};
|
|
55
|
+
const result = resolveProfileConfig({
|
|
56
|
+
enabled: true,
|
|
57
|
+
profiles: {
|
|
58
|
+
work: workProfile,
|
|
59
|
+
personal: {
|
|
60
|
+
enabled: true,
|
|
61
|
+
telegram: {
|
|
62
|
+
enabled: true,
|
|
63
|
+
botToken: "personal-token",
|
|
64
|
+
chatId: "personal-chat",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
}, "work");
|
|
69
|
+
assert.deepEqual(result, workProfile);
|
|
70
|
+
});
|
|
71
|
+
it("resolves OMX_NOTIFY_PROFILE env var when no explicit name", () => {
|
|
72
|
+
process.env[PROFILE_ENV_KEY] = "personal";
|
|
73
|
+
const personalProfile = {
|
|
74
|
+
enabled: true,
|
|
75
|
+
telegram: {
|
|
76
|
+
enabled: true,
|
|
77
|
+
botToken: "personal-token",
|
|
78
|
+
chatId: "personal-chat",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const result = resolveProfileConfig({
|
|
82
|
+
enabled: true,
|
|
83
|
+
profiles: {
|
|
84
|
+
work: { enabled: true },
|
|
85
|
+
personal: personalProfile,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
assert.deepEqual(result, personalProfile);
|
|
89
|
+
});
|
|
90
|
+
it("explicit profileName takes priority over env var", () => {
|
|
91
|
+
process.env[PROFILE_ENV_KEY] = "personal";
|
|
92
|
+
const workProfile = {
|
|
93
|
+
enabled: true,
|
|
94
|
+
"discord-bot": {
|
|
95
|
+
enabled: true,
|
|
96
|
+
botToken: "bot-t",
|
|
97
|
+
channelId: "ch-1",
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const result = resolveProfileConfig({
|
|
101
|
+
enabled: true,
|
|
102
|
+
profiles: {
|
|
103
|
+
work: workProfile,
|
|
104
|
+
personal: { enabled: true },
|
|
105
|
+
},
|
|
106
|
+
}, "work");
|
|
107
|
+
assert.deepEqual(result, workProfile);
|
|
108
|
+
});
|
|
109
|
+
it("falls back to defaultProfile when no explicit name or env var", () => {
|
|
110
|
+
const defaultProfile = {
|
|
111
|
+
enabled: true,
|
|
112
|
+
slack: {
|
|
113
|
+
enabled: true,
|
|
114
|
+
webhookUrl: "https://hooks.slack.com/services/default",
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
const result = resolveProfileConfig({
|
|
118
|
+
enabled: true,
|
|
119
|
+
defaultProfile: "main",
|
|
120
|
+
profiles: {
|
|
121
|
+
main: defaultProfile,
|
|
122
|
+
secondary: { enabled: true },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
assert.deepEqual(result, defaultProfile);
|
|
126
|
+
});
|
|
127
|
+
it("returns null when selected profile name does not exist", () => {
|
|
128
|
+
const result = resolveProfileConfig({
|
|
129
|
+
enabled: true,
|
|
130
|
+
profiles: {
|
|
131
|
+
work: { enabled: true },
|
|
132
|
+
},
|
|
133
|
+
}, "nonexistent");
|
|
134
|
+
assert.equal(result, null);
|
|
135
|
+
});
|
|
136
|
+
it("returns null when no profile selected and no defaultProfile", () => {
|
|
137
|
+
const result = resolveProfileConfig({
|
|
138
|
+
enabled: true,
|
|
139
|
+
profiles: {
|
|
140
|
+
work: { enabled: true },
|
|
141
|
+
personal: { enabled: true },
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
assert.equal(result, null);
|
|
145
|
+
});
|
|
146
|
+
it("profile with enabled=false is returned as-is", () => {
|
|
147
|
+
const silentProfile = { enabled: false };
|
|
148
|
+
const result = resolveProfileConfig({
|
|
149
|
+
enabled: true,
|
|
150
|
+
profiles: {
|
|
151
|
+
silent: silentProfile,
|
|
152
|
+
loud: { enabled: true },
|
|
153
|
+
},
|
|
154
|
+
}, "silent");
|
|
155
|
+
assert.deepEqual(result, silentProfile);
|
|
156
|
+
});
|
|
157
|
+
it("profile with per-event config is preserved", () => {
|
|
158
|
+
const profile = {
|
|
159
|
+
enabled: true,
|
|
160
|
+
telegram: { enabled: true, botToken: "t", chatId: "c" },
|
|
161
|
+
events: {
|
|
162
|
+
"session-end": {
|
|
163
|
+
enabled: true,
|
|
164
|
+
messageTemplate: "Done: {{summary}}",
|
|
165
|
+
},
|
|
166
|
+
"session-start": { enabled: false },
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const result = resolveProfileConfig({
|
|
170
|
+
enabled: true,
|
|
171
|
+
profiles: { custom: profile },
|
|
172
|
+
}, "custom");
|
|
173
|
+
assert.deepEqual(result.events, profile.events);
|
|
174
|
+
});
|
|
175
|
+
it("priority order: explicit > env > defaultProfile", () => {
|
|
176
|
+
process.env[PROFILE_ENV_KEY] = "env-profile";
|
|
177
|
+
const config = {
|
|
178
|
+
enabled: true,
|
|
179
|
+
defaultProfile: "default-profile",
|
|
180
|
+
profiles: {
|
|
181
|
+
"explicit-profile": {
|
|
182
|
+
enabled: true,
|
|
183
|
+
telegram: { enabled: true, botToken: "explicit", chatId: "e" },
|
|
184
|
+
},
|
|
185
|
+
"env-profile": {
|
|
186
|
+
enabled: true,
|
|
187
|
+
telegram: { enabled: true, botToken: "env", chatId: "e" },
|
|
188
|
+
},
|
|
189
|
+
"default-profile": {
|
|
190
|
+
enabled: true,
|
|
191
|
+
telegram: { enabled: true, botToken: "default", chatId: "d" },
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
// Explicit wins over env and default
|
|
196
|
+
const r1 = resolveProfileConfig(config, "explicit-profile");
|
|
197
|
+
assert.equal(r1.telegram.botToken, "explicit");
|
|
198
|
+
// Env wins over default when no explicit
|
|
199
|
+
const r2 = resolveProfileConfig(config);
|
|
200
|
+
assert.equal(r2.telegram.botToken, "env");
|
|
201
|
+
// Default used when no explicit and no env
|
|
202
|
+
delete process.env[PROFILE_ENV_KEY];
|
|
203
|
+
const r3 = resolveProfileConfig(config);
|
|
204
|
+
assert.equal(r3.telegram.botToken, "default");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ---------- getNotificationConfig with profiles ----------
|
|
208
|
+
describe("getNotificationConfig with profiles", () => {
|
|
209
|
+
// We test through the public API by manipulating env vars
|
|
210
|
+
// and relying on the fact that env-only config doesn't use profiles.
|
|
211
|
+
// For file-based tests we need to test resolveProfileConfig integration.
|
|
212
|
+
beforeEach(() => {
|
|
213
|
+
clearProfileEnv();
|
|
214
|
+
});
|
|
215
|
+
afterEach(() => {
|
|
216
|
+
clearProfileEnv();
|
|
217
|
+
});
|
|
218
|
+
it("env-only config still works without profiles", async () => {
|
|
219
|
+
process.env.OMX_TELEGRAM_BOT_TOKEN = "123:abc";
|
|
220
|
+
process.env.OMX_TELEGRAM_CHAT_ID = "999";
|
|
221
|
+
const { getNotificationConfig } = await import("../config.js");
|
|
222
|
+
const config = getNotificationConfig();
|
|
223
|
+
assert.ok(config);
|
|
224
|
+
assert.equal(config.enabled, true);
|
|
225
|
+
assert.equal(config.telegram.botToken, "123:abc");
|
|
226
|
+
});
|
|
227
|
+
it("getNotificationConfig passes profileName to resolver", async () => {
|
|
228
|
+
// When no file config exists and only env, profileName is a no-op
|
|
229
|
+
// but should not break anything
|
|
230
|
+
process.env.OMX_TELEGRAM_BOT_TOKEN = "123:abc";
|
|
231
|
+
process.env.OMX_TELEGRAM_CHAT_ID = "999";
|
|
232
|
+
const { getNotificationConfig } = await import("../config.js");
|
|
233
|
+
const config = getNotificationConfig("nonexistent");
|
|
234
|
+
assert.ok(config);
|
|
235
|
+
assert.equal(config.telegram.botToken, "123:abc");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
// ---------- listProfiles / getActiveProfileName ----------
|
|
239
|
+
describe("listProfiles", () => {
|
|
240
|
+
beforeEach(() => {
|
|
241
|
+
clearProfileEnv();
|
|
242
|
+
});
|
|
243
|
+
afterEach(() => {
|
|
244
|
+
clearProfileEnv();
|
|
245
|
+
});
|
|
246
|
+
it("returns empty array when no config file", async () => {
|
|
247
|
+
const { listProfiles } = await import("../config.js");
|
|
248
|
+
// Without a config file, should return empty
|
|
249
|
+
const profiles = listProfiles();
|
|
250
|
+
assert.ok(Array.isArray(profiles));
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
describe("getActiveProfileName", () => {
|
|
254
|
+
beforeEach(() => {
|
|
255
|
+
clearProfileEnv();
|
|
256
|
+
});
|
|
257
|
+
afterEach(() => {
|
|
258
|
+
clearProfileEnv();
|
|
259
|
+
});
|
|
260
|
+
it("returns env var value when OMX_NOTIFY_PROFILE is set", async () => {
|
|
261
|
+
process.env[PROFILE_ENV_KEY] = "my-profile";
|
|
262
|
+
const { getActiveProfileName } = await import("../config.js");
|
|
263
|
+
const name = getActiveProfileName();
|
|
264
|
+
assert.equal(name, "my-profile");
|
|
265
|
+
});
|
|
266
|
+
it("returns null when no env var and no config file", async () => {
|
|
267
|
+
const { getActiveProfileName } = await import("../config.js");
|
|
268
|
+
const name = getActiveProfileName();
|
|
269
|
+
// Without a config file with profiles, should be null
|
|
270
|
+
assert.ok(name === null || typeof name === "string");
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
// ---------- NotificationsBlock type compatibility ----------
|
|
274
|
+
describe("NotificationsBlock type compatibility", () => {
|
|
275
|
+
it("flat config (no profiles) is assignable to NotificationsBlock", async () => {
|
|
276
|
+
const { resolveProfileConfig } = await import("../config.js");
|
|
277
|
+
// A flat config with no profiles should work with resolveProfileConfig
|
|
278
|
+
const flat = {
|
|
279
|
+
enabled: true,
|
|
280
|
+
discord: {
|
|
281
|
+
enabled: true,
|
|
282
|
+
webhookUrl: "https://discord.com/api/webhooks/test",
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
const result = resolveProfileConfig(flat);
|
|
286
|
+
assert.equal(result, null); // no profiles = null, use flat
|
|
287
|
+
});
|
|
288
|
+
it("profiled config works with resolveProfileConfig", async () => {
|
|
289
|
+
const { resolveProfileConfig } = await import("../config.js");
|
|
290
|
+
const profiled = {
|
|
291
|
+
enabled: true,
|
|
292
|
+
defaultProfile: "work",
|
|
293
|
+
profiles: {
|
|
294
|
+
work: {
|
|
295
|
+
enabled: true,
|
|
296
|
+
discord: {
|
|
297
|
+
enabled: true,
|
|
298
|
+
webhookUrl: "https://discord.com/api/webhooks/work",
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
personal: {
|
|
302
|
+
enabled: true,
|
|
303
|
+
telegram: {
|
|
304
|
+
enabled: true,
|
|
305
|
+
botToken: "123:abc",
|
|
306
|
+
chatId: "456",
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
const result = resolveProfileConfig(profiled);
|
|
312
|
+
assert.ok(result);
|
|
313
|
+
assert.equal(result.discord.webhookUrl, "https://discord.com/api/webhooks/work");
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
// ---------- Edge cases ----------
|
|
317
|
+
describe("profile edge cases", () => {
|
|
318
|
+
beforeEach(() => {
|
|
319
|
+
clearProfileEnv();
|
|
320
|
+
});
|
|
321
|
+
afterEach(() => {
|
|
322
|
+
clearProfileEnv();
|
|
323
|
+
});
|
|
324
|
+
it("profile can have multiple platforms configured", async () => {
|
|
325
|
+
const { resolveProfileConfig } = await import("../config.js");
|
|
326
|
+
const profile = {
|
|
327
|
+
enabled: true,
|
|
328
|
+
discord: {
|
|
329
|
+
enabled: true,
|
|
330
|
+
webhookUrl: "https://discord.com/api/webhooks/multi",
|
|
331
|
+
},
|
|
332
|
+
telegram: { enabled: true, botToken: "t", chatId: "c" },
|
|
333
|
+
slack: {
|
|
334
|
+
enabled: true,
|
|
335
|
+
webhookUrl: "https://hooks.slack.com/services/multi",
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
const result = resolveProfileConfig({
|
|
339
|
+
enabled: true,
|
|
340
|
+
profiles: { multi: profile },
|
|
341
|
+
}, "multi");
|
|
342
|
+
assert.ok(result.discord);
|
|
343
|
+
assert.ok(result.telegram);
|
|
344
|
+
assert.ok(result.slack);
|
|
345
|
+
});
|
|
346
|
+
it("env vars merge into selected profile config", async () => {
|
|
347
|
+
process.env.OMX_TELEGRAM_BOT_TOKEN = "env-token";
|
|
348
|
+
process.env.OMX_TELEGRAM_CHAT_ID = "env-chat";
|
|
349
|
+
const { buildConfigFromEnv, resolveProfileConfig } = await import("../config.js");
|
|
350
|
+
// Simulate what getNotificationConfig does: resolve profile, then merge env
|
|
351
|
+
const profile = {
|
|
352
|
+
enabled: true,
|
|
353
|
+
discord: {
|
|
354
|
+
enabled: true,
|
|
355
|
+
webhookUrl: "https://discord.com/api/webhooks/test",
|
|
356
|
+
},
|
|
357
|
+
};
|
|
358
|
+
const resolved = resolveProfileConfig({ enabled: true, profiles: { work: profile } }, "work");
|
|
359
|
+
assert.ok(resolved);
|
|
360
|
+
assert.equal(resolved.discord.enabled, true);
|
|
361
|
+
// Env config should be buildable separately
|
|
362
|
+
const envConfig = buildConfigFromEnv();
|
|
363
|
+
assert.ok(envConfig);
|
|
364
|
+
assert.equal(envConfig.telegram.botToken, "env-token");
|
|
365
|
+
});
|
|
366
|
+
it("profile names are case-sensitive", async () => {
|
|
367
|
+
const { resolveProfileConfig } = await import("../config.js");
|
|
368
|
+
const config = {
|
|
369
|
+
enabled: true,
|
|
370
|
+
profiles: {
|
|
371
|
+
Work: { enabled: true },
|
|
372
|
+
work: {
|
|
373
|
+
enabled: true,
|
|
374
|
+
telegram: { enabled: true, botToken: "lower", chatId: "c" },
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
const upper = resolveProfileConfig(config, "Work");
|
|
379
|
+
const lower = resolveProfileConfig(config, "work");
|
|
380
|
+
assert.ok(upper);
|
|
381
|
+
assert.ok(lower);
|
|
382
|
+
assert.equal(upper.telegram, undefined);
|
|
383
|
+
assert.equal(lower.telegram.botToken, "lower");
|
|
384
|
+
});
|
|
385
|
+
it("profile names can contain hyphens and dots", async () => {
|
|
386
|
+
const { resolveProfileConfig } = await import("../config.js");
|
|
387
|
+
const config = {
|
|
388
|
+
enabled: true,
|
|
389
|
+
profiles: {
|
|
390
|
+
"my-work.profile": {
|
|
391
|
+
enabled: true,
|
|
392
|
+
slack: {
|
|
393
|
+
enabled: true,
|
|
394
|
+
webhookUrl: "https://hooks.slack.com/services/hp",
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
const result = resolveProfileConfig(config, "my-work.profile");
|
|
400
|
+
assert.ok(result);
|
|
401
|
+
assert.ok(result.slack);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
//# sourceMappingURL=profiles.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.test.js","sourceRoot":"","sources":["../../../src/notifications/__tests__/profiles.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-listener.test.d.ts","sourceRoot":"","sources":["../../../src/notifications/__tests__/reply-listener.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { sanitizeReplyInput } from '../reply-listener.js';
|
|
4
|
+
describe('sanitizeReplyInput', () => {
|
|
5
|
+
it('passes through normal text', () => {
|
|
6
|
+
assert.equal(sanitizeReplyInput('hello world'), 'hello world');
|
|
7
|
+
});
|
|
8
|
+
it('strips control characters', () => {
|
|
9
|
+
assert.equal(sanitizeReplyInput('hello\x00world'), 'helloworld');
|
|
10
|
+
assert.equal(sanitizeReplyInput('test\x07bell'), 'testbell');
|
|
11
|
+
assert.equal(sanitizeReplyInput('test\x1bescseq'), 'testescseq');
|
|
12
|
+
});
|
|
13
|
+
it('replaces newlines with spaces', () => {
|
|
14
|
+
assert.equal(sanitizeReplyInput('line1\nline2'), 'line1 line2');
|
|
15
|
+
assert.equal(sanitizeReplyInput('line1\r\nline2'), 'line1 line2');
|
|
16
|
+
});
|
|
17
|
+
it('escapes backslashes', () => {
|
|
18
|
+
assert.equal(sanitizeReplyInput('path\\to\\file'), 'path\\\\to\\\\file');
|
|
19
|
+
});
|
|
20
|
+
it('escapes backticks', () => {
|
|
21
|
+
assert.equal(sanitizeReplyInput('run `cmd`'), 'run \\`cmd\\`');
|
|
22
|
+
});
|
|
23
|
+
it('escapes $( command substitution', () => {
|
|
24
|
+
assert.equal(sanitizeReplyInput('$(whoami)'), '\\$(whoami)');
|
|
25
|
+
});
|
|
26
|
+
it('escapes ${ variable expansion', () => {
|
|
27
|
+
assert.equal(sanitizeReplyInput('${HOME}'), '\\${HOME}');
|
|
28
|
+
});
|
|
29
|
+
it('trims whitespace', () => {
|
|
30
|
+
assert.equal(sanitizeReplyInput(' hello '), 'hello');
|
|
31
|
+
});
|
|
32
|
+
it('handles empty string', () => {
|
|
33
|
+
assert.equal(sanitizeReplyInput(''), '');
|
|
34
|
+
});
|
|
35
|
+
it('handles whitespace-only string', () => {
|
|
36
|
+
assert.equal(sanitizeReplyInput(' '), '');
|
|
37
|
+
});
|
|
38
|
+
it('handles combined dangerous patterns', () => {
|
|
39
|
+
const input = '$(rm -rf /) && `evil` ${PATH}\nmore';
|
|
40
|
+
const result = sanitizeReplyInput(input);
|
|
41
|
+
// Should not contain unescaped backticks or newlines
|
|
42
|
+
assert.ok(!result.includes('\n'));
|
|
43
|
+
// $( should be escaped to \$(
|
|
44
|
+
assert.ok(result.includes('\\$('));
|
|
45
|
+
// ${ should be escaped to \${
|
|
46
|
+
assert.ok(result.includes('\\${'));
|
|
47
|
+
// backticks should be escaped
|
|
48
|
+
assert.ok(result.includes('\\`'));
|
|
49
|
+
});
|
|
50
|
+
it('preserves normal special characters', () => {
|
|
51
|
+
assert.equal(sanitizeReplyInput('hello! @user #tag'), 'hello! @user #tag');
|
|
52
|
+
});
|
|
53
|
+
it('handles unicode text', () => {
|
|
54
|
+
const result = sanitizeReplyInput('Hello world');
|
|
55
|
+
assert.ok(result.length > 0);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=reply-listener.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-listener.test.js","sourceRoot":"","sources":["../../../src/notifications/__tests__/reply-listener.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-registry.test.d.ts","sourceRoot":"","sources":["../../../src/notifications/__tests__/session-registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
// The session-registry module uses hardcoded paths under ~/.omx/state/.
|
|
5
|
+
// We test the data shapes and logic patterns rather than filesystem integration
|
|
6
|
+
// to avoid polluting the real state directory.
|
|
7
|
+
function createMockMapping(overrides) {
|
|
8
|
+
return {
|
|
9
|
+
platform: 'discord-bot',
|
|
10
|
+
messageId: randomUUID(),
|
|
11
|
+
sessionId: randomUUID(),
|
|
12
|
+
tmuxPaneId: '%0',
|
|
13
|
+
tmuxSessionName: 'test-session',
|
|
14
|
+
event: 'session-idle',
|
|
15
|
+
createdAt: new Date().toISOString(),
|
|
16
|
+
projectPath: '/tmp/test',
|
|
17
|
+
...overrides,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
describe('SessionMapping shape', () => {
|
|
21
|
+
it('creates valid mapping with all required fields', () => {
|
|
22
|
+
const mapping = createMockMapping();
|
|
23
|
+
assert.ok(mapping.platform);
|
|
24
|
+
assert.ok(mapping.messageId);
|
|
25
|
+
assert.ok(mapping.sessionId);
|
|
26
|
+
assert.ok(mapping.tmuxPaneId);
|
|
27
|
+
assert.ok(mapping.tmuxSessionName !== undefined);
|
|
28
|
+
assert.ok(mapping.event);
|
|
29
|
+
assert.ok(mapping.createdAt);
|
|
30
|
+
});
|
|
31
|
+
it('supports discord-bot platform', () => {
|
|
32
|
+
const mapping = createMockMapping({ platform: 'discord-bot' });
|
|
33
|
+
assert.equal(mapping.platform, 'discord-bot');
|
|
34
|
+
});
|
|
35
|
+
it('supports telegram platform', () => {
|
|
36
|
+
const mapping = createMockMapping({ platform: 'telegram' });
|
|
37
|
+
assert.equal(mapping.platform, 'telegram');
|
|
38
|
+
});
|
|
39
|
+
it('serializes to valid JSON', () => {
|
|
40
|
+
const mapping = createMockMapping();
|
|
41
|
+
const json = JSON.stringify(mapping);
|
|
42
|
+
const parsed = JSON.parse(json);
|
|
43
|
+
assert.equal(parsed.platform, mapping.platform);
|
|
44
|
+
assert.equal(parsed.messageId, mapping.messageId);
|
|
45
|
+
assert.equal(parsed.sessionId, mapping.sessionId);
|
|
46
|
+
});
|
|
47
|
+
it('supports optional projectPath', () => {
|
|
48
|
+
const withPath = createMockMapping({ projectPath: '/test/path' });
|
|
49
|
+
assert.equal(withPath.projectPath, '/test/path');
|
|
50
|
+
const withoutPath = createMockMapping();
|
|
51
|
+
delete withoutPath.projectPath;
|
|
52
|
+
const json = JSON.stringify(withoutPath);
|
|
53
|
+
const parsed = JSON.parse(json);
|
|
54
|
+
assert.equal(parsed.projectPath, undefined);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('JSONL format', () => {
|
|
58
|
+
it('produces valid JSONL lines from mappings', () => {
|
|
59
|
+
const mappings = [
|
|
60
|
+
createMockMapping({ messageId: 'msg-1' }),
|
|
61
|
+
createMockMapping({ messageId: 'msg-2' }),
|
|
62
|
+
createMockMapping({ messageId: 'msg-3' }),
|
|
63
|
+
];
|
|
64
|
+
const jsonl = mappings.map(m => JSON.stringify(m)).join('\n') + '\n';
|
|
65
|
+
const lines = jsonl.split('\n').filter(line => line.trim());
|
|
66
|
+
assert.equal(lines.length, 3);
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
const parsed = JSON.parse(line);
|
|
69
|
+
assert.ok(parsed.messageId);
|
|
70
|
+
assert.ok(parsed.platform);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
it('can lookup mapping by messageId from parsed JSONL', () => {
|
|
74
|
+
const target = createMockMapping({ messageId: 'target-msg', platform: 'telegram' });
|
|
75
|
+
const mappings = [
|
|
76
|
+
createMockMapping({ messageId: 'other-1' }),
|
|
77
|
+
target,
|
|
78
|
+
createMockMapping({ messageId: 'other-2' }),
|
|
79
|
+
];
|
|
80
|
+
const found = mappings.find(m => m.platform === 'telegram' && m.messageId === 'target-msg');
|
|
81
|
+
assert.ok(found);
|
|
82
|
+
assert.equal(found.messageId, 'target-msg');
|
|
83
|
+
assert.equal(found.platform, 'telegram');
|
|
84
|
+
});
|
|
85
|
+
it('can filter mappings by sessionId', () => {
|
|
86
|
+
const sessionId = 'session-to-remove';
|
|
87
|
+
const mappings = [
|
|
88
|
+
createMockMapping({ sessionId }),
|
|
89
|
+
createMockMapping({ sessionId: 'other-session' }),
|
|
90
|
+
createMockMapping({ sessionId }),
|
|
91
|
+
];
|
|
92
|
+
const filtered = mappings.filter(m => m.sessionId !== sessionId);
|
|
93
|
+
assert.equal(filtered.length, 1);
|
|
94
|
+
assert.equal(filtered[0].sessionId, 'other-session');
|
|
95
|
+
});
|
|
96
|
+
it('can filter mappings by paneId', () => {
|
|
97
|
+
const mappings = [
|
|
98
|
+
createMockMapping({ tmuxPaneId: '%0' }),
|
|
99
|
+
createMockMapping({ tmuxPaneId: '%1' }),
|
|
100
|
+
createMockMapping({ tmuxPaneId: '%0' }),
|
|
101
|
+
];
|
|
102
|
+
const filtered = mappings.filter(m => m.tmuxPaneId !== '%0');
|
|
103
|
+
assert.equal(filtered.length, 1);
|
|
104
|
+
assert.equal(filtered[0].tmuxPaneId, '%1');
|
|
105
|
+
});
|
|
106
|
+
it('can prune stale entries by age', () => {
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
const maxAgeMs = 24 * 60 * 60 * 1000;
|
|
109
|
+
const mappings = [
|
|
110
|
+
createMockMapping({ createdAt: new Date(now - maxAgeMs - 1000).toISOString() }), // stale
|
|
111
|
+
createMockMapping({ createdAt: new Date(now - 1000).toISOString() }), // fresh
|
|
112
|
+
createMockMapping({ createdAt: new Date(now - maxAgeMs + 60000).toISOString() }), // just within
|
|
113
|
+
];
|
|
114
|
+
const filtered = mappings.filter(m => {
|
|
115
|
+
const age = now - new Date(m.createdAt).getTime();
|
|
116
|
+
return age < maxAgeMs;
|
|
117
|
+
});
|
|
118
|
+
assert.equal(filtered.length, 2);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('session-registry module exports', () => {
|
|
122
|
+
it('exports registerMessage function', async () => {
|
|
123
|
+
const mod = await import('../session-registry.js');
|
|
124
|
+
assert.equal(typeof mod.registerMessage, 'function');
|
|
125
|
+
});
|
|
126
|
+
it('exports loadAllMappings function', async () => {
|
|
127
|
+
const mod = await import('../session-registry.js');
|
|
128
|
+
assert.equal(typeof mod.loadAllMappings, 'function');
|
|
129
|
+
});
|
|
130
|
+
it('exports lookupByMessageId function', async () => {
|
|
131
|
+
const mod = await import('../session-registry.js');
|
|
132
|
+
assert.equal(typeof mod.lookupByMessageId, 'function');
|
|
133
|
+
});
|
|
134
|
+
it('exports removeSession function', async () => {
|
|
135
|
+
const mod = await import('../session-registry.js');
|
|
136
|
+
assert.equal(typeof mod.removeSession, 'function');
|
|
137
|
+
});
|
|
138
|
+
it('exports removeMessagesByPane function', async () => {
|
|
139
|
+
const mod = await import('../session-registry.js');
|
|
140
|
+
assert.equal(typeof mod.removeMessagesByPane, 'function');
|
|
141
|
+
});
|
|
142
|
+
it('exports pruneStale function', async () => {
|
|
143
|
+
const mod = await import('../session-registry.js');
|
|
144
|
+
assert.equal(typeof mod.pruneStale, 'function');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=session-registry.test.js.map
|