@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,258 @@
1
+ import { writeFile, readFile, mkdir } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { getConfig } from '../config.js';
5
+ // Track current context
6
+ let currentPodName = null;
7
+ let currentLoopNumber = null;
8
+ let currentLoopStartTime = null;
9
+ /**
10
+ * Gets the stats file path for the current pod
11
+ * Structure: .horizon/output/{pod-name}/stats.json
12
+ */
13
+ function getStatsFilePath() {
14
+ if (!currentPodName) {
15
+ return null;
16
+ }
17
+ const config = getConfig();
18
+ const outputDir = join(config.workingDirectory, '.horizon', 'output');
19
+ return join(outputDir, currentPodName, 'stats.json');
20
+ }
21
+ /**
22
+ * Ensures the directory structure exists for a given file path
23
+ */
24
+ async function ensureDir(filePath) {
25
+ const dir = filePath.substring(0, filePath.lastIndexOf('/'));
26
+ if (!existsSync(dir)) {
27
+ await mkdir(dir, { recursive: true });
28
+ }
29
+ }
30
+ /**
31
+ * Reads existing stats or creates initial structure
32
+ */
33
+ async function readOrCreateStats() {
34
+ const statsPath = getStatsFilePath();
35
+ if (!statsPath || !currentPodName) {
36
+ return null;
37
+ }
38
+ try {
39
+ if (existsSync(statsPath)) {
40
+ const content = await readFile(statsPath, 'utf-8');
41
+ return JSON.parse(content);
42
+ }
43
+ }
44
+ catch {
45
+ // File doesn't exist or is corrupted, create new
46
+ }
47
+ // Create initial stats structure
48
+ return {
49
+ podName: currentPodName,
50
+ startedAt: new Date().toISOString(),
51
+ updatedAt: new Date().toISOString(),
52
+ loops: [],
53
+ grandTotals: {
54
+ loopCount: 0,
55
+ tokens: { input: 0, output: 0, cached: 0 },
56
+ cost: 0,
57
+ costEstimated: false,
58
+ durationSeconds: 0,
59
+ },
60
+ };
61
+ }
62
+ /**
63
+ * Writes stats to file
64
+ */
65
+ async function writeStats(stats) {
66
+ const statsPath = getStatsFilePath();
67
+ if (!statsPath) {
68
+ return;
69
+ }
70
+ try {
71
+ await ensureDir(statsPath);
72
+ stats.updatedAt = new Date().toISOString();
73
+ await writeFile(statsPath, JSON.stringify(stats, null, 2), 'utf-8');
74
+ }
75
+ catch (error) {
76
+ // Silently fail - stats logging should not interrupt main process
77
+ console.error('Failed to write stats:', error);
78
+ }
79
+ }
80
+ /**
81
+ * Initializes stats tracking for a new loop iteration
82
+ * Should be called at the start of each loop
83
+ * @param podName - The pod name (e.g., "calm-pegasus")
84
+ * @param loopNumber - The loop iteration number (0, 1, 2, ...)
85
+ */
86
+ export function initLoopStats(podName, loopNumber) {
87
+ currentPodName = podName;
88
+ currentLoopNumber = loopNumber;
89
+ currentLoopStartTime = new Date();
90
+ }
91
+ /**
92
+ * Gets the current loop from stats, creating it if needed
93
+ */
94
+ function getOrCreateCurrentLoop(stats) {
95
+ if (currentLoopNumber === null || !currentPodName || !currentLoopStartTime) {
96
+ throw new Error('Loop stats not initialized');
97
+ }
98
+ let loop = stats.loops.find(l => l.loopNumber === currentLoopNumber);
99
+ if (!loop) {
100
+ loop = {
101
+ loopNumber: currentLoopNumber,
102
+ podName: currentPodName,
103
+ startedAt: currentLoopStartTime.toISOString(),
104
+ agents: [],
105
+ totals: {
106
+ tokens: { input: 0, output: 0, cached: 0 },
107
+ cost: 0,
108
+ costEstimated: false,
109
+ durationSeconds: 0,
110
+ },
111
+ };
112
+ stats.loops.push(loop);
113
+ stats.grandTotals.loopCount = stats.loops.length;
114
+ }
115
+ return loop;
116
+ }
117
+ /**
118
+ * Recalculates loop totals from agent stats
119
+ */
120
+ function recalculateLoopTotals(loop) {
121
+ loop.totals = {
122
+ tokens: { input: 0, output: 0, cached: 0 },
123
+ cost: 0,
124
+ costEstimated: false,
125
+ durationSeconds: 0,
126
+ };
127
+ for (const agent of loop.agents) {
128
+ loop.totals.tokens.input += agent.tokens.input;
129
+ loop.totals.tokens.output += agent.tokens.output;
130
+ loop.totals.tokens.cached += agent.tokens.cached;
131
+ loop.totals.cost += agent.cost;
132
+ loop.totals.durationSeconds += agent.durationSeconds;
133
+ if (agent.costEstimated) {
134
+ loop.totals.costEstimated = true;
135
+ }
136
+ }
137
+ }
138
+ /**
139
+ * Recalculates grand totals from all loops
140
+ */
141
+ function recalculateGrandTotals(stats) {
142
+ stats.grandTotals = {
143
+ loopCount: stats.loops.length,
144
+ tokens: { input: 0, output: 0, cached: 0 },
145
+ cost: 0,
146
+ costEstimated: false,
147
+ durationSeconds: 0,
148
+ };
149
+ for (const loop of stats.loops) {
150
+ stats.grandTotals.tokens.input += loop.totals.tokens.input;
151
+ stats.grandTotals.tokens.output += loop.totals.tokens.output;
152
+ stats.grandTotals.tokens.cached += loop.totals.tokens.cached;
153
+ stats.grandTotals.cost += loop.totals.cost;
154
+ stats.grandTotals.durationSeconds += loop.totals.durationSeconds;
155
+ if (loop.totals.costEstimated) {
156
+ stats.grandTotals.costEstimated = true;
157
+ }
158
+ }
159
+ }
160
+ /**
161
+ * Agent name mapping
162
+ */
163
+ const AGENT_NAMES = {
164
+ 1: 'Linear Reader',
165
+ 2: 'Worker',
166
+ 3: 'Linear Writer',
167
+ };
168
+ /**
169
+ * Logs stats for a completed agent run
170
+ * Should be called after each agent finishes
171
+ */
172
+ export async function logAgentStats(agentNumber, provider, model, result) {
173
+ const stats = await readOrCreateStats();
174
+ if (!stats) {
175
+ return;
176
+ }
177
+ const loop = getOrCreateCurrentLoop(stats);
178
+ // Extract max context % and compaction count from raw output
179
+ const { maxContextPercent, compactionCount } = parseContextMetrics(result.output);
180
+ const agentStats = {
181
+ agentNumber,
182
+ agentName: AGENT_NAMES[agentNumber] || `Agent ${agentNumber}`,
183
+ provider,
184
+ model,
185
+ tokens: {
186
+ input: result.tokenUsage.input,
187
+ output: result.tokenUsage.output,
188
+ cached: result.tokenUsage.cached,
189
+ },
190
+ cost: result.cost,
191
+ costEstimated: result.costEstimated,
192
+ maxContextWindowPercent: maxContextPercent,
193
+ compactionCount,
194
+ durationSeconds: Math.round(result.duration / 1000),
195
+ exitCode: result.exitCode,
196
+ rateLimited: result.rateLimited,
197
+ completedAt: new Date().toISOString(),
198
+ };
199
+ // Remove existing stats for this agent number (in case of retry)
200
+ loop.agents = loop.agents.filter(a => a.agentNumber !== agentNumber);
201
+ loop.agents.push(agentStats);
202
+ // Sort by agent number
203
+ loop.agents.sort((a, b) => a.agentNumber - b.agentNumber);
204
+ // Recalculate totals
205
+ recalculateLoopTotals(loop);
206
+ recalculateGrandTotals(stats);
207
+ await writeStats(stats);
208
+ }
209
+ /**
210
+ * Marks the current loop as completed
211
+ * Should be called at the end of each loop
212
+ */
213
+ export async function finalizeLoopStats() {
214
+ const stats = await readOrCreateStats();
215
+ if (!stats || currentLoopNumber === null) {
216
+ return;
217
+ }
218
+ const loop = stats.loops.find(l => l.loopNumber === currentLoopNumber);
219
+ if (loop) {
220
+ loop.completedAt = new Date().toISOString();
221
+ await writeStats(stats);
222
+ }
223
+ }
224
+ /**
225
+ * Parses raw streaming output to extract context metrics
226
+ * - maxContextPercent: highest context window usage seen
227
+ * - compactionCount: number of compact_boundary events
228
+ */
229
+ function parseContextMetrics(rawOutput) {
230
+ let maxContextPercent = 0;
231
+ let compactionCount = 0;
232
+ const lines = rawOutput.split('\n');
233
+ for (const line of lines) {
234
+ if (!line.trim())
235
+ continue;
236
+ try {
237
+ const json = JSON.parse(line);
238
+ // Count compaction events
239
+ if (json.type === 'system' && json.subtype === 'compact_boundary') {
240
+ compactionCount++;
241
+ }
242
+ // Track max context usage from assistant messages
243
+ if (json.type === 'assistant' && json.message?.usage) {
244
+ const usage = json.message.usage;
245
+ const total = (usage.cache_creation_input_tokens || 0) + (usage.cache_read_input_tokens || 0);
246
+ const pct = Math.floor((total * 100) / 168000); // 168K effective limit
247
+ if (pct > maxContextPercent) {
248
+ maxContextPercent = pct;
249
+ }
250
+ }
251
+ }
252
+ catch {
253
+ // Not JSON, skip
254
+ }
255
+ }
256
+ return { maxContextPercent, compactionCount };
257
+ }
258
+ //# sourceMappingURL=stats-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-logger.js","sourceRoot":"","sources":["../../src/lib/stats-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface UpdateCheckResult {
2
+ currentVersion: string;
3
+ latestVersion: string | null;
4
+ updateAvailable: boolean;
5
+ }
6
+ /**
7
+ * Checks for available updates.
8
+ * Uses a 24-hour cache to avoid excessive network requests.
9
+ * Returns the current and latest versions, and whether an update is available.
10
+ */
11
+ export declare function checkForUpdates(): Promise<UpdateCheckResult>;
12
+ /**
13
+ * Displays an update notification if an update is available.
14
+ * This is designed to be non-intrusive - just a simple message in yellow.
15
+ */
16
+ export declare function displayUpdateNotification(result: UpdateCheckResult): void;
17
+ //# sourceMappingURL=update-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-checker.d.ts","sourceRoot":"","sources":["../../src/lib/update-checker.ts"],"names":[],"mappings":"AAoGA,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAgClE;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAWzE"}
@@ -0,0 +1,140 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ import { getVersion, getPackageName } from './version.js';
5
+ const CACHE_DIR = join(homedir(), '.horizon');
6
+ const CACHE_FILE = join(CACHE_DIR, 'update-check.json');
7
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
8
+ /**
9
+ * Reads the cached update check result.
10
+ */
11
+ function readCache() {
12
+ try {
13
+ if (!existsSync(CACHE_FILE)) {
14
+ return null;
15
+ }
16
+ const data = readFileSync(CACHE_FILE, 'utf-8');
17
+ return JSON.parse(data);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ /**
24
+ * Writes the update check result to cache.
25
+ */
26
+ function writeCache(cache) {
27
+ try {
28
+ if (!existsSync(CACHE_DIR)) {
29
+ mkdirSync(CACHE_DIR, { recursive: true });
30
+ }
31
+ writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
32
+ }
33
+ catch {
34
+ // Ignore cache write errors
35
+ }
36
+ }
37
+ /**
38
+ * Fetches the latest version from npm registry.
39
+ * Returns null if the fetch fails.
40
+ */
41
+ async function fetchLatestVersion() {
42
+ const packageName = getPackageName();
43
+ const registryUrl = `https://registry.npmjs.org/${packageName}/latest`;
44
+ try {
45
+ const controller = new AbortController();
46
+ const timeout = setTimeout(() => controller.abort(), 5000); // 5 second timeout
47
+ const response = await fetch(registryUrl, {
48
+ signal: controller.signal,
49
+ headers: {
50
+ Accept: 'application/json',
51
+ },
52
+ });
53
+ clearTimeout(timeout);
54
+ if (!response.ok) {
55
+ return null;
56
+ }
57
+ const data = await response.json();
58
+ return data.version || null;
59
+ }
60
+ catch {
61
+ // Network error, timeout, or parsing error
62
+ return null;
63
+ }
64
+ }
65
+ /**
66
+ * Compares two semver versions.
67
+ * Returns true if version2 is greater than version1.
68
+ */
69
+ function isNewerVersion(current, latest) {
70
+ const parseVersion = (v) => {
71
+ const parts = v.replace(/^v/, '').split('.').map(Number);
72
+ return {
73
+ major: parts[0] || 0,
74
+ minor: parts[1] || 0,
75
+ patch: parts[2] || 0,
76
+ };
77
+ };
78
+ const c = parseVersion(current);
79
+ const l = parseVersion(latest);
80
+ if (l.major > c.major)
81
+ return true;
82
+ if (l.major < c.major)
83
+ return false;
84
+ if (l.minor > c.minor)
85
+ return true;
86
+ if (l.minor < c.minor)
87
+ return false;
88
+ return l.patch > c.patch;
89
+ }
90
+ /**
91
+ * Checks for available updates.
92
+ * Uses a 24-hour cache to avoid excessive network requests.
93
+ * Returns the current and latest versions, and whether an update is available.
94
+ */
95
+ export async function checkForUpdates() {
96
+ const currentVersion = getVersion();
97
+ // Check cache first
98
+ const cache = readCache();
99
+ const now = Date.now();
100
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
101
+ // Use cached result
102
+ return {
103
+ currentVersion,
104
+ latestVersion: cache.latestVersion,
105
+ updateAvailable: cache.latestVersion
106
+ ? isNewerVersion(currentVersion, cache.latestVersion)
107
+ : false,
108
+ };
109
+ }
110
+ // Fetch from npm registry (non-blocking, with timeout)
111
+ const latestVersion = await fetchLatestVersion();
112
+ // Update cache
113
+ writeCache({
114
+ lastCheck: now,
115
+ latestVersion,
116
+ });
117
+ return {
118
+ currentVersion,
119
+ latestVersion,
120
+ updateAvailable: latestVersion ? isNewerVersion(currentVersion, latestVersion) : false,
121
+ };
122
+ }
123
+ // ANSI color codes
124
+ const yellow = '\x1b[33m';
125
+ const reset = '\x1b[0m';
126
+ /**
127
+ * Displays an update notification if an update is available.
128
+ * This is designed to be non-intrusive - just a simple message in yellow.
129
+ */
130
+ export function displayUpdateNotification(result) {
131
+ if (!result.updateAvailable || !result.latestVersion) {
132
+ return;
133
+ }
134
+ const packageName = getPackageName();
135
+ console.log('');
136
+ console.log(`${yellow} Update available: ${result.currentVersion} → ${result.latestVersion}`);
137
+ console.log(` Run: npm install -g ${packageName}@latest${reset}`);
138
+ console.log('');
139
+ }
140
+ //# sourceMappingURL=update-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-checker.js","sourceRoot":"","sources":["../../src/lib/update-checker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Gets the current version from package.json.
3
+ * Reads from the installed package location, not cwd.
4
+ */
5
+ export declare function getVersion(): string;
6
+ /**
7
+ * Gets the package name from package.json.
8
+ */
9
+ export declare function getPackageName(): string;
10
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAanC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAUvC"}
@@ -0,0 +1,37 @@
1
+ import { readFileSync } from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ import { dirname, join } from 'path';
4
+ /**
5
+ * Gets the current version from package.json.
6
+ * Reads from the installed package location, not cwd.
7
+ */
8
+ export function getVersion() {
9
+ try {
10
+ // Get the directory of this module (installed package location)
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ // Navigate up from dist/lib/ to package root
14
+ const packageJsonPath = join(__dirname, '..', '..', 'package.json');
15
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
16
+ return packageJson.version;
17
+ }
18
+ catch {
19
+ return 'unknown';
20
+ }
21
+ }
22
+ /**
23
+ * Gets the package name from package.json.
24
+ */
25
+ export function getPackageName() {
26
+ try {
27
+ const __filename = fileURLToPath(import.meta.url);
28
+ const __dirname = dirname(__filename);
29
+ const packageJsonPath = join(__dirname, '..', '..', 'package.json');
30
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
31
+ return packageJson.name;
32
+ }
33
+ catch {
34
+ return '@ob1-sg/horizon';
35
+ }
36
+ }
37
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,gEAAgE;QAChE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAEtC,6CAA6C;QAC7C,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QACvE,OAAO,WAAW,CAAC,OAAO,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QACvE,OAAO,WAAW,CAAC,IAAI,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,iBAAiB,CAAC;IAC3B,CAAC;AACH,CAAC"}
@@ -0,0 +1,92 @@
1
+ export type ProviderName = 'claude' | 'codex';
2
+ export type ClaudeModel = 'opus' | 'sonnet' | 'haiku';
3
+ export type CodexReasoningEffort = 'low' | 'medium' | 'high' | 'extra_high';
4
+ export type MergeMode = 'auto' | 'merge' | 'pr';
5
+ export interface ClaudeOptions {
6
+ prompt: string;
7
+ model: 'sonnet' | 'opus' | 'haiku';
8
+ allowedTools?: string[];
9
+ }
10
+ export interface ClaudeResult {
11
+ output: string;
12
+ rateLimited: boolean;
13
+ retryAfterMs?: number;
14
+ cost: number;
15
+ duration: number;
16
+ exitCode: number;
17
+ }
18
+ export type LinearStateType = 'backlog' | 'unstarted' | 'started' | 'completed' | 'canceled';
19
+ export interface WorkflowState {
20
+ id: string;
21
+ name: string;
22
+ type: LinearStateType;
23
+ position: number;
24
+ color?: string;
25
+ }
26
+ export interface HorizonStatusDefinition {
27
+ name: string;
28
+ type: LinearStateType;
29
+ }
30
+ export interface InitResult {
31
+ success: boolean;
32
+ created: string[];
33
+ existing: string[];
34
+ errors: string[];
35
+ }
36
+ export interface AttachmentInfo {
37
+ id: string;
38
+ url: string;
39
+ filename: string;
40
+ source: 'attachment' | 'embedded';
41
+ }
42
+ export interface DownloadResult {
43
+ success: boolean;
44
+ attachments: DownloadedAttachment[];
45
+ errors: string[];
46
+ }
47
+ export interface DownloadedAttachment {
48
+ originalUrl: string;
49
+ localPath: string;
50
+ filename: string;
51
+ }
52
+ export interface CodexAgentReasoningConfig {
53
+ agent1: CodexReasoningEffort;
54
+ agent2: CodexReasoningEffort;
55
+ agent3: CodexReasoningEffort;
56
+ }
57
+ export interface HorizonConfig {
58
+ workingDirectory: string;
59
+ linearApiKey?: string;
60
+ linearTeamId?: string;
61
+ gitBranch: string;
62
+ staleTimeoutHours: number;
63
+ noWorkSleepMinutes: number;
64
+ errorSleepMinutes: number;
65
+ provider: ProviderName;
66
+ claudeModel: ClaudeModel;
67
+ codexModel: string;
68
+ codexReasoningEffort: CodexReasoningEffort;
69
+ codexAgentReasoning: CodexAgentReasoningConfig;
70
+ maxIterations: number;
71
+ rateLimitMaxRetries: number;
72
+ gcpAutoStop: boolean;
73
+ quickCheckIntervalMinutes: number;
74
+ fullCheckIntervalMinutes: number;
75
+ mergeMode: MergeMode;
76
+ }
77
+ export interface QuickCheckResult {
78
+ hasWork: boolean;
79
+ ticketCount: number;
80
+ error?: string;
81
+ }
82
+ export interface StatusCategoryCounts {
83
+ backlog: number;
84
+ unstarted: number;
85
+ started: number;
86
+ completed: number;
87
+ canceled: number;
88
+ }
89
+ export interface PulseCheckResult extends QuickCheckResult {
90
+ statusCounts: StatusCategoryCounts;
91
+ }
92
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Provider types
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iBAAiB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ob1-sg/horizon",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Linear-orchestrated autonomous agent system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",