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.
Files changed (131) hide show
  1. package/dist/cli/__tests__/doctor-team.test.js +58 -0
  2. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  3. package/dist/cli/__tests__/index.test.js +3 -3
  4. package/dist/cli/__tests__/index.test.js.map +1 -1
  5. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +2 -0
  6. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +1 -0
  7. package/dist/cli/__tests__/lifecycle-notifications.test.js +48 -0
  8. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +1 -0
  9. package/dist/cli/doctor.js +28 -0
  10. package/dist/cli/doctor.js.map +1 -1
  11. package/dist/cli/index.d.ts.map +1 -1
  12. package/dist/cli/index.js +41 -1
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/config/__tests__/models.test.d.ts +2 -0
  15. package/dist/config/__tests__/models.test.d.ts.map +1 -0
  16. package/dist/config/__tests__/models.test.js +69 -0
  17. package/dist/config/__tests__/models.test.js.map +1 -0
  18. package/dist/config/models.d.ts +24 -0
  19. package/dist/config/models.d.ts.map +1 -0
  20. package/dist/config/models.js +53 -0
  21. package/dist/config/models.js.map +1 -0
  22. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +221 -36
  23. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  24. package/dist/mcp/__tests__/state-paths.test.js +21 -1
  25. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  26. package/dist/mcp/__tests__/state-server-team-tools.test.js +53 -1
  27. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +1 -1
  28. package/dist/mcp/state-paths.d.ts +1 -0
  29. package/dist/mcp/state-paths.d.ts.map +1 -1
  30. package/dist/mcp/state-paths.js +34 -1
  31. package/dist/mcp/state-paths.js.map +1 -1
  32. package/dist/mcp/state-server.d.ts.map +1 -1
  33. package/dist/mcp/state-server.js +46 -11
  34. package/dist/mcp/state-server.js.map +1 -1
  35. package/dist/notifications/__tests__/config.test.d.ts +2 -0
  36. package/dist/notifications/__tests__/config.test.d.ts.map +1 -0
  37. package/dist/notifications/__tests__/config.test.js +186 -0
  38. package/dist/notifications/__tests__/config.test.js.map +1 -0
  39. package/dist/notifications/__tests__/dispatcher.test.d.ts +2 -0
  40. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +1 -0
  41. package/dist/notifications/__tests__/dispatcher.test.js +202 -0
  42. package/dist/notifications/__tests__/dispatcher.test.js.map +1 -0
  43. package/dist/notifications/__tests__/formatter.test.d.ts +2 -0
  44. package/dist/notifications/__tests__/formatter.test.d.ts.map +1 -0
  45. package/dist/notifications/__tests__/formatter.test.js +103 -0
  46. package/dist/notifications/__tests__/formatter.test.js.map +1 -0
  47. package/dist/notifications/__tests__/notifier.test.d.ts +2 -0
  48. package/dist/notifications/__tests__/notifier.test.d.ts.map +1 -0
  49. package/dist/notifications/__tests__/notifier.test.js +104 -0
  50. package/dist/notifications/__tests__/notifier.test.js.map +1 -0
  51. package/dist/notifications/__tests__/profiles.test.d.ts +2 -0
  52. package/dist/notifications/__tests__/profiles.test.d.ts.map +1 -0
  53. package/dist/notifications/__tests__/profiles.test.js +404 -0
  54. package/dist/notifications/__tests__/profiles.test.js.map +1 -0
  55. package/dist/notifications/__tests__/reply-listener.test.d.ts +2 -0
  56. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +1 -0
  57. package/dist/notifications/__tests__/reply-listener.test.js +58 -0
  58. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -0
  59. package/dist/notifications/__tests__/session-registry.test.d.ts +2 -0
  60. package/dist/notifications/__tests__/session-registry.test.d.ts.map +1 -0
  61. package/dist/notifications/__tests__/session-registry.test.js +147 -0
  62. package/dist/notifications/__tests__/session-registry.test.js.map +1 -0
  63. package/dist/notifications/__tests__/tmux-detector.test.d.ts +2 -0
  64. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +1 -0
  65. package/dist/notifications/__tests__/tmux-detector.test.js +77 -0
  66. package/dist/notifications/__tests__/tmux-detector.test.js.map +1 -0
  67. package/dist/notifications/__tests__/tmux.test.d.ts +2 -0
  68. package/dist/notifications/__tests__/tmux.test.d.ts.map +1 -0
  69. package/dist/notifications/__tests__/tmux.test.js +86 -0
  70. package/dist/notifications/__tests__/tmux.test.js.map +1 -0
  71. package/dist/notifications/config.d.ts +44 -0
  72. package/dist/notifications/config.d.ts.map +1 -0
  73. package/dist/notifications/config.js +407 -0
  74. package/dist/notifications/config.js.map +1 -0
  75. package/dist/notifications/dispatcher.d.ts +15 -0
  76. package/dist/notifications/dispatcher.d.ts.map +1 -0
  77. package/dist/notifications/dispatcher.js +410 -0
  78. package/dist/notifications/dispatcher.js.map +1 -0
  79. package/dist/notifications/formatter.d.ts +14 -0
  80. package/dist/notifications/formatter.d.ts.map +1 -0
  81. package/dist/notifications/formatter.js +134 -0
  82. package/dist/notifications/formatter.js.map +1 -0
  83. package/dist/notifications/index.d.ts +32 -0
  84. package/dist/notifications/index.d.ts.map +1 -0
  85. package/dist/notifications/index.js +93 -0
  86. package/dist/notifications/index.js.map +1 -0
  87. package/dist/notifications/reply-listener.d.ts +47 -0
  88. package/dist/notifications/reply-listener.d.ts.map +1 -0
  89. package/dist/notifications/reply-listener.js +656 -0
  90. package/dist/notifications/reply-listener.js.map +1 -0
  91. package/dist/notifications/session-registry.d.ts +26 -0
  92. package/dist/notifications/session-registry.d.ts.map +1 -0
  93. package/dist/notifications/session-registry.js +275 -0
  94. package/dist/notifications/session-registry.js.map +1 -0
  95. package/dist/notifications/tmux-detector.d.ts +17 -0
  96. package/dist/notifications/tmux-detector.d.ts.map +1 -0
  97. package/dist/notifications/tmux-detector.js +77 -0
  98. package/dist/notifications/tmux-detector.js.map +1 -0
  99. package/dist/notifications/tmux.d.ts +28 -0
  100. package/dist/notifications/tmux.d.ts.map +1 -0
  101. package/dist/notifications/tmux.js +203 -0
  102. package/dist/notifications/tmux.js.map +1 -0
  103. package/dist/notifications/types.d.ts +181 -0
  104. package/dist/notifications/types.d.ts.map +1 -0
  105. package/dist/notifications/types.js +9 -0
  106. package/dist/notifications/types.js.map +1 -0
  107. package/dist/team/__tests__/runtime.test.js +54 -2
  108. package/dist/team/__tests__/runtime.test.js.map +1 -1
  109. package/dist/team/__tests__/state.test.js +30 -0
  110. package/dist/team/__tests__/state.test.js.map +1 -1
  111. package/dist/team/__tests__/worker-bootstrap.test.js +59 -1
  112. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  113. package/dist/team/runtime.d.ts +2 -2
  114. package/dist/team/runtime.d.ts.map +1 -1
  115. package/dist/team/runtime.js +50 -23
  116. package/dist/team/runtime.js.map +1 -1
  117. package/dist/team/state.d.ts +1 -1
  118. package/dist/team/state.d.ts.map +1 -1
  119. package/dist/team/state.js +5 -0
  120. package/dist/team/state.js.map +1 -1
  121. package/dist/team/tmux-session.d.ts.map +1 -1
  122. package/dist/team/tmux-session.js +53 -10
  123. package/dist/team/tmux-session.js.map +1 -1
  124. package/dist/team/worker-bootstrap.d.ts +12 -0
  125. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  126. package/dist/team/worker-bootstrap.js +37 -0
  127. package/dist/team/worker-bootstrap.js.map +1 -1
  128. package/package.json +1 -1
  129. package/prompts/planner.md +3 -3
  130. package/scripts/notify-hook.js +137 -7
  131. package/skills/team/SKILL.md +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.test.js","sourceRoot":"","sources":["../../../src/notifications/__tests__/session-registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tmux-detector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-detector.test.d.ts","sourceRoot":"","sources":["../../../src/notifications/__tests__/tmux-detector.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,77 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { analyzePaneContent } from '../tmux-detector.js';
4
+ describe('analyzePaneContent', () => {
5
+ it('returns zero confidence for empty content', () => {
6
+ const result = analyzePaneContent('');
7
+ assert.equal(result.hasCodex, false);
8
+ assert.equal(result.hasRateLimitMessage, false);
9
+ assert.equal(result.isBlocked, false);
10
+ assert.equal(result.confidence, 0);
11
+ });
12
+ it('detects "codex" keyword', () => {
13
+ const result = analyzePaneContent('Running Codex agent...');
14
+ assert.equal(result.hasCodex, true);
15
+ assert.ok(result.confidence >= 0.5);
16
+ });
17
+ it('detects "omx" keyword', () => {
18
+ const result = analyzePaneContent('omx session started');
19
+ assert.equal(result.hasCodex, true);
20
+ });
21
+ it('detects "oh-my-codex" keyword', () => {
22
+ const result = analyzePaneContent('oh-my-codex v1.0');
23
+ assert.equal(result.hasCodex, true);
24
+ });
25
+ it('detects "openai" keyword', () => {
26
+ const result = analyzePaneContent('openai api call');
27
+ assert.equal(result.hasCodex, true);
28
+ });
29
+ it('is case insensitive', () => {
30
+ const result = analyzePaneContent('CODEX RUNNING');
31
+ assert.equal(result.hasCodex, true);
32
+ });
33
+ it('detects rate limit messages', () => {
34
+ const result = analyzePaneContent('Error: rate limit exceeded');
35
+ assert.equal(result.hasRateLimitMessage, true);
36
+ });
37
+ it('detects rate-limit with hyphen', () => {
38
+ const result = analyzePaneContent('rate-limit error');
39
+ assert.equal(result.hasRateLimitMessage, true);
40
+ });
41
+ it('detects 429 status code', () => {
42
+ const result = analyzePaneContent('HTTP 429 Too Many Requests');
43
+ assert.equal(result.hasRateLimitMessage, true);
44
+ });
45
+ it('detects blocked/waiting state', () => {
46
+ const result = analyzePaneContent('Waiting for user input...');
47
+ assert.equal(result.isBlocked, true);
48
+ });
49
+ it('detects paused state', () => {
50
+ const result = analyzePaneContent('Agent paused');
51
+ assert.equal(result.isBlocked, true);
52
+ });
53
+ it('adds confidence for prompt characters', () => {
54
+ const result = analyzePaneContent('$ some command\n> next line');
55
+ assert.ok(result.confidence >= 0.2);
56
+ });
57
+ it('adds confidence for agent/task keywords', () => {
58
+ const result = analyzePaneContent('agent running task 1');
59
+ assert.ok(result.confidence >= 0.1);
60
+ });
61
+ it('gives high confidence for codex content with prompt chars', () => {
62
+ const result = analyzePaneContent('Codex > Running agent task...');
63
+ assert.equal(result.hasCodex, true);
64
+ // codex=0.5, >=0.1, agent/task=0.1, non-empty=0.1 = 0.8
65
+ assert.ok(result.confidence >= 0.7, `Expected confidence >= 0.7, got ${result.confidence}`);
66
+ });
67
+ it('caps confidence at 1.0', () => {
68
+ const result = analyzePaneContent('Codex $ > agent task running omx');
69
+ assert.ok(result.confidence <= 1.0);
70
+ });
71
+ it('gives some confidence for non-empty non-codex content', () => {
72
+ const result = analyzePaneContent('some random text here');
73
+ assert.equal(result.hasCodex, false);
74
+ assert.ok(result.confidence > 0);
75
+ });
76
+ });
77
+ //# sourceMappingURL=tmux-detector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-detector.test.js","sourceRoot":"","sources":["../../../src/notifications/__tests__/tmux-detector.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tmux.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.test.d.ts","sourceRoot":"","sources":["../../../src/notifications/__tests__/tmux.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ import { describe, it, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { getCurrentTmuxSession, getCurrentTmuxPaneId, formatTmuxInfo, getTeamTmuxSessions, } from '../tmux.js';
4
+ describe('getCurrentTmuxSession', () => {
5
+ const originalTmux = process.env.TMUX;
6
+ afterEach(() => {
7
+ if (originalTmux !== undefined) {
8
+ process.env.TMUX = originalTmux;
9
+ }
10
+ else {
11
+ delete process.env.TMUX;
12
+ }
13
+ });
14
+ it('returns null when TMUX env is not set', () => {
15
+ delete process.env.TMUX;
16
+ assert.equal(getCurrentTmuxSession(), null);
17
+ });
18
+ });
19
+ describe('getCurrentTmuxPaneId', () => {
20
+ const originalTmux = process.env.TMUX;
21
+ const originalPane = process.env.TMUX_PANE;
22
+ afterEach(() => {
23
+ if (originalTmux !== undefined) {
24
+ process.env.TMUX = originalTmux;
25
+ }
26
+ else {
27
+ delete process.env.TMUX;
28
+ }
29
+ if (originalPane !== undefined) {
30
+ process.env.TMUX_PANE = originalPane;
31
+ }
32
+ else {
33
+ delete process.env.TMUX_PANE;
34
+ }
35
+ });
36
+ it('returns null when TMUX env is not set', () => {
37
+ delete process.env.TMUX;
38
+ assert.equal(getCurrentTmuxPaneId(), null);
39
+ });
40
+ it('returns TMUX_PANE when valid format', () => {
41
+ process.env.TMUX = '/tmp/tmux-1000/default,12345,0';
42
+ process.env.TMUX_PANE = '%0';
43
+ assert.equal(getCurrentTmuxPaneId(), '%0');
44
+ });
45
+ it('returns TMUX_PANE for multi-digit pane id', () => {
46
+ process.env.TMUX = '/tmp/tmux-1000/default,12345,0';
47
+ process.env.TMUX_PANE = '%42';
48
+ assert.equal(getCurrentTmuxPaneId(), '%42');
49
+ });
50
+ it('ignores invalid TMUX_PANE format', () => {
51
+ process.env.TMUX = '/tmp/tmux-1000/default,12345,0';
52
+ process.env.TMUX_PANE = 'invalid';
53
+ // Falls back to tmux command, which may or may not work
54
+ const result = getCurrentTmuxPaneId();
55
+ assert.ok(result === null || /^%\d+$/.test(result));
56
+ });
57
+ });
58
+ describe('formatTmuxInfo', () => {
59
+ const originalTmux = process.env.TMUX;
60
+ afterEach(() => {
61
+ if (originalTmux !== undefined) {
62
+ process.env.TMUX = originalTmux;
63
+ }
64
+ else {
65
+ delete process.env.TMUX;
66
+ }
67
+ });
68
+ it('returns null when not in tmux', () => {
69
+ delete process.env.TMUX;
70
+ assert.equal(formatTmuxInfo(), null);
71
+ });
72
+ });
73
+ describe('getTeamTmuxSessions', () => {
74
+ it('returns empty array for empty team name', () => {
75
+ assert.deepEqual(getTeamTmuxSessions(''), []);
76
+ });
77
+ it('returns empty array for special-character-only team name', () => {
78
+ assert.deepEqual(getTeamTmuxSessions('!@#$'), []);
79
+ });
80
+ it('sanitizes team name (strips non-alphanumeric except hyphens)', () => {
81
+ // Should not throw even with weird input
82
+ const result = getTeamTmuxSessions('test<script>');
83
+ assert.ok(Array.isArray(result));
84
+ });
85
+ });
86
+ //# sourceMappingURL=tmux.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.test.js","sourceRoot":"","sources":["../../../src/notifications/__tests__/tmux.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Notification Configuration Reader
3
+ *
4
+ * Reads notification config from .omx-config.json and provides
5
+ * backward compatibility with the old stopHookCallbacks format.
6
+ */
7
+ import type { FullNotificationConfig, NotificationsBlock, NotificationEvent, NotificationPlatform } from "./types.js";
8
+ export declare function validateMention(raw: string | undefined): string | undefined;
9
+ export declare function parseMentionAllowedMentions(mention: string | undefined): {
10
+ users?: string[];
11
+ roles?: string[];
12
+ };
13
+ export declare function buildConfigFromEnv(): FullNotificationConfig | null;
14
+ /**
15
+ * Resolve a named profile from the notifications block.
16
+ *
17
+ * Priority:
18
+ * 1. Explicit `profileName` argument
19
+ * 2. OMX_NOTIFY_PROFILE environment variable
20
+ * 3. `defaultProfile` field in config
21
+ * 4. null (no profile selected → fall back to flat config)
22
+ */
23
+ export declare function resolveProfileConfig(notifications: NotificationsBlock, profileName?: string): FullNotificationConfig | null;
24
+ /**
25
+ * List available profile names from the config file.
26
+ */
27
+ export declare function listProfiles(): string[];
28
+ /**
29
+ * Get the active profile name based on resolution priority.
30
+ * Returns null if no profile is active (flat config mode).
31
+ */
32
+ export declare function getActiveProfileName(): string | null;
33
+ export declare function getNotificationConfig(profileName?: string): FullNotificationConfig | null;
34
+ export declare function isEventEnabled(config: FullNotificationConfig, event: NotificationEvent): boolean;
35
+ export declare function getEnabledPlatforms(config: FullNotificationConfig, event: NotificationEvent): NotificationPlatform[];
36
+ export declare function getReplyListenerPlatformConfig(config: FullNotificationConfig | null): {
37
+ telegramBotToken?: string;
38
+ telegramChatId?: string;
39
+ discordBotToken?: string;
40
+ discordChannelId?: string;
41
+ discordMention?: string;
42
+ };
43
+ export declare function getReplyConfig(): import("./types.js").ReplyConfig | null;
44
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/notifications/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EAKrB,MAAM,YAAY,CAAC;AAuDpB,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAO3E;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAOxC;AAED,wBAAgB,kBAAkB,IAAI,sBAAsB,GAAG,IAAI,CAyDlE;AAmDD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,kBAAkB,EACjC,WAAW,CAAC,EAAE,MAAM,GACnB,sBAAsB,GAAG,IAAI,CAwB/B;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAMvC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAWpD;AAED,wBAAgB,qBAAqB,CACnC,WAAW,CAAC,EAAE,MAAM,GACnB,sBAAsB,GAAG,IAAI,CAkD/B;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAkCT;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,iBAAiB,GACvB,oBAAoB,EAAE,CAwCxB;AAqCD,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,sBAAsB,GAAG,IAAI,GACpC;IACD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAwBA;AAuBD,wBAAgB,cAAc,IAAI,OAAO,YAAY,EAAE,WAAW,GAAG,IAAI,CAwCxE"}
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Notification Configuration Reader
3
+ *
4
+ * Reads notification config from .omx-config.json and provides
5
+ * backward compatibility with the old stopHookCallbacks format.
6
+ */
7
+ import { readFileSync, existsSync } from "fs";
8
+ import { join } from "path";
9
+ import { codexHome } from "../utils/paths.js";
10
+ const CONFIG_FILE = join(codexHome(), ".omx-config.json");
11
+ function readRawConfig() {
12
+ if (!existsSync(CONFIG_FILE))
13
+ return null;
14
+ try {
15
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ function migrateStopHookCallbacks(raw) {
22
+ const callbacks = raw.stopHookCallbacks;
23
+ if (!callbacks)
24
+ return null;
25
+ const config = {
26
+ enabled: true,
27
+ events: {
28
+ "session-end": { enabled: true },
29
+ },
30
+ };
31
+ const telegram = callbacks.telegram;
32
+ if (telegram?.enabled) {
33
+ const telegramConfig = {
34
+ enabled: true,
35
+ botToken: telegram.botToken || "",
36
+ chatId: telegram.chatId || "",
37
+ };
38
+ config.telegram = telegramConfig;
39
+ }
40
+ const discord = callbacks.discord;
41
+ if (discord?.enabled) {
42
+ const discordConfig = {
43
+ enabled: true,
44
+ webhookUrl: discord.webhookUrl || "",
45
+ };
46
+ config.discord = discordConfig;
47
+ }
48
+ return config;
49
+ }
50
+ function normalizeOptional(value) {
51
+ const trimmed = value?.trim();
52
+ return trimmed || undefined;
53
+ }
54
+ export function validateMention(raw) {
55
+ const mention = normalizeOptional(raw);
56
+ if (!mention)
57
+ return undefined;
58
+ if (/^<@!?\d{17,20}>$/.test(mention) || /^<@&\d{17,20}>$/.test(mention)) {
59
+ return mention;
60
+ }
61
+ return undefined;
62
+ }
63
+ export function parseMentionAllowedMentions(mention) {
64
+ if (!mention)
65
+ return {};
66
+ const userMatch = mention.match(/^<@!?(\d{17,20})>$/);
67
+ if (userMatch)
68
+ return { users: [userMatch[1]] };
69
+ const roleMatch = mention.match(/^<@&(\d{17,20})>$/);
70
+ if (roleMatch)
71
+ return { roles: [roleMatch[1]] };
72
+ return {};
73
+ }
74
+ export function buildConfigFromEnv() {
75
+ const config = { enabled: false };
76
+ let hasAnyPlatform = false;
77
+ const discordMention = validateMention(process.env.OMX_DISCORD_MENTION);
78
+ const discordBotToken = process.env.OMX_DISCORD_NOTIFIER_BOT_TOKEN;
79
+ const discordChannel = process.env.OMX_DISCORD_NOTIFIER_CHANNEL;
80
+ if (discordBotToken && discordChannel) {
81
+ config["discord-bot"] = {
82
+ enabled: true,
83
+ botToken: discordBotToken,
84
+ channelId: discordChannel,
85
+ mention: discordMention,
86
+ };
87
+ hasAnyPlatform = true;
88
+ }
89
+ const discordWebhook = process.env.OMX_DISCORD_WEBHOOK_URL;
90
+ if (discordWebhook) {
91
+ config.discord = {
92
+ enabled: true,
93
+ webhookUrl: discordWebhook,
94
+ mention: discordMention,
95
+ };
96
+ hasAnyPlatform = true;
97
+ }
98
+ const telegramToken = process.env.OMX_TELEGRAM_BOT_TOKEN ||
99
+ process.env.OMX_TELEGRAM_NOTIFIER_BOT_TOKEN;
100
+ const telegramChatId = process.env.OMX_TELEGRAM_CHAT_ID ||
101
+ process.env.OMX_TELEGRAM_NOTIFIER_CHAT_ID ||
102
+ process.env.OMX_TELEGRAM_NOTIFIER_UID;
103
+ if (telegramToken && telegramChatId) {
104
+ config.telegram = {
105
+ enabled: true,
106
+ botToken: telegramToken,
107
+ chatId: telegramChatId,
108
+ };
109
+ hasAnyPlatform = true;
110
+ }
111
+ const slackWebhook = process.env.OMX_SLACK_WEBHOOK_URL;
112
+ if (slackWebhook) {
113
+ config.slack = {
114
+ enabled: true,
115
+ webhookUrl: slackWebhook,
116
+ };
117
+ hasAnyPlatform = true;
118
+ }
119
+ if (!hasAnyPlatform)
120
+ return null;
121
+ config.enabled = true;
122
+ return config;
123
+ }
124
+ function mergeEnvIntoFileConfig(fileConfig, envConfig) {
125
+ const merged = { ...fileConfig };
126
+ if (!merged["discord-bot"] && envConfig["discord-bot"]) {
127
+ merged["discord-bot"] = envConfig["discord-bot"];
128
+ }
129
+ else if (merged["discord-bot"] && envConfig["discord-bot"]) {
130
+ merged["discord-bot"] = {
131
+ ...merged["discord-bot"],
132
+ botToken: merged["discord-bot"].botToken || envConfig["discord-bot"].botToken,
133
+ channelId: merged["discord-bot"].channelId || envConfig["discord-bot"].channelId,
134
+ mention: merged["discord-bot"].mention !== undefined
135
+ ? validateMention(merged["discord-bot"].mention)
136
+ : envConfig["discord-bot"].mention,
137
+ };
138
+ }
139
+ if (!merged.discord && envConfig.discord) {
140
+ merged.discord = envConfig.discord;
141
+ }
142
+ else if (merged.discord && envConfig.discord) {
143
+ merged.discord = {
144
+ ...merged.discord,
145
+ webhookUrl: merged.discord.webhookUrl || envConfig.discord.webhookUrl,
146
+ mention: merged.discord.mention !== undefined
147
+ ? validateMention(merged.discord.mention)
148
+ : envConfig.discord.mention,
149
+ };
150
+ }
151
+ else if (merged.discord) {
152
+ merged.discord = {
153
+ ...merged.discord,
154
+ mention: validateMention(merged.discord.mention),
155
+ };
156
+ }
157
+ if (!merged.telegram && envConfig.telegram) {
158
+ merged.telegram = envConfig.telegram;
159
+ }
160
+ if (!merged.slack && envConfig.slack) {
161
+ merged.slack = envConfig.slack;
162
+ }
163
+ return merged;
164
+ }
165
+ /**
166
+ * Resolve a named profile from the notifications block.
167
+ *
168
+ * Priority:
169
+ * 1. Explicit `profileName` argument
170
+ * 2. OMX_NOTIFY_PROFILE environment variable
171
+ * 3. `defaultProfile` field in config
172
+ * 4. null (no profile selected → fall back to flat config)
173
+ */
174
+ export function resolveProfileConfig(notifications, profileName) {
175
+ const profiles = notifications.profiles;
176
+ if (!profiles || Object.keys(profiles).length === 0) {
177
+ return null; // no profiles defined, use flat config
178
+ }
179
+ const name = profileName ||
180
+ process.env.OMX_NOTIFY_PROFILE ||
181
+ notifications.defaultProfile;
182
+ if (!name) {
183
+ return null; // no profile selected, use flat config
184
+ }
185
+ const profile = profiles[name];
186
+ if (!profile) {
187
+ console.warn(`[notifications] Profile "${name}" not found. Available: ${Object.keys(profiles).join(", ")}`);
188
+ return null;
189
+ }
190
+ return profile;
191
+ }
192
+ /**
193
+ * List available profile names from the config file.
194
+ */
195
+ export function listProfiles() {
196
+ const raw = readRawConfig();
197
+ if (!raw)
198
+ return [];
199
+ const notifications = raw.notifications;
200
+ if (!notifications?.profiles)
201
+ return [];
202
+ return Object.keys(notifications.profiles);
203
+ }
204
+ /**
205
+ * Get the active profile name based on resolution priority.
206
+ * Returns null if no profile is active (flat config mode).
207
+ */
208
+ export function getActiveProfileName() {
209
+ if (process.env.OMX_NOTIFY_PROFILE) {
210
+ return process.env.OMX_NOTIFY_PROFILE;
211
+ }
212
+ const raw = readRawConfig();
213
+ if (!raw)
214
+ return null;
215
+ const notifications = raw.notifications;
216
+ if (!notifications?.profiles || Object.keys(notifications.profiles).length === 0) {
217
+ return null;
218
+ }
219
+ return notifications.defaultProfile || null;
220
+ }
221
+ export function getNotificationConfig(profileName) {
222
+ const raw = readRawConfig();
223
+ if (raw) {
224
+ const notifications = raw.notifications;
225
+ if (notifications) {
226
+ // Try profile resolution first
227
+ const profileConfig = resolveProfileConfig(notifications, profileName);
228
+ if (profileConfig) {
229
+ if (typeof profileConfig.enabled !== "boolean") {
230
+ return null;
231
+ }
232
+ const envConfig = buildConfigFromEnv();
233
+ if (envConfig) {
234
+ return mergeEnvIntoFileConfig(profileConfig, envConfig);
235
+ }
236
+ return profileConfig;
237
+ }
238
+ // Fall back to flat config (backward compatible)
239
+ if (typeof notifications.enabled !== "boolean") {
240
+ return null;
241
+ }
242
+ const envConfig = buildConfigFromEnv();
243
+ if (envConfig) {
244
+ return mergeEnvIntoFileConfig(notifications, envConfig);
245
+ }
246
+ const envMention = validateMention(process.env.OMX_DISCORD_MENTION);
247
+ if (envMention) {
248
+ const patched = { ...notifications };
249
+ if (patched["discord-bot"] && patched["discord-bot"].mention === undefined) {
250
+ patched["discord-bot"] = { ...patched["discord-bot"], mention: envMention };
251
+ }
252
+ if (patched.discord && patched.discord.mention === undefined) {
253
+ patched.discord = { ...patched.discord, mention: envMention };
254
+ }
255
+ return patched;
256
+ }
257
+ return notifications;
258
+ }
259
+ }
260
+ const envConfig = buildConfigFromEnv();
261
+ if (envConfig)
262
+ return envConfig;
263
+ if (raw) {
264
+ return migrateStopHookCallbacks(raw);
265
+ }
266
+ return null;
267
+ }
268
+ export function isEventEnabled(config, event) {
269
+ if (!config.enabled)
270
+ return false;
271
+ const eventConfig = config.events?.[event];
272
+ if (eventConfig && eventConfig.enabled === false)
273
+ return false;
274
+ if (!eventConfig) {
275
+ return !!(config.discord?.enabled ||
276
+ config["discord-bot"]?.enabled ||
277
+ config.telegram?.enabled ||
278
+ config.slack?.enabled ||
279
+ config.webhook?.enabled);
280
+ }
281
+ if (eventConfig.discord?.enabled ||
282
+ eventConfig["discord-bot"]?.enabled ||
283
+ eventConfig.telegram?.enabled ||
284
+ eventConfig.slack?.enabled ||
285
+ eventConfig.webhook?.enabled) {
286
+ return true;
287
+ }
288
+ return !!(config.discord?.enabled ||
289
+ config["discord-bot"]?.enabled ||
290
+ config.telegram?.enabled ||
291
+ config.slack?.enabled ||
292
+ config.webhook?.enabled);
293
+ }
294
+ export function getEnabledPlatforms(config, event) {
295
+ if (!config.enabled)
296
+ return [];
297
+ const platforms = [];
298
+ const eventConfig = config.events?.[event];
299
+ if (eventConfig && eventConfig.enabled === false)
300
+ return [];
301
+ const checkPlatform = (platform) => {
302
+ const eventPlatform = eventConfig?.[platform];
303
+ if (eventPlatform &&
304
+ typeof eventPlatform === "object" &&
305
+ "enabled" in eventPlatform) {
306
+ if (eventPlatform.enabled) {
307
+ platforms.push(platform);
308
+ }
309
+ return;
310
+ }
311
+ const topLevel = config[platform];
312
+ if (topLevel &&
313
+ typeof topLevel === "object" &&
314
+ "enabled" in topLevel &&
315
+ topLevel.enabled) {
316
+ platforms.push(platform);
317
+ }
318
+ };
319
+ checkPlatform("discord");
320
+ checkPlatform("discord-bot");
321
+ checkPlatform("telegram");
322
+ checkPlatform("slack");
323
+ checkPlatform("webhook");
324
+ return platforms;
325
+ }
326
+ const REPLY_PLATFORM_EVENTS = [
327
+ "session-start",
328
+ "ask-user-question",
329
+ "session-stop",
330
+ "session-idle",
331
+ "session-end",
332
+ ];
333
+ function getEnabledReplyPlatformConfig(config, platform) {
334
+ const topLevel = config[platform];
335
+ if (topLevel?.enabled) {
336
+ return topLevel;
337
+ }
338
+ for (const event of REPLY_PLATFORM_EVENTS) {
339
+ const eventConfig = config.events?.[event];
340
+ const eventPlatform = eventConfig?.[platform];
341
+ if (eventPlatform &&
342
+ typeof eventPlatform === "object" &&
343
+ "enabled" in eventPlatform &&
344
+ eventPlatform.enabled) {
345
+ return eventPlatform;
346
+ }
347
+ }
348
+ return undefined;
349
+ }
350
+ export function getReplyListenerPlatformConfig(config) {
351
+ if (!config)
352
+ return {};
353
+ const telegramConfig = getEnabledReplyPlatformConfig(config, "telegram");
354
+ const discordBotConfig = getEnabledReplyPlatformConfig(config, "discord-bot");
355
+ return {
356
+ telegramBotToken: telegramConfig?.botToken || config.telegram?.botToken,
357
+ telegramChatId: telegramConfig?.chatId || config.telegram?.chatId,
358
+ discordBotToken: discordBotConfig?.botToken || config["discord-bot"]?.botToken,
359
+ discordChannelId: discordBotConfig?.channelId || config["discord-bot"]?.channelId,
360
+ discordMention: discordBotConfig?.mention || config["discord-bot"]?.mention,
361
+ };
362
+ }
363
+ function parseDiscordUserIds(envValue, configValue) {
364
+ if (envValue) {
365
+ const ids = envValue
366
+ .split(",")
367
+ .map((id) => id.trim())
368
+ .filter((id) => /^\d{17,20}$/.test(id));
369
+ if (ids.length > 0)
370
+ return ids;
371
+ }
372
+ if (Array.isArray(configValue)) {
373
+ const ids = configValue
374
+ .filter((id) => typeof id === "string" && /^\d{17,20}$/.test(id));
375
+ if (ids.length > 0)
376
+ return ids;
377
+ }
378
+ return [];
379
+ }
380
+ export function getReplyConfig() {
381
+ const notifConfig = getNotificationConfig();
382
+ if (!notifConfig?.enabled)
383
+ return null;
384
+ const hasDiscordBot = !!getEnabledReplyPlatformConfig(notifConfig, "discord-bot");
385
+ const hasTelegram = !!getEnabledReplyPlatformConfig(notifConfig, "telegram");
386
+ if (!hasDiscordBot && !hasTelegram)
387
+ return null;
388
+ const raw = readRawConfig();
389
+ const replyRaw = raw?.notifications?.reply;
390
+ const enabled = process.env.OMX_REPLY_ENABLED === "true" || replyRaw?.enabled === true;
391
+ if (!enabled)
392
+ return null;
393
+ const authorizedDiscordUserIds = parseDiscordUserIds(process.env.OMX_REPLY_DISCORD_USER_IDS, replyRaw?.authorizedDiscordUserIds);
394
+ if (hasDiscordBot && authorizedDiscordUserIds.length === 0) {
395
+ console.warn("[notifications] Discord reply listening disabled: authorizedDiscordUserIds is empty. " +
396
+ "Set OMX_REPLY_DISCORD_USER_IDS or add to .omx-config.json notifications.reply.authorizedDiscordUserIds");
397
+ }
398
+ return {
399
+ enabled: true,
400
+ pollIntervalMs: parseInt(process.env.OMX_REPLY_POLL_INTERVAL_MS || "") || replyRaw?.pollIntervalMs || 3000,
401
+ maxMessageLength: replyRaw?.maxMessageLength || 500,
402
+ rateLimitPerMinute: parseInt(process.env.OMX_REPLY_RATE_LIMIT || "") || replyRaw?.rateLimitPerMinute || 10,
403
+ includePrefix: process.env.OMX_REPLY_INCLUDE_PREFIX !== "false" && (replyRaw?.includePrefix !== false),
404
+ authorizedDiscordUserIds,
405
+ };
406
+ }
407
+ //# sourceMappingURL=config.js.map