@generacy-ai/generacy 0.4.0 → 0.6.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 (137) hide show
  1. package/dist/cli/commands/cockpit/clarification-answer-marker.d.ts +8 -0
  2. package/dist/cli/commands/cockpit/clarification-answer-marker.d.ts.map +1 -0
  3. package/dist/cli/commands/cockpit/clarification-answer-marker.js +76 -0
  4. package/dist/cli/commands/cockpit/clarification-answer-marker.js.map +1 -0
  5. package/dist/cli/commands/cockpit/clarification-comment-finder.d.ts.map +1 -1
  6. package/dist/cli/commands/cockpit/clarification-comment-finder.js +33 -3
  7. package/dist/cli/commands/cockpit/clarification-comment-finder.js.map +1 -1
  8. package/dist/cli/commands/cockpit/clarify-relay.d.ts +38 -0
  9. package/dist/cli/commands/cockpit/clarify-relay.d.ts.map +1 -0
  10. package/dist/cli/commands/cockpit/clarify-relay.js +120 -0
  11. package/dist/cli/commands/cockpit/clarify-relay.js.map +1 -0
  12. package/dist/cli/commands/cockpit/doorbell/aggregate-on-demand.d.ts +43 -0
  13. package/dist/cli/commands/cockpit/doorbell/aggregate-on-demand.d.ts.map +1 -0
  14. package/dist/cli/commands/cockpit/doorbell/aggregate-on-demand.js +72 -0
  15. package/dist/cli/commands/cockpit/doorbell/aggregate-on-demand.js.map +1 -0
  16. package/dist/cli/commands/cockpit/doorbell/channel-discovery.d.ts +37 -0
  17. package/dist/cli/commands/cockpit/doorbell/channel-discovery.d.ts.map +1 -0
  18. package/dist/cli/commands/cockpit/doorbell/channel-discovery.js +92 -0
  19. package/dist/cli/commands/cockpit/doorbell/channel-discovery.js.map +1 -0
  20. package/dist/cli/commands/cockpit/doorbell/smee-source.d.ts +73 -0
  21. package/dist/cli/commands/cockpit/doorbell/smee-source.d.ts.map +1 -0
  22. package/dist/cli/commands/cockpit/doorbell/smee-source.js +362 -0
  23. package/dist/cli/commands/cockpit/doorbell/smee-source.js.map +1 -0
  24. package/dist/cli/commands/cockpit/doorbell/source-selector.d.ts +56 -0
  25. package/dist/cli/commands/cockpit/doorbell/source-selector.d.ts.map +1 -0
  26. package/dist/cli/commands/cockpit/doorbell/source-selector.js +182 -0
  27. package/dist/cli/commands/cockpit/doorbell/source-selector.js.map +1 -0
  28. package/dist/cli/commands/cockpit/doorbell/sse-parser.d.ts +15 -0
  29. package/dist/cli/commands/cockpit/doorbell/sse-parser.d.ts.map +1 -0
  30. package/dist/cli/commands/cockpit/doorbell/sse-parser.js +43 -0
  31. package/dist/cli/commands/cockpit/doorbell/sse-parser.js.map +1 -0
  32. package/dist/cli/commands/cockpit/doorbell/startup-retry.d.ts +55 -0
  33. package/dist/cli/commands/cockpit/doorbell/startup-retry.d.ts.map +1 -0
  34. package/dist/cli/commands/cockpit/doorbell/startup-retry.js +159 -0
  35. package/dist/cli/commands/cockpit/doorbell/startup-retry.js.map +1 -0
  36. package/dist/cli/commands/cockpit/doorbell/subscribe.d.ts +19 -0
  37. package/dist/cli/commands/cockpit/doorbell/subscribe.d.ts.map +1 -0
  38. package/dist/cli/commands/cockpit/doorbell/subscribe.js +54 -0
  39. package/dist/cli/commands/cockpit/doorbell/subscribe.js.map +1 -0
  40. package/dist/cli/commands/cockpit/doorbell/webhook-to-event.d.ts +28 -0
  41. package/dist/cli/commands/cockpit/doorbell/webhook-to-event.d.ts.map +1 -0
  42. package/dist/cli/commands/cockpit/doorbell/webhook-to-event.js +159 -0
  43. package/dist/cli/commands/cockpit/doorbell/webhook-to-event.js.map +1 -0
  44. package/dist/cli/commands/cockpit/doorbell.d.ts +58 -0
  45. package/dist/cli/commands/cockpit/doorbell.d.ts.map +1 -0
  46. package/dist/cli/commands/cockpit/doorbell.js +477 -0
  47. package/dist/cli/commands/cockpit/doorbell.js.map +1 -0
  48. package/dist/cli/commands/cockpit/index.d.ts +1 -0
  49. package/dist/cli/commands/cockpit/index.d.ts.map +1 -1
  50. package/dist/cli/commands/cockpit/index.js +5 -0
  51. package/dist/cli/commands/cockpit/index.js.map +1 -1
  52. package/dist/cli/commands/cockpit/mcp/errors.d.ts +1 -1
  53. package/dist/cli/commands/cockpit/mcp/errors.d.ts.map +1 -1
  54. package/dist/cli/commands/cockpit/mcp/errors.js.map +1 -1
  55. package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts +2 -1
  56. package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts.map +1 -1
  57. package/dist/cli/commands/cockpit/mcp/event-bus-registry.js +38 -9
  58. package/dist/cli/commands/cockpit/mcp/event-bus-registry.js.map +1 -1
  59. package/dist/cli/commands/cockpit/mcp/schemas.d.ts +184 -1
  60. package/dist/cli/commands/cockpit/mcp/schemas.d.ts.map +1 -1
  61. package/dist/cli/commands/cockpit/mcp/schemas.js +43 -2
  62. package/dist/cli/commands/cockpit/mcp/schemas.js.map +1 -1
  63. package/dist/cli/commands/cockpit/mcp/server.d.ts.map +1 -1
  64. package/dist/cli/commands/cockpit/mcp/server.js +16 -1
  65. package/dist/cli/commands/cockpit/mcp/server.js.map +1 -1
  66. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts +19 -3
  67. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts.map +1 -1
  68. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js +40 -2
  69. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js.map +1 -1
  70. package/dist/cli/commands/cockpit/mcp/tools/cockpit_relay_clarify_answers.d.ts +45 -0
  71. package/dist/cli/commands/cockpit/mcp/tools/cockpit_relay_clarify_answers.d.ts.map +1 -0
  72. package/dist/cli/commands/cockpit/mcp/tools/cockpit_relay_clarify_answers.js +45 -0
  73. package/dist/cli/commands/cockpit/mcp/tools/cockpit_relay_clarify_answers.js.map +1 -0
  74. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.d.ts +31 -0
  75. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.d.ts.map +1 -0
  76. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.js +81 -0
  77. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_add.js.map +1 -0
  78. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.d.ts +30 -0
  79. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.d.ts.map +1 -0
  80. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.js +80 -0
  81. package/dist/cli/commands/cockpit/mcp/tools/cockpit_scope_remove.js.map +1 -0
  82. package/dist/cli/commands/cockpit/queue.d.ts +15 -0
  83. package/dist/cli/commands/cockpit/queue.d.ts.map +1 -1
  84. package/dist/cli/commands/cockpit/queue.js +142 -29
  85. package/dist/cli/commands/cockpit/queue.js.map +1 -1
  86. package/dist/cli/commands/cockpit/resume.d.ts +12 -6
  87. package/dist/cli/commands/cockpit/resume.d.ts.map +1 -1
  88. package/dist/cli/commands/cockpit/resume.js +27 -11
  89. package/dist/cli/commands/cockpit/resume.js.map +1 -1
  90. package/dist/cli/commands/cockpit/scope/errors.d.ts +21 -0
  91. package/dist/cli/commands/cockpit/scope/errors.d.ts.map +1 -0
  92. package/dist/cli/commands/cockpit/scope/errors.js +17 -0
  93. package/dist/cli/commands/cockpit/scope/errors.js.map +1 -0
  94. package/dist/cli/commands/cockpit/scope/retry.d.ts +24 -0
  95. package/dist/cli/commands/cockpit/scope/retry.d.ts.map +1 -0
  96. package/dist/cli/commands/cockpit/scope/retry.js +52 -0
  97. package/dist/cli/commands/cockpit/scope/retry.js.map +1 -0
  98. package/dist/cli/commands/cockpit/scope/writer.d.ts +21 -0
  99. package/dist/cli/commands/cockpit/scope/writer.d.ts.map +1 -0
  100. package/dist/cli/commands/cockpit/scope/writer.js +141 -0
  101. package/dist/cli/commands/cockpit/scope/writer.js.map +1 -0
  102. package/dist/cli/commands/cockpit/scope.d.ts +22 -0
  103. package/dist/cli/commands/cockpit/scope.d.ts.map +1 -0
  104. package/dist/cli/commands/cockpit/scope.js +110 -0
  105. package/dist/cli/commands/cockpit/scope.js.map +1 -0
  106. package/dist/cli/commands/cockpit/status/group.d.ts +4 -2
  107. package/dist/cli/commands/cockpit/status/group.d.ts.map +1 -1
  108. package/dist/cli/commands/cockpit/status/group.js +17 -2
  109. package/dist/cli/commands/cockpit/status/group.js.map +1 -1
  110. package/dist/cli/commands/cockpit/status.d.ts.map +1 -1
  111. package/dist/cli/commands/cockpit/status.js +17 -2
  112. package/dist/cli/commands/cockpit/status.js.map +1 -1
  113. package/dist/cli/commands/cockpit/watch/diff.d.ts +6 -2
  114. package/dist/cli/commands/cockpit/watch/diff.d.ts.map +1 -1
  115. package/dist/cli/commands/cockpit/watch/diff.js +11 -3
  116. package/dist/cli/commands/cockpit/watch/diff.js.map +1 -1
  117. package/dist/cli/commands/cockpit/watch/poll-loop.d.ts +2 -0
  118. package/dist/cli/commands/cockpit/watch/poll-loop.d.ts.map +1 -1
  119. package/dist/cli/commands/cockpit/watch/poll-loop.js +38 -6
  120. package/dist/cli/commands/cockpit/watch/poll-loop.js.map +1 -1
  121. package/dist/cli/commands/cockpit/watch/pr-state.d.ts +15 -1
  122. package/dist/cli/commands/cockpit/watch/pr-state.d.ts.map +1 -1
  123. package/dist/cli/commands/cockpit/watch/pr-state.js +38 -0
  124. package/dist/cli/commands/cockpit/watch/pr-state.js.map +1 -1
  125. package/dist/cli/commands/cockpit/watch/snapshot.d.ts +6 -1
  126. package/dist/cli/commands/cockpit/watch/snapshot.d.ts.map +1 -1
  127. package/dist/cli/commands/cockpit/watch/snapshot.js +3 -1
  128. package/dist/cli/commands/cockpit/watch/snapshot.js.map +1 -1
  129. package/dist/cli/commands/cockpit/watch.d.ts +2 -1
  130. package/dist/cli/commands/cockpit/watch.d.ts.map +1 -1
  131. package/dist/cli/commands/cockpit/watch.js +25 -13
  132. package/dist/cli/commands/cockpit/watch.js.map +1 -1
  133. package/dist/config/schema.d.ts +788 -0
  134. package/dist/config/schema.d.ts.map +1 -1
  135. package/dist/config/schema.js +12 -1
  136. package/dist/config/schema.js.map +1 -1
  137. package/package.json +6 -6
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `SmeeDoorbellSource` — SSE consumer for the smee.io channel. Filters
3
+ * payloads by the epic's ref set and emits `CockpitStreamEvent`s to a
4
+ * caller-supplied sink. Models the reconnect ladder on
5
+ * `packages/orchestrator/src/services/smee-receiver.ts`.
6
+ *
7
+ * Contract: `specs/978-summary-generacy-cockpit/contracts/smee-doorbell-source.md`.
8
+ */
9
+ import { type CommandRunner, type GhWrapper } from '@generacy-ai/cockpit';
10
+ import type { CockpitStreamEvent } from '../watch/stream-event.js';
11
+ export declare const DEFAULT_BASE_RECONNECT_DELAY_MS = 5000;
12
+ export declare const MAX_BACKOFF_MS = 300000;
13
+ export declare const DEFAULT_REFRESH_DEBOUNCE_MS = 500;
14
+ export declare const DEFAULT_SAFETY_NET_INTERVAL_MS = 600000;
15
+ export interface SmeeDoorbellSourceOptions {
16
+ channelUrl: string;
17
+ epicRef: string;
18
+ gh: GhWrapper;
19
+ runner?: CommandRunner;
20
+ logger: {
21
+ warn: (msg: string) => void;
22
+ info?: (msg: string) => void;
23
+ };
24
+ onEvent: (event: CockpitStreamEvent) => Promise<void>;
25
+ onReconnectAttempt: (failedAttempts: number) => void;
26
+ onReconnectSuccess: () => void;
27
+ onRefSetRefreshFailure?: (err: unknown) => void;
28
+ now?: () => number;
29
+ fetch?: typeof globalThis.fetch;
30
+ refreshDebounceMs?: number;
31
+ safetyNetIntervalMs?: number;
32
+ baseReconnectDelayMs?: number;
33
+ }
34
+ export declare class SmeeDoorbellSource {
35
+ private readonly channelUrl;
36
+ private readonly epicRef;
37
+ private readonly gh;
38
+ private readonly logger;
39
+ private readonly onEvent;
40
+ private readonly onReconnectAttempt;
41
+ private readonly onReconnectSuccess;
42
+ private readonly onRefSetRefreshFailure?;
43
+ private readonly now;
44
+ private readonly fetchImpl;
45
+ private readonly refreshDebounceMs;
46
+ private readonly safetyNetIntervalMs;
47
+ private readonly baseReconnectDelayMs;
48
+ private refSet;
49
+ private aggState;
50
+ private prev;
51
+ private currentResolved;
52
+ private reconnectAttempt;
53
+ private running;
54
+ private abortController;
55
+ private refreshTimer;
56
+ private refreshDebounceTimer;
57
+ private aggregateDebounceTimer;
58
+ private pendingAggregateTrigger;
59
+ private runLoopPromise;
60
+ constructor(options: SmeeDoorbellSourceOptions);
61
+ start(): Promise<void>;
62
+ stop(): Promise<void>;
63
+ private calculateBackoffDelay;
64
+ private sleep;
65
+ private runLoop;
66
+ private connect;
67
+ private processEventBlock;
68
+ private scheduleRefSetRefresh;
69
+ private refreshRefSet;
70
+ private scheduleAggregateRefresh;
71
+ private runAggregateRefresh;
72
+ }
73
+ //# sourceMappingURL=smee-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smee-source.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/doorbell/smee-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,362 @@
1
+ /**
2
+ * `SmeeDoorbellSource` — SSE consumer for the smee.io channel. Filters
3
+ * payloads by the epic's ref set and emits `CockpitStreamEvent`s to a
4
+ * caller-supplied sink. Models the reconnect ladder on
5
+ * `packages/orchestrator/src/services/smee-receiver.ts`.
6
+ *
7
+ * Contract: `specs/978-summary-generacy-cockpit/contracts/smee-doorbell-source.md`.
8
+ */
9
+ import { resolveEpic, } from '@generacy-ai/cockpit';
10
+ import { initialAggregateState } from '../watch/aggregate.js';
11
+ import { parseSseEventBlock } from './sse-parser.js';
12
+ import { webhookToStreamEvent, } from './webhook-to-event.js';
13
+ import { maybeRefreshAggregate, } from './aggregate-on-demand.js';
14
+ export const DEFAULT_BASE_RECONNECT_DELAY_MS = 5_000;
15
+ export const MAX_BACKOFF_MS = 300_000;
16
+ export const DEFAULT_REFRESH_DEBOUNCE_MS = 500;
17
+ export const DEFAULT_SAFETY_NET_INTERVAL_MS = 600_000;
18
+ const AGGREGATE_TRIGGER_DEBOUNCE_MS = 500;
19
+ function repoRefsToSets(allRefs) {
20
+ const issues = new Set();
21
+ const prs = new Set();
22
+ const repos = new Set();
23
+ for (const ref of allRefs) {
24
+ const key = `${ref.repo}#${ref.number}`;
25
+ issues.add(key);
26
+ prs.add(key);
27
+ repos.add(ref.repo);
28
+ }
29
+ return { issues, prs, repos };
30
+ }
31
+ function buildRefSet(resolved) {
32
+ const sets = repoRefsToSets(resolved.parsed.allRefs);
33
+ sets.issues.add(`${resolved.epic.repo}#${resolved.epic.number}`);
34
+ sets.repos.add(resolved.epic.repo);
35
+ return {
36
+ epicRef: `${resolved.epic.repo}#${resolved.epic.number}`,
37
+ epicNumber: resolved.epic.number,
38
+ epicRepo: resolved.epic.repo,
39
+ issues: sets.issues,
40
+ prs: sets.prs,
41
+ watchedRepos: sets.repos,
42
+ };
43
+ }
44
+ function deriveTrigger(payload) {
45
+ if (payload.githubEvent === 'issues' && payload.action === 'labeled') {
46
+ const labelObj = payload.body['label'];
47
+ if (labelObj != null && typeof labelObj === 'object') {
48
+ const name = labelObj['name'];
49
+ if (typeof name === 'string' && name.startsWith('completed:')) {
50
+ return { kind: 'completed-label', label: name };
51
+ }
52
+ }
53
+ }
54
+ if (payload.githubEvent === 'issues' && payload.action === 'closed') {
55
+ return { kind: 'issue-closed' };
56
+ }
57
+ if (payload.githubEvent === 'pull_request' && payload.action === 'closed') {
58
+ return { kind: 'pr-closed' };
59
+ }
60
+ return null;
61
+ }
62
+ function isEpicPayload(payload, epicNumber) {
63
+ if (payload.githubEvent !== 'issues')
64
+ return false;
65
+ if (payload.action !== 'edited' &&
66
+ payload.action !== 'labeled' &&
67
+ payload.action !== 'unlabeled') {
68
+ return false;
69
+ }
70
+ const issueObj = payload.body['issue'];
71
+ if (issueObj == null || typeof issueObj !== 'object')
72
+ return false;
73
+ const num = issueObj['number'];
74
+ return num === epicNumber;
75
+ }
76
+ export class SmeeDoorbellSource {
77
+ channelUrl;
78
+ epicRef;
79
+ gh;
80
+ logger;
81
+ onEvent;
82
+ onReconnectAttempt;
83
+ onReconnectSuccess;
84
+ onRefSetRefreshFailure;
85
+ now;
86
+ fetchImpl;
87
+ refreshDebounceMs;
88
+ safetyNetIntervalMs;
89
+ baseReconnectDelayMs;
90
+ refSet = null;
91
+ aggState = initialAggregateState();
92
+ prev = new Map();
93
+ currentResolved = null;
94
+ reconnectAttempt = 0;
95
+ running = false;
96
+ abortController = null;
97
+ refreshTimer = null;
98
+ refreshDebounceTimer = null;
99
+ aggregateDebounceTimer = null;
100
+ pendingAggregateTrigger = null;
101
+ runLoopPromise = null;
102
+ constructor(options) {
103
+ this.channelUrl = options.channelUrl;
104
+ this.epicRef = options.epicRef;
105
+ this.gh = options.gh;
106
+ this.logger = options.logger;
107
+ this.onEvent = options.onEvent;
108
+ this.onReconnectAttempt = options.onReconnectAttempt;
109
+ this.onReconnectSuccess = options.onReconnectSuccess;
110
+ if (options.onRefSetRefreshFailure != null) {
111
+ this.onRefSetRefreshFailure = options.onRefSetRefreshFailure;
112
+ }
113
+ this.now = options.now ?? (() => Date.now());
114
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
115
+ this.refreshDebounceMs = options.refreshDebounceMs ?? DEFAULT_REFRESH_DEBOUNCE_MS;
116
+ this.safetyNetIntervalMs =
117
+ options.safetyNetIntervalMs ?? DEFAULT_SAFETY_NET_INTERVAL_MS;
118
+ this.baseReconnectDelayMs =
119
+ options.baseReconnectDelayMs ?? DEFAULT_BASE_RECONNECT_DELAY_MS;
120
+ }
121
+ async start() {
122
+ if (this.running)
123
+ return;
124
+ // Blocking startup ref-set refresh: propagate resolveEpic failures so the
125
+ // caller (`runSmeeMode`) can demote to poll-fallback.
126
+ const resolved = await resolveEpic({
127
+ epicRef: this.epicRef,
128
+ gh: this.gh,
129
+ logger: this.logger,
130
+ });
131
+ this.currentResolved = resolved;
132
+ this.refSet = buildRefSet(resolved);
133
+ this.running = true;
134
+ this.abortController = new AbortController();
135
+ this.refreshTimer = setInterval(() => this.refreshRefSet(), this.safetyNetIntervalMs);
136
+ if (typeof this.refreshTimer.unref === 'function')
137
+ this.refreshTimer.unref();
138
+ this.runLoopPromise = this.runLoop();
139
+ }
140
+ async stop() {
141
+ if (!this.running)
142
+ return;
143
+ this.running = false;
144
+ if (this.abortController != null) {
145
+ this.abortController.abort();
146
+ this.abortController = null;
147
+ }
148
+ if (this.refreshTimer != null) {
149
+ clearInterval(this.refreshTimer);
150
+ this.refreshTimer = null;
151
+ }
152
+ if (this.refreshDebounceTimer != null) {
153
+ clearTimeout(this.refreshDebounceTimer);
154
+ this.refreshDebounceTimer = null;
155
+ }
156
+ if (this.aggregateDebounceTimer != null) {
157
+ clearTimeout(this.aggregateDebounceTimer);
158
+ this.aggregateDebounceTimer = null;
159
+ }
160
+ if (this.runLoopPromise != null) {
161
+ try {
162
+ await this.runLoopPromise;
163
+ }
164
+ catch {
165
+ /* drain */
166
+ }
167
+ this.runLoopPromise = null;
168
+ }
169
+ }
170
+ calculateBackoffDelay(attempt) {
171
+ const delay = this.baseReconnectDelayMs * Math.pow(2, attempt);
172
+ return Math.min(delay, MAX_BACKOFF_MS);
173
+ }
174
+ sleep(ms, signal) {
175
+ return new Promise((resolve) => {
176
+ if (signal.aborted) {
177
+ resolve();
178
+ return;
179
+ }
180
+ const timer = setTimeout(resolve, ms);
181
+ if (typeof timer.unref === 'function')
182
+ timer.unref();
183
+ const onAbort = () => {
184
+ clearTimeout(timer);
185
+ resolve();
186
+ };
187
+ signal.addEventListener('abort', onAbort, { once: true });
188
+ });
189
+ }
190
+ async runLoop() {
191
+ const signal = this.abortController?.signal;
192
+ if (signal == null)
193
+ return;
194
+ while (this.running && !signal.aborted) {
195
+ let sleepMs = this.calculateBackoffDelay(this.reconnectAttempt);
196
+ try {
197
+ await this.connect(signal);
198
+ this.reconnectAttempt = 0;
199
+ sleepMs = this.calculateBackoffDelay(this.reconnectAttempt);
200
+ }
201
+ catch (err) {
202
+ if (signal.aborted)
203
+ break;
204
+ this.reconnectAttempt++;
205
+ sleepMs = this.calculateBackoffDelay(this.reconnectAttempt);
206
+ this.logger.warn(`cockpit doorbell: smee connection lost, reconnecting in ${sleepMs}ms (attempt ${this.reconnectAttempt}): ${err instanceof Error ? err.message : String(err)}`);
207
+ try {
208
+ this.onReconnectAttempt(this.reconnectAttempt);
209
+ }
210
+ catch {
211
+ /* callback failures don't stop the loop */
212
+ }
213
+ }
214
+ if (this.running && !signal.aborted) {
215
+ await this.sleep(sleepMs, signal);
216
+ }
217
+ }
218
+ }
219
+ async connect(signal) {
220
+ const response = await this.fetchImpl(this.channelUrl, {
221
+ headers: { Accept: 'text/event-stream' },
222
+ signal,
223
+ });
224
+ if (!response.ok) {
225
+ throw new Error(`smee connection failed: ${response.status} ${response.statusText}`);
226
+ }
227
+ if (response.body == null) {
228
+ throw new Error('smee response has no body');
229
+ }
230
+ try {
231
+ this.onReconnectSuccess();
232
+ }
233
+ catch {
234
+ /* callback failures don't stop the loop */
235
+ }
236
+ const reader = response.body.getReader();
237
+ const decoder = new TextDecoder();
238
+ let buffer = '';
239
+ try {
240
+ while (!signal.aborted) {
241
+ const { done, value } = await reader.read();
242
+ if (done)
243
+ break;
244
+ buffer += decoder.decode(value, { stream: true });
245
+ const events = buffer.split('\n\n');
246
+ buffer = events.pop() ?? '';
247
+ for (const block of events) {
248
+ if (!block.trim())
249
+ continue;
250
+ await this.processEventBlock(block);
251
+ }
252
+ }
253
+ }
254
+ finally {
255
+ reader.releaseLock();
256
+ }
257
+ }
258
+ async processEventBlock(block) {
259
+ const payload = parseSseEventBlock(block);
260
+ if (payload == null)
261
+ return;
262
+ if (this.refSet == null)
263
+ return;
264
+ if (isEpicPayload(payload, this.refSet.epicNumber)) {
265
+ this.scheduleRefSetRefresh();
266
+ }
267
+ const result = webhookToStreamEvent(payload.githubEvent, payload.action, payload.body, this.refSet, () => new Date(this.now()).toISOString());
268
+ if (result != null) {
269
+ const events = Array.isArray(result) ? result : [result];
270
+ for (const ev of events) {
271
+ try {
272
+ await this.onEvent(ev);
273
+ }
274
+ catch (err) {
275
+ this.logger.warn(`cockpit doorbell: onEvent sink rejected: ${err instanceof Error ? err.message : String(err)}`);
276
+ }
277
+ }
278
+ }
279
+ const trigger = deriveTrigger(payload);
280
+ if (trigger != null) {
281
+ this.scheduleAggregateRefresh(trigger);
282
+ }
283
+ }
284
+ scheduleRefSetRefresh() {
285
+ if (this.refreshDebounceTimer != null)
286
+ clearTimeout(this.refreshDebounceTimer);
287
+ this.refreshDebounceTimer = setTimeout(() => {
288
+ this.refreshDebounceTimer = null;
289
+ void this.refreshRefSet();
290
+ }, this.refreshDebounceMs);
291
+ if (typeof this.refreshDebounceTimer.unref === 'function') {
292
+ this.refreshDebounceTimer.unref();
293
+ }
294
+ }
295
+ async refreshRefSet() {
296
+ if (!this.running)
297
+ return;
298
+ try {
299
+ const resolved = await resolveEpic({
300
+ epicRef: this.epicRef,
301
+ gh: this.gh,
302
+ logger: this.logger,
303
+ });
304
+ this.currentResolved = resolved;
305
+ this.refSet = buildRefSet(resolved);
306
+ }
307
+ catch (err) {
308
+ this.logger.warn(`cockpit doorbell: ref-set refresh failed: ${err instanceof Error ? err.message : String(err)}`);
309
+ if (this.onRefSetRefreshFailure != null) {
310
+ try {
311
+ this.onRefSetRefreshFailure(err);
312
+ }
313
+ catch {
314
+ /* callback errors are swallowed */
315
+ }
316
+ }
317
+ }
318
+ }
319
+ scheduleAggregateRefresh(trigger) {
320
+ this.pendingAggregateTrigger = trigger;
321
+ if (this.aggregateDebounceTimer != null) {
322
+ clearTimeout(this.aggregateDebounceTimer);
323
+ }
324
+ this.aggregateDebounceTimer = setTimeout(() => {
325
+ this.aggregateDebounceTimer = null;
326
+ const next = this.pendingAggregateTrigger;
327
+ this.pendingAggregateTrigger = null;
328
+ void this.runAggregateRefresh(next);
329
+ }, AGGREGATE_TRIGGER_DEBOUNCE_MS);
330
+ if (typeof this.aggregateDebounceTimer.unref === 'function') {
331
+ this.aggregateDebounceTimer.unref();
332
+ }
333
+ }
334
+ async runAggregateRefresh(trigger) {
335
+ if (!this.running || this.refSet == null)
336
+ return;
337
+ const output = await maybeRefreshAggregate({
338
+ trigger,
339
+ epicRef: this.epicRef,
340
+ epicRepo: this.refSet.epicRepo,
341
+ epicNumber: this.refSet.epicNumber,
342
+ prevAgg: this.aggState,
343
+ prev: this.prev,
344
+ currentResolved: this.currentResolved,
345
+ gh: this.gh,
346
+ logger: this.logger,
347
+ now: () => new Date(this.now()).toISOString(),
348
+ });
349
+ this.aggState = output.nextAgg;
350
+ this.prev = output.nextPrev;
351
+ this.currentResolved = output.nextResolved;
352
+ for (const ev of output.events) {
353
+ try {
354
+ await this.onEvent(ev);
355
+ }
356
+ catch (err) {
357
+ this.logger.warn(`cockpit doorbell: aggregate onEvent sink rejected: ${err instanceof Error ? err.message : String(err)}`);
358
+ }
359
+ }
360
+ }
361
+ }
362
+ //# sourceMappingURL=smee-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smee-source.js","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/doorbell/smee-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `SourceSelector` — owns the runtime demotion/re-promotion state for the
3
+ * doorbell's wake source (Q3=D policy). Emits exactly one FR-006 `source=…`
4
+ * stderr line per transition.
5
+ *
6
+ * Contract: `specs/978-summary-generacy-cockpit/contracts/source-selector.md`.
7
+ */
8
+ export type SourceMode = 'smee-attempt' | 'smee-active' | 'poll-fallback';
9
+ export type SourceReason = 'startup-no-channel' | 'startup-smee-selected' | 'smee-runtime-lost' | 'smee-re-promoted';
10
+ export interface SourceSelectorOptions {
11
+ initial: 'smee-attempt' | 'poll-fallback';
12
+ stderr: {
13
+ write(chunk: string): boolean | void;
14
+ };
15
+ logger?: {
16
+ warn: (msg: string) => void;
17
+ info?: (msg: string) => void;
18
+ };
19
+ demoteAfterConsecutiveFailures?: number;
20
+ demoteAfterMsWithoutSuccess?: number;
21
+ rePromoteIntervalMs?: number;
22
+ now?: () => number;
23
+ }
24
+ export type ModeChangeCallback = (next: SourceMode, reason: SourceReason) => void;
25
+ export declare const DEFAULT_DEMOTE_AFTER_FAILURES = 5;
26
+ export declare const DEFAULT_DEMOTE_AFTER_MS_WITHOUT_SUCCESS = 300000;
27
+ export declare const DEFAULT_RE_PROMOTE_INTERVAL_MS = 300000;
28
+ export declare class SourceSelector {
29
+ private _current;
30
+ private consecutiveReconnectFailures;
31
+ private lastSuccessfulConnectAt;
32
+ private demotedAt;
33
+ private rePromoteTimer;
34
+ private elapsedTicker;
35
+ private modeChangeCbs;
36
+ private stopped;
37
+ private readonly initialWasSmee;
38
+ private readonly demoteAfterFailures;
39
+ private readonly demoteAfterMsWithoutSuccess;
40
+ private readonly rePromoteIntervalMs;
41
+ private readonly now;
42
+ private readonly stderr;
43
+ private readonly logger?;
44
+ private pendingRePromoteEmit;
45
+ constructor(options: SourceSelectorOptions);
46
+ get currentSource(): SourceMode;
47
+ onModeChange(cb: ModeChangeCallback): void;
48
+ onReconnectAttempt(failedAttempts: number): void;
49
+ onReconnectSuccess(): void;
50
+ observeElapsed(): void;
51
+ stop(): void;
52
+ private transition;
53
+ private tickRePromote;
54
+ private writeLine;
55
+ }
56
+ //# sourceMappingURL=source-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-selector.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/doorbell/source-selector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,aAAa,GAAG,eAAe,CAAC;AAE1E,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,uBAAuB,GACvB,mBAAmB,GACnB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,cAAc,GAAG,eAAe,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IACvE,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;AAElF,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,uCAAuC,SAAU,CAAC;AAC/D,eAAO,MAAM,8BAA8B,SAAU,CAAC;AAQtD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,4BAA4B,CAAK;IACzC,OAAO,CAAC,uBAAuB,CAAuB;IACtD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAS;IACrD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAClE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAgE;IACxF,OAAO,CAAC,oBAAoB,CAAS;gBAEzB,OAAO,EAAE,qBAAqB;IAuB1C,IAAI,aAAa,IAAI,UAAU,CAE9B;IAED,YAAY,CAAC,EAAE,EAAE,kBAAkB,GAAG,IAAI;IAI1C,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAShD,kBAAkB,IAAI,IAAI;IAsB1B,cAAc,IAAI,IAAI;IAUtB,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,UAAU;IAgClB,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,SAAS;CAOlB"}