@ginkoai/cli 1.6.1 → 1.7.0

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 (246) hide show
  1. package/README.md +34 -0
  2. package/dist/commands/agent/agent-client.d.ts +150 -0
  3. package/dist/commands/agent/agent-client.d.ts.map +1 -0
  4. package/dist/commands/agent/agent-client.js +170 -0
  5. package/dist/commands/agent/agent-client.js.map +1 -0
  6. package/dist/commands/agent/index.d.ts +22 -0
  7. package/dist/commands/agent/index.d.ts.map +1 -0
  8. package/dist/commands/agent/index.js +121 -0
  9. package/dist/commands/agent/index.js.map +1 -0
  10. package/dist/commands/agent/list.d.ts +22 -0
  11. package/dist/commands/agent/list.d.ts.map +1 -0
  12. package/dist/commands/agent/list.js +119 -0
  13. package/dist/commands/agent/list.js.map +1 -0
  14. package/dist/commands/agent/register.d.ts +21 -0
  15. package/dist/commands/agent/register.d.ts.map +1 -0
  16. package/dist/commands/agent/register.js +97 -0
  17. package/dist/commands/agent/register.js.map +1 -0
  18. package/dist/commands/agent/status.d.ts +19 -0
  19. package/dist/commands/agent/status.d.ts.map +1 -0
  20. package/dist/commands/agent/status.js +271 -0
  21. package/dist/commands/agent/status.js.map +1 -0
  22. package/dist/commands/agent/work.d.ts +22 -0
  23. package/dist/commands/agent/work.d.ts.map +1 -0
  24. package/dist/commands/agent/work.js +459 -0
  25. package/dist/commands/agent/work.js.map +1 -0
  26. package/dist/commands/checkpoint/create.d.ts +27 -0
  27. package/dist/commands/checkpoint/create.d.ts.map +1 -0
  28. package/dist/commands/checkpoint/create.js +82 -0
  29. package/dist/commands/checkpoint/create.js.map +1 -0
  30. package/dist/commands/checkpoint/index.d.ts +23 -0
  31. package/dist/commands/checkpoint/index.d.ts.map +1 -0
  32. package/dist/commands/checkpoint/index.js +91 -0
  33. package/dist/commands/checkpoint/index.js.map +1 -0
  34. package/dist/commands/checkpoint/list.d.ts +27 -0
  35. package/dist/commands/checkpoint/list.d.ts.map +1 -0
  36. package/dist/commands/checkpoint/list.js +115 -0
  37. package/dist/commands/checkpoint/list.js.map +1 -0
  38. package/dist/commands/checkpoint/show.d.ts +23 -0
  39. package/dist/commands/checkpoint/show.d.ts.map +1 -0
  40. package/dist/commands/checkpoint/show.js +102 -0
  41. package/dist/commands/checkpoint/show.js.map +1 -0
  42. package/dist/commands/dlq.d.ts +24 -0
  43. package/dist/commands/dlq.d.ts.map +1 -0
  44. package/dist/commands/dlq.js +172 -0
  45. package/dist/commands/dlq.js.map +1 -0
  46. package/dist/commands/epic.d.ts +29 -0
  47. package/dist/commands/epic.d.ts.map +1 -0
  48. package/dist/commands/epic.js +322 -0
  49. package/dist/commands/epic.js.map +1 -0
  50. package/dist/commands/escalation/create.d.ts +22 -0
  51. package/dist/commands/escalation/create.d.ts.map +1 -0
  52. package/dist/commands/escalation/create.js +122 -0
  53. package/dist/commands/escalation/create.js.map +1 -0
  54. package/dist/commands/escalation/escalation-client.d.ts +101 -0
  55. package/dist/commands/escalation/escalation-client.d.ts.map +1 -0
  56. package/dist/commands/escalation/escalation-client.js +129 -0
  57. package/dist/commands/escalation/escalation-client.js.map +1 -0
  58. package/dist/commands/escalation/index.d.ts +22 -0
  59. package/dist/commands/escalation/index.d.ts.map +1 -0
  60. package/dist/commands/escalation/index.js +94 -0
  61. package/dist/commands/escalation/index.js.map +1 -0
  62. package/dist/commands/escalation/list.d.ts +24 -0
  63. package/dist/commands/escalation/list.d.ts.map +1 -0
  64. package/dist/commands/escalation/list.js +170 -0
  65. package/dist/commands/escalation/list.js.map +1 -0
  66. package/dist/commands/escalation/resolve.d.ts +20 -0
  67. package/dist/commands/escalation/resolve.d.ts.map +1 -0
  68. package/dist/commands/escalation/resolve.js +102 -0
  69. package/dist/commands/escalation/resolve.js.map +1 -0
  70. package/dist/commands/graph/api-client.d.ts +222 -1
  71. package/dist/commands/graph/api-client.d.ts.map +1 -1
  72. package/dist/commands/graph/api-client.js +82 -0
  73. package/dist/commands/graph/api-client.js.map +1 -1
  74. package/dist/commands/handoff.d.ts.map +1 -1
  75. package/dist/commands/handoff.js +9 -1
  76. package/dist/commands/handoff.js.map +1 -1
  77. package/dist/commands/log.d.ts +3 -0
  78. package/dist/commands/log.d.ts.map +1 -1
  79. package/dist/commands/log.js +110 -16
  80. package/dist/commands/log.js.map +1 -1
  81. package/dist/commands/notifications/history.d.ts +21 -0
  82. package/dist/commands/notifications/history.d.ts.map +1 -0
  83. package/dist/commands/notifications/history.js +160 -0
  84. package/dist/commands/notifications/history.js.map +1 -0
  85. package/dist/commands/notifications/index.d.ts +22 -0
  86. package/dist/commands/notifications/index.d.ts.map +1 -0
  87. package/dist/commands/notifications/index.js +87 -0
  88. package/dist/commands/notifications/index.js.map +1 -0
  89. package/dist/commands/notifications/list.d.ts +19 -0
  90. package/dist/commands/notifications/list.d.ts.map +1 -0
  91. package/dist/commands/notifications/list.js +132 -0
  92. package/dist/commands/notifications/list.js.map +1 -0
  93. package/dist/commands/notifications/test.d.ts +19 -0
  94. package/dist/commands/notifications/test.d.ts.map +1 -0
  95. package/dist/commands/notifications/test.js +217 -0
  96. package/dist/commands/notifications/test.js.map +1 -0
  97. package/dist/commands/orchestrate.d.ts +25 -0
  98. package/dist/commands/orchestrate.d.ts.map +1 -0
  99. package/dist/commands/orchestrate.js +858 -0
  100. package/dist/commands/orchestrate.js.map +1 -0
  101. package/dist/commands/sprint/deps.d.ts +29 -0
  102. package/dist/commands/sprint/deps.d.ts.map +1 -0
  103. package/dist/commands/sprint/deps.js +269 -0
  104. package/dist/commands/sprint/deps.js.map +1 -0
  105. package/dist/commands/sprint/index.d.ts +10 -5
  106. package/dist/commands/sprint/index.d.ts.map +1 -1
  107. package/dist/commands/sprint/index.js +26 -5
  108. package/dist/commands/sprint/index.js.map +1 -1
  109. package/dist/commands/start/index.d.ts.map +1 -1
  110. package/dist/commands/start/index.js +6 -0
  111. package/dist/commands/start/index.js.map +1 -1
  112. package/dist/commands/start/start-reflection.d.ts +11 -0
  113. package/dist/commands/start/start-reflection.d.ts.map +1 -1
  114. package/dist/commands/start/start-reflection.js +150 -12
  115. package/dist/commands/start/start-reflection.js.map +1 -1
  116. package/dist/commands/verify.d.ts +17 -0
  117. package/dist/commands/verify.d.ts.map +1 -0
  118. package/dist/commands/verify.js +232 -0
  119. package/dist/commands/verify.js.map +1 -0
  120. package/dist/core/session-log-manager.d.ts +1 -1
  121. package/dist/core/session-log-manager.d.ts.map +1 -1
  122. package/dist/core/session-log-manager.js +12 -3
  123. package/dist/core/session-log-manager.js.map +1 -1
  124. package/dist/index.js +98 -1
  125. package/dist/index.js.map +1 -1
  126. package/dist/lib/__tests__/task-timeout.test.d.ts +12 -0
  127. package/dist/lib/__tests__/task-timeout.test.d.ts.map +1 -0
  128. package/dist/lib/__tests__/task-timeout.test.js +278 -0
  129. package/dist/lib/__tests__/task-timeout.test.js.map +1 -0
  130. package/dist/lib/agent-heartbeat.d.ts +68 -0
  131. package/dist/lib/agent-heartbeat.d.ts.map +1 -0
  132. package/dist/lib/agent-heartbeat.js +117 -0
  133. package/dist/lib/agent-heartbeat.js.map +1 -0
  134. package/dist/lib/checkpoint.d.ts +85 -0
  135. package/dist/lib/checkpoint.d.ts.map +1 -0
  136. package/dist/lib/checkpoint.js +323 -0
  137. package/dist/lib/checkpoint.js.map +1 -0
  138. package/dist/lib/context-metrics.d.ts +230 -0
  139. package/dist/lib/context-metrics.d.ts.map +1 -0
  140. package/dist/lib/context-metrics.js +372 -0
  141. package/dist/lib/context-metrics.js.map +1 -0
  142. package/dist/lib/dead-letter-queue.d.ts +108 -0
  143. package/dist/lib/dead-letter-queue.d.ts.map +1 -0
  144. package/dist/lib/dead-letter-queue.js +378 -0
  145. package/dist/lib/dead-letter-queue.js.map +1 -0
  146. package/dist/lib/event-logger.d.ts +9 -1
  147. package/dist/lib/event-logger.d.ts.map +1 -1
  148. package/dist/lib/event-logger.js +45 -3
  149. package/dist/lib/event-logger.js.map +1 -1
  150. package/dist/lib/event-queue.d.ts.map +1 -1
  151. package/dist/lib/event-queue.js +13 -2
  152. package/dist/lib/event-queue.js.map +1 -1
  153. package/dist/lib/examples/timeout-demo.d.ts +13 -0
  154. package/dist/lib/examples/timeout-demo.d.ts.map +1 -0
  155. package/dist/lib/examples/timeout-demo.js +102 -0
  156. package/dist/lib/examples/timeout-demo.js.map +1 -0
  157. package/dist/lib/examples/timeout-integration-example.d.ts +17 -0
  158. package/dist/lib/examples/timeout-integration-example.d.ts.map +1 -0
  159. package/dist/lib/examples/timeout-integration-example.js +223 -0
  160. package/dist/lib/examples/timeout-integration-example.js.map +1 -0
  161. package/dist/lib/notification-hooks.d.ts +103 -0
  162. package/dist/lib/notification-hooks.d.ts.map +1 -0
  163. package/dist/lib/notification-hooks.js +223 -0
  164. package/dist/lib/notification-hooks.js.map +1 -0
  165. package/dist/lib/notifications/discord.d.ts +20 -0
  166. package/dist/lib/notifications/discord.d.ts.map +1 -0
  167. package/dist/lib/notifications/discord.js +140 -0
  168. package/dist/lib/notifications/discord.js.map +1 -0
  169. package/dist/lib/notifications/index.d.ts +66 -0
  170. package/dist/lib/notifications/index.d.ts.map +1 -0
  171. package/dist/lib/notifications/index.js +120 -0
  172. package/dist/lib/notifications/index.js.map +1 -0
  173. package/dist/lib/notifications/slack.d.ts +20 -0
  174. package/dist/lib/notifications/slack.d.ts.map +1 -0
  175. package/dist/lib/notifications/slack.js +186 -0
  176. package/dist/lib/notifications/slack.js.map +1 -0
  177. package/dist/lib/notifications/teams.d.ts +20 -0
  178. package/dist/lib/notifications/teams.d.ts.map +1 -0
  179. package/dist/lib/notifications/teams.js +146 -0
  180. package/dist/lib/notifications/teams.js.map +1 -0
  181. package/dist/lib/notifications/webhook.d.ts +23 -0
  182. package/dist/lib/notifications/webhook.d.ts.map +1 -0
  183. package/dist/lib/notifications/webhook.js +65 -0
  184. package/dist/lib/notifications/webhook.js.map +1 -0
  185. package/dist/lib/orchestrator-state.d.ts +194 -0
  186. package/dist/lib/orchestrator-state.d.ts.map +1 -0
  187. package/dist/lib/orchestrator-state.js +332 -0
  188. package/dist/lib/orchestrator-state.js.map +1 -0
  189. package/dist/lib/output-formatter.d.ts +25 -1
  190. package/dist/lib/output-formatter.d.ts.map +1 -1
  191. package/dist/lib/output-formatter.js +37 -17
  192. package/dist/lib/output-formatter.js.map +1 -1
  193. package/dist/lib/realtime-cursor.d.ts +107 -0
  194. package/dist/lib/realtime-cursor.d.ts.map +1 -0
  195. package/dist/lib/realtime-cursor.js +260 -0
  196. package/dist/lib/realtime-cursor.js.map +1 -0
  197. package/dist/lib/rollback.d.ts +86 -0
  198. package/dist/lib/rollback.d.ts.map +1 -0
  199. package/dist/lib/rollback.js +405 -0
  200. package/dist/lib/rollback.js.map +1 -0
  201. package/dist/lib/sprint-loader.d.ts +41 -2
  202. package/dist/lib/sprint-loader.d.ts.map +1 -1
  203. package/dist/lib/sprint-loader.js +335 -9
  204. package/dist/lib/sprint-loader.js.map +1 -1
  205. package/dist/lib/stale-agent-detector.d.ts +102 -0
  206. package/dist/lib/stale-agent-detector.d.ts.map +1 -0
  207. package/dist/lib/stale-agent-detector.js +156 -0
  208. package/dist/lib/stale-agent-detector.js.map +1 -0
  209. package/dist/lib/task-dependencies.d.ts +143 -0
  210. package/dist/lib/task-dependencies.d.ts.map +1 -0
  211. package/dist/lib/task-dependencies.js +357 -0
  212. package/dist/lib/task-dependencies.js.map +1 -0
  213. package/dist/lib/task-timeout.d.ts +153 -0
  214. package/dist/lib/task-timeout.d.ts.map +1 -0
  215. package/dist/lib/task-timeout.js +505 -0
  216. package/dist/lib/task-timeout.js.map +1 -0
  217. package/dist/lib/verification/build-check.d.ts +55 -0
  218. package/dist/lib/verification/build-check.d.ts.map +1 -0
  219. package/dist/lib/verification/build-check.js +111 -0
  220. package/dist/lib/verification/build-check.js.map +1 -0
  221. package/dist/lib/verification/index.d.ts +19 -0
  222. package/dist/lib/verification/index.d.ts.map +1 -0
  223. package/dist/lib/verification/index.js +17 -0
  224. package/dist/lib/verification/index.js.map +1 -0
  225. package/dist/lib/verification/lint-check.d.ts +34 -0
  226. package/dist/lib/verification/lint-check.d.ts.map +1 -0
  227. package/dist/lib/verification/lint-check.js +215 -0
  228. package/dist/lib/verification/lint-check.js.map +1 -0
  229. package/dist/lib/verification/test-runner.d.ts +50 -0
  230. package/dist/lib/verification/test-runner.d.ts.map +1 -0
  231. package/dist/lib/verification/test-runner.js +225 -0
  232. package/dist/lib/verification/test-runner.js.map +1 -0
  233. package/dist/templates/ai-instructions-template.d.ts +3 -2
  234. package/dist/templates/ai-instructions-template.d.ts.map +1 -1
  235. package/dist/templates/ai-instructions-template.js +104 -2
  236. package/dist/templates/ai-instructions-template.js.map +1 -1
  237. package/dist/templates/epic-template.md +319 -0
  238. package/dist/utils/command-helpers.d.ts +10 -0
  239. package/dist/utils/command-helpers.d.ts.map +1 -1
  240. package/dist/utils/command-helpers.js +59 -1
  241. package/dist/utils/command-helpers.js.map +1 -1
  242. package/dist/utils/pattern-confidence.d.ts +82 -0
  243. package/dist/utils/pattern-confidence.d.ts.map +1 -0
  244. package/dist/utils/pattern-confidence.js +172 -0
  245. package/dist/utils/pattern-confidence.js.map +1 -0
  246. package/package.json +1 -1
@@ -0,0 +1,278 @@
1
+ /**
2
+ * @fileType: test
3
+ * @status: current
4
+ * @updated: 2025-12-07
5
+ * @tags: [test, timeout, orchestrator, epic-004-sprint5, task-6]
6
+ * @related: [task-timeout.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [vitest, fs-extra]
10
+ */
11
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
12
+ import fs from 'fs-extra';
13
+ import path from 'path';
14
+ import { startTaskTimeout, checkTimeouts, clearTaskTimeout, getActiveTimeouts, getTaskTimeout, getAllTimeouts, cleanupOldTimeouts, handleTimeout, TimeoutMonitor } from '../task-timeout.js';
15
+ // Mock dependencies
16
+ vi.mock('../../utils/helpers.js', () => ({
17
+ getGinkoDir: vi.fn(async () => '/tmp/ginko-test/.ginko'),
18
+ getUserEmail: vi.fn(async () => 'test@example.com'),
19
+ getProjectRoot: vi.fn(async () => '/tmp/ginko-test')
20
+ }));
21
+ vi.mock('../checkpoint.js', () => ({
22
+ createCheckpoint: vi.fn(async (taskId, agentId, message) => ({
23
+ id: `cp_${Date.now()}_test`,
24
+ taskId,
25
+ agentId,
26
+ timestamp: new Date(),
27
+ gitCommit: 'abc123',
28
+ filesModified: [],
29
+ eventsSince: 'event_123',
30
+ metadata: {},
31
+ message
32
+ }))
33
+ }));
34
+ vi.mock('../event-logger.js', () => ({
35
+ logEvent: vi.fn(async (entry) => ({
36
+ id: `event_${Date.now()}_test`,
37
+ user_id: 'test@example.com',
38
+ organization_id: 'org_test',
39
+ project_id: 'proj_test',
40
+ timestamp: new Date().toISOString(),
41
+ ...entry
42
+ }))
43
+ }));
44
+ describe('task-timeout', () => {
45
+ const testDir = '/tmp/ginko-test/.ginko/timeouts';
46
+ beforeEach(async () => {
47
+ // Clean up test directory
48
+ await fs.remove(testDir);
49
+ await fs.ensureDir(testDir);
50
+ });
51
+ afterEach(async () => {
52
+ // Clean up after tests
53
+ await fs.remove(testDir);
54
+ });
55
+ describe('startTaskTimeout', () => {
56
+ it('should create a timeout with default configuration', async () => {
57
+ const timeout = await startTaskTimeout('TASK-1', 60000, // 60 seconds
58
+ 'agent-123');
59
+ expect(timeout.taskId).toBe('TASK-1');
60
+ expect(timeout.agentId).toBe('agent-123');
61
+ expect(timeout.maxDuration).toBe(60000);
62
+ expect(timeout.status).toBe('active');
63
+ expect(timeout.startedAt).toBeInstanceOf(Date);
64
+ expect(timeout.timeoutAt).toBeInstanceOf(Date);
65
+ expect(timeout.warningAt).toBeInstanceOf(Date);
66
+ // Verify warning threshold (80%)
67
+ const expectedWarning = timeout.startedAt.getTime() + (60000 * 0.8);
68
+ expect(timeout.warningAt.getTime()).toBeCloseTo(expectedWarning, -1);
69
+ // Verify timeout time
70
+ const expectedTimeout = timeout.startedAt.getTime() + 60000;
71
+ expect(timeout.timeoutAt.getTime()).toBeCloseTo(expectedTimeout, -1);
72
+ });
73
+ it('should create a timeout with custom warning threshold', async () => {
74
+ const timeout = await startTaskTimeout('TASK-2', 60000, 'agent-456', { warningThreshold: 0.5 } // 50%
75
+ );
76
+ // Verify warning at 50%
77
+ const expectedWarning = timeout.startedAt.getTime() + (60000 * 0.5);
78
+ expect(timeout.warningAt.getTime()).toBeCloseTo(expectedWarning, -1);
79
+ });
80
+ it('should save timeout to file', async () => {
81
+ const timeout = await startTaskTimeout('TASK-3', 60000, 'agent-789');
82
+ const filePath = path.join(testDir, 'TASK-3.json');
83
+ const fileExists = await fs.pathExists(filePath);
84
+ expect(fileExists).toBe(true);
85
+ const savedData = await fs.readJSON(filePath);
86
+ expect(savedData.taskId).toBe('TASK-3');
87
+ expect(savedData.agentId).toBe('agent-789');
88
+ });
89
+ });
90
+ describe('getTaskTimeout', () => {
91
+ it('should retrieve timeout by task ID', async () => {
92
+ await startTaskTimeout('TASK-4', 60000, 'agent-111');
93
+ const timeout = await getTaskTimeout('TASK-4');
94
+ expect(timeout).not.toBeNull();
95
+ expect(timeout.taskId).toBe('TASK-4');
96
+ expect(timeout.agentId).toBe('agent-111');
97
+ });
98
+ it('should return null for non-existent timeout', async () => {
99
+ const timeout = await getTaskTimeout('TASK-NONEXISTENT');
100
+ expect(timeout).toBeNull();
101
+ });
102
+ });
103
+ describe('getActiveTimeouts', () => {
104
+ it('should return all active timeouts', async () => {
105
+ await startTaskTimeout('TASK-5', 60000, 'agent-222');
106
+ await startTaskTimeout('TASK-6', 60000, 'agent-333');
107
+ const activeTimeouts = await getActiveTimeouts();
108
+ expect(activeTimeouts).toHaveLength(2);
109
+ expect(activeTimeouts.map(t => t.taskId)).toContain('TASK-5');
110
+ expect(activeTimeouts.map(t => t.taskId)).toContain('TASK-6');
111
+ });
112
+ it('should not return completed timeouts', async () => {
113
+ await startTaskTimeout('TASK-7', 60000, 'agent-444');
114
+ await startTaskTimeout('TASK-8', 60000, 'agent-555');
115
+ // Complete one timeout
116
+ await clearTaskTimeout('TASK-7');
117
+ const activeTimeouts = await getActiveTimeouts();
118
+ expect(activeTimeouts).toHaveLength(1);
119
+ expect(activeTimeouts[0].taskId).toBe('TASK-8');
120
+ });
121
+ });
122
+ describe('clearTaskTimeout', () => {
123
+ it('should mark timeout as completed', async () => {
124
+ await startTaskTimeout('TASK-9', 60000, 'agent-666');
125
+ await clearTaskTimeout('TASK-9');
126
+ const timeout = await getTaskTimeout('TASK-9');
127
+ expect(timeout).not.toBeNull();
128
+ expect(timeout.status).toBe('completed');
129
+ });
130
+ it('should remove from active timeouts', async () => {
131
+ await startTaskTimeout('TASK-10', 60000, 'agent-777');
132
+ let activeTimeouts = await getActiveTimeouts();
133
+ expect(activeTimeouts).toHaveLength(1);
134
+ await clearTaskTimeout('TASK-10');
135
+ activeTimeouts = await getActiveTimeouts();
136
+ expect(activeTimeouts).toHaveLength(0);
137
+ });
138
+ });
139
+ describe('checkTimeouts', () => {
140
+ it('should detect timed out tasks', async () => {
141
+ // Create timeout with very short duration (100ms)
142
+ await startTaskTimeout('TASK-11', 100, 'agent-888');
143
+ // Wait for timeout to expire
144
+ await new Promise(resolve => setTimeout(resolve, 150));
145
+ const timedOutTasks = await checkTimeouts();
146
+ expect(timedOutTasks).toHaveLength(1);
147
+ expect(timedOutTasks[0].taskId).toBe('TASK-11');
148
+ expect(timedOutTasks[0].agentId).toBe('agent-888');
149
+ expect(timedOutTasks[0].checkpointId).toBeDefined();
150
+ expect(timedOutTasks[0].escalationEventId).toBeDefined();
151
+ });
152
+ it('should update status to warning at threshold', async () => {
153
+ // Create timeout with 100ms duration, warning at 50ms (50%)
154
+ await startTaskTimeout('TASK-12', 100, 'agent-999', { warningThreshold: 0.5 });
155
+ // Wait for warning threshold
156
+ await new Promise(resolve => setTimeout(resolve, 60));
157
+ await checkTimeouts();
158
+ const timeout = await getTaskTimeout('TASK-12');
159
+ expect(timeout).not.toBeNull();
160
+ expect(timeout.status).toBe('warning');
161
+ });
162
+ it('should not process already timed out tasks', async () => {
163
+ // Create and timeout a task
164
+ await startTaskTimeout('TASK-13', 100, 'agent-1010');
165
+ await new Promise(resolve => setTimeout(resolve, 150));
166
+ const firstCheck = await checkTimeouts();
167
+ expect(firstCheck).toHaveLength(1);
168
+ // Check again
169
+ const secondCheck = await checkTimeouts();
170
+ // Should not process again
171
+ expect(secondCheck).toHaveLength(0);
172
+ });
173
+ });
174
+ describe('handleTimeout', () => {
175
+ it('should create checkpoint and escalation event', async () => {
176
+ const { createCheckpoint } = await import('../checkpoint.js');
177
+ const { logEvent } = await import('../event-logger.js');
178
+ await startTaskTimeout('TASK-14', 100, 'agent-1111');
179
+ await new Promise(resolve => setTimeout(resolve, 150));
180
+ const result = await handleTimeout('TASK-14');
181
+ expect(result).not.toBeNull();
182
+ expect(result.taskId).toBe('TASK-14');
183
+ expect(result.checkpointId).toBeDefined();
184
+ expect(result.escalationEventId).toBeDefined();
185
+ // Verify checkpoint was created
186
+ expect(createCheckpoint).toHaveBeenCalledWith('TASK-14', 'agent-1111', expect.stringContaining('timeout'), expect.objectContaining({ reason: 'timeout' }));
187
+ // Verify escalation event was logged
188
+ expect(logEvent).toHaveBeenCalledWith(expect.objectContaining({
189
+ category: 'blocker',
190
+ description: expect.stringContaining('TASK-14 timed out'),
191
+ blocker_severity: 'high'
192
+ }));
193
+ });
194
+ it('should update timeout status to timed_out', async () => {
195
+ await startTaskTimeout('TASK-15', 100, 'agent-1212');
196
+ await new Promise(resolve => setTimeout(resolve, 150));
197
+ await handleTimeout('TASK-15');
198
+ const timeout = await getTaskTimeout('TASK-15');
199
+ expect(timeout).not.toBeNull();
200
+ expect(timeout.status).toBe('timed_out');
201
+ expect(timeout.checkpointId).toBeDefined();
202
+ expect(timeout.escalationEventId).toBeDefined();
203
+ });
204
+ it('should return null for non-existent timeout', async () => {
205
+ const result = await handleTimeout('TASK-NONEXISTENT');
206
+ expect(result).toBeNull();
207
+ });
208
+ });
209
+ describe('getAllTimeouts', () => {
210
+ it('should return all timeouts regardless of status', async () => {
211
+ await startTaskTimeout('TASK-16', 60000, 'agent-1313');
212
+ await startTaskTimeout('TASK-17', 100, 'agent-1414');
213
+ // Complete one
214
+ await clearTaskTimeout('TASK-16');
215
+ // Timeout another
216
+ await new Promise(resolve => setTimeout(resolve, 150));
217
+ await checkTimeouts();
218
+ const allTimeouts = await getAllTimeouts();
219
+ expect(allTimeouts).toHaveLength(2);
220
+ const statuses = allTimeouts.map(t => t.status).sort();
221
+ expect(statuses).toContain('completed');
222
+ expect(statuses).toContain('timed_out');
223
+ });
224
+ });
225
+ describe('cleanupOldTimeouts', () => {
226
+ it('should remove old completed timeouts', async () => {
227
+ await startTaskTimeout('TASK-18', 60000, 'agent-1515');
228
+ // Manually set old timestamp
229
+ const filePath = path.join(testDir, 'TASK-18.json');
230
+ const timeout = await fs.readJSON(filePath);
231
+ const oldDate = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000); // 8 days ago
232
+ timeout.startedAt = oldDate.toISOString();
233
+ timeout.status = 'completed';
234
+ await fs.writeJSON(filePath, timeout);
235
+ // Clean up timeouts older than 7 days
236
+ const cleanedCount = await cleanupOldTimeouts(7 * 24 * 60 * 60 * 1000);
237
+ expect(cleanedCount).toBe(1);
238
+ const fileExists = await fs.pathExists(filePath);
239
+ expect(fileExists).toBe(false);
240
+ });
241
+ it('should not remove active timeouts', async () => {
242
+ await startTaskTimeout('TASK-19', 60000, 'agent-1616');
243
+ // Manually set old timestamp but keep active
244
+ const filePath = path.join(testDir, 'TASK-19.json');
245
+ const timeout = await fs.readJSON(filePath);
246
+ const oldDate = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000);
247
+ timeout.startedAt = oldDate.toISOString();
248
+ // status remains 'active'
249
+ await fs.writeJSON(filePath, timeout);
250
+ const cleanedCount = await cleanupOldTimeouts(7 * 24 * 60 * 60 * 1000);
251
+ expect(cleanedCount).toBe(0);
252
+ const fileExists = await fs.pathExists(filePath);
253
+ expect(fileExists).toBe(true);
254
+ });
255
+ });
256
+ describe('TimeoutMonitor', () => {
257
+ it('should start and stop monitoring', () => {
258
+ const monitor = new TimeoutMonitor({ checkInterval: 1000 });
259
+ monitor.start();
260
+ let status = monitor.getStatus();
261
+ expect(status.isRunning).toBe(true);
262
+ expect(status.checkInterval).toBe(1000);
263
+ monitor.stop();
264
+ status = monitor.getStatus();
265
+ expect(status.isRunning).toBe(false);
266
+ });
267
+ it('should not start twice', () => {
268
+ const monitor = new TimeoutMonitor();
269
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
270
+ monitor.start();
271
+ monitor.start();
272
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('already started'));
273
+ monitor.stop();
274
+ consoleSpy.mockRestore();
275
+ });
276
+ });
277
+ });
278
+ //# sourceMappingURL=task-timeout.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-timeout.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/task-timeout.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileType: utility
3
+ * @status: current
4
+ * @updated: 2025-12-05
5
+ * @tags: [agent, heartbeat, epic-004, multi-agent]
6
+ * @related: [event-queue.ts, ../commands/graph/api-client.ts]
7
+ * @priority: high
8
+ * @complexity: low
9
+ * @dependencies: []
10
+ */
11
+ /**
12
+ * Agent Heartbeat Manager
13
+ *
14
+ * Sends periodic heartbeat signals to dashboard API to maintain agent online status.
15
+ *
16
+ * Pattern:
17
+ * - Sends heartbeat every 30 seconds when active
18
+ * - Uses .unref() on timer to allow process to exit if no other work pending
19
+ * - Stale agents (no heartbeat for 5 min) marked offline by dashboard
20
+ * - Offline agents excluded from task assignment
21
+ *
22
+ * Usage:
23
+ * ```typescript
24
+ * const { startHeartbeat, stopHeartbeat } = require('./agent-heartbeat');
25
+ *
26
+ * // Start heartbeat when agent becomes active
27
+ * startHeartbeat('agent_123456_abc');
28
+ *
29
+ * // Stop heartbeat when agent deactivates
30
+ * stopHeartbeat();
31
+ * ```
32
+ */
33
+ /**
34
+ * Heartbeat configuration
35
+ */
36
+ interface HeartbeatConfig {
37
+ intervalMs: number;
38
+ dashboardUrl: string;
39
+ }
40
+ /**
41
+ * Start sending periodic heartbeats
42
+ *
43
+ * @param agentId - Agent ID to send heartbeats for
44
+ * @param config - Optional configuration overrides
45
+ */
46
+ export declare function startHeartbeat(agentId: string, config?: Partial<HeartbeatConfig>): void;
47
+ /**
48
+ * Stop sending heartbeats
49
+ */
50
+ export declare function stopHeartbeat(): void;
51
+ /**
52
+ * Graceful shutdown - send final heartbeat and stop
53
+ */
54
+ export declare function shutdownHeartbeat(): Promise<void>;
55
+ /**
56
+ * Check if heartbeat is currently running
57
+ *
58
+ * @returns True if heartbeat is active
59
+ */
60
+ export declare function isHeartbeatRunning(): boolean;
61
+ /**
62
+ * Get current agent ID (if heartbeat is running)
63
+ *
64
+ * @returns Current agent ID or null
65
+ */
66
+ export declare function getCurrentAgentId(): string | null;
67
+ export {};
68
+ //# sourceMappingURL=agent-heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-heartbeat.d.ts","sourceRoot":"","sources":["../../src/lib/agent-heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;GAEG;AACH,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqCD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CA0BvF;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAOpC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBvD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * @fileType: utility
3
+ * @status: current
4
+ * @updated: 2025-12-05
5
+ * @tags: [agent, heartbeat, epic-004, multi-agent]
6
+ * @related: [event-queue.ts, ../commands/graph/api-client.ts]
7
+ * @priority: high
8
+ * @complexity: low
9
+ * @dependencies: []
10
+ */
11
+ const DEFAULT_CONFIG = {
12
+ intervalMs: 30 * 1000, // 30 seconds
13
+ dashboardUrl: process.env.GINKO_DASHBOARD_URL || 'https://app.ginkoai.com',
14
+ };
15
+ /**
16
+ * Global heartbeat state
17
+ */
18
+ let heartbeatTimer = null;
19
+ let currentAgentId = null;
20
+ let isShuttingDown = false;
21
+ /**
22
+ * Send heartbeat to dashboard API
23
+ *
24
+ * @param agentId - Agent ID to send heartbeat for
25
+ * @returns Promise that resolves when heartbeat is sent
26
+ */
27
+ async function sendHeartbeat(agentId) {
28
+ if (isShuttingDown) {
29
+ return;
30
+ }
31
+ try {
32
+ // Import graph API client lazily
33
+ const { sendAgentHeartbeat } = await import('../commands/graph/api-client.js');
34
+ // Send heartbeat via API client
35
+ await sendAgentHeartbeat(agentId);
36
+ }
37
+ catch (error) {
38
+ // Log but don't throw - heartbeat failures shouldn't crash the CLI
39
+ console.warn('[AgentHeartbeat] Failed to send heartbeat:', error instanceof Error ? error.message : String(error));
40
+ }
41
+ }
42
+ /**
43
+ * Start sending periodic heartbeats
44
+ *
45
+ * @param agentId - Agent ID to send heartbeats for
46
+ * @param config - Optional configuration overrides
47
+ */
48
+ export function startHeartbeat(agentId, config) {
49
+ if (heartbeatTimer) {
50
+ console.warn('[AgentHeartbeat] Heartbeat already running, stopping previous instance');
51
+ stopHeartbeat();
52
+ }
53
+ const finalConfig = { ...DEFAULT_CONFIG, ...config };
54
+ currentAgentId = agentId;
55
+ console.log(`[AgentHeartbeat] Starting heartbeat for agent ${agentId} (interval: ${finalConfig.intervalMs / 1000}s)`);
56
+ // Send initial heartbeat immediately
57
+ sendHeartbeat(agentId).catch(error => {
58
+ console.warn('[AgentHeartbeat] Initial heartbeat failed:', error instanceof Error ? error.message : String(error));
59
+ });
60
+ // Schedule periodic heartbeats
61
+ // Use unref() to allow process to exit if no other work pending
62
+ heartbeatTimer = setInterval(() => {
63
+ sendHeartbeat(agentId).catch(error => {
64
+ console.warn('[AgentHeartbeat] Scheduled heartbeat failed:', error instanceof Error ? error.message : String(error));
65
+ });
66
+ }, finalConfig.intervalMs);
67
+ // Don't keep process alive just for this timer
68
+ heartbeatTimer.unref();
69
+ }
70
+ /**
71
+ * Stop sending heartbeats
72
+ */
73
+ export function stopHeartbeat() {
74
+ if (heartbeatTimer) {
75
+ clearInterval(heartbeatTimer);
76
+ heartbeatTimer = null;
77
+ console.log('[AgentHeartbeat] Heartbeat stopped');
78
+ }
79
+ currentAgentId = null;
80
+ }
81
+ /**
82
+ * Graceful shutdown - send final heartbeat and stop
83
+ */
84
+ export async function shutdownHeartbeat() {
85
+ console.log('[AgentHeartbeat] Initiating graceful shutdown...');
86
+ isShuttingDown = true;
87
+ // Send final heartbeat if we have an agent ID
88
+ if (currentAgentId) {
89
+ try {
90
+ await sendHeartbeat(currentAgentId);
91
+ console.log('[AgentHeartbeat] Final heartbeat sent');
92
+ }
93
+ catch (error) {
94
+ console.warn('[AgentHeartbeat] Final heartbeat failed:', error instanceof Error ? error.message : String(error));
95
+ }
96
+ }
97
+ // Stop timer
98
+ stopHeartbeat();
99
+ console.log('[AgentHeartbeat] Shutdown complete');
100
+ }
101
+ /**
102
+ * Check if heartbeat is currently running
103
+ *
104
+ * @returns True if heartbeat is active
105
+ */
106
+ export function isHeartbeatRunning() {
107
+ return heartbeatTimer !== null;
108
+ }
109
+ /**
110
+ * Get current agent ID (if heartbeat is running)
111
+ *
112
+ * @returns Current agent ID or null
113
+ */
114
+ export function getCurrentAgentId() {
115
+ return currentAgentId;
116
+ }
117
+ //# sourceMappingURL=agent-heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-heartbeat.js","sourceRoot":"","sources":["../../src/lib/agent-heartbeat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @fileType: utility
3
+ * @status: current
4
+ * @updated: 2025-12-07
5
+ * @tags: [checkpoint, resilience, rollback, epic-004-sprint5, task-1]
6
+ * @related: [rollback.ts, event-logger.ts, orchestrator-state.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [fs-extra, uuid, simple-git]
10
+ */
11
+ /**
12
+ * Checkpoint interface (EPIC-004 Sprint 5 TASK-1)
13
+ *
14
+ * Checkpoints are lightweight references to work state, not full snapshots.
15
+ * They capture git commit, modified files, and event stream position.
16
+ * Actual rollback uses git operations, not stored copies.
17
+ */
18
+ export interface Checkpoint {
19
+ id: string;
20
+ taskId: string;
21
+ agentId: string;
22
+ timestamp: Date;
23
+ gitCommit: string;
24
+ filesModified: string[];
25
+ eventsSince: string;
26
+ metadata: Record<string, any>;
27
+ message?: string;
28
+ }
29
+ /**
30
+ * Create a checkpoint
31
+ *
32
+ * Captures current work state:
33
+ * - Git commit hash
34
+ * - Modified files since task start
35
+ * - Last event ID from event stream
36
+ * - Optional message and metadata
37
+ *
38
+ * @param taskId - Task ID this checkpoint belongs to
39
+ * @param agentId - Agent creating checkpoint (optional, auto-detected)
40
+ * @param message - Optional description
41
+ * @param metadata - Optional additional data
42
+ */
43
+ export declare function createCheckpoint(taskId: string, agentId?: string, message?: string, metadata?: Record<string, any>): Promise<Checkpoint>;
44
+ /**
45
+ * Get a specific checkpoint by ID
46
+ *
47
+ * @param checkpointId - Checkpoint ID
48
+ * @returns Checkpoint object or null if not found
49
+ */
50
+ export declare function getCheckpoint(checkpointId: string): Promise<Checkpoint | null>;
51
+ /**
52
+ * List checkpoints, optionally filtered by task ID
53
+ *
54
+ * @param taskId - Optional task ID to filter by
55
+ * @returns Array of checkpoints, sorted by timestamp (newest first)
56
+ */
57
+ export declare function listCheckpoints(taskId?: string): Promise<Checkpoint[]>;
58
+ /**
59
+ * Delete a checkpoint
60
+ *
61
+ * @param checkpointId - Checkpoint ID to delete
62
+ */
63
+ export declare function deleteCheckpoint(checkpointId: string): Promise<void>;
64
+ /**
65
+ * Get checkpoints for a specific task, grouped by day
66
+ * Useful for displaying checkpoint history
67
+ */
68
+ export declare function getCheckpointsByTask(taskId: string): Promise<Map<string, Checkpoint[]>>;
69
+ /**
70
+ * Get the most recent checkpoint for a task
71
+ */
72
+ export declare function getLatestCheckpoint(taskId: string): Promise<Checkpoint | null>;
73
+ /**
74
+ * Check if a checkpoint exists
75
+ */
76
+ export declare function checkpointExists(checkpointId: string): Promise<boolean>;
77
+ /**
78
+ * Export checkpoint data for backup or transfer
79
+ */
80
+ export declare function exportCheckpoint(checkpointId: string): Promise<string>;
81
+ /**
82
+ * Import checkpoint data from backup
83
+ */
84
+ export declare function importCheckpoint(checkpointData: string): Promise<Checkpoint>;
85
+ //# sourceMappingURL=checkpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/lib/checkpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA+ID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,OAAO,CAAC,UAAU,CAAC,CAqCrB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAkBpF;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAoC5E;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1E;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAe7F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmBlF"}