@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,267 @@
1
+ import { LinearClient } from '@linear/sdk';
2
+ // Horizon status prefix to avoid conflicts with user's existing statuses
3
+ export const HORIZON_STATUS_PREFIX = '∞';
4
+ // Color scheme for Horizon statuses (Linear requires hex colors)
5
+ const STATE_COLORS = {
6
+ backlog: '#95a2b3', // Gray - backlog
7
+ unstarted: '#e2e2e2', // Light gray - ready/unstarted
8
+ started: '#f2c94c', // Yellow - in progress
9
+ completed: '#5e6ad2', // Purple - done
10
+ canceled: '#95a2b3', // Gray - canceled
11
+ };
12
+ // All Horizon statuses that need to exist in Linear
13
+ export const HORIZON_STATUS_DEFINITIONS = [
14
+ { name: `${HORIZON_STATUS_PREFIX} Backlog`, type: 'backlog', color: STATE_COLORS.backlog },
15
+ { name: `${HORIZON_STATUS_PREFIX} Needs Research`, type: 'unstarted', color: STATE_COLORS.unstarted },
16
+ { name: `${HORIZON_STATUS_PREFIX} Needs Specification`, type: 'unstarted', color: STATE_COLORS.unstarted },
17
+ { name: `${HORIZON_STATUS_PREFIX} Needs Plan`, type: 'unstarted', color: STATE_COLORS.unstarted },
18
+ { name: `${HORIZON_STATUS_PREFIX} Needs Implement`, type: 'unstarted', color: STATE_COLORS.unstarted },
19
+ { name: `${HORIZON_STATUS_PREFIX} Needs Validate`, type: 'unstarted', color: STATE_COLORS.unstarted },
20
+ { name: `${HORIZON_STATUS_PREFIX} Research In Progress`, type: 'started', color: STATE_COLORS.started },
21
+ { name: `${HORIZON_STATUS_PREFIX} Specification In Progress`, type: 'started', color: STATE_COLORS.started },
22
+ { name: `${HORIZON_STATUS_PREFIX} Plan In Progress`, type: 'started', color: STATE_COLORS.started },
23
+ { name: `${HORIZON_STATUS_PREFIX} Implement In Progress`, type: 'started', color: STATE_COLORS.started },
24
+ { name: `${HORIZON_STATUS_PREFIX} Validate In Progress`, type: 'started', color: STATE_COLORS.started },
25
+ { name: `${HORIZON_STATUS_PREFIX} Oneshot In Progress`, type: 'started', color: STATE_COLORS.started },
26
+ { name: `${HORIZON_STATUS_PREFIX} Blocked`, type: 'started', color: '#eb5757' }, // Red - requires human intervention
27
+ { name: `${HORIZON_STATUS_PREFIX} Awaiting Merge`, type: 'started', color: STATE_COLORS.started }, // PR created, waiting for human merge
28
+ { name: `${HORIZON_STATUS_PREFIX} Done`, type: 'completed', color: STATE_COLORS.completed },
29
+ { name: `${HORIZON_STATUS_PREFIX} Canceled`, type: 'canceled', color: STATE_COLORS.canceled },
30
+ ];
31
+ // Create Linear client with API key
32
+ export function createLinearClient(apiKey) {
33
+ return new LinearClient({ apiKey });
34
+ }
35
+ // Create Linear client with signed file URLs (for downloading attachments)
36
+ // The public-file-urls-expire-in header makes Linear return signed URLs in responses
37
+ // See: https://linear.app/developers/file-storage-authentication
38
+ export function createLinearClientWithSignedUrls(apiKey, expireInSeconds = 3600) {
39
+ return new LinearClient({
40
+ apiKey,
41
+ headers: {
42
+ 'public-file-urls-expire-in': String(expireInSeconds),
43
+ },
44
+ });
45
+ }
46
+ // Get all workflow states for a team
47
+ export async function listWorkflowStates(client, teamId) {
48
+ const team = await client.team(teamId);
49
+ const statesConnection = await team.states();
50
+ const states = statesConnection.nodes;
51
+ return states.map((state) => ({
52
+ id: state.id,
53
+ name: state.name,
54
+ type: state.type,
55
+ position: state.position,
56
+ color: state.color ?? undefined,
57
+ }));
58
+ }
59
+ // Create a new workflow state in a team
60
+ export async function createWorkflowState(client, teamId, state) {
61
+ // Use workflowStateCreate mutation via the client
62
+ const payload = await client.createWorkflowState({
63
+ teamId,
64
+ name: state.name,
65
+ type: state.type,
66
+ color: state.color,
67
+ });
68
+ const createdState = await payload.workflowState;
69
+ if (!createdState) {
70
+ throw new Error(`Failed to create workflow state: ${state.name}`);
71
+ }
72
+ return {
73
+ id: createdState.id,
74
+ name: createdState.name,
75
+ type: createdState.type,
76
+ position: createdState.position,
77
+ color: createdState.color ?? undefined,
78
+ };
79
+ }
80
+ // Get all Horizon status names
81
+ export function getHorizonStatusNames() {
82
+ return HORIZON_STATUS_DEFINITIONS.map((s) => s.name);
83
+ }
84
+ // Check if all Horizon statuses exist in the team
85
+ export async function checkHorizonStatusesExist(client, teamId) {
86
+ const existingStates = await listWorkflowStates(client, teamId);
87
+ const existingNames = new Set(existingStates.map((s) => s.name));
88
+ const horizonNames = getHorizonStatusNames();
89
+ return horizonNames.every((name) => existingNames.has(name));
90
+ }
91
+ // Ensure all Horizon statuses exist, creating any that are missing
92
+ export async function ensureHorizonStatuses(client, teamId) {
93
+ const result = {
94
+ success: true,
95
+ created: [],
96
+ existing: [],
97
+ errors: [],
98
+ };
99
+ // Get existing states
100
+ const existingStates = await listWorkflowStates(client, teamId);
101
+ const existingByName = new Map(existingStates.map((s) => [s.name, s]));
102
+ async function migrateAwaitingMergeState(existing, desired) {
103
+ // Linear does not allow updating a workflow state's `type` after creation.
104
+ // To migrate existing teams, we:
105
+ // 1) Rename the legacy state (freeing up the canonical name)
106
+ // 2) Create a new state with the correct type/color and the canonical name
107
+ // 3) Move any issues from the legacy state into the new canonical state
108
+ const legacyBase = `${HORIZON_STATUS_PREFIX} Awaiting Merge (Legacy)`;
109
+ let legacyName = legacyBase;
110
+ let suffix = 2;
111
+ while (existingByName.has(legacyName)) {
112
+ legacyName = `${legacyBase} ${suffix}`;
113
+ suffix++;
114
+ }
115
+ await client.updateWorkflowState(existing.id, { name: legacyName });
116
+ console.log(` Renamed: ${desired.name} → ${legacyName}`);
117
+ const created = await createWorkflowState(client, teamId, desired);
118
+ console.log(` Created: ${desired.name}`);
119
+ let migratedCount = 0;
120
+ let after;
121
+ while (true) {
122
+ const issues = await client.issues({
123
+ first: 50,
124
+ after,
125
+ filter: {
126
+ team: { id: { eq: teamId } },
127
+ state: { id: { eq: existing.id } },
128
+ },
129
+ });
130
+ for (const issue of issues.nodes) {
131
+ await client.updateIssue(issue.id, { stateId: created.id });
132
+ migratedCount++;
133
+ }
134
+ if (!issues.pageInfo.hasNextPage)
135
+ break;
136
+ after = issues.pageInfo.endCursor ?? undefined;
137
+ if (!after)
138
+ break;
139
+ }
140
+ if (migratedCount > 0) {
141
+ console.log(` Migrated: ${migratedCount} issue(s) → ${desired.name}`);
142
+ }
143
+ }
144
+ // Check each Horizon status
145
+ for (const statusDef of HORIZON_STATUS_DEFINITIONS) {
146
+ const existing = existingByName.get(statusDef.name);
147
+ if (existing) {
148
+ result.existing.push(statusDef.name);
149
+ // Upgrade path for existing teams:
150
+ // Allow updating specific Horizon statuses (∞-prefixed) when our definitions change.
151
+ if (statusDef.name === `${HORIZON_STATUS_PREFIX} Awaiting Merge`) {
152
+ const typeMismatch = existing.type !== statusDef.type;
153
+ const colorMismatch = existing.color !== undefined && existing.color !== statusDef.color;
154
+ try {
155
+ if (typeMismatch) {
156
+ await migrateAwaitingMergeState(existing, statusDef);
157
+ result.created.push(statusDef.name);
158
+ }
159
+ else if (colorMismatch) {
160
+ await client.updateWorkflowState(existing.id, { color: statusDef.color });
161
+ console.log(` Updated: ${statusDef.name}`);
162
+ }
163
+ }
164
+ catch (error) {
165
+ const errorMessage = error instanceof Error ? error.message : String(error);
166
+ result.errors.push(`${statusDef.name}: ${errorMessage}`);
167
+ result.success = false;
168
+ console.error(` Error upgrading ${statusDef.name}: ${errorMessage}`);
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ try {
174
+ await createWorkflowState(client, teamId, statusDef);
175
+ result.created.push(statusDef.name);
176
+ console.log(` Created: ${statusDef.name}`);
177
+ }
178
+ catch (error) {
179
+ const errorMessage = error instanceof Error ? error.message : String(error);
180
+ result.errors.push(`${statusDef.name}: ${errorMessage}`);
181
+ result.success = false;
182
+ console.error(` Error creating ${statusDef.name}: ${errorMessage}`);
183
+ }
184
+ }
185
+ }
186
+ return result;
187
+ }
188
+ // Get team by key (e.g., "RSK") or ID
189
+ export async function getTeamByKeyOrId(client, keyOrId) {
190
+ // First try to get by key
191
+ const teams = await client.teams();
192
+ const team = teams.nodes.find((t) => t.key === keyOrId || t.id === keyOrId);
193
+ if (team) {
194
+ return {
195
+ id: team.id,
196
+ name: team.name,
197
+ key: team.key,
198
+ };
199
+ }
200
+ return undefined;
201
+ }
202
+ // Validate API key by trying to fetch current user
203
+ export async function validateApiKey(client) {
204
+ try {
205
+ await client.viewer;
206
+ return true;
207
+ }
208
+ catch {
209
+ return false;
210
+ }
211
+ }
212
+ // Get issue count for a workflow state
213
+ async function getIssueCountForState(client, stateId) {
214
+ const state = await client.workflowState(stateId);
215
+ const issues = await state.issues();
216
+ return issues.nodes.length;
217
+ }
218
+ // Fetch issue description with fresh pre-signed URLs
219
+ // Linear generates short-lived signed URLs for uploads, so we need to fetch fresh URLs right before download
220
+ export async function getIssueDescription(client, issueIdentifier) {
221
+ try {
222
+ const searchResult = await client.searchIssues(issueIdentifier);
223
+ const issues = searchResult.nodes;
224
+ if (!issues || issues.length === 0)
225
+ return null;
226
+ // Find exact match for identifier
227
+ const issue = issues.find((i) => i.identifier === issueIdentifier);
228
+ if (!issue)
229
+ return null;
230
+ return issue.description ?? null;
231
+ }
232
+ catch {
233
+ return null;
234
+ }
235
+ }
236
+ // Delete Horizon workflow statuses that have no issues
237
+ export async function deleteHorizonStatuses(client, teamId) {
238
+ const result = {
239
+ deleted: [],
240
+ skipped: [],
241
+ errors: [],
242
+ };
243
+ // Get existing states
244
+ const existingStates = await listWorkflowStates(client, teamId);
245
+ const horizonStatusNames = getHorizonStatusNames();
246
+ // Find Horizon statuses in the team
247
+ const horizonStates = existingStates.filter((s) => horizonStatusNames.includes(s.name));
248
+ for (const state of horizonStates) {
249
+ try {
250
+ // Check if any issues are using this status
251
+ const issueCount = await getIssueCountForState(client, state.id);
252
+ if (issueCount > 0) {
253
+ result.skipped.push({ name: state.name, issueCount });
254
+ continue;
255
+ }
256
+ // No issues - safe to archive (Linear archives rather than deletes)
257
+ await client.archiveWorkflowState(state.id);
258
+ result.deleted.push(state.name);
259
+ }
260
+ catch (error) {
261
+ const errorMessage = error instanceof Error ? error.message : String(error);
262
+ result.errors.push(`${state.name}: ${errorMessage}`);
263
+ }
264
+ }
265
+ return result;
266
+ }
267
+ //# sourceMappingURL=linear-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-api.js","sourceRoot":"","sources":["../../src/lib/linear-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { PulseCheckResult } from '../types.js';
2
+ /**
3
+ * Performs a pulse check that returns ticket counts by status category.
4
+ *
5
+ * This queries the Linear API for all issues in the team and groups them by
6
+ * status type (backlog, unstarted, started, completed, canceled).
7
+ *
8
+ * @param apiKey - Linear API key
9
+ * @param teamKey - Team key (e.g., "F")
10
+ * @returns PulseCheckResult with hasWork boolean, ticket count, and status breakdown
11
+ */
12
+ export declare function checkForUncompletedTickets(apiKey: string, teamKey: string): Promise<PulseCheckResult>;
13
+ //# sourceMappingURL=linear-quick-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-quick-check.d.ts","sourceRoot":"","sources":["../../src/lib/linear-quick-check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAyC,MAAM,aAAa,CAAC;AAEtF;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC,CAqD3B"}
@@ -0,0 +1,61 @@
1
+ import { LinearClient } from '@linear/sdk';
2
+ /**
3
+ * Performs a pulse check that returns ticket counts by status category.
4
+ *
5
+ * This queries the Linear API for all issues in the team and groups them by
6
+ * status type (backlog, unstarted, started, completed, canceled).
7
+ *
8
+ * @param apiKey - Linear API key
9
+ * @param teamKey - Team key (e.g., "F")
10
+ * @returns PulseCheckResult with hasWork boolean, ticket count, and status breakdown
11
+ */
12
+ export async function checkForUncompletedTickets(apiKey, teamKey) {
13
+ const emptyStatusCounts = {
14
+ backlog: 0,
15
+ unstarted: 0,
16
+ started: 0,
17
+ completed: 0,
18
+ canceled: 0,
19
+ };
20
+ try {
21
+ const client = new LinearClient({ apiKey });
22
+ // Get all issues for the team to count by status category
23
+ // Using a reasonable limit to get accurate counts
24
+ const issues = await client.issues({
25
+ first: 250,
26
+ filter: {
27
+ team: { key: { eq: teamKey } },
28
+ },
29
+ includeArchived: false,
30
+ });
31
+ // Count issues by status type
32
+ const statusCounts = { ...emptyStatusCounts };
33
+ for (const issue of issues.nodes) {
34
+ const state = await issue.state;
35
+ if (state) {
36
+ const stateType = state.type;
37
+ if (stateType in statusCounts) {
38
+ statusCounts[stateType]++;
39
+ }
40
+ }
41
+ }
42
+ // Ready-to-work tickets are those in backlog or unstarted
43
+ const readyToWorkCount = statusCounts.backlog + statusCounts.unstarted;
44
+ const hasWork = readyToWorkCount > 0;
45
+ return {
46
+ hasWork,
47
+ ticketCount: readyToWorkCount,
48
+ statusCounts,
49
+ };
50
+ }
51
+ catch (error) {
52
+ const errorMessage = error instanceof Error ? error.message : String(error);
53
+ return {
54
+ hasWork: false,
55
+ ticketCount: 0,
56
+ statusCounts: emptyStatusCounts,
57
+ error: errorMessage,
58
+ };
59
+ }
60
+ }
61
+ //# sourceMappingURL=linear-quick-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-quick-check.js","sourceRoot":"","sources":["../../src/lib/linear-quick-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAc,EACd,OAAe;IAEf,MAAM,iBAAiB,GAAyB;QAC9C,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;KACZ,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAE5C,0DAA0D;QAC1D,kDAAkD;QAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACjC,KAAK,EAAE,GAAG;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;aAC/B;YACD,eAAe,EAAE,KAAK;SACvB,CAAC,CAAC;QAEH,8BAA8B;QAC9B,MAAM,YAAY,GAAyB,EAAE,GAAG,iBAAiB,EAAE,CAAC;QAEpE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC;YAChC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,SAAS,GAAG,KAAK,CAAC,IAAuB,CAAC;gBAChD,IAAI,SAAS,IAAI,YAAY,EAAE,CAAC;oBAC9B,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;QAED,0DAA0D;QAC1D,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC;QACvE,MAAM,OAAO,GAAG,gBAAgB,GAAG,CAAC,CAAC;QAErC,OAAO;YACL,OAAO;YACP,WAAW,EAAE,gBAAgB;YAC7B,YAAY;SACb,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO;YACL,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,iBAAiB;YAC/B,KAAK,EAAE,YAAY;SACpB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generates a unique pod name (adjective-animal combination)
3
+ * Example: "calm-pegasus"
4
+ *
5
+ * The name is deterministic based on the current timestamp (Unix seconds),
6
+ * ensuring each pod gets a unique name while being reproducible for debugging.
7
+ * This name persists for the entire Horizon session (across all loops).
8
+ */
9
+ export declare function generatePodName(): string;
10
+ /**
11
+ * Generates a unique name for a loop instance (legacy format, kept for compatibility)
12
+ * Format: {YYYYMMDD-HHMMSS}-{adjective}-{animal}
13
+ * Example: "20250125-143052-calm-pegasus"
14
+ *
15
+ * The timestamp prefix enables easy chronological sorting in file explorers.
16
+ * The name is deterministic based on the current timestamp (Unix seconds),
17
+ * ensuring each loop gets a unique name while being reproducible for debugging.
18
+ *
19
+ * @deprecated Use generatePodName() for persistent pod names across loops
20
+ */
21
+ export declare function generateLoopInstanceName(): string;
22
+ /**
23
+ * Extracts the human-readable part of a loop instance name (adjective-animal)
24
+ * Current format: "20250125-143052-calm-pegasus" -> "calm-pegasus"
25
+ * Old format (backwards compatible): "calm-pegasus-20250125-143052" -> "calm-pegasus"
26
+ * Legacy format: "red-giraffe-1706223456" -> "red-giraffe"
27
+ */
28
+ export declare function getLoopInstanceNameDisplay(fullName: string): string;
29
+ //# sourceMappingURL=loop-instance-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-instance-name.d.ts","sourceRoot":"","sources":["../../src/lib/loop-instance-name.ts"],"names":[],"mappings":"AAmDA;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAaxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAMjD;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiBnE"}
@@ -0,0 +1,105 @@
1
+ // Loop instance name generator
2
+ // Generates unique, memorable names for loop instances (e.g., "20250125-143052-calm-pegasus")
3
+ // Timestamp prefix enables easy sorting by date/time in file explorers
4
+ // This helps identify which loop instance made comments in Linear when multiple instances work in parallel
5
+ // Word lists for generating memorable names
6
+ // Expanded lists provide more unique combinations (64 adjectives x 64 animals = 4,096 combinations)
7
+ const ADJECTIVES = [
8
+ // Colors
9
+ 'red', 'blue', 'green', 'purple', 'orange', 'yellow', 'silver', 'golden',
10
+ 'crimson', 'azure', 'emerald', 'violet', 'amber', 'ivory', 'bronze', 'copper',
11
+ // Qualities
12
+ 'swift', 'calm', 'bold', 'wise', 'keen', 'bright', 'quick', 'steady',
13
+ 'noble', 'brave', 'gentle', 'fierce', 'proud', 'silent', 'clever', 'nimble',
14
+ // Cosmic/Nature
15
+ 'cosmic', 'lunar', 'solar', 'stellar', 'crystal', 'mystic', 'arctic', 'tropic',
16
+ 'misty', 'frozen', 'blazing', 'radiant', 'shadow', 'thunder', 'starlit', 'ancient',
17
+ // Additional
18
+ 'vivid', 'serene', 'mighty', 'agile', 'lofty', 'daring', 'loyal', 'gallant',
19
+ 'gleaming', 'glowing', 'shining', 'dusk', 'dawn', 'twilight', 'velvet', 'marble',
20
+ ];
21
+ const ANIMALS = [
22
+ // Safari/Wild
23
+ 'giraffe', 'zebra', 'falcon', 'otter', 'panda', 'koala', 'eagle', 'dolphin',
24
+ 'tiger', 'wolf', 'bear', 'hawk', 'owl', 'fox', 'lynx', 'raven',
25
+ 'leopard', 'cheetah', 'jaguar', 'panther', 'gazelle', 'antelope', 'bison', 'mustang',
26
+ // Mythical
27
+ 'phoenix', 'dragon', 'griffin', 'unicorn', 'pegasus', 'sphinx', 'hydra', 'kraken',
28
+ 'chimera', 'basilisk', 'wyvern', 'manticore', 'cerberus', 'hippogriff', 'thunderbird', 'leviathan',
29
+ // Ocean/Sky
30
+ 'shark', 'whale', 'seal', 'penguin', 'pelican', 'heron', 'condor', 'albatross',
31
+ 'stingray', 'orca', 'narwhal', 'walrus', 'osprey', 'harrier', 'kestrel', 'merlin',
32
+ // Additional
33
+ 'badger', 'mongoose', 'wolverine', 'marten', 'viper', 'cobra', 'python', 'iguana',
34
+ ];
35
+ /**
36
+ * Formats a date as YYYYMMDD-HHMMSS (human-readable timestamp)
37
+ * Example: "20250125-143052"
38
+ */
39
+ function formatTimestamp(date) {
40
+ const year = date.getUTCFullYear();
41
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
42
+ const day = String(date.getUTCDate()).padStart(2, '0');
43
+ const hours = String(date.getUTCHours()).padStart(2, '0');
44
+ const minutes = String(date.getUTCMinutes()).padStart(2, '0');
45
+ const seconds = String(date.getUTCSeconds()).padStart(2, '0');
46
+ return `${year}${month}${day}-${hours}${minutes}${seconds}`;
47
+ }
48
+ /**
49
+ * Generates a unique pod name (adjective-animal combination)
50
+ * Example: "calm-pegasus"
51
+ *
52
+ * The name is deterministic based on the current timestamp (Unix seconds),
53
+ * ensuring each pod gets a unique name while being reproducible for debugging.
54
+ * This name persists for the entire Horizon session (across all loops).
55
+ */
56
+ export function generatePodName() {
57
+ const now = new Date();
58
+ const timestamp = Math.floor(now.getTime() / 1000);
59
+ // Use Unix timestamp to deterministically select words (but with enough variation)
60
+ // This ensures the same second always produces the same name
61
+ const adjIndex = timestamp % ADJECTIVES.length;
62
+ const animalIndex = Math.floor(timestamp / ADJECTIVES.length) % ANIMALS.length;
63
+ const adjective = ADJECTIVES[adjIndex];
64
+ const animal = ANIMALS[animalIndex];
65
+ return `${adjective}-${animal}`;
66
+ }
67
+ /**
68
+ * Generates a unique name for a loop instance (legacy format, kept for compatibility)
69
+ * Format: {YYYYMMDD-HHMMSS}-{adjective}-{animal}
70
+ * Example: "20250125-143052-calm-pegasus"
71
+ *
72
+ * The timestamp prefix enables easy chronological sorting in file explorers.
73
+ * The name is deterministic based on the current timestamp (Unix seconds),
74
+ * ensuring each loop gets a unique name while being reproducible for debugging.
75
+ *
76
+ * @deprecated Use generatePodName() for persistent pod names across loops
77
+ */
78
+ export function generateLoopInstanceName() {
79
+ const now = new Date();
80
+ const humanTimestamp = formatTimestamp(now);
81
+ const podName = generatePodName();
82
+ return `${humanTimestamp}-${podName}`;
83
+ }
84
+ /**
85
+ * Extracts the human-readable part of a loop instance name (adjective-animal)
86
+ * Current format: "20250125-143052-calm-pegasus" -> "calm-pegasus"
87
+ * Old format (backwards compatible): "calm-pegasus-20250125-143052" -> "calm-pegasus"
88
+ * Legacy format: "red-giraffe-1706223456" -> "red-giraffe"
89
+ */
90
+ export function getLoopInstanceNameDisplay(fullName) {
91
+ const parts = fullName.split('-');
92
+ // Current format: YYYYMMDD-HHMMSS-adjective-animal (4 parts with timestamp first)
93
+ // Check if first part looks like a date (8 digits)
94
+ if (parts.length >= 4 && /^\d{8}$/.test(parts[0])) {
95
+ // Return adjective-animal (last two parts)
96
+ return `${parts[2]}-${parts[3]}`;
97
+ }
98
+ // Old format: adjective-animal-YYYYMMDD-HHMMSS or adjective-animal-unixTimestamp
99
+ if (parts.length >= 3) {
100
+ // Return just adjective-animal (first two parts)
101
+ return `${parts[0]}-${parts[1]}`;
102
+ }
103
+ return fullName;
104
+ }
105
+ //# sourceMappingURL=loop-instance-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-instance-name.js","sourceRoot":"","sources":["../../src/lib/loop-instance-name.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Initializes the output logger for a new loop iteration
3
+ * @param podName - The pod name (e.g., "arctic-lynx") - persists for entire session
4
+ * @param loopNumber - The loop iteration number (0, 1, 2, ...)
5
+ */
6
+ export declare function initLoopLogger(podName: string, loopNumber: number): void;
7
+ /**
8
+ * Logs a line of output for a specific agent (raw LLM JSON)
9
+ * @param agentNumber - The agent number (1, 2, or 3)
10
+ * @param line - The raw line of output to log (typically JSON from Claude)
11
+ */
12
+ export declare function logAgentOutput(agentNumber: number, line: string): Promise<void>;
13
+ /**
14
+ * Logs terminal output for a specific agent (formatted shell output)
15
+ * @param agentNumber - The agent number (1, 2, or 3)
16
+ * @param text - The formatted text that was printed to the terminal
17
+ */
18
+ export declare function logTerminalOutput(agentNumber: number, text: string): Promise<void>;
19
+ /**
20
+ * Gets the current output directory for diagnostics
21
+ */
22
+ export declare function getCurrentOutputDir(): string | null;
23
+ //# sourceMappingURL=output-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-logger.d.ts","sourceRoot":"","sources":["../../src/lib/output-logger.ts"],"names":[],"mappings":"AAkEA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAGxE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAarF;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAaxF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAQnD"}
@@ -0,0 +1,104 @@
1
+ import { mkdir, appendFile } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { getConfig } from '../config.js';
5
+ // Track current logging context
6
+ let currentPodName = null;
7
+ let currentLoopNumber = null;
8
+ /**
9
+ * Gets the base output directory path (.horizon/output/ in the working directory)
10
+ * Output lives inside the .horizon folder which contains all Horizon runtime data.
11
+ */
12
+ function getOutputDir() {
13
+ const config = getConfig();
14
+ return join(config.workingDirectory, '.horizon', 'output');
15
+ }
16
+ /**
17
+ * Gets the log file path for a specific agent (raw LLM JSON output)
18
+ * Structure: .horizon/output/{pod-name}/loop-{n}/agent-{n}.log
19
+ */
20
+ function getAgentLogPath(agentNumber) {
21
+ if (!currentPodName || currentLoopNumber === null) {
22
+ return null;
23
+ }
24
+ const outputDir = getOutputDir();
25
+ return join(outputDir, currentPodName, `loop-${currentLoopNumber}`, `agent-${agentNumber}.log`);
26
+ }
27
+ /**
28
+ * Gets the terminal log file path for a specific agent (formatted shell output)
29
+ * Structure: .horizon/output/{pod-name}/loop-{n}/agent-{n}-terminal.log
30
+ */
31
+ function getAgentTerminalLogPath(agentNumber) {
32
+ if (!currentPodName || currentLoopNumber === null) {
33
+ return null;
34
+ }
35
+ const outputDir = getOutputDir();
36
+ return join(outputDir, currentPodName, `loop-${currentLoopNumber}`, `agent-${agentNumber}-terminal.log`);
37
+ }
38
+ /**
39
+ * Ensures the directory structure exists for a given file path
40
+ */
41
+ async function ensureDir(filePath) {
42
+ const dir = filePath.substring(0, filePath.lastIndexOf('/'));
43
+ if (!existsSync(dir)) {
44
+ await mkdir(dir, { recursive: true });
45
+ }
46
+ }
47
+ /**
48
+ * Initializes the output logger for a new loop iteration
49
+ * @param podName - The pod name (e.g., "arctic-lynx") - persists for entire session
50
+ * @param loopNumber - The loop iteration number (0, 1, 2, ...)
51
+ */
52
+ export function initLoopLogger(podName, loopNumber) {
53
+ currentPodName = podName;
54
+ currentLoopNumber = loopNumber;
55
+ }
56
+ /**
57
+ * Logs a line of output for a specific agent (raw LLM JSON)
58
+ * @param agentNumber - The agent number (1, 2, or 3)
59
+ * @param line - The raw line of output to log (typically JSON from Claude)
60
+ */
61
+ export async function logAgentOutput(agentNumber, line) {
62
+ const logPath = getAgentLogPath(agentNumber);
63
+ if (!logPath) {
64
+ // Logger not initialized, skip logging
65
+ return;
66
+ }
67
+ try {
68
+ await ensureDir(logPath);
69
+ await appendFile(logPath, line + '\n', 'utf-8');
70
+ }
71
+ catch (error) {
72
+ // Silently fail - logging should not interrupt the main process
73
+ }
74
+ }
75
+ /**
76
+ * Logs terminal output for a specific agent (formatted shell output)
77
+ * @param agentNumber - The agent number (1, 2, or 3)
78
+ * @param text - The formatted text that was printed to the terminal
79
+ */
80
+ export async function logTerminalOutput(agentNumber, text) {
81
+ const logPath = getAgentTerminalLogPath(agentNumber);
82
+ if (!logPath) {
83
+ // Logger not initialized, skip logging
84
+ return;
85
+ }
86
+ try {
87
+ await ensureDir(logPath);
88
+ await appendFile(logPath, text + '\n', 'utf-8');
89
+ }
90
+ catch (error) {
91
+ // Silently fail - logging should not interrupt the main process
92
+ }
93
+ }
94
+ /**
95
+ * Gets the current output directory for diagnostics
96
+ */
97
+ export function getCurrentOutputDir() {
98
+ if (!currentPodName || currentLoopNumber === null) {
99
+ return null;
100
+ }
101
+ const outputDir = getOutputDir();
102
+ return join(outputDir, currentPodName, `loop-${currentLoopNumber}`);
103
+ }
104
+ //# sourceMappingURL=output-logger.js.map