@proletariat/cli 0.3.94 → 0.3.95

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 (237) hide show
  1. package/dist/commands/agent/cleanup.d.ts +3 -4
  2. package/dist/commands/agent/cleanup.js +5 -4
  3. package/dist/commands/agent/cleanup.js.map +1 -1
  4. package/dist/commands/agent/gc.d.ts +3 -4
  5. package/dist/commands/agent/gc.js +5 -4
  6. package/dist/commands/agent/gc.js.map +1 -1
  7. package/dist/commands/agent/index.d.ts +3 -4
  8. package/dist/commands/agent/index.js +5 -4
  9. package/dist/commands/agent/index.js.map +1 -1
  10. package/dist/commands/agent/list.d.ts +3 -4
  11. package/dist/commands/agent/list.js +5 -4
  12. package/dist/commands/agent/list.js.map +1 -1
  13. package/dist/commands/agent/remove.d.ts +3 -4
  14. package/dist/commands/agent/remove.js +5 -4
  15. package/dist/commands/agent/remove.js.map +1 -1
  16. package/dist/commands/agent/staff/index.d.ts +3 -4
  17. package/dist/commands/agent/staff/index.js +5 -4
  18. package/dist/commands/agent/staff/index.js.map +1 -1
  19. package/dist/commands/agent/staff/remove.d.ts +3 -4
  20. package/dist/commands/agent/staff/remove.js +5 -4
  21. package/dist/commands/agent/staff/remove.js.map +1 -1
  22. package/dist/commands/agent/status.d.ts +3 -4
  23. package/dist/commands/agent/status.js +5 -4
  24. package/dist/commands/agent/status.js.map +1 -1
  25. package/dist/commands/agent/visit.d.ts +3 -4
  26. package/dist/commands/agent/visit.js +5 -4
  27. package/dist/commands/agent/visit.js.map +1 -1
  28. package/dist/commands/branch/create.js +1 -12
  29. package/dist/commands/branch/create.js.map +1 -1
  30. package/dist/commands/branch/list.d.ts +3 -4
  31. package/dist/commands/branch/list.js +5 -4
  32. package/dist/commands/branch/list.js.map +1 -1
  33. package/dist/commands/branch/validate.d.ts +3 -4
  34. package/dist/commands/branch/validate.js +6 -5
  35. package/dist/commands/branch/validate.js.map +1 -1
  36. package/dist/commands/branch/where.d.ts +3 -4
  37. package/dist/commands/branch/where.js +5 -4
  38. package/dist/commands/branch/where.js.map +1 -1
  39. package/dist/commands/commit.js +1 -1
  40. package/dist/commands/commit.js.map +1 -1
  41. package/dist/commands/db/backup.d.ts +16 -0
  42. package/dist/commands/db/backup.js +125 -0
  43. package/dist/commands/db/backup.js.map +1 -0
  44. package/dist/commands/db/repair.js +8 -11
  45. package/dist/commands/db/repair.js.map +1 -1
  46. package/dist/commands/execution/config.d.ts +3 -4
  47. package/dist/commands/execution/config.js +5 -4
  48. package/dist/commands/execution/config.js.map +1 -1
  49. package/dist/commands/execution/index.d.ts +3 -4
  50. package/dist/commands/execution/index.js +5 -4
  51. package/dist/commands/execution/index.js.map +1 -1
  52. package/dist/commands/execution/list.d.ts +3 -4
  53. package/dist/commands/execution/list.js +5 -4
  54. package/dist/commands/execution/list.js.map +1 -1
  55. package/dist/commands/execution/logs.d.ts +3 -4
  56. package/dist/commands/execution/logs.js +5 -4
  57. package/dist/commands/execution/logs.js.map +1 -1
  58. package/dist/commands/execution/stop.d.ts +3 -4
  59. package/dist/commands/execution/stop.js +5 -4
  60. package/dist/commands/execution/stop.js.map +1 -1
  61. package/dist/commands/execution/view.d.ts +3 -4
  62. package/dist/commands/execution/view.js +5 -4
  63. package/dist/commands/execution/view.js.map +1 -1
  64. package/dist/commands/hook/export.d.ts +3 -4
  65. package/dist/commands/hook/export.js +5 -4
  66. package/dist/commands/hook/export.js.map +1 -1
  67. package/dist/commands/hook/fire.d.ts +3 -4
  68. package/dist/commands/hook/fire.js +5 -4
  69. package/dist/commands/hook/fire.js.map +1 -1
  70. package/dist/commands/hook/list.d.ts +3 -4
  71. package/dist/commands/hook/list.js +5 -4
  72. package/dist/commands/hook/list.js.map +1 -1
  73. package/dist/commands/hook/preset.d.ts +3 -4
  74. package/dist/commands/hook/preset.js +5 -4
  75. package/dist/commands/hook/preset.js.map +1 -1
  76. package/dist/commands/orchestrate/index.d.ts +3 -4
  77. package/dist/commands/orchestrate/index.js +5 -4
  78. package/dist/commands/orchestrate/index.js.map +1 -1
  79. package/dist/commands/orchestrator/index.d.ts +3 -4
  80. package/dist/commands/orchestrator/index.js +5 -4
  81. package/dist/commands/orchestrator/index.js.map +1 -1
  82. package/dist/commands/pr/checks.d.ts +3 -4
  83. package/dist/commands/pr/checks.js +5 -4
  84. package/dist/commands/pr/checks.js.map +1 -1
  85. package/dist/commands/repo/add.d.ts +3 -4
  86. package/dist/commands/repo/add.js +5 -4
  87. package/dist/commands/repo/add.js.map +1 -1
  88. package/dist/commands/repo/create.d.ts +3 -4
  89. package/dist/commands/repo/create.js +5 -4
  90. package/dist/commands/repo/create.js.map +1 -1
  91. package/dist/commands/repo/fix-remotes.d.ts +3 -4
  92. package/dist/commands/repo/fix-remotes.js +5 -4
  93. package/dist/commands/repo/fix-remotes.js.map +1 -1
  94. package/dist/commands/repo/index.d.ts +3 -4
  95. package/dist/commands/repo/index.js +5 -4
  96. package/dist/commands/repo/index.js.map +1 -1
  97. package/dist/commands/repo/list.d.ts +3 -4
  98. package/dist/commands/repo/list.js +5 -4
  99. package/dist/commands/repo/list.js.map +1 -1
  100. package/dist/commands/session/cleanup.d.ts +3 -4
  101. package/dist/commands/session/cleanup.js +5 -4
  102. package/dist/commands/session/cleanup.js.map +1 -1
  103. package/dist/commands/session/create.d.ts +3 -4
  104. package/dist/commands/session/create.js +5 -4
  105. package/dist/commands/session/create.js.map +1 -1
  106. package/dist/commands/session/exec.d.ts +3 -4
  107. package/dist/commands/session/exec.js +5 -4
  108. package/dist/commands/session/exec.js.map +1 -1
  109. package/dist/commands/session/health.js +18 -0
  110. package/dist/commands/session/health.js.map +1 -1
  111. package/dist/commands/session/index.d.ts +3 -4
  112. package/dist/commands/session/index.js +9 -4
  113. package/dist/commands/session/index.js.map +1 -1
  114. package/dist/commands/session/inspect.d.ts +3 -4
  115. package/dist/commands/session/inspect.js +5 -4
  116. package/dist/commands/session/inspect.js.map +1 -1
  117. package/dist/commands/session/list.d.ts +3 -4
  118. package/dist/commands/session/list.js +19 -5
  119. package/dist/commands/session/list.js.map +1 -1
  120. package/dist/commands/session/prune.d.ts +3 -4
  121. package/dist/commands/session/prune.js +5 -4
  122. package/dist/commands/session/prune.js.map +1 -1
  123. package/dist/commands/session/report.d.ts +25 -5
  124. package/dist/commands/session/report.js +201 -5
  125. package/dist/commands/session/report.js.map +1 -1
  126. package/dist/commands/session/restart.d.ts +3 -4
  127. package/dist/commands/session/restart.js +5 -4
  128. package/dist/commands/session/restart.js.map +1 -1
  129. package/dist/commands/session/watch.d.ts +17 -0
  130. package/dist/commands/session/watch.js +139 -0
  131. package/dist/commands/session/watch.js.map +1 -0
  132. package/dist/commands/ticket/index.d.ts +3 -4
  133. package/dist/commands/ticket/index.js +5 -4
  134. package/dist/commands/ticket/index.js.map +1 -1
  135. package/dist/commands/web.d.ts +20 -0
  136. package/dist/commands/web.js +82 -0
  137. package/dist/commands/web.js.map +1 -0
  138. package/dist/commands/work/hooks/add.d.ts +3 -4
  139. package/dist/commands/work/hooks/add.js +5 -4
  140. package/dist/commands/work/hooks/add.js.map +1 -1
  141. package/dist/commands/work/hooks/list.d.ts +3 -4
  142. package/dist/commands/work/hooks/list.js +5 -4
  143. package/dist/commands/work/hooks/list.js.map +1 -1
  144. package/dist/commands/work/hooks/toggle.d.ts +3 -4
  145. package/dist/commands/work/hooks/toggle.js +5 -4
  146. package/dist/commands/work/hooks/toggle.js.map +1 -1
  147. package/dist/commands/work/peek.d.ts +3 -4
  148. package/dist/commands/work/peek.js +5 -4
  149. package/dist/commands/work/peek.js.map +1 -1
  150. package/dist/commands/work/propose.d.ts +23 -0
  151. package/dist/commands/work/propose.js +57 -0
  152. package/dist/commands/work/propose.js.map +1 -0
  153. package/dist/commands/work/ready.js +2 -2
  154. package/dist/commands/work/ready.js.map +1 -1
  155. package/dist/commands/work/rebase.d.ts +1 -1
  156. package/dist/commands/work/rebase.js +52 -49
  157. package/dist/commands/work/rebase.js.map +1 -1
  158. package/dist/commands/work/ship.d.ts +6 -0
  159. package/dist/commands/work/ship.js +217 -48
  160. package/dist/commands/work/ship.js.map +1 -1
  161. package/dist/commands/work/start.js +3 -6
  162. package/dist/commands/work/start.js.map +1 -1
  163. package/dist/commands/work/stop.d.ts +3 -4
  164. package/dist/commands/work/stop.js +5 -4
  165. package/dist/commands/work/stop.js.map +1 -1
  166. package/dist/hooks/init.js +11 -1
  167. package/dist/hooks/init.js.map +1 -1
  168. package/dist/lib/branch/index.d.ts +6 -5
  169. package/dist/lib/branch/index.js +8 -13
  170. package/dist/lib/branch/index.js.map +1 -1
  171. package/dist/lib/dashboard/html.d.ts +2 -1
  172. package/dist/lib/dashboard/html.js +150 -522
  173. package/dist/lib/dashboard/html.js.map +1 -1
  174. package/dist/lib/database/db-safety.d.ts +48 -9
  175. package/dist/lib/database/db-safety.js +308 -43
  176. package/dist/lib/database/db-safety.js.map +1 -1
  177. package/dist/lib/database/index.d.ts +1 -1
  178. package/dist/lib/database/index.js +1 -1
  179. package/dist/lib/database/index.js.map +1 -1
  180. package/dist/lib/database/workspace.js +3 -1
  181. package/dist/lib/database/workspace.js.map +1 -1
  182. package/dist/lib/execution/runners/docker.js +8 -0
  183. package/dist/lib/execution/runners/docker.js.map +1 -1
  184. package/dist/lib/execution/runners/prompt-builder.js +9 -6
  185. package/dist/lib/execution/runners/prompt-builder.js.map +1 -1
  186. package/dist/lib/execution/spawner.js +2 -4
  187. package/dist/lib/execution/spawner.js.map +1 -1
  188. package/dist/lib/execution/storage.d.ts +29 -1
  189. package/dist/lib/execution/storage.js +77 -0
  190. package/dist/lib/execution/storage.js.map +1 -1
  191. package/dist/lib/execution/types.d.ts +17 -6
  192. package/dist/lib/execution/types.js +10 -7
  193. package/dist/lib/execution/types.js.map +1 -1
  194. package/dist/lib/machine-config.d.ts +8 -0
  195. package/dist/lib/machine-config.js +37 -0
  196. package/dist/lib/machine-config.js.map +1 -1
  197. package/dist/lib/orchestrate/poller.d.ts +1 -1
  198. package/dist/lib/orchestrate/poller.js +1 -1
  199. package/dist/lib/pmo/storage/base.js +5 -3
  200. package/dist/lib/pmo/storage/base.js.map +1 -1
  201. package/dist/lib/providers/index.d.ts +1 -0
  202. package/dist/lib/providers/index.js +1 -0
  203. package/dist/lib/providers/index.js.map +1 -1
  204. package/dist/lib/providers/resolver.js +16 -0
  205. package/dist/lib/providers/resolver.js.map +1 -1
  206. package/dist/lib/providers/trello-provider.d.ts +28 -0
  207. package/dist/lib/providers/trello-provider.js +381 -0
  208. package/dist/lib/providers/trello-provider.js.map +1 -0
  209. package/dist/lib/session/heartbeat.d.ts +45 -0
  210. package/dist/lib/session/heartbeat.js +150 -0
  211. package/dist/lib/session/heartbeat.js.map +1 -0
  212. package/dist/lib/session/index.d.ts +7 -0
  213. package/dist/lib/session/index.js +8 -0
  214. package/dist/lib/session/index.js.map +1 -0
  215. package/dist/lib/session/watcher.d.ts +79 -0
  216. package/dist/lib/session/watcher.js +142 -0
  217. package/dist/lib/session/watcher.js.map +1 -0
  218. package/dist/lib/shipping/auto-merge.d.ts +57 -0
  219. package/dist/lib/shipping/auto-merge.js +311 -0
  220. package/dist/lib/shipping/auto-merge.js.map +1 -0
  221. package/dist/lib/shipping/github.d.ts +68 -0
  222. package/dist/lib/shipping/github.js +217 -0
  223. package/dist/lib/shipping/github.js.map +1 -0
  224. package/dist/lib/shipping/index.d.ts +13 -0
  225. package/dist/lib/shipping/index.js +11 -0
  226. package/dist/lib/shipping/index.js.map +1 -0
  227. package/dist/lib/shipping/rebase.d.ts +35 -0
  228. package/dist/lib/shipping/rebase.js +107 -0
  229. package/dist/lib/shipping/rebase.js.map +1 -0
  230. package/dist/lib/shipping/types.d.ts +181 -0
  231. package/dist/lib/shipping/types.js +9 -0
  232. package/dist/lib/shipping/types.js.map +1 -0
  233. package/dist/lib/trello/client.d.ts +1 -0
  234. package/dist/lib/trello/client.js +6 -0
  235. package/dist/lib/trello/client.js.map +1 -1
  236. package/oclif.manifest.json +908 -1009
  237. package/package.json +8 -8
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Session Watcher
3
+ *
4
+ * Host-side cron/poll loop that monitors agent heartbeats and takes action
5
+ * on stale executions. This is the safety net for detecting hung agents
6
+ * that can't self-report (OOM kills, zombie processes, container crashes).
7
+ *
8
+ * Architecture:
9
+ * 1. Poll: Check all running executions for heartbeat timeout
10
+ * 2. Update: Record heartbeats for alive agents (tmux pane inspection)
11
+ * 3. Detect: Find stale executions that exceeded the timeout
12
+ * 4. Act: Mark failed, kill containers, fire events
13
+ */
14
+ import type Database from 'better-sqlite3';
15
+ import type { AgentWork } from '../execution/types.js';
16
+ import { type StaleExecution } from './heartbeat.js';
17
+ export interface WatcherOptions {
18
+ /** Database connection */
19
+ db: Database.Database;
20
+ /** Poll interval in minutes (default: 5) */
21
+ intervalMinutes?: number;
22
+ /** Heartbeat timeout in minutes (default: 15) */
23
+ timeoutMinutes?: number;
24
+ /** Whether to kill containers on timeout (default: true) */
25
+ autoKill?: boolean;
26
+ /** Logger function */
27
+ log?: (msg: string) => void;
28
+ /** Callback when a stale execution is detected and handled */
29
+ onStaleDetected?: (execution: AgentWork, reason: string) => void | Promise<void>;
30
+ }
31
+ export interface WatchCycleResult {
32
+ /** Number of active executions checked */
33
+ checked: number;
34
+ /** Number of heartbeats updated (agents confirmed alive) */
35
+ heartbeatsUpdated: number;
36
+ /** Stale executions detected and acted upon */
37
+ staleExecutions: StaleExecution[];
38
+ /** Number of containers killed */
39
+ containersKilled: number;
40
+ }
41
+ export declare class SessionWatcher {
42
+ private storage;
43
+ private db;
44
+ private intervalMinutes;
45
+ private timeoutMinutes;
46
+ private autoKill;
47
+ private log;
48
+ private onStaleDetected?;
49
+ private timer;
50
+ private running;
51
+ constructor(options: WatcherOptions);
52
+ /**
53
+ * Run a single watch cycle.
54
+ * Can be called directly for one-shot checking, or used by the polling loop.
55
+ */
56
+ runCycle(): Promise<WatchCycleResult>;
57
+ /**
58
+ * Start the polling loop.
59
+ * Runs an initial cycle immediately, then polls at the configured interval.
60
+ */
61
+ start(): void;
62
+ /**
63
+ * Stop the polling loop.
64
+ */
65
+ stop(): void;
66
+ /**
67
+ * Check if the watcher is currently running.
68
+ */
69
+ isRunning(): boolean;
70
+ /**
71
+ * Get current configuration.
72
+ */
73
+ getConfig(): {
74
+ intervalMinutes: number;
75
+ timeoutMinutes: number;
76
+ autoKill: boolean;
77
+ };
78
+ private runCycleWithErrorHandling;
79
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Session Watcher
3
+ *
4
+ * Host-side cron/poll loop that monitors agent heartbeats and takes action
5
+ * on stale executions. This is the safety net for detecting hung agents
6
+ * that can't self-report (OOM kills, zombie processes, container crashes).
7
+ *
8
+ * Architecture:
9
+ * 1. Poll: Check all running executions for heartbeat timeout
10
+ * 2. Update: Record heartbeats for alive agents (tmux pane inspection)
11
+ * 3. Detect: Find stale executions that exceeded the timeout
12
+ * 4. Act: Mark failed, kill containers, fire events
13
+ */
14
+ import { ExecutionStorage } from '../execution/storage.js';
15
+ import { recordAllHeartbeats, detectStaleExecutions, killContainer, } from './heartbeat.js';
16
+ // =============================================================================
17
+ // Session Watcher
18
+ // =============================================================================
19
+ export class SessionWatcher {
20
+ storage;
21
+ db;
22
+ intervalMinutes;
23
+ timeoutMinutes;
24
+ autoKill;
25
+ log;
26
+ onStaleDetected;
27
+ timer = null;
28
+ running = false;
29
+ constructor(options) {
30
+ this.db = options.db;
31
+ this.storage = new ExecutionStorage(options.db);
32
+ this.intervalMinutes = options.intervalMinutes ?? 5;
33
+ this.timeoutMinutes = options.timeoutMinutes ?? 15;
34
+ this.autoKill = options.autoKill ?? true;
35
+ this.log = options.log ?? (() => { });
36
+ this.onStaleDetected = options.onStaleDetected;
37
+ }
38
+ /**
39
+ * Run a single watch cycle.
40
+ * Can be called directly for one-shot checking, or used by the polling loop.
41
+ */
42
+ async runCycle() {
43
+ const result = {
44
+ checked: 0,
45
+ heartbeatsUpdated: 0,
46
+ staleExecutions: [],
47
+ containersKilled: 0,
48
+ };
49
+ // Phase 1: Record heartbeats for all active executions
50
+ // This is the "push" side — we check tmux panes and update heartbeats
51
+ const heartbeats = recordAllHeartbeats(this.storage);
52
+ result.heartbeatsUpdated = heartbeats.size;
53
+ result.checked = heartbeats.size;
54
+ // Phase 2: Detect stale executions that exceeded timeout
55
+ // This is the "pull" side — safety net for completely dead agents
56
+ const staleExecutions = detectStaleExecutions(this.storage, this.timeoutMinutes);
57
+ result.staleExecutions = staleExecutions;
58
+ // Phase 3: Act on stale executions
59
+ for (const stale of staleExecutions) {
60
+ const exec = stale.execution;
61
+ this.log(`[watcher] Stale agent detected: ${exec.agentName} (${exec.ticketId}) — ${stale.reason}`);
62
+ // Mark execution as failed due to heartbeat timeout
63
+ this.storage.markHeartbeatTimeout(exec.id);
64
+ // Kill container if configured and applicable
65
+ if (this.autoKill && exec.containerId) {
66
+ this.log(`[watcher] Killing container ${exec.containerId} for ${exec.agentName}`);
67
+ const killed = killContainer(exec.containerId);
68
+ if (killed) {
69
+ result.containersKilled++;
70
+ this.log(`[watcher] Container ${exec.containerId} killed`);
71
+ }
72
+ else {
73
+ this.log(`[watcher] Failed to kill container ${exec.containerId}`);
74
+ }
75
+ }
76
+ // Fire callback
77
+ if (this.onStaleDetected) {
78
+ await this.onStaleDetected(exec, stale.reason);
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ /**
84
+ * Start the polling loop.
85
+ * Runs an initial cycle immediately, then polls at the configured interval.
86
+ */
87
+ start() {
88
+ if (this.running)
89
+ return;
90
+ this.running = true;
91
+ this.log(`[watcher] Starting session watcher (interval: ${this.intervalMinutes}m, timeout: ${this.timeoutMinutes}m, auto-kill: ${this.autoKill})`);
92
+ // Run initial cycle
93
+ void this.runCycleWithErrorHandling();
94
+ // Start polling
95
+ const intervalMs = this.intervalMinutes * 60 * 1000;
96
+ this.timer = setInterval(() => {
97
+ void this.runCycleWithErrorHandling();
98
+ }, intervalMs);
99
+ }
100
+ /**
101
+ * Stop the polling loop.
102
+ */
103
+ stop() {
104
+ if (!this.running)
105
+ return;
106
+ this.running = false;
107
+ if (this.timer) {
108
+ clearInterval(this.timer);
109
+ this.timer = null;
110
+ }
111
+ this.log('[watcher] Session watcher stopped');
112
+ }
113
+ /**
114
+ * Check if the watcher is currently running.
115
+ */
116
+ isRunning() {
117
+ return this.running;
118
+ }
119
+ /**
120
+ * Get current configuration.
121
+ */
122
+ getConfig() {
123
+ return {
124
+ intervalMinutes: this.intervalMinutes,
125
+ timeoutMinutes: this.timeoutMinutes,
126
+ autoKill: this.autoKill,
127
+ };
128
+ }
129
+ async runCycleWithErrorHandling() {
130
+ try {
131
+ const result = await this.runCycle();
132
+ if (result.staleExecutions.length > 0) {
133
+ this.log(`[watcher] Cycle complete: ${result.checked} checked, ${result.heartbeatsUpdated} heartbeats, ` +
134
+ `${result.staleExecutions.length} stale, ${result.containersKilled} killed`);
135
+ }
136
+ }
137
+ catch (error) {
138
+ this.log(`[watcher] Error during watch cycle: ${error instanceof Error ? error.message : error}`);
139
+ }
140
+ }
141
+ }
142
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/lib/session/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE1D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,GAEd,MAAM,gBAAgB,CAAA;AAgCvB,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,MAAM,OAAO,cAAc;IACjB,OAAO,CAAkB;IACzB,EAAE,CAAmB;IACrB,eAAe,CAAQ;IACvB,cAAc,CAAQ;IACtB,QAAQ,CAAS;IACjB,GAAG,CAAuB;IAC1B,eAAe,CAAiE;IAChF,KAAK,GAA0C,IAAI,CAAA;IACnD,OAAO,GAAG,KAAK,CAAA;IAEvB,YAAY,OAAuB;QACjC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC/C,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,CAAA;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,EAAE,CAAA;QAClD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAA;QACxC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAA;IAChD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,MAAM,GAAqB;YAC/B,OAAO,EAAE,CAAC;YACV,iBAAiB,EAAE,CAAC;YACpB,eAAe,EAAE,EAAE;YACnB,gBAAgB,EAAE,CAAC;SACpB,CAAA;QAED,uDAAuD;QACvD,sEAAsE;QACtE,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACpD,MAAM,CAAC,iBAAiB,GAAG,UAAU,CAAC,IAAI,CAAA;QAC1C,MAAM,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAA;QAEhC,yDAAyD;QACzD,kEAAkE;QAClE,MAAM,eAAe,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QAChF,MAAM,CAAC,eAAe,GAAG,eAAe,CAAA;QAExC,mCAAmC;QACnC,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAA;YAC5B,IAAI,CAAC,GAAG,CACN,mCAAmC,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,CACzF,CAAA;YAED,oDAAoD;YACpD,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAE1C,8CAA8C;YAC9C,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtC,IAAI,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,WAAW,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;gBACjF,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;gBAC9C,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,CAAC,gBAAgB,EAAE,CAAA;oBACzB,IAAI,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,WAAW,SAAS,CAAC,CAAA;gBAC5D,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,CAAC,sCAAsC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;gBACpE,CAAC;YACH,CAAC;YAED,gBAAgB;YAChB,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzB,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;YAChD,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QAEnB,IAAI,CAAC,GAAG,CACN,iDAAiD,IAAI,CAAC,eAAe,eAAe,IAAI,CAAC,cAAc,iBAAiB,IAAI,CAAC,QAAQ,GAAG,CACzI,CAAA;QAED,oBAAoB;QACpB,KAAK,IAAI,CAAC,yBAAyB,EAAE,CAAA;QAErC,gBAAgB;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,GAAG,EAAE,GAAG,IAAI,CAAA;QACnD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,yBAAyB,EAAE,CAAA;QACvC,CAAC,EAAE,UAAU,CAAC,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAM;QACzB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QAEpB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACnB,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;IAC/C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO;YACL,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAA;IACH,CAAC;IAEO,KAAK,CAAC,yBAAyB;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAA;YACpC,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,IAAI,CAAC,GAAG,CACN,6BAA6B,MAAM,CAAC,OAAO,aAAa,MAAM,CAAC,iBAAiB,eAAe;oBAC/F,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,WAAW,MAAM,CAAC,gBAAgB,SAAS,CAC5E,CAAA;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,uCAAuC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;QACnG,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Auto-Merge Orchestration
3
+ *
4
+ * Implements the --when-green watch loop that polls CI status and
5
+ * automatically merges a PR once all checks pass. Handles the full
6
+ * rebase+CI cycle automatically.
7
+ *
8
+ * Flow:
9
+ * 1. Optionally enable native auto-merge as a safety net
10
+ * 2. Poll CI status at regular intervals
11
+ * 3. If CI is green and branch is up to date, merge
12
+ * 4. If branch has conflicts, rebase and wait for CI to rerun
13
+ * 5. If CI fails, exit with error
14
+ * 6. If timeout, exit with error
15
+ */
16
+ import { getPRChecks, mergePR } from '../pr/index.js';
17
+ import type { AutoMergeProvider } from './types.js';
18
+ import type { WhenGreenOptions, WhenGreenResult } from './types.js';
19
+ declare function sleep(ms: number): Promise<void>;
20
+ /**
21
+ * Check if a PR has merge conflicts with its base branch.
22
+ */
23
+ declare function checkMergeConflicts(prNumber: number, cwd?: string): boolean;
24
+ /**
25
+ * Check if a PR has already been merged.
26
+ */
27
+ declare function isPRMerged(prNumber: number, cwd?: string): boolean;
28
+ /**
29
+ * Rebase a PR branch onto its base branch and force-push.
30
+ */
31
+ declare function rebaseOntoBase(headBranch: string, baseBranch: string, cwd?: string): {
32
+ success: boolean;
33
+ error?: string;
34
+ };
35
+ export interface WatchAndShipDeps {
36
+ getPRChecks: typeof getPRChecks;
37
+ mergePR: typeof mergePR;
38
+ checkMergeConflicts: typeof checkMergeConflicts;
39
+ isPRMerged: typeof isPRMerged;
40
+ rebaseOntoBase: typeof rebaseOntoBase;
41
+ sleep: typeof sleep;
42
+ }
43
+ /**
44
+ * Watch a PR and ship it when CI turns green.
45
+ *
46
+ * This is the core implementation of `--when-green`. It enters a poll loop
47
+ * that checks CI status and handles the rebase+merge cycle automatically.
48
+ *
49
+ * If a native auto-merge provider is given, it will be enabled as a safety net
50
+ * so that even if this process dies, the PR will still auto-merge when ready.
51
+ *
52
+ * @param options - Watch loop configuration
53
+ * @param autoMergeProvider - Optional provider for native auto-merge
54
+ * @param deps - Injectable dependencies for testing
55
+ */
56
+ export declare function watchAndShip(options: WhenGreenOptions, autoMergeProvider?: AutoMergeProvider | null, deps?: WatchAndShipDeps): Promise<WhenGreenResult>;
57
+ export {};
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Auto-Merge Orchestration
3
+ *
4
+ * Implements the --when-green watch loop that polls CI status and
5
+ * automatically merges a PR once all checks pass. Handles the full
6
+ * rebase+CI cycle automatically.
7
+ *
8
+ * Flow:
9
+ * 1. Optionally enable native auto-merge as a safety net
10
+ * 2. Poll CI status at regular intervals
11
+ * 3. If CI is green and branch is up to date, merge
12
+ * 4. If branch has conflicts, rebase and wait for CI to rerun
13
+ * 5. If CI fails, exit with error
14
+ * 6. If timeout, exit with error
15
+ */
16
+ import { getPRChecks, mergePR, } from '../pr/index.js';
17
+ import { execSync } from 'node:child_process';
18
+ const DEFAULT_TIMEOUT_MS = 60 * 60 * 1000; // 60 minutes
19
+ const DEFAULT_POLL_INTERVAL_MS = 30 * 1000; // 30 seconds
20
+ function sleep(ms) {
21
+ return new Promise(resolve => setTimeout(resolve, ms));
22
+ }
23
+ /**
24
+ * Check if a PR has merge conflicts with its base branch.
25
+ */
26
+ function checkMergeConflicts(prNumber, cwd) {
27
+ try {
28
+ const result = execSync(`gh pr view ${prNumber} --json mergeable -q .mergeable`, {
29
+ cwd,
30
+ encoding: 'utf-8',
31
+ stdio: ['pipe', 'pipe', 'pipe'],
32
+ }).trim();
33
+ return result === 'CONFLICTING';
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ /**
40
+ * Check if a PR has already been merged.
41
+ */
42
+ function isPRMerged(prNumber, cwd) {
43
+ try {
44
+ const result = execSync(`gh pr view ${prNumber} --json state -q .state`, {
45
+ cwd,
46
+ encoding: 'utf-8',
47
+ stdio: ['pipe', 'pipe', 'pipe'],
48
+ }).trim();
49
+ return result === 'MERGED';
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ /**
56
+ * Rebase a PR branch onto its base branch and force-push.
57
+ */
58
+ function rebaseOntoBase(headBranch, baseBranch, cwd) {
59
+ try {
60
+ execSync('git fetch origin', {
61
+ cwd,
62
+ stdio: ['pipe', 'pipe', 'pipe'],
63
+ });
64
+ execSync(`git checkout ${headBranch}`, {
65
+ cwd,
66
+ stdio: ['pipe', 'pipe', 'pipe'],
67
+ });
68
+ execSync(`git rebase origin/${baseBranch}`, {
69
+ cwd,
70
+ stdio: ['pipe', 'pipe', 'pipe'],
71
+ });
72
+ execSync(`git push --force-with-lease origin ${headBranch}`, {
73
+ cwd,
74
+ stdio: ['pipe', 'pipe', 'pipe'],
75
+ });
76
+ return { success: true };
77
+ }
78
+ catch (error) {
79
+ try {
80
+ execSync('git rebase --abort', {
81
+ cwd,
82
+ stdio: ['pipe', 'pipe', 'pipe'],
83
+ });
84
+ }
85
+ catch {
86
+ // Ignore abort failures
87
+ }
88
+ return {
89
+ success: false,
90
+ error: error instanceof Error ? error.message : 'Unknown rebase error',
91
+ };
92
+ }
93
+ }
94
+ const defaultDeps = {
95
+ getPRChecks,
96
+ mergePR,
97
+ checkMergeConflicts,
98
+ isPRMerged,
99
+ rebaseOntoBase,
100
+ sleep,
101
+ };
102
+ /**
103
+ * Watch a PR and ship it when CI turns green.
104
+ *
105
+ * This is the core implementation of `--when-green`. It enters a poll loop
106
+ * that checks CI status and handles the rebase+merge cycle automatically.
107
+ *
108
+ * If a native auto-merge provider is given, it will be enabled as a safety net
109
+ * so that even if this process dies, the PR will still auto-merge when ready.
110
+ *
111
+ * @param options - Watch loop configuration
112
+ * @param autoMergeProvider - Optional provider for native auto-merge
113
+ * @param deps - Injectable dependencies for testing
114
+ */
115
+ export async function watchAndShip(options, autoMergeProvider, deps = defaultDeps) {
116
+ const { prNumber, method, deleteBranch, admin, noRebase, cwd, headBranch, baseBranch, onProgress, onWarning, timeoutMs = DEFAULT_TIMEOUT_MS, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, } = options;
117
+ let autoMergeEnabled = false;
118
+ let pollCycles = 0;
119
+ let rebasePerformed = false;
120
+ // Step 1: Try to enable native auto-merge as a safety net
121
+ if (autoMergeProvider) {
122
+ const autoResult = autoMergeProvider.enableAutoMerge(prNumber, method, cwd);
123
+ if (autoResult.success) {
124
+ autoMergeEnabled = true;
125
+ if (autoResult.alreadyEnabled) {
126
+ onProgress?.('Auto-merge already enabled');
127
+ }
128
+ else {
129
+ onProgress?.('Enabled native auto-merge as safety net');
130
+ }
131
+ }
132
+ else {
133
+ onWarning?.(`Could not enable native auto-merge: ${autoResult.error}. Will poll manually.`);
134
+ }
135
+ }
136
+ // Step 2: Enter poll loop
137
+ const startTime = Date.now();
138
+ const maxRebasesPerCycle = 3; // Prevent infinite rebase loops
139
+ let rebaseCount = 0;
140
+ while (Date.now() - startTime < timeoutMs) {
141
+ pollCycles++;
142
+ // Check if PR was already merged (by auto-merge or someone else)
143
+ if (deps.isPRMerged(prNumber, cwd)) {
144
+ onProgress?.('PR was merged (auto-merge or external)');
145
+ return {
146
+ merged: true,
147
+ autoMergeEnabled,
148
+ pollCycles,
149
+ rebasePerformed,
150
+ };
151
+ }
152
+ // Check CI status
153
+ const checks = deps.getPRChecks(prNumber, cwd);
154
+ // No checks configured — can merge immediately
155
+ if (checks.length === 0) {
156
+ onProgress?.('No CI checks configured — merging immediately');
157
+ const mergeResult = deps.mergePR(prNumber, { method, deleteBranch, admin, cwd });
158
+ if (mergeResult.success) {
159
+ return {
160
+ merged: true,
161
+ autoMergeEnabled,
162
+ pollCycles,
163
+ rebasePerformed,
164
+ };
165
+ }
166
+ return {
167
+ merged: false,
168
+ autoMergeEnabled,
169
+ pollCycles,
170
+ rebasePerformed,
171
+ error: `Merge failed: ${mergeResult.error}`,
172
+ errorCode: 'MERGE_FAILED',
173
+ };
174
+ }
175
+ const failed = checks.filter(c => c.conclusion === 'FAILURE');
176
+ const pending = checks.filter(c => !c.conclusion || c.status === 'IN_PROGRESS' || c.status === 'QUEUED');
177
+ const passed = checks.filter(c => c.conclusion === 'SUCCESS' || c.conclusion === 'SKIPPED');
178
+ // CI has failures — exit
179
+ if (pending.length === 0 && failed.length > 0) {
180
+ const failedNames = failed.map(c => c.name).join(', ');
181
+ // Disable auto-merge if we enabled it
182
+ if (autoMergeEnabled && autoMergeProvider) {
183
+ autoMergeProvider.disableAutoMerge(prNumber, cwd);
184
+ }
185
+ return {
186
+ merged: false,
187
+ autoMergeEnabled,
188
+ pollCycles,
189
+ rebasePerformed,
190
+ error: `CI checks failed: ${failedNames}. Fix the failures before shipping.`,
191
+ errorCode: 'CI_FAILED',
192
+ };
193
+ }
194
+ // CI still pending — wait
195
+ if (pending.length > 0) {
196
+ if (pollCycles === 1) {
197
+ onProgress?.(`Waiting for CI (${pending.length} pending, ${passed.length} passed)...`);
198
+ }
199
+ else if (pollCycles % 4 === 0) {
200
+ // Log progress every ~2 minutes
201
+ const elapsed = Math.round((Date.now() - startTime) / 60_000);
202
+ onProgress?.(`Still waiting for CI — ${pending.length} pending (${elapsed}m elapsed)`);
203
+ }
204
+ await deps.sleep(pollIntervalMs);
205
+ continue;
206
+ }
207
+ // All CI checks passed! Check for merge conflicts.
208
+ onProgress?.(`CI green (${passed.length} checks passed)`);
209
+ const hasConflicts = deps.checkMergeConflicts(prNumber, cwd);
210
+ if (hasConflicts) {
211
+ if (noRebase) {
212
+ if (autoMergeEnabled && autoMergeProvider) {
213
+ autoMergeProvider.disableAutoMerge(prNumber, cwd);
214
+ }
215
+ return {
216
+ merged: false,
217
+ autoMergeEnabled,
218
+ pollCycles,
219
+ rebasePerformed,
220
+ error: `PR #${prNumber} has merge conflicts. Resolve them manually or run without --no-rebase.`,
221
+ errorCode: 'MERGE_CONFLICTS',
222
+ };
223
+ }
224
+ if (rebaseCount >= maxRebasesPerCycle) {
225
+ if (autoMergeEnabled && autoMergeProvider) {
226
+ autoMergeProvider.disableAutoMerge(prNumber, cwd);
227
+ }
228
+ return {
229
+ merged: false,
230
+ autoMergeEnabled,
231
+ pollCycles,
232
+ rebasePerformed,
233
+ error: `Rebase limit reached (${maxRebasesPerCycle}). Base branch is changing too quickly.`,
234
+ errorCode: 'REBASE_LIMIT',
235
+ };
236
+ }
237
+ onProgress?.('Merge conflicts detected, rebasing...');
238
+ const rebaseResult = deps.rebaseOntoBase(headBranch, baseBranch, cwd);
239
+ if (!rebaseResult.success) {
240
+ if (autoMergeEnabled && autoMergeProvider) {
241
+ autoMergeProvider.disableAutoMerge(prNumber, cwd);
242
+ }
243
+ return {
244
+ merged: false,
245
+ autoMergeEnabled,
246
+ pollCycles,
247
+ rebasePerformed,
248
+ error: `Rebase failed: ${rebaseResult.error}. Resolve conflicts manually.`,
249
+ errorCode: 'REBASE_FAILED',
250
+ };
251
+ }
252
+ rebasePerformed = true;
253
+ rebaseCount++;
254
+ onProgress?.('Rebased and force-pushed. Waiting for CI to rerun...');
255
+ await deps.sleep(pollIntervalMs);
256
+ continue;
257
+ }
258
+ // CI green + no conflicts — merge!
259
+ // If auto-merge is enabled, it may have already merged. Check first.
260
+ if (deps.isPRMerged(prNumber, cwd)) {
261
+ onProgress?.('PR was auto-merged');
262
+ return {
263
+ merged: true,
264
+ autoMergeEnabled,
265
+ pollCycles,
266
+ rebasePerformed,
267
+ };
268
+ }
269
+ onProgress?.(`Merging PR #${prNumber} (${method})...`);
270
+ const mergeResult = deps.mergePR(prNumber, { method, deleteBranch, admin, cwd });
271
+ if (mergeResult.success) {
272
+ return {
273
+ merged: true,
274
+ autoMergeEnabled,
275
+ pollCycles,
276
+ rebasePerformed,
277
+ };
278
+ }
279
+ // Merge failed — could be a race condition. Check if already merged.
280
+ if (deps.isPRMerged(prNumber, cwd)) {
281
+ onProgress?.('PR was merged by another process');
282
+ return {
283
+ merged: true,
284
+ autoMergeEnabled,
285
+ pollCycles,
286
+ rebasePerformed,
287
+ };
288
+ }
289
+ return {
290
+ merged: false,
291
+ autoMergeEnabled,
292
+ pollCycles,
293
+ rebasePerformed,
294
+ error: `Merge failed: ${mergeResult.error}`,
295
+ errorCode: 'MERGE_FAILED',
296
+ };
297
+ }
298
+ // Timeout — auto-merge may still complete later if enabled
299
+ const timeoutMinutes = Math.round(timeoutMs / 60_000);
300
+ return {
301
+ merged: false,
302
+ autoMergeEnabled,
303
+ pollCycles,
304
+ rebasePerformed,
305
+ error: autoMergeEnabled
306
+ ? `Timed out after ${timeoutMinutes} minutes. Native auto-merge is still enabled — PR will merge automatically when ready.`
307
+ : `Timed out after ${timeoutMinutes} minutes waiting for CI. Check manually.`,
308
+ errorCode: 'TIMEOUT',
309
+ };
310
+ }
311
+ //# sourceMappingURL=auto-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-merge.js","sourceRoot":"","sources":["../../../src/lib/shipping/auto-merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * GitHub Git Provider & Auto-Merge Provider
3
+ *
4
+ * Implements the GitProvider interface for sibling rebase (PRLT-1143)
5
+ * and the AutoMergeProvider interface for auto-merge (PRLT-1144),
6
+ * both using the GitHub API via `gh` CLI.
7
+ */
8
+ import type { PRInfo, MergeableState } from '../pr/index.js';
9
+ import type { GitProvider, UpdateBranchResult, AutoMergeProvider, AutoMergeResult } from './types.js';
10
+ /**
11
+ * GitHub implementation of GitProvider.
12
+ *
13
+ * Uses the `gh api` CLI for API-based operations where possible,
14
+ * falling back to local git operations when the API is unavailable.
15
+ */
16
+ export declare class GitHubProvider implements GitProvider {
17
+ readonly name: "github";
18
+ listOpenPRs(cwd?: string): PRInfo[];
19
+ getMergeableState(prNumber: number, cwd?: string): MergeableState;
20
+ /**
21
+ * Update a PR branch using GitHub's update-branch API.
22
+ *
23
+ * Uses: PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch
24
+ *
25
+ * This merges the base branch into the PR branch server-side,
26
+ * without requiring a local checkout or force-push.
27
+ *
28
+ * Falls back to local git rebase if the API call fails with a
29
+ * non-conflict error (e.g., permissions, network issues).
30
+ */
31
+ updatePRBranch(prNumber: number, cwd?: string): UpdateBranchResult;
32
+ /**
33
+ * Add a label to a GitHub PR.
34
+ */
35
+ addLabel(prNumber: number, label: string, cwd?: string): boolean;
36
+ /**
37
+ * Add a comment to a GitHub PR.
38
+ */
39
+ addComment(prNumber: number, body: string, cwd?: string): boolean;
40
+ }
41
+ /**
42
+ * GitHub implementation of AutoMergeProvider.
43
+ *
44
+ * Uses GitHub's native auto-merge feature when available, which
45
+ * automatically merges a PR once all required status checks pass.
46
+ */
47
+ export declare class GitHubAutoMergeProvider implements AutoMergeProvider {
48
+ readonly name: "github";
49
+ /**
50
+ * Enable GitHub's native auto-merge on a PR.
51
+ *
52
+ * Uses `gh pr merge --auto` which sets the PR to auto-merge once
53
+ * all required status checks pass and branch protections are satisfied.
54
+ *
55
+ * Requires: auto-merge must be enabled in the repository settings.
56
+ */
57
+ enableAutoMerge(prNumber: number, method: 'merge' | 'squash' | 'rebase', cwd?: string): AutoMergeResult;
58
+ /**
59
+ * Disable GitHub's native auto-merge on a PR.
60
+ *
61
+ * Uses `gh pr merge --disable-auto` to cancel auto-merge.
62
+ */
63
+ disableAutoMerge(prNumber: number, cwd?: string): AutoMergeResult;
64
+ /**
65
+ * Check if a PR has been merged.
66
+ */
67
+ isPRMerged(prNumber: number, cwd?: string): boolean;
68
+ }