@ob1-sg/horizon 0.1.10 → 0.1.11

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 (153) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +43 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/config.d.ts +10 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +293 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +629 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/__tests__/attachment-downloader.test.d.ts +2 -0
  14. package/dist/lib/__tests__/attachment-downloader.test.d.ts.map +1 -0
  15. package/dist/lib/__tests__/attachment-downloader.test.js +163 -0
  16. package/dist/lib/__tests__/attachment-downloader.test.js.map +1 -0
  17. package/dist/lib/__tests__/cli-detection.test.d.ts +2 -0
  18. package/dist/lib/__tests__/cli-detection.test.d.ts.map +1 -0
  19. package/dist/lib/__tests__/cli-detection.test.js +119 -0
  20. package/dist/lib/__tests__/cli-detection.test.js.map +1 -0
  21. package/dist/lib/__tests__/config.test.d.ts +2 -0
  22. package/dist/lib/__tests__/config.test.d.ts.map +1 -0
  23. package/dist/lib/__tests__/config.test.js +291 -0
  24. package/dist/lib/__tests__/config.test.js.map +1 -0
  25. package/dist/lib/__tests__/gcp.test.d.ts +2 -0
  26. package/dist/lib/__tests__/gcp.test.d.ts.map +1 -0
  27. package/dist/lib/__tests__/gcp.test.js +104 -0
  28. package/dist/lib/__tests__/gcp.test.js.map +1 -0
  29. package/dist/lib/__tests__/git.test.d.ts +2 -0
  30. package/dist/lib/__tests__/git.test.d.ts.map +1 -0
  31. package/dist/lib/__tests__/git.test.js +62 -0
  32. package/dist/lib/__tests__/git.test.js.map +1 -0
  33. package/dist/lib/__tests__/linear-quick-check.test.d.ts +2 -0
  34. package/dist/lib/__tests__/linear-quick-check.test.d.ts.map +1 -0
  35. package/dist/lib/__tests__/linear-quick-check.test.js +152 -0
  36. package/dist/lib/__tests__/linear-quick-check.test.js.map +1 -0
  37. package/dist/lib/__tests__/loop-instance-name.test.d.ts +2 -0
  38. package/dist/lib/__tests__/loop-instance-name.test.d.ts.map +1 -0
  39. package/dist/lib/__tests__/loop-instance-name.test.js +90 -0
  40. package/dist/lib/__tests__/loop-instance-name.test.js.map +1 -0
  41. package/dist/lib/__tests__/output-logger.test.d.ts +2 -0
  42. package/dist/lib/__tests__/output-logger.test.d.ts.map +1 -0
  43. package/dist/lib/__tests__/output-logger.test.js +136 -0
  44. package/dist/lib/__tests__/output-logger.test.js.map +1 -0
  45. package/dist/lib/__tests__/prompts.test.d.ts +2 -0
  46. package/dist/lib/__tests__/prompts.test.d.ts.map +1 -0
  47. package/dist/lib/__tests__/prompts.test.js +70 -0
  48. package/dist/lib/__tests__/prompts.test.js.map +1 -0
  49. package/dist/lib/__tests__/provider.test.d.ts +2 -0
  50. package/dist/lib/__tests__/provider.test.d.ts.map +1 -0
  51. package/dist/lib/__tests__/provider.test.js +89 -0
  52. package/dist/lib/__tests__/provider.test.js.map +1 -0
  53. package/dist/lib/__tests__/rate-limit.test.d.ts +2 -0
  54. package/dist/lib/__tests__/rate-limit.test.d.ts.map +1 -0
  55. package/dist/lib/__tests__/rate-limit.test.js +275 -0
  56. package/dist/lib/__tests__/rate-limit.test.js.map +1 -0
  57. package/dist/lib/__tests__/readline.test.d.ts +2 -0
  58. package/dist/lib/__tests__/readline.test.d.ts.map +1 -0
  59. package/dist/lib/__tests__/readline.test.js +55 -0
  60. package/dist/lib/__tests__/readline.test.js.map +1 -0
  61. package/dist/lib/__tests__/stats-logger.test.d.ts +2 -0
  62. package/dist/lib/__tests__/stats-logger.test.d.ts.map +1 -0
  63. package/dist/lib/__tests__/stats-logger.test.js +297 -0
  64. package/dist/lib/__tests__/stats-logger.test.js.map +1 -0
  65. package/dist/lib/__tests__/update-checker.test.d.ts +2 -0
  66. package/dist/lib/__tests__/update-checker.test.d.ts.map +1 -0
  67. package/dist/lib/__tests__/update-checker.test.js +141 -0
  68. package/dist/lib/__tests__/update-checker.test.js.map +1 -0
  69. package/dist/lib/__tests__/version.test.d.ts +2 -0
  70. package/dist/lib/__tests__/version.test.d.ts.map +1 -0
  71. package/dist/lib/__tests__/version.test.js +51 -0
  72. package/dist/lib/__tests__/version.test.js.map +1 -0
  73. package/dist/lib/attachment-downloader.d.ts +26 -0
  74. package/dist/lib/attachment-downloader.d.ts.map +1 -0
  75. package/dist/lib/attachment-downloader.js +259 -0
  76. package/dist/lib/attachment-downloader.js.map +1 -0
  77. package/dist/lib/claude.d.ts +6 -0
  78. package/dist/lib/claude.d.ts.map +1 -0
  79. package/dist/lib/claude.js +358 -0
  80. package/dist/lib/claude.js.map +1 -0
  81. package/dist/lib/cli-detection.d.ts +25 -0
  82. package/dist/lib/cli-detection.d.ts.map +1 -0
  83. package/dist/lib/cli-detection.js +53 -0
  84. package/dist/lib/cli-detection.js.map +1 -0
  85. package/dist/lib/codex.d.ts +4 -0
  86. package/dist/lib/codex.d.ts.map +1 -0
  87. package/dist/lib/codex.js +285 -0
  88. package/dist/lib/codex.js.map +1 -0
  89. package/dist/lib/gcp.d.ts +21 -0
  90. package/dist/lib/gcp.d.ts.map +1 -0
  91. package/dist/lib/gcp.js +96 -0
  92. package/dist/lib/gcp.js.map +1 -0
  93. package/dist/lib/git.d.ts +3 -0
  94. package/dist/lib/git.d.ts.map +1 -0
  95. package/dist/lib/git.js +24 -0
  96. package/dist/lib/git.js.map +1 -0
  97. package/dist/lib/init-project.d.ts +13 -0
  98. package/dist/lib/init-project.d.ts.map +1 -0
  99. package/dist/lib/init-project.js +420 -0
  100. package/dist/lib/init-project.js.map +1 -0
  101. package/dist/lib/linear-api.d.ts +32 -0
  102. package/dist/lib/linear-api.d.ts.map +1 -0
  103. package/dist/lib/linear-api.js +267 -0
  104. package/dist/lib/linear-api.js.map +1 -0
  105. package/dist/lib/linear-quick-check.d.ts +13 -0
  106. package/dist/lib/linear-quick-check.d.ts.map +1 -0
  107. package/dist/lib/linear-quick-check.js +61 -0
  108. package/dist/lib/linear-quick-check.js.map +1 -0
  109. package/dist/lib/loop-instance-name.d.ts +29 -0
  110. package/dist/lib/loop-instance-name.d.ts.map +1 -0
  111. package/dist/lib/loop-instance-name.js +105 -0
  112. package/dist/lib/loop-instance-name.js.map +1 -0
  113. package/dist/lib/output-logger.d.ts +23 -0
  114. package/dist/lib/output-logger.d.ts.map +1 -0
  115. package/dist/lib/output-logger.js +104 -0
  116. package/dist/lib/output-logger.js.map +1 -0
  117. package/dist/lib/prompts.d.ts +17 -0
  118. package/dist/lib/prompts.d.ts.map +1 -0
  119. package/dist/lib/prompts.js +65 -0
  120. package/dist/lib/prompts.js.map +1 -0
  121. package/dist/lib/provider.d.ts +32 -0
  122. package/dist/lib/provider.d.ts.map +1 -0
  123. package/dist/lib/provider.js +27 -0
  124. package/dist/lib/provider.js.map +1 -0
  125. package/dist/lib/rate-limit.d.ts +14 -0
  126. package/dist/lib/rate-limit.d.ts.map +1 -0
  127. package/dist/lib/rate-limit.js +154 -0
  128. package/dist/lib/rate-limit.js.map +1 -0
  129. package/dist/lib/readline.d.ts +4 -0
  130. package/dist/lib/readline.d.ts.map +1 -0
  131. package/dist/lib/readline.js +39 -0
  132. package/dist/lib/readline.js.map +1 -0
  133. package/dist/lib/setup.d.ts +123 -0
  134. package/dist/lib/setup.d.ts.map +1 -0
  135. package/dist/lib/setup.js +492 -0
  136. package/dist/lib/setup.js.map +1 -0
  137. package/dist/lib/stats-logger.d.ts +92 -0
  138. package/dist/lib/stats-logger.d.ts.map +1 -0
  139. package/dist/lib/stats-logger.js +258 -0
  140. package/dist/lib/stats-logger.js.map +1 -0
  141. package/dist/lib/update-checker.d.ts +17 -0
  142. package/dist/lib/update-checker.d.ts.map +1 -0
  143. package/dist/lib/update-checker.js +140 -0
  144. package/dist/lib/update-checker.js.map +1 -0
  145. package/dist/lib/version.d.ts +10 -0
  146. package/dist/lib/version.d.ts.map +1 -0
  147. package/dist/lib/version.js +37 -0
  148. package/dist/lib/version.js.map +1 -0
  149. package/dist/types.d.ts +92 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +3 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=attachment-downloader.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-downloader.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/attachment-downloader.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,163 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { extractLinearUrls, parseAgent1Attachments, ensureAttachmentDir } from '../attachment-downloader.js';
3
+ // Mock dependencies
4
+ vi.mock('fs', () => ({
5
+ existsSync: vi.fn(),
6
+ mkdirSync: vi.fn(),
7
+ writeFileSync: vi.fn(),
8
+ }));
9
+ vi.mock('../../config.js', () => ({
10
+ getRepoRoot: vi.fn(() => '/mock/repo'),
11
+ }));
12
+ import * as fs from 'fs';
13
+ describe('attachment-downloader module', () => {
14
+ beforeEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+ describe('extractLinearUrls()', () => {
18
+ it('extracts URL from markdown image syntax `![alt](url)`', () => {
19
+ const markdown = '![screenshot.png](https://uploads.linear.app/abc/def/screenshot.png)';
20
+ const result = extractLinearUrls(markdown);
21
+ expect(result).toHaveLength(1);
22
+ expect(result[0].url).toBe('https://uploads.linear.app/abc/def/screenshot.png');
23
+ });
24
+ it('uses alt text as filename when it has extension', () => {
25
+ const markdown = '![my-image.png](https://uploads.linear.app/abc/def/random-id)';
26
+ const result = extractLinearUrls(markdown);
27
+ expect(result).toHaveLength(1);
28
+ expect(result[0].filename).toBe('my-image.png');
29
+ });
30
+ it('falls back to URL path for filename', () => {
31
+ const markdown = '![Description](https://uploads.linear.app/abc/def/image.png)';
32
+ const result = extractLinearUrls(markdown);
33
+ expect(result).toHaveLength(1);
34
+ expect(result[0].filename).toBe('image.png');
35
+ });
36
+ it('handles multiple URLs in one string', () => {
37
+ const markdown = `
38
+ ![first.png](https://uploads.linear.app/a/b/first.png)
39
+ Some text here
40
+ ![second.jpg](https://uploads.linear.app/c/d/second.jpg)
41
+ `;
42
+ const result = extractLinearUrls(markdown);
43
+ expect(result).toHaveLength(2);
44
+ expect(result[0].filename).toBe('first.png');
45
+ expect(result[1].filename).toBe('second.jpg');
46
+ });
47
+ it('deduplicates URLs (returns unique set)', () => {
48
+ const markdown = `
49
+ ![first.png](https://uploads.linear.app/a/b/image.png)
50
+ ![second.png](https://uploads.linear.app/a/b/image.png)
51
+ `;
52
+ const result = extractLinearUrls(markdown);
53
+ expect(result).toHaveLength(1);
54
+ });
55
+ it('generates unique ID from URL hash', () => {
56
+ const markdown = '![test.png](https://uploads.linear.app/a/b/test.png)';
57
+ const result = extractLinearUrls(markdown);
58
+ expect(result[0].id).toBeTruthy();
59
+ expect(typeof result[0].id).toBe('string');
60
+ expect(result[0].id.length).toBe(12);
61
+ });
62
+ it('handles standalone URLs (not in markdown syntax)', () => {
63
+ const markdown = 'Check this: https://uploads.linear.app/abc/def/file.pdf';
64
+ const result = extractLinearUrls(markdown);
65
+ expect(result).toHaveLength(1);
66
+ expect(result[0].url).toBe('https://uploads.linear.app/abc/def/file.pdf');
67
+ });
68
+ it('handles mixed markdown images and standalone URLs', () => {
69
+ const markdown = `
70
+ ![first.png](https://uploads.linear.app/a/b/first.png)
71
+ Also see: https://uploads.linear.app/c/d/second.pdf
72
+ `;
73
+ const result = extractLinearUrls(markdown);
74
+ expect(result).toHaveLength(2);
75
+ });
76
+ it('returns empty array for no matches', () => {
77
+ const markdown = 'No Linear URLs here, just regular text and https://example.com';
78
+ const result = extractLinearUrls(markdown);
79
+ expect(result).toHaveLength(0);
80
+ });
81
+ it('decodes URL-encoded filenames', () => {
82
+ const markdown = '![test file.png](https://uploads.linear.app/a/b/test%20file.png)';
83
+ const result = extractLinearUrls(markdown);
84
+ expect(result[0].filename).toBe('test file.png');
85
+ });
86
+ });
87
+ describe('parseAgent1Attachments()', () => {
88
+ it('extracts URLs from entire output', () => {
89
+ const output = `
90
+ Some text here
91
+ ![image.png](https://uploads.linear.app/a/b/image.png)
92
+ More text
93
+ `;
94
+ const result = parseAgent1Attachments(output);
95
+ expect(result).toHaveLength(1);
96
+ expect(result[0].filename).toBe('image.png');
97
+ });
98
+ it('marks section URLs as "attachment" source', () => {
99
+ const output = `
100
+ ## Description
101
+ Some text
102
+
103
+ ### Attachments
104
+ - Screenshot: https://uploads.linear.app/a/b/screenshot.png
105
+
106
+ ## Other Section
107
+ `;
108
+ const result = parseAgent1Attachments(output);
109
+ const attachmentUrls = result.filter(a => a.source === 'attachment');
110
+ expect(attachmentUrls).toHaveLength(1);
111
+ });
112
+ it('marks embedded URLs as "embedded" source', () => {
113
+ const output = `
114
+ ## Description
115
+ Check this ![image.png](https://uploads.linear.app/a/b/image.png)
116
+ `;
117
+ const result = parseAgent1Attachments(output);
118
+ expect(result[0].source).toBe('embedded');
119
+ });
120
+ it('deduplicates across sections', () => {
121
+ const output = `
122
+ ## Description
123
+ ![image.png](https://uploads.linear.app/a/b/image.png)
124
+
125
+ ### Attachments
126
+ - image: https://uploads.linear.app/a/b/image.png
127
+ `;
128
+ const result = parseAgent1Attachments(output);
129
+ expect(result).toHaveLength(1);
130
+ // The attachment section version should mark it as 'attachment'
131
+ expect(result[0].source).toBe('attachment');
132
+ });
133
+ it('handles output with no attachments section', () => {
134
+ const output = `
135
+ ## Description
136
+ Just some text, no attachments
137
+ ## Summary
138
+ More text
139
+ `;
140
+ const result = parseAgent1Attachments(output);
141
+ expect(result).toHaveLength(0);
142
+ });
143
+ });
144
+ describe('ensureAttachmentDir()', () => {
145
+ it('creates directory if not exists', () => {
146
+ vi.mocked(fs.existsSync).mockReturnValue(false);
147
+ ensureAttachmentDir('F-123');
148
+ expect(fs.mkdirSync).toHaveBeenCalledWith('/mock/repo/.horizon/attachments/F-123', { recursive: true });
149
+ });
150
+ it('returns correct path', () => {
151
+ vi.mocked(fs.existsSync).mockReturnValue(false);
152
+ const result = ensureAttachmentDir('F-456');
153
+ expect(result).toBe('/mock/repo/.horizon/attachments/F-456');
154
+ });
155
+ it('works when directory already exists', () => {
156
+ vi.mocked(fs.existsSync).mockReturnValue(true);
157
+ const result = ensureAttachmentDir('F-789');
158
+ expect(fs.mkdirSync).not.toHaveBeenCalled();
159
+ expect(result).toBe('/mock/repo/.horizon/attachments/F-789');
160
+ });
161
+ });
162
+ });
163
+ //# sourceMappingURL=attachment-downloader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-downloader.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/attachment-downloader.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli-detection.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-detection.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/cli-detection.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,119 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ // Mock child_process before importing the module
3
+ vi.mock('child_process', () => ({
4
+ execSync: vi.fn(),
5
+ }));
6
+ import { execSync } from 'child_process';
7
+ import { isClaudeCliInstalled, isCodexCliInstalled, detectAvailableClis, hasAnyCli, } from '../cli-detection.js';
8
+ describe('cli-detection module', () => {
9
+ beforeEach(() => {
10
+ vi.clearAllMocks();
11
+ });
12
+ describe('isClaudeCliInstalled()', () => {
13
+ it('returns true when `claude --version` succeeds', () => {
14
+ vi.mocked(execSync).mockReturnValue('claude version 1.0.0');
15
+ const result = isClaudeCliInstalled();
16
+ expect(result).toBe(true);
17
+ expect(execSync).toHaveBeenCalledWith('claude --version', {
18
+ encoding: 'utf-8',
19
+ timeout: 5000,
20
+ stdio: ['pipe', 'pipe', 'pipe'],
21
+ });
22
+ });
23
+ it('returns false when command fails', () => {
24
+ vi.mocked(execSync).mockImplementation(() => {
25
+ throw new Error('Command not found');
26
+ });
27
+ const result = isClaudeCliInstalled();
28
+ expect(result).toBe(false);
29
+ });
30
+ it('handles timeout gracefully', () => {
31
+ vi.mocked(execSync).mockImplementation(() => {
32
+ const error = new Error('ETIMEDOUT');
33
+ error.code = 'ETIMEDOUT';
34
+ throw error;
35
+ });
36
+ const result = isClaudeCliInstalled();
37
+ expect(result).toBe(false);
38
+ });
39
+ });
40
+ describe('isCodexCliInstalled()', () => {
41
+ it('returns true when `codex --version` succeeds', () => {
42
+ vi.mocked(execSync).mockReturnValue('codex version 2.0.0');
43
+ const result = isCodexCliInstalled();
44
+ expect(result).toBe(true);
45
+ expect(execSync).toHaveBeenCalledWith('codex --version', {
46
+ encoding: 'utf-8',
47
+ timeout: 5000,
48
+ stdio: ['pipe', 'pipe', 'pipe'],
49
+ });
50
+ });
51
+ it('returns false when command fails', () => {
52
+ vi.mocked(execSync).mockImplementation(() => {
53
+ throw new Error('Command not found');
54
+ });
55
+ const result = isCodexCliInstalled();
56
+ expect(result).toBe(false);
57
+ });
58
+ it('handles timeout gracefully', () => {
59
+ vi.mocked(execSync).mockImplementation(() => {
60
+ const error = new Error('ETIMEDOUT');
61
+ error.code = 'ETIMEDOUT';
62
+ throw error;
63
+ });
64
+ const result = isCodexCliInstalled();
65
+ expect(result).toBe(false);
66
+ });
67
+ });
68
+ describe('detectAvailableClis()', () => {
69
+ it('returns correct availability object', () => {
70
+ vi.mocked(execSync)
71
+ .mockReturnValueOnce('claude version 1.0.0') // claude
72
+ .mockImplementationOnce(() => {
73
+ throw new Error('not found'); // codex
74
+ });
75
+ const result = detectAvailableClis();
76
+ expect(result).toEqual({
77
+ claude: true,
78
+ codex: false,
79
+ });
80
+ });
81
+ it('both false when neither installed', () => {
82
+ vi.mocked(execSync).mockImplementation(() => {
83
+ throw new Error('Command not found');
84
+ });
85
+ const result = detectAvailableClis();
86
+ expect(result).toEqual({
87
+ claude: false,
88
+ codex: false,
89
+ });
90
+ });
91
+ it('both true when both installed', () => {
92
+ vi.mocked(execSync).mockReturnValue('version 1.0.0');
93
+ const result = detectAvailableClis();
94
+ expect(result).toEqual({
95
+ claude: true,
96
+ codex: true,
97
+ });
98
+ });
99
+ });
100
+ describe('hasAnyCli()', () => {
101
+ it('returns true if claude available', () => {
102
+ const availability = { claude: true, codex: false };
103
+ expect(hasAnyCli(availability)).toBe(true);
104
+ });
105
+ it('returns true if codex available', () => {
106
+ const availability = { claude: false, codex: true };
107
+ expect(hasAnyCli(availability)).toBe(true);
108
+ });
109
+ it('returns true if both available', () => {
110
+ const availability = { claude: true, codex: true };
111
+ expect(hasAnyCli(availability)).toBe(true);
112
+ });
113
+ it('returns false if neither available', () => {
114
+ const availability = { claude: false, codex: false };
115
+ expect(hasAnyCli(availability)).toBe(false);
116
+ });
117
+ });
118
+ });
119
+ //# sourceMappingURL=cli-detection.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-detection.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/cli-detection.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,291 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { execSync } from 'child_process';
3
+ import { join } from 'path';
4
+ // `src/config.ts` loads `.horizon/env` at import-time. Make tests deterministic even if a developer
5
+ // has that file locally by pretending it doesn't exist.
6
+ const REPO_ROOT = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
7
+ const HORIZON_ENV_PATH = join(REPO_ROOT, '.horizon', 'env');
8
+ vi.mock('fs', async (importOriginal) => {
9
+ const actual = await importOriginal();
10
+ return {
11
+ ...actual,
12
+ existsSync: vi.fn((path) => {
13
+ if (path === HORIZON_ENV_PATH) {
14
+ return false;
15
+ }
16
+ return actual.existsSync(path);
17
+ }),
18
+ readFileSync: vi.fn((path, ...rest) => {
19
+ if (path === HORIZON_ENV_PATH) {
20
+ return '';
21
+ }
22
+ return actual.readFileSync(path, ...rest);
23
+ }),
24
+ };
25
+ });
26
+ // Store original env
27
+ const originalEnv = process.env;
28
+ describe('config module', () => {
29
+ beforeEach(() => {
30
+ vi.resetModules();
31
+ process.env = { ...originalEnv };
32
+ // Clear all HORIZON and CODEX env vars to get defaults
33
+ Object.keys(process.env).forEach(key => {
34
+ if (key.startsWith('HORIZON_') || key.startsWith('CODEX_')) {
35
+ delete process.env[key];
36
+ }
37
+ });
38
+ // Prevent local .horizon/env from affecting test defaults
39
+ process.env.HORIZON_SKIP_ENV_FILE = '1';
40
+ });
41
+ afterEach(() => {
42
+ process.env = originalEnv;
43
+ });
44
+ describe('getRepoRoot()', () => {
45
+ it('returns git repo root when in repo', async () => {
46
+ const { getRepoRoot } = await import('../../config.js');
47
+ const result = getRepoRoot();
48
+ // Should return a valid path (we're running in a git repo)
49
+ expect(result).toBeTruthy();
50
+ expect(typeof result).toBe('string');
51
+ });
52
+ it('returns a string path', async () => {
53
+ const { getRepoRoot } = await import('../../config.js');
54
+ const result = getRepoRoot();
55
+ // Path should not be empty
56
+ expect(result.length).toBeGreaterThan(0);
57
+ });
58
+ });
59
+ describe('isGitRepository()', () => {
60
+ it('returns true when in git repo', async () => {
61
+ const { isGitRepository } = await import('../../config.js');
62
+ const result = isGitRepository();
63
+ // We're running in the horizon git repo
64
+ expect(result).toBe(true);
65
+ });
66
+ });
67
+ describe('getConfig() - provider configuration', () => {
68
+ it('returns claude as default provider', async () => {
69
+ delete process.env.HORIZON_PROVIDER;
70
+ const { getConfig } = await import('../../config.js');
71
+ const config = getConfig(true);
72
+ expect(config.provider).toBe('claude');
73
+ });
74
+ it('returns codex when HORIZON_PROVIDER=codex', async () => {
75
+ process.env.HORIZON_PROVIDER = 'codex';
76
+ const { getConfig } = await import('../../config.js');
77
+ const config = getConfig(true);
78
+ expect(config.provider).toBe('codex');
79
+ });
80
+ it('returns opus as default claude model', async () => {
81
+ delete process.env.HORIZON_CLAUDE_MODEL;
82
+ const { getConfig } = await import('../../config.js');
83
+ const config = getConfig(true);
84
+ expect(config.claudeModel).toBe('opus');
85
+ });
86
+ it('returns sonnet when HORIZON_CLAUDE_MODEL=sonnet', async () => {
87
+ process.env.HORIZON_CLAUDE_MODEL = 'sonnet';
88
+ const { getConfig } = await import('../../config.js');
89
+ const config = getConfig(true);
90
+ expect(config.claudeModel).toBe('sonnet');
91
+ });
92
+ it('returns haiku when HORIZON_CLAUDE_MODEL=haiku', async () => {
93
+ process.env.HORIZON_CLAUDE_MODEL = 'haiku';
94
+ const { getConfig } = await import('../../config.js');
95
+ const config = getConfig(true);
96
+ expect(config.claudeModel).toBe('haiku');
97
+ });
98
+ });
99
+ describe('getConfig() - max iterations', () => {
100
+ it('returns 0 (unlimited) by default', async () => {
101
+ delete process.env.HORIZON_MAX_ITERATIONS;
102
+ const { getConfig } = await import('../../config.js');
103
+ const config = getConfig(true);
104
+ expect(config.maxIterations).toBe(0);
105
+ });
106
+ it('returns positive number when set', async () => {
107
+ process.env.HORIZON_MAX_ITERATIONS = '5';
108
+ const { getConfig } = await import('../../config.js');
109
+ const config = getConfig(true);
110
+ expect(config.maxIterations).toBe(5);
111
+ });
112
+ it('returns 0 for invalid value', async () => {
113
+ process.env.HORIZON_MAX_ITERATIONS = 'invalid';
114
+ const { getConfig } = await import('../../config.js');
115
+ const config = getConfig(true);
116
+ expect(config.maxIterations).toBe(0);
117
+ });
118
+ });
119
+ describe('getConfig() - rate limit retries', () => {
120
+ it('returns 3 by default', async () => {
121
+ delete process.env.HORIZON_RATE_LIMIT_MAX_RETRIES;
122
+ const { getConfig } = await import('../../config.js');
123
+ const config = getConfig(true);
124
+ expect(config.rateLimitMaxRetries).toBe(3);
125
+ });
126
+ it('returns custom value when set', async () => {
127
+ process.env.HORIZON_RATE_LIMIT_MAX_RETRIES = '5';
128
+ const { getConfig } = await import('../../config.js');
129
+ const config = getConfig(true);
130
+ expect(config.rateLimitMaxRetries).toBe(5);
131
+ });
132
+ });
133
+ describe('getConfig() - GCP auto stop', () => {
134
+ it('returns false by default', async () => {
135
+ delete process.env.HORIZON_GCP_AUTO_STOP;
136
+ const { getConfig } = await import('../../config.js');
137
+ const config = getConfig(true);
138
+ expect(config.gcpAutoStop).toBe(false);
139
+ });
140
+ it('returns true when HORIZON_GCP_AUTO_STOP=true', async () => {
141
+ process.env.HORIZON_GCP_AUTO_STOP = 'true';
142
+ const { getConfig } = await import('../../config.js');
143
+ const config = getConfig(true);
144
+ expect(config.gcpAutoStop).toBe(true);
145
+ });
146
+ it('returns true when HORIZON_GCP_AUTO_STOP=1', async () => {
147
+ process.env.HORIZON_GCP_AUTO_STOP = '1';
148
+ const { getConfig } = await import('../../config.js');
149
+ const config = getConfig(true);
150
+ expect(config.gcpAutoStop).toBe(true);
151
+ });
152
+ });
153
+ describe('getConfig() - quick check interval', () => {
154
+ it('returns 5 minutes by default', async () => {
155
+ delete process.env.HORIZON_QUICK_CHECK_INTERVAL_MINUTES;
156
+ const { getConfig } = await import('../../config.js');
157
+ const config = getConfig(true);
158
+ expect(config.quickCheckIntervalMinutes).toBe(5);
159
+ });
160
+ it('returns custom value when set', async () => {
161
+ process.env.HORIZON_QUICK_CHECK_INTERVAL_MINUTES = '10';
162
+ const { getConfig } = await import('../../config.js');
163
+ const config = getConfig(true);
164
+ expect(config.quickCheckIntervalMinutes).toBe(10);
165
+ });
166
+ });
167
+ describe('getConfig() - full check interval', () => {
168
+ it('returns 120 minutes by default', async () => {
169
+ delete process.env.HORIZON_FULL_CHECK_INTERVAL_MINUTES;
170
+ const { getConfig } = await import('../../config.js');
171
+ const config = getConfig(true);
172
+ expect(config.fullCheckIntervalMinutes).toBe(120);
173
+ });
174
+ it('returns custom value when set', async () => {
175
+ process.env.HORIZON_FULL_CHECK_INTERVAL_MINUTES = '60';
176
+ const { getConfig } = await import('../../config.js');
177
+ const config = getConfig(true);
178
+ expect(config.fullCheckIntervalMinutes).toBe(60);
179
+ });
180
+ });
181
+ describe('getConfig() - codex reasoning effort', () => {
182
+ it('returns high by default', async () => {
183
+ delete process.env.CODEX_REASONING_EFFORT;
184
+ const { getConfig } = await import('../../config.js');
185
+ const config = getConfig(true);
186
+ expect(config.codexReasoningEffort).toBe('high');
187
+ });
188
+ it('returns low when CODEX_REASONING_EFFORT=low', async () => {
189
+ process.env.CODEX_REASONING_EFFORT = 'low';
190
+ const { getConfig } = await import('../../config.js');
191
+ const config = getConfig(true);
192
+ expect(config.codexReasoningEffort).toBe('low');
193
+ });
194
+ it('returns medium when CODEX_REASONING_EFFORT=medium', async () => {
195
+ process.env.CODEX_REASONING_EFFORT = 'medium';
196
+ const { getConfig } = await import('../../config.js');
197
+ const config = getConfig(true);
198
+ expect(config.codexReasoningEffort).toBe('medium');
199
+ });
200
+ it('returns extra_high when CODEX_REASONING_EFFORT=extra_high', async () => {
201
+ process.env.CODEX_REASONING_EFFORT = 'extra_high';
202
+ const { getConfig } = await import('../../config.js');
203
+ const config = getConfig(true);
204
+ expect(config.codexReasoningEffort).toBe('extra_high');
205
+ });
206
+ });
207
+ describe('getConfig() - per-agent codex reasoning', () => {
208
+ it('uses global default for agent1', async () => {
209
+ process.env.CODEX_REASONING_EFFORT = 'low';
210
+ delete process.env.CODEX_AGENT1_REASONING;
211
+ const { getConfig } = await import('../../config.js');
212
+ const config = getConfig(true);
213
+ expect(config.codexAgentReasoning.agent1).toBe('low');
214
+ });
215
+ it('uses CODEX_AGENT1_REASONING when set', async () => {
216
+ process.env.CODEX_AGENT1_REASONING = 'extra_high';
217
+ const { getConfig } = await import('../../config.js');
218
+ const config = getConfig(true);
219
+ expect(config.codexAgentReasoning.agent1).toBe('extra_high');
220
+ });
221
+ it('agent3 defaults to medium', async () => {
222
+ delete process.env.CODEX_AGENT3_REASONING;
223
+ const { getConfig } = await import('../../config.js');
224
+ const config = getConfig(true);
225
+ expect(config.codexAgentReasoning.agent3).toBe('medium');
226
+ });
227
+ });
228
+ describe('getConfig() - merge mode', () => {
229
+ it('returns "auto" when HORIZON_MERGE_MODE=auto', async () => {
230
+ process.env.HORIZON_MERGE_MODE = 'auto';
231
+ vi.resetModules();
232
+ const { getConfig } = await import('../../config.js');
233
+ const config = getConfig(true);
234
+ expect(config.mergeMode).toBe('auto');
235
+ });
236
+ it('returns "auto" when HORIZON_MERGE_MODE=AUTO (case insensitive)', async () => {
237
+ process.env.HORIZON_MERGE_MODE = 'AUTO';
238
+ vi.resetModules();
239
+ const { getConfig } = await import('../../config.js');
240
+ const config = getConfig(true);
241
+ expect(config.mergeMode).toBe('auto');
242
+ });
243
+ it('returns "merge" when explicitly set', async () => {
244
+ // Explicitly set to merge (overrides .horizon/env file)
245
+ process.env.HORIZON_MERGE_MODE = 'merge';
246
+ vi.resetModules();
247
+ const { getConfig } = await import('../../config.js');
248
+ const config = getConfig(true);
249
+ expect(config.mergeMode).toBe('merge');
250
+ });
251
+ it('returns "pr" when HORIZON_MERGE_MODE=pr', async () => {
252
+ process.env.HORIZON_MERGE_MODE = 'pr';
253
+ vi.resetModules();
254
+ const { getConfig } = await import('../../config.js');
255
+ const config = getConfig(true);
256
+ expect(config.mergeMode).toBe('pr');
257
+ });
258
+ it('returns "pr" when HORIZON_MERGE_MODE=PR (case insensitive)', async () => {
259
+ process.env.HORIZON_MERGE_MODE = 'PR';
260
+ vi.resetModules();
261
+ const { getConfig } = await import('../../config.js');
262
+ const config = getConfig(true);
263
+ expect(config.mergeMode).toBe('pr');
264
+ });
265
+ it('returns "auto" for invalid values', async () => {
266
+ process.env.HORIZON_MERGE_MODE = 'invalid';
267
+ vi.resetModules();
268
+ const { getConfig } = await import('../../config.js');
269
+ const config = getConfig(true);
270
+ expect(config.mergeMode).toBe('auto');
271
+ });
272
+ });
273
+ describe('getConfig() - caching behavior', () => {
274
+ it('returns cached config by default', async () => {
275
+ const { getConfig } = await import('../../config.js');
276
+ const config1 = getConfig();
277
+ const config2 = getConfig();
278
+ expect(config1).toBe(config2);
279
+ });
280
+ it('rebuilds config when reload=true', async () => {
281
+ // Use a different env var to avoid polluting merge mode tests
282
+ const { getConfig } = await import('../../config.js');
283
+ const config1 = getConfig();
284
+ // Change env and reload
285
+ process.env.HORIZON_MAX_ITERATIONS = '99';
286
+ const config2 = getConfig(true);
287
+ expect(config2.maxIterations).toBe(99);
288
+ });
289
+ });
290
+ });
291
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gcp.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcp.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/gcp.test.ts"],"names":[],"mappings":""}