@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,70 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { existsSync, readFileSync } from 'fs';
3
+ // Mock fs module
4
+ vi.mock('fs', () => ({
5
+ existsSync: vi.fn(),
6
+ readFileSync: vi.fn(),
7
+ }));
8
+ // Mock config to avoid side effects
9
+ vi.mock('../../config.js', () => ({
10
+ getRepoRoot: () => '/mock/repo',
11
+ }));
12
+ describe('loadPrompt', () => {
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ });
16
+ it('substitutes template variables', async () => {
17
+ const mockExistsSync = vi.mocked(existsSync);
18
+ const mockReadFileSync = vi.mocked(readFileSync);
19
+ mockExistsSync.mockReturnValue(true);
20
+ mockReadFileSync.mockReturnValue('Hello {{NAME}}, mode is {{MODE}}.');
21
+ const { loadPrompt } = await import('../prompts.js');
22
+ const result = loadPrompt('test', { NAME: 'World', MODE: 'pr' });
23
+ expect(result).toBe('Hello World, mode is pr.');
24
+ });
25
+ it('returns content unchanged when no variables provided', async () => {
26
+ const mockExistsSync = vi.mocked(existsSync);
27
+ const mockReadFileSync = vi.mocked(readFileSync);
28
+ mockExistsSync.mockReturnValue(true);
29
+ mockReadFileSync.mockReturnValue('No variables here.');
30
+ const { loadPrompt } = await import('../prompts.js');
31
+ const result = loadPrompt('test');
32
+ expect(result).toBe('No variables here.');
33
+ });
34
+ it('replaces multiple occurrences of same variable', async () => {
35
+ const mockExistsSync = vi.mocked(existsSync);
36
+ const mockReadFileSync = vi.mocked(readFileSync);
37
+ mockExistsSync.mockReturnValue(true);
38
+ mockReadFileSync.mockReturnValue('{{X}} and {{X}} again.');
39
+ const { loadPrompt } = await import('../prompts.js');
40
+ const result = loadPrompt('test', { X: 'value' });
41
+ expect(result).toBe('value and value again.');
42
+ });
43
+ it('throws error when prompt not found', async () => {
44
+ const mockExistsSync = vi.mocked(existsSync);
45
+ mockExistsSync.mockReturnValue(false);
46
+ const { loadPrompt } = await import('../prompts.js');
47
+ expect(() => loadPrompt('nonexistent')).toThrow('Prompt not found: nonexistent');
48
+ });
49
+ });
50
+ describe('loadPromptFragment', () => {
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ });
54
+ it('loads fragment content from fragments directory', async () => {
55
+ const mockExistsSync = vi.mocked(existsSync);
56
+ const mockReadFileSync = vi.mocked(readFileSync);
57
+ mockExistsSync.mockReturnValue(true);
58
+ mockReadFileSync.mockReturnValue('Fragment content here.');
59
+ const { loadPromptFragment } = await import('../prompts.js');
60
+ const result = loadPromptFragment('merge-direct');
61
+ expect(result).toBe('Fragment content here.');
62
+ });
63
+ it('throws error when fragment not found', async () => {
64
+ const mockExistsSync = vi.mocked(existsSync);
65
+ mockExistsSync.mockReturnValue(false);
66
+ const { loadPromptFragment } = await import('../prompts.js');
67
+ expect(() => loadPromptFragment('nonexistent')).toThrow('Prompt fragment not found: nonexistent');
68
+ });
69
+ });
70
+ //# sourceMappingURL=prompts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/prompts.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/provider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { registerClaudeProvider, registerCodexProvider, createProvider, } from '../provider.js';
3
+ describe('provider module', () => {
4
+ // Create mock providers for testing
5
+ const createMockProvider = (name) => ({
6
+ name,
7
+ spawn: async () => ({
8
+ output: '',
9
+ finalOutput: 'test',
10
+ rateLimited: false,
11
+ cost: 0,
12
+ costEstimated: false,
13
+ duration: 0,
14
+ exitCode: 0,
15
+ tokenUsage: { input: 0, output: 0, cached: 0 },
16
+ }),
17
+ });
18
+ describe('registerClaudeProvider()', () => {
19
+ it('registers factory function', () => {
20
+ const mockClaudeProvider = createMockProvider('claude');
21
+ registerClaudeProvider(() => mockClaudeProvider);
22
+ const provider = createProvider('claude');
23
+ expect(provider.name).toBe('claude');
24
+ });
25
+ it('allows re-registration', () => {
26
+ const mockProvider1 = createMockProvider('claude');
27
+ const mockProvider2 = { ...createMockProvider('claude'), customField: 'test' };
28
+ registerClaudeProvider(() => mockProvider1);
29
+ registerClaudeProvider(() => mockProvider2);
30
+ const provider = createProvider('claude');
31
+ expect(provider.name).toBe('claude');
32
+ });
33
+ });
34
+ describe('registerCodexProvider()', () => {
35
+ it('registers factory function', () => {
36
+ const mockCodexProvider = createMockProvider('codex');
37
+ registerCodexProvider(() => mockCodexProvider);
38
+ const provider = createProvider('codex');
39
+ expect(provider.name).toBe('codex');
40
+ });
41
+ it('allows re-registration', () => {
42
+ const mockProvider1 = createMockProvider('codex');
43
+ const mockProvider2 = { ...createMockProvider('codex'), customField: 'test' };
44
+ registerCodexProvider(() => mockProvider1);
45
+ registerCodexProvider(() => mockProvider2);
46
+ const provider = createProvider('codex');
47
+ expect(provider.name).toBe('codex');
48
+ });
49
+ });
50
+ describe('createProvider()', () => {
51
+ beforeEach(() => {
52
+ // Register both providers for these tests
53
+ registerClaudeProvider(() => createMockProvider('claude'));
54
+ registerCodexProvider(() => createMockProvider('codex'));
55
+ });
56
+ it('returns Claude provider when registered', () => {
57
+ const provider = createProvider('claude');
58
+ expect(provider.name).toBe('claude');
59
+ expect(typeof provider.spawn).toBe('function');
60
+ });
61
+ it('returns Codex provider when registered', () => {
62
+ const provider = createProvider('codex');
63
+ expect(provider.name).toBe('codex');
64
+ expect(typeof provider.spawn).toBe('function');
65
+ });
66
+ it('throws for unknown provider name', () => {
67
+ expect(() => createProvider('unknown')).toThrow('Unknown provider: unknown');
68
+ });
69
+ it('creates new provider instance on each call', () => {
70
+ const provider1 = createProvider('claude');
71
+ const provider2 = createProvider('claude');
72
+ // Each call should create a new provider instance (factory pattern)
73
+ expect(provider1).not.toBe(provider2);
74
+ });
75
+ it('provider spawn returns expected result structure', async () => {
76
+ const provider = createProvider('claude');
77
+ const result = await provider.spawn({ prompt: 'test' });
78
+ expect(result).toHaveProperty('output');
79
+ expect(result).toHaveProperty('finalOutput');
80
+ expect(result).toHaveProperty('rateLimited');
81
+ expect(result).toHaveProperty('cost');
82
+ expect(result).toHaveProperty('tokenUsage');
83
+ expect(result.tokenUsage).toHaveProperty('input');
84
+ expect(result.tokenUsage).toHaveProperty('output');
85
+ expect(result.tokenUsage).toHaveProperty('cached');
86
+ });
87
+ });
88
+ });
89
+ //# sourceMappingURL=provider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/provider.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAM,MAAM,QAAQ,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,cAAc,GAGf,MAAM,gBAAgB,CAAC;AAExB,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,oCAAoC;IACpC,MAAM,kBAAkB,GAAG,CAAC,IAAkB,EAAe,EAAE,CAAC,CAAC;QAC/D,IAAI;QACJ,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YAClB,MAAM,EAAE,EAAE;YACV,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,KAAK;YAClB,IAAI,EAAE,CAAC;YACP,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;SAC/C,CAAC;KACH,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YACxD,sBAAsB,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;YAChC,MAAM,aAAa,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,aAAa,GAAG,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YAE/E,sBAAsB,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;YAC5C,sBAAsB,CAAC,GAAG,EAAE,CAAC,aAAuC,CAAC,CAAC;YAEtE,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACvC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACtD,qBAAqB,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC;YAE/C,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;YAChC,MAAM,aAAa,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,aAAa,GAAG,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YAE9E,qBAAqB,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;YAC3C,qBAAqB,CAAC,GAAG,EAAE,CAAC,aAAuC,CAAC,CAAC;YAErE,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,UAAU,CAAC,GAAG,EAAE;YACd,0CAA0C;YAC1C,sBAAsB,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3D,qBAAqB,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,SAAyB,CAAC,CAAC,CAAC,OAAO,CAC7D,2BAA2B,CAC5B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAE3C,oEAAoE;YACpE,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YAExD,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rate-limit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/rate-limit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,275 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { sleep, parseRateLimitReset, isRateLimitError, handleRateLimit, executeWithRateLimitRetry, } from '../rate-limit.js';
3
+ describe('rate-limit module', () => {
4
+ beforeEach(() => {
5
+ vi.useFakeTimers();
6
+ });
7
+ afterEach(() => {
8
+ vi.useRealTimers();
9
+ });
10
+ describe('sleep()', () => {
11
+ it('returns a promise that resolves after specified time', async () => {
12
+ const sleepPromise = sleep(1000);
13
+ vi.advanceTimersByTime(1000);
14
+ await expect(sleepPromise).resolves.toBeUndefined();
15
+ });
16
+ it('does not resolve before specified time', async () => {
17
+ let resolved = false;
18
+ sleep(1000).then(() => {
19
+ resolved = true;
20
+ });
21
+ vi.advanceTimersByTime(500);
22
+ expect(resolved).toBe(false);
23
+ vi.advanceTimersByTime(500);
24
+ await Promise.resolve(); // flush microtasks
25
+ expect(resolved).toBe(true);
26
+ });
27
+ });
28
+ describe('parseRateLimitReset()', () => {
29
+ it('parses "resets at 10:30 am (PST)" format', () => {
30
+ // Set system time to 10:00 AM PST (18:00 UTC) on a specific date
31
+ const now = new Date('2026-01-15T18:00:00.000Z');
32
+ vi.setSystemTime(now);
33
+ const result = parseRateLimitReset('Rate limit resets at 10:30 am (PST)');
34
+ // 10:30 AM PST = 18:30 UTC, which is 30 minutes from now + 1 minute buffer
35
+ expect(result).toBeGreaterThan(30 * 60 * 1000);
36
+ expect(result).toBeLessThan(32 * 60 * 1000);
37
+ });
38
+ it('parses "resets 12am (America/Los_Angeles)" format', () => {
39
+ // Set system time to 11:00 PM PST (07:00 UTC next day) on a specific date
40
+ const now = new Date('2026-01-15T07:00:00.000Z');
41
+ vi.setSystemTime(now);
42
+ const result = parseRateLimitReset('Your limit resets 12am (America/Los_Angeles)');
43
+ // 12:00 AM PST = 08:00 UTC, which is 1 hour from now + 1 minute buffer
44
+ expect(result).toBeGreaterThan(60 * 60 * 1000);
45
+ expect(result).toBeLessThan(62 * 60 * 1000);
46
+ });
47
+ it('handles 12-hour time with PM', () => {
48
+ const now = new Date('2026-01-15T18:00:00.000Z'); // 10:00 AM PST
49
+ vi.setSystemTime(now);
50
+ const result = parseRateLimitReset('Rate limit resets at 2:30 pm (PST)');
51
+ // 2:30 PM PST = 22:30 UTC, which is 4.5 hours from now
52
+ expect(result).toBeGreaterThan(4 * 60 * 60 * 1000);
53
+ expect(result).toBeLessThan(5 * 60 * 60 * 1000);
54
+ });
55
+ it('handles 12-hour time with AM (midnight case)', () => {
56
+ const now = new Date('2026-01-15T07:00:00.000Z'); // 11:00 PM PST
57
+ vi.setSystemTime(now);
58
+ const result = parseRateLimitReset('resets at 12:00 am (PST)');
59
+ // 12:00 AM PST = 08:00 UTC next day
60
+ expect(result).toBeGreaterThan(60 * 60 * 1000);
61
+ });
62
+ it('returns time in the future (rolls to next day if past)', () => {
63
+ // Set time to 11:00 AM PST (19:00 UTC)
64
+ const now = new Date('2026-01-15T19:00:00.000Z');
65
+ vi.setSystemTime(now);
66
+ const result = parseRateLimitReset('Rate limit resets at 10:30 am (PST)');
67
+ // 10:30 AM is in the past today, so should roll to tomorrow
68
+ // That's about 23.5 hours from now
69
+ expect(result).toBeGreaterThan(23 * 60 * 60 * 1000);
70
+ expect(result).toBeLessThan(24 * 60 * 60 * 1000);
71
+ });
72
+ it('handles string input', () => {
73
+ const now = new Date('2026-01-15T18:00:00.000Z');
74
+ vi.setSystemTime(now);
75
+ const result = parseRateLimitReset('Rate limit resets at 10:30 am (PST)');
76
+ expect(result).toBeGreaterThan(30 * 60 * 1000);
77
+ });
78
+ it('handles object input with `result` field', () => {
79
+ const now = new Date('2026-01-15T18:00:00.000Z');
80
+ vi.setSystemTime(now);
81
+ const result = parseRateLimitReset({
82
+ result: 'Rate limit resets at 10:30 am (PST)',
83
+ });
84
+ expect(result).toBeGreaterThan(30 * 60 * 1000);
85
+ });
86
+ it('handles object input with nested `message.content[0].text`', () => {
87
+ const now = new Date('2026-01-15T18:00:00.000Z');
88
+ vi.setSystemTime(now);
89
+ const result = parseRateLimitReset({
90
+ message: {
91
+ content: [{ text: 'Rate limit resets at 10:30 am (PST)' }],
92
+ },
93
+ });
94
+ expect(result).toBeGreaterThan(30 * 60 * 1000);
95
+ });
96
+ it('returns default 5 minutes when no match', () => {
97
+ const result = parseRateLimitReset('Some unrelated error message');
98
+ expect(result).toBe(5 * 60 * 1000);
99
+ });
100
+ it('adds 1-minute buffer to calculated time', () => {
101
+ // Set time to exactly 10:00 AM PST (18:00 UTC)
102
+ const now = new Date('2026-01-15T18:00:00.000Z');
103
+ vi.setSystemTime(now);
104
+ const result = parseRateLimitReset('Rate limit resets at 10:30 am (PST)');
105
+ // 10:30 AM PST = 18:30 UTC = 30 minutes from now
106
+ // With 1 minute buffer = 31 minutes
107
+ expect(result).toBe(31 * 60 * 1000);
108
+ });
109
+ });
110
+ describe('isRateLimitError()', () => {
111
+ it('detects "rate limit" (case insensitive)', () => {
112
+ expect(isRateLimitError('You have hit a rate limit')).toBe(true);
113
+ expect(isRateLimitError('RATE LIMIT exceeded')).toBe(true);
114
+ expect(isRateLimitError('rate-limit error')).toBe(true);
115
+ });
116
+ it('detects "too many requests"', () => {
117
+ expect(isRateLimitError('Error: Too many requests')).toBe(true);
118
+ expect(isRateLimitError('too many requests, please slow down')).toBe(true);
119
+ });
120
+ it('detects "quota exceeded"', () => {
121
+ expect(isRateLimitError('Your API quota exceeded')).toBe(true);
122
+ expect(isRateLimitError('Quota Exceeded')).toBe(true);
123
+ });
124
+ it('detects "usage limit"', () => {
125
+ expect(isRateLimitError('You hit your usage limit')).toBe(true);
126
+ expect(isRateLimitError('usage_limit reached')).toBe(true);
127
+ });
128
+ it('detects "hit your limit" (Claude-specific)', () => {
129
+ expect(isRateLimitError("You've hit your limit for today")).toBe(true);
130
+ expect(isRateLimitError('hit your limit')).toBe(true);
131
+ });
132
+ it('detects "RateLimitError" (Codex-specific)', () => {
133
+ expect(isRateLimitError('RateLimitError: API rate limit reached')).toBe(true);
134
+ });
135
+ it('detects "request limit reached"', () => {
136
+ expect(isRateLimitError('Request limit reached for the day')).toBe(true);
137
+ });
138
+ it('returns false for non-rate-limit errors', () => {
139
+ expect(isRateLimitError('Connection timeout')).toBe(false);
140
+ expect(isRateLimitError('Internal server error')).toBe(false);
141
+ expect(isRateLimitError('Authentication failed')).toBe(false);
142
+ expect(isRateLimitError('File not found')).toBe(false);
143
+ });
144
+ });
145
+ describe('handleRateLimit()', () => {
146
+ it('logs the wait time in minutes', async () => {
147
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
148
+ const handlePromise = handleRateLimit(3 * 60 * 1000);
149
+ vi.advanceTimersByTime(3 * 60 * 1000);
150
+ await handlePromise;
151
+ expect(consoleSpy).toHaveBeenCalledWith('Rate limited. Sleeping 3 minute(s)...');
152
+ consoleSpy.mockRestore();
153
+ });
154
+ it('calls sleep with correct duration', async () => {
155
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
156
+ const waitMs = 2 * 60 * 1000;
157
+ const handlePromise = handleRateLimit(waitMs);
158
+ // Verify it waits the full duration
159
+ vi.advanceTimersByTime(waitMs - 1);
160
+ // Promise should still be pending - we can't directly check this, but we can
161
+ // verify by advancing the remaining time and seeing it resolves
162
+ vi.advanceTimersByTime(1);
163
+ await handlePromise;
164
+ consoleSpy.mockRestore();
165
+ });
166
+ });
167
+ describe('executeWithRateLimitRetry()', () => {
168
+ it('returns immediately if not rate limited', async () => {
169
+ const operation = vi.fn().mockResolvedValue({
170
+ rateLimited: false,
171
+ data: 'success',
172
+ });
173
+ const config = { maxRetries: 3 };
174
+ const result = await executeWithRateLimitRetry(operation, config, 'Test Agent');
175
+ expect(result.rateLimited).toBe(false);
176
+ expect(operation).toHaveBeenCalledTimes(1);
177
+ });
178
+ it('retries on rate limit up to maxRetries', async () => {
179
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
180
+ let callCount = 0;
181
+ const operation = vi.fn().mockImplementation(async () => {
182
+ callCount++;
183
+ if (callCount < 3) {
184
+ return {
185
+ rateLimited: true,
186
+ retryAfterMs: 60000, // 1 minute
187
+ };
188
+ }
189
+ return { rateLimited: false };
190
+ });
191
+ const config = { maxRetries: 3 };
192
+ const resultPromise = executeWithRateLimitRetry(operation, config, 'Test Agent');
193
+ // Use runAllTimersAsync to properly handle all timers and async operations
194
+ await vi.runAllTimersAsync();
195
+ const result = await resultPromise;
196
+ expect(result.rateLimited).toBe(false);
197
+ expect(operation).toHaveBeenCalledTimes(3);
198
+ consoleSpy.mockRestore();
199
+ });
200
+ it('returns after maxRetries exceeded', async () => {
201
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
202
+ const operation = vi.fn().mockResolvedValue({
203
+ rateLimited: true,
204
+ retryAfterMs: 60000,
205
+ });
206
+ const config = { maxRetries: 2 };
207
+ const resultPromise = executeWithRateLimitRetry(operation, config, 'Test Agent');
208
+ // First call - rate limited (attempt 1)
209
+ await Promise.resolve();
210
+ vi.advanceTimersByTime(60000);
211
+ // Second call - rate limited (attempt 2 = maxRetries)
212
+ await Promise.resolve();
213
+ const result = await resultPromise;
214
+ expect(result.rateLimited).toBe(true);
215
+ expect(operation).toHaveBeenCalledTimes(2);
216
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('max retries reached'));
217
+ consoleSpy.mockRestore();
218
+ });
219
+ it('uses retryAfterMs from result', async () => {
220
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
221
+ let callCount = 0;
222
+ const operation = vi.fn().mockImplementation(async () => {
223
+ callCount++;
224
+ if (callCount === 1) {
225
+ return {
226
+ rateLimited: true,
227
+ retryAfterMs: 120000, // 2 minutes
228
+ };
229
+ }
230
+ return { rateLimited: false };
231
+ });
232
+ const config = { maxRetries: 3 };
233
+ const resultPromise = executeWithRateLimitRetry(operation, config, 'Test Agent');
234
+ // First call - rate limited with 2 minute wait
235
+ await Promise.resolve();
236
+ // Should not proceed before 2 minutes
237
+ vi.advanceTimersByTime(60000);
238
+ expect(operation).toHaveBeenCalledTimes(1);
239
+ // Advance remaining time
240
+ vi.advanceTimersByTime(60000);
241
+ const result = await resultPromise;
242
+ expect(result.rateLimited).toBe(false);
243
+ expect(operation).toHaveBeenCalledTimes(2);
244
+ consoleSpy.mockRestore();
245
+ });
246
+ it('defaults to 5 minutes if no retryAfterMs', async () => {
247
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
248
+ let callCount = 0;
249
+ const operation = vi.fn().mockImplementation(async () => {
250
+ callCount++;
251
+ if (callCount === 1) {
252
+ return {
253
+ rateLimited: true,
254
+ // No retryAfterMs
255
+ };
256
+ }
257
+ return { rateLimited: false };
258
+ });
259
+ const config = { maxRetries: 3 };
260
+ const resultPromise = executeWithRateLimitRetry(operation, config, 'Test Agent');
261
+ // First call - rate limited with default 5 minute wait
262
+ await Promise.resolve();
263
+ // Should not proceed before 5 minutes
264
+ vi.advanceTimersByTime(4 * 60 * 1000);
265
+ expect(operation).toHaveBeenCalledTimes(1);
266
+ // Advance remaining time
267
+ vi.advanceTimersByTime(60000);
268
+ const result = await resultPromise;
269
+ expect(result.rateLimited).toBe(false);
270
+ expect(operation).toHaveBeenCalledTimes(2);
271
+ consoleSpy.mockRestore();
272
+ });
273
+ });
274
+ });
275
+ //# sourceMappingURL=rate-limit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/rate-limit.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=readline.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readline.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/readline.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ let answers = [];
3
+ const closeMock = vi.fn();
4
+ const createInterfaceMock = vi.fn(() => ({
5
+ question: (question, cb) => {
6
+ cb(answers.shift() ?? '');
7
+ },
8
+ close: closeMock,
9
+ }));
10
+ vi.mock('readline', () => ({
11
+ createInterface: createInterfaceMock,
12
+ }));
13
+ describe('readline helpers', () => {
14
+ beforeEach(() => {
15
+ vi.resetModules();
16
+ vi.clearAllMocks();
17
+ answers = [];
18
+ });
19
+ afterEach(() => {
20
+ vi.unstubAllGlobals();
21
+ });
22
+ it('prompt() trims input and closes the interface', async () => {
23
+ answers.push(' hello ');
24
+ const { prompt } = await import('../readline.js');
25
+ await expect(prompt('Question: ')).resolves.toBe('hello');
26
+ expect(createInterfaceMock).toHaveBeenCalledTimes(1);
27
+ expect(closeMock).toHaveBeenCalledTimes(1);
28
+ });
29
+ it('confirm() returns true for y/yes (case-insensitive)', async () => {
30
+ const { confirm } = await import('../readline.js');
31
+ answers.push('Y');
32
+ await expect(confirm('Proceed?')).resolves.toBe(true);
33
+ answers.push(' yes ');
34
+ await expect(confirm('Proceed?')).resolves.toBe(true);
35
+ });
36
+ it('confirm() returns false for other values', async () => {
37
+ const { confirm } = await import('../readline.js');
38
+ answers.push('n');
39
+ await expect(confirm('Proceed?')).resolves.toBe(false);
40
+ answers.push('nope');
41
+ await expect(confirm('Proceed?')).resolves.toBe(false);
42
+ });
43
+ it('selectFromList() retries on invalid input and returns the selected option', async () => {
44
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
45
+ // invalid -> valid (select option #2)
46
+ answers.push('0');
47
+ answers.push('2');
48
+ const { selectFromList } = await import('../readline.js');
49
+ await expect(selectFromList('Pick one:', ['a', 'b', 'c'])).resolves.toBe('b');
50
+ const combined = logSpy.mock.calls.map(([line]) => String(line)).join('\n');
51
+ expect(combined).toContain('Invalid selection. Please try again.');
52
+ expect(closeMock).toHaveBeenCalledTimes(2);
53
+ });
54
+ });
55
+ //# sourceMappingURL=readline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readline.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/readline.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stats-logger.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-logger.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/stats-logger.test.ts"],"names":[],"mappings":""}