@generacy-ai/generacy 0.3.3 → 0.4.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 (219) hide show
  1. package/README.md +153 -0
  2. package/dist/cli/commands/cluster/scaffolder.d.ts.map +1 -1
  3. package/dist/cli/commands/cluster/scaffolder.js +2 -0
  4. package/dist/cli/commands/cluster/scaffolder.js.map +1 -1
  5. package/dist/cli/commands/cockpit/advance.d.ts +42 -0
  6. package/dist/cli/commands/cockpit/advance.d.ts.map +1 -0
  7. package/dist/cli/commands/cockpit/advance.js +136 -0
  8. package/dist/cli/commands/cockpit/advance.js.map +1 -0
  9. package/dist/cli/commands/cockpit/clarification-comment-finder.d.ts +13 -0
  10. package/dist/cli/commands/cockpit/clarification-comment-finder.d.ts.map +1 -0
  11. package/dist/cli/commands/cockpit/clarification-comment-finder.js +31 -0
  12. package/dist/cli/commands/cockpit/clarification-comment-finder.js.map +1 -0
  13. package/dist/cli/commands/cockpit/code-references.d.ts +27 -0
  14. package/dist/cli/commands/cockpit/code-references.d.ts.map +1 -0
  15. package/dist/cli/commands/cockpit/code-references.js +48 -0
  16. package/dist/cli/commands/cockpit/code-references.js.map +1 -0
  17. package/dist/cli/commands/cockpit/context.d.ts +90 -0
  18. package/dist/cli/commands/cockpit/context.d.ts.map +1 -0
  19. package/dist/cli/commands/cockpit/context.js +280 -0
  20. package/dist/cli/commands/cockpit/context.js.map +1 -0
  21. package/dist/cli/commands/cockpit/exit.d.ts +12 -0
  22. package/dist/cli/commands/cockpit/exit.d.ts.map +1 -0
  23. package/dist/cli/commands/cockpit/exit.js +18 -0
  24. package/dist/cli/commands/cockpit/exit.js.map +1 -0
  25. package/dist/cli/commands/cockpit/gate-vocabulary.d.ts +48 -0
  26. package/dist/cli/commands/cockpit/gate-vocabulary.d.ts.map +1 -0
  27. package/dist/cli/commands/cockpit/gate-vocabulary.js +96 -0
  28. package/dist/cli/commands/cockpit/gate-vocabulary.js.map +1 -0
  29. package/dist/cli/commands/cockpit/index.d.ts +20 -0
  30. package/dist/cli/commands/cockpit/index.d.ts.map +1 -0
  31. package/dist/cli/commands/cockpit/index.js +40 -0
  32. package/dist/cli/commands/cockpit/index.js.map +1 -0
  33. package/dist/cli/commands/cockpit/manual-advance-marker.d.ts +18 -0
  34. package/dist/cli/commands/cockpit/manual-advance-marker.d.ts.map +1 -0
  35. package/dist/cli/commands/cockpit/manual-advance-marker.js +43 -0
  36. package/dist/cli/commands/cockpit/manual-advance-marker.js.map +1 -0
  37. package/dist/cli/commands/cockpit/mcp/errors.d.ts +54 -0
  38. package/dist/cli/commands/cockpit/mcp/errors.d.ts.map +1 -0
  39. package/dist/cli/commands/cockpit/mcp/errors.js +190 -0
  40. package/dist/cli/commands/cockpit/mcp/errors.js.map +1 -0
  41. package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts +59 -0
  42. package/dist/cli/commands/cockpit/mcp/event-bus-registry.d.ts.map +1 -0
  43. package/dist/cli/commands/cockpit/mcp/event-bus-registry.js +305 -0
  44. package/dist/cli/commands/cockpit/mcp/event-bus-registry.js.map +1 -0
  45. package/dist/cli/commands/cockpit/mcp/event-bus.d.ts +82 -0
  46. package/dist/cli/commands/cockpit/mcp/event-bus.d.ts.map +1 -0
  47. package/dist/cli/commands/cockpit/mcp/event-bus.js +230 -0
  48. package/dist/cli/commands/cockpit/mcp/event-bus.js.map +1 -0
  49. package/dist/cli/commands/cockpit/mcp/index.d.ts +17 -0
  50. package/dist/cli/commands/cockpit/mcp/index.d.ts.map +1 -0
  51. package/dist/cli/commands/cockpit/mcp/index.js +37 -0
  52. package/dist/cli/commands/cockpit/mcp/index.js.map +1 -0
  53. package/dist/cli/commands/cockpit/mcp/ref-input.d.ts +52 -0
  54. package/dist/cli/commands/cockpit/mcp/ref-input.d.ts.map +1 -0
  55. package/dist/cli/commands/cockpit/mcp/ref-input.js +132 -0
  56. package/dist/cli/commands/cockpit/mcp/ref-input.js.map +1 -0
  57. package/dist/cli/commands/cockpit/mcp/schemas.d.ts +287 -0
  58. package/dist/cli/commands/cockpit/mcp/schemas.d.ts.map +1 -0
  59. package/dist/cli/commands/cockpit/mcp/schemas.js +84 -0
  60. package/dist/cli/commands/cockpit/mcp/schemas.js.map +1 -0
  61. package/dist/cli/commands/cockpit/mcp/server.d.ts +17 -0
  62. package/dist/cli/commands/cockpit/mcp/server.d.ts.map +1 -0
  63. package/dist/cli/commands/cockpit/mcp/server.js +62 -0
  64. package/dist/cli/commands/cockpit/mcp/server.js.map +1 -0
  65. package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.d.ts +42 -0
  66. package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.d.ts.map +1 -0
  67. package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.js +73 -0
  68. package/dist/cli/commands/cockpit/mcp/tools/cockpit_advance.js.map +1 -0
  69. package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.d.ts +34 -0
  70. package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.d.ts.map +1 -0
  71. package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.js +115 -0
  72. package/dist/cli/commands/cockpit/mcp/tools/cockpit_await_events.js.map +1 -0
  73. package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.d.ts +21 -0
  74. package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.d.ts.map +1 -0
  75. package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.js +35 -0
  76. package/dist/cli/commands/cockpit/mcp/tools/cockpit_context.js.map +1 -0
  77. package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.d.ts +43 -0
  78. package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.d.ts.map +1 -0
  79. package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.js +99 -0
  80. package/dist/cli/commands/cockpit/mcp/tools/cockpit_merge.js.map +1 -0
  81. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts +43 -0
  82. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.d.ts.map +1 -0
  83. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js +68 -0
  84. package/dist/cli/commands/cockpit/mcp/tools/cockpit_queue.js.map +1 -0
  85. package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.d.ts +38 -0
  86. package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.d.ts.map +1 -0
  87. package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.js +79 -0
  88. package/dist/cli/commands/cockpit/mcp/tools/cockpit_resume.js.map +1 -0
  89. package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.d.ts +21 -0
  90. package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.d.ts.map +1 -0
  91. package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.js +59 -0
  92. package/dist/cli/commands/cockpit/mcp/tools/cockpit_status.js.map +1 -0
  93. package/dist/cli/commands/cockpit/merge.d.ts +42 -0
  94. package/dist/cli/commands/cockpit/merge.d.ts.map +1 -0
  95. package/dist/cli/commands/cockpit/merge.js +360 -0
  96. package/dist/cli/commands/cockpit/merge.js.map +1 -0
  97. package/dist/cli/commands/cockpit/plan-dependency-extractor.d.ts +30 -0
  98. package/dist/cli/commands/cockpit/plan-dependency-extractor.d.ts.map +1 -0
  99. package/dist/cli/commands/cockpit/plan-dependency-extractor.js +135 -0
  100. package/dist/cli/commands/cockpit/plan-dependency-extractor.js.map +1 -0
  101. package/dist/cli/commands/cockpit/queue.d.ts +85 -0
  102. package/dist/cli/commands/cockpit/queue.d.ts.map +1 -0
  103. package/dist/cli/commands/cockpit/queue.js +438 -0
  104. package/dist/cli/commands/cockpit/queue.js.map +1 -0
  105. package/dist/cli/commands/cockpit/resolver.d.ts +70 -0
  106. package/dist/cli/commands/cockpit/resolver.d.ts.map +1 -0
  107. package/dist/cli/commands/cockpit/resolver.js +117 -0
  108. package/dist/cli/commands/cockpit/resolver.js.map +1 -0
  109. package/dist/cli/commands/cockpit/resume.d.ts +38 -0
  110. package/dist/cli/commands/cockpit/resume.d.ts.map +1 -0
  111. package/dist/cli/commands/cockpit/resume.js +167 -0
  112. package/dist/cli/commands/cockpit/resume.js.map +1 -0
  113. package/dist/cli/commands/cockpit/shared/classify-issue.d.ts +12 -0
  114. package/dist/cli/commands/cockpit/shared/classify-issue.d.ts.map +1 -0
  115. package/dist/cli/commands/cockpit/shared/classify-issue.js +10 -0
  116. package/dist/cli/commands/cockpit/shared/classify-issue.js.map +1 -0
  117. package/dist/cli/commands/cockpit/shared/failing-check-json.d.ts +53 -0
  118. package/dist/cli/commands/cockpit/shared/failing-check-json.d.ts.map +1 -0
  119. package/dist/cli/commands/cockpit/shared/failing-check-json.js +170 -0
  120. package/dist/cli/commands/cockpit/shared/failing-check-json.js.map +1 -0
  121. package/dist/cli/commands/cockpit/shared/identity.d.ts +54 -0
  122. package/dist/cli/commands/cockpit/shared/identity.d.ts.map +1 -0
  123. package/dist/cli/commands/cockpit/shared/identity.js +65 -0
  124. package/dist/cli/commands/cockpit/shared/identity.js.map +1 -0
  125. package/dist/cli/commands/cockpit/shared/is-done-snapshot.d.ts +16 -0
  126. package/dist/cli/commands/cockpit/shared/is-done-snapshot.d.ts.map +1 -0
  127. package/dist/cli/commands/cockpit/shared/is-done-snapshot.js +17 -0
  128. package/dist/cli/commands/cockpit/shared/is-done-snapshot.js.map +1 -0
  129. package/dist/cli/commands/cockpit/shared/pagination.d.ts +17 -0
  130. package/dist/cli/commands/cockpit/shared/pagination.d.ts.map +1 -0
  131. package/dist/cli/commands/cockpit/shared/pagination.js +50 -0
  132. package/dist/cli/commands/cockpit/shared/pagination.js.map +1 -0
  133. package/dist/cli/commands/cockpit/shared/pr-link.d.ts +8 -0
  134. package/dist/cli/commands/cockpit/shared/pr-link.d.ts.map +1 -0
  135. package/dist/cli/commands/cockpit/shared/pr-link.js +15 -0
  136. package/dist/cli/commands/cockpit/shared/pr-link.js.map +1 -0
  137. package/dist/cli/commands/cockpit/shared/required-checks.d.ts +17 -0
  138. package/dist/cli/commands/cockpit/shared/required-checks.d.ts.map +1 -0
  139. package/dist/cli/commands/cockpit/shared/required-checks.js +38 -0
  140. package/dist/cli/commands/cockpit/shared/required-checks.js.map +1 -0
  141. package/dist/cli/commands/cockpit/shared/review-context-json.d.ts +29 -0
  142. package/dist/cli/commands/cockpit/shared/review-context-json.d.ts.map +1 -0
  143. package/dist/cli/commands/cockpit/shared/review-context-json.js +28 -0
  144. package/dist/cli/commands/cockpit/shared/review-context-json.js.map +1 -0
  145. package/dist/cli/commands/cockpit/status/color.d.ts +11 -0
  146. package/dist/cli/commands/cockpit/status/color.d.ts.map +1 -0
  147. package/dist/cli/commands/cockpit/status/color.js +33 -0
  148. package/dist/cli/commands/cockpit/status/color.js.map +1 -0
  149. package/dist/cli/commands/cockpit/status/group.d.ts +8 -0
  150. package/dist/cli/commands/cockpit/status/group.d.ts.map +1 -0
  151. package/dist/cli/commands/cockpit/status/group.js +35 -0
  152. package/dist/cli/commands/cockpit/status/group.js.map +1 -0
  153. package/dist/cli/commands/cockpit/status/render-table.d.ts +24 -0
  154. package/dist/cli/commands/cockpit/status/render-table.d.ts.map +1 -0
  155. package/dist/cli/commands/cockpit/status/render-table.js +71 -0
  156. package/dist/cli/commands/cockpit/status/render-table.js.map +1 -0
  157. package/dist/cli/commands/cockpit/status/row.d.ts +18 -0
  158. package/dist/cli/commands/cockpit/status/row.d.ts.map +1 -0
  159. package/dist/cli/commands/cockpit/status/row.js +17 -0
  160. package/dist/cli/commands/cockpit/status/row.js.map +1 -0
  161. package/dist/cli/commands/cockpit/status.d.ts +18 -0
  162. package/dist/cli/commands/cockpit/status.d.ts.map +1 -0
  163. package/dist/cli/commands/cockpit/status.js +138 -0
  164. package/dist/cli/commands/cockpit/status.js.map +1 -0
  165. package/dist/cli/commands/cockpit/watch/actionable.d.ts +15 -0
  166. package/dist/cli/commands/cockpit/watch/actionable.d.ts.map +1 -0
  167. package/dist/cli/commands/cockpit/watch/actionable.js +32 -0
  168. package/dist/cli/commands/cockpit/watch/actionable.js.map +1 -0
  169. package/dist/cli/commands/cockpit/watch/aggregate-emit.d.ts +107 -0
  170. package/dist/cli/commands/cockpit/watch/aggregate-emit.d.ts.map +1 -0
  171. package/dist/cli/commands/cockpit/watch/aggregate-emit.js +41 -0
  172. package/dist/cli/commands/cockpit/watch/aggregate-emit.js.map +1 -0
  173. package/dist/cli/commands/cockpit/watch/aggregate.d.ts +25 -0
  174. package/dist/cli/commands/cockpit/watch/aggregate.d.ts.map +1 -0
  175. package/dist/cli/commands/cockpit/watch/aggregate.js +67 -0
  176. package/dist/cli/commands/cockpit/watch/aggregate.js.map +1 -0
  177. package/dist/cli/commands/cockpit/watch/check-rollup.d.ts +9 -0
  178. package/dist/cli/commands/cockpit/watch/check-rollup.d.ts.map +1 -0
  179. package/dist/cli/commands/cockpit/watch/check-rollup.js +22 -0
  180. package/dist/cli/commands/cockpit/watch/check-rollup.js.map +1 -0
  181. package/dist/cli/commands/cockpit/watch/diff.d.ts +29 -0
  182. package/dist/cli/commands/cockpit/watch/diff.d.ts.map +1 -0
  183. package/dist/cli/commands/cockpit/watch/diff.js +85 -0
  184. package/dist/cli/commands/cockpit/watch/diff.js.map +1 -0
  185. package/dist/cli/commands/cockpit/watch/emit.d.ts +58 -0
  186. package/dist/cli/commands/cockpit/watch/emit.d.ts.map +1 -0
  187. package/dist/cli/commands/cockpit/watch/emit.js +30 -0
  188. package/dist/cli/commands/cockpit/watch/emit.js.map +1 -0
  189. package/dist/cli/commands/cockpit/watch/poll-loop.d.ts +29 -0
  190. package/dist/cli/commands/cockpit/watch/poll-loop.d.ts.map +1 -0
  191. package/dist/cli/commands/cockpit/watch/poll-loop.js +81 -0
  192. package/dist/cli/commands/cockpit/watch/poll-loop.js.map +1 -0
  193. package/dist/cli/commands/cockpit/watch/pr-state.d.ts +17 -0
  194. package/dist/cli/commands/cockpit/watch/pr-state.d.ts.map +1 -0
  195. package/dist/cli/commands/cockpit/watch/pr-state.js +33 -0
  196. package/dist/cli/commands/cockpit/watch/pr-state.js.map +1 -0
  197. package/dist/cli/commands/cockpit/watch/snapshot.d.ts +33 -0
  198. package/dist/cli/commands/cockpit/watch/snapshot.d.ts.map +1 -0
  199. package/dist/cli/commands/cockpit/watch/snapshot.js +30 -0
  200. package/dist/cli/commands/cockpit/watch/snapshot.js.map +1 -0
  201. package/dist/cli/commands/cockpit/watch/stream-event.d.ts +82 -0
  202. package/dist/cli/commands/cockpit/watch/stream-event.d.ts.map +1 -0
  203. package/dist/cli/commands/cockpit/watch/stream-event.js +9 -0
  204. package/dist/cli/commands/cockpit/watch/stream-event.js.map +1 -0
  205. package/dist/cli/commands/cockpit/watch.d.ts +22 -0
  206. package/dist/cli/commands/cockpit/watch.d.ts.map +1 -0
  207. package/dist/cli/commands/cockpit/watch.js +186 -0
  208. package/dist/cli/commands/cockpit/watch.js.map +1 -0
  209. package/dist/cli/commands/setup/build.d.ts.map +1 -1
  210. package/dist/cli/commands/setup/build.js +59 -0
  211. package/dist/cli/commands/setup/build.js.map +1 -1
  212. package/dist/cli/index.d.ts.map +1 -1
  213. package/dist/cli/index.js +2 -0
  214. package/dist/cli/index.js.map +1 -1
  215. package/dist/index.d.ts +2 -0
  216. package/dist/index.d.ts.map +1 -1
  217. package/dist/index.js +2 -0
  218. package/dist/index.js.map +1 -1
  219. package/package.json +11 -5
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Per-orchestrator-process registry of `EpicEventBus` instances, keyed by
3
+ * epic-ref string (`"owner/repo#number"`).
4
+ *
5
+ * Each bus is driven by a private poller — mirrors `watch.ts` but emits into
6
+ * the bus instead of stdout NDJSON. Multiple concurrent `cockpit_await_events`
7
+ * callers against the same epic share the subscriber; refcounted via
8
+ * `acquire` / `release`.
9
+ *
10
+ * Bus lifetime is decoupled from call lifetime (#924): `release()` at
11
+ * refcount 0 pauses the poller and arms an idle-TTL timer instead of tearing
12
+ * down the bus. The next `acquire()` disarms the timer, resumes the poller,
13
+ * and runs a synchronous catch-up poll so between-call events are captured.
14
+ * A soft cap on live buses evicts the least-recently-active on overflow.
15
+ *
16
+ * Env knobs:
17
+ * `COCKPIT_MCP_BUS_IDLE_TTL_MS` — idle-TTL for refcount-0 buses (default 600_000).
18
+ * `COCKPIT_MCP_BUS_MAX` — soft cap on live buses (default 100).
19
+ */
20
+ import { GhCliWrapper, LoudResolverError, resolveEpic, } from '@generacy-ai/cockpit';
21
+ import { resolveIssueContext } from '../resolver.js';
22
+ import { runOnePoll } from '../watch/poll-loop.js';
23
+ import { computeAggregateEvents, initialAggregateState, } from '../watch/aggregate.js';
24
+ import { EpicEventBus } from './event-bus.js';
25
+ const DEFAULT_INTERVAL_MS = 30_000;
26
+ /** Env knob `COCKPIT_MCP_BUS_IDLE_TTL_MS` — idle-TTL for refcount-0 buses. */
27
+ const DEFAULT_IDLE_TTL_MS = 600_000;
28
+ /** Env knob `COCKPIT_MCP_BUS_MAX` — soft cap on live buses. */
29
+ const DEFAULT_MAX_BUSES = 100;
30
+ function parsePositiveIntEnv(raw, fallback, name, logger) {
31
+ if (raw == null || raw === '')
32
+ return fallback;
33
+ const n = Number.parseInt(raw, 10);
34
+ if (Number.isNaN(n) || n <= 0) {
35
+ logger?.warn(`event-bus: invalid ${name}=${raw}; using default ${fallback}`);
36
+ return fallback;
37
+ }
38
+ return n;
39
+ }
40
+ const registry = new Map();
41
+ export async function acquireEpicBus(options) {
42
+ const expandedRef = await expandRef(options.epicRef, options.runner);
43
+ const now = options.now ?? Date.now;
44
+ const logger = options.logger ?? { warn: () => undefined };
45
+ const idleTtlMs = parsePositiveIntEnv(process.env.COCKPIT_MCP_BUS_IDLE_TTL_MS, options.idleTtlMs ?? DEFAULT_IDLE_TTL_MS, 'COCKPIT_MCP_BUS_IDLE_TTL_MS', logger);
46
+ const maxBuses = parsePositiveIntEnv(process.env.COCKPIT_MCP_BUS_MAX, options.maxBuses ?? DEFAULT_MAX_BUSES, 'COCKPIT_MCP_BUS_MAX', logger);
47
+ const existing = registry.get(expandedRef);
48
+ if (existing != null) {
49
+ const wasPaused = existing.refCount === 0;
50
+ if (existing.idleTimer != null) {
51
+ clearTimeout(existing.idleTimer);
52
+ existing.idleTimer = null;
53
+ }
54
+ existing.refCount += 1;
55
+ existing.lastActiveAt = now();
56
+ // Reinsert at tail for LRU ordering.
57
+ registry.delete(expandedRef);
58
+ registry.set(expandedRef, existing);
59
+ // Catch-up only runs when the poller was paused (refcount had been 0);
60
+ // concurrent-caller acquires (refcount was already > 0) skip it.
61
+ if (wasPaused) {
62
+ await existing.catchUpPoll();
63
+ existing.resumePoller();
64
+ }
65
+ return { bus: existing.bus, release: () => releaseKey(expandedRef) };
66
+ }
67
+ // New bus. Evict LRU if at soft cap.
68
+ if (registry.size >= maxBuses) {
69
+ const evictedKey = registry.keys().next().value;
70
+ if (evictedKey != null) {
71
+ const evicted = registry.get(evictedKey);
72
+ if (evicted != null) {
73
+ if (evicted.idleTimer != null)
74
+ clearTimeout(evicted.idleTimer);
75
+ evicted.stop();
76
+ registry.delete(evictedKey);
77
+ logger.warn(`event-bus: LRU eviction of ${evictedKey} at cap ${maxBuses}`);
78
+ }
79
+ }
80
+ }
81
+ const bus = new EpicEventBus({ epic: expandedRef });
82
+ if (options.noPoll === true && options.runCycle == null) {
83
+ const sub = {
84
+ bus,
85
+ refCount: 1,
86
+ stop: () => undefined,
87
+ pausePoller: () => undefined,
88
+ resumePoller: () => undefined,
89
+ catchUpPoll: async () => undefined,
90
+ idleTimer: null,
91
+ lastActiveAt: now(),
92
+ idleTtlMs,
93
+ logger,
94
+ };
95
+ registry.set(expandedRef, sub);
96
+ return { bus, release: () => releaseKey(expandedRef) };
97
+ }
98
+ const gh = options.gh ?? new GhCliWrapper(options.runner);
99
+ const interval = options.intervalMs ?? DEFAULT_INTERVAL_MS;
100
+ const state = {
101
+ prev: new Map(),
102
+ aggState: initialAggregateState(),
103
+ firstPoll: true,
104
+ currentResolved: null,
105
+ };
106
+ const controller = new AbortController();
107
+ const pauseState = {
108
+ paused: false,
109
+ resumeResolver: null,
110
+ };
111
+ const runCycle = options.runCycle
112
+ ? () => options.runCycle(bus)
113
+ : () => runRealCycle(bus, expandedRef, gh, state, logger);
114
+ const catchUpPoll = async () => {
115
+ try {
116
+ await runCycle();
117
+ logger.info?.(`event-bus: catch-up poll for ${expandedRef}`);
118
+ }
119
+ catch (err) {
120
+ logger.warn(`event-bus: catch-up poll failed for ${expandedRef}: ${err instanceof Error ? err.message : String(err)}`);
121
+ }
122
+ };
123
+ const stop = () => {
124
+ controller.abort();
125
+ // Also wake any pending resume waiter so the loop exits promptly.
126
+ if (pauseState.resumeResolver != null) {
127
+ const r = pauseState.resumeResolver;
128
+ pauseState.resumeResolver = null;
129
+ r();
130
+ }
131
+ };
132
+ const pausePoller = () => {
133
+ pauseState.paused = true;
134
+ };
135
+ const resumePoller = () => {
136
+ if (!pauseState.paused)
137
+ return;
138
+ pauseState.paused = false;
139
+ if (pauseState.resumeResolver != null) {
140
+ const r = pauseState.resumeResolver;
141
+ pauseState.resumeResolver = null;
142
+ r();
143
+ }
144
+ };
145
+ const sub = {
146
+ bus,
147
+ refCount: 1,
148
+ stop,
149
+ pausePoller,
150
+ resumePoller,
151
+ catchUpPoll,
152
+ idleTimer: null,
153
+ lastActiveAt: now(),
154
+ idleTtlMs,
155
+ logger,
156
+ };
157
+ registry.set(expandedRef, sub);
158
+ // Kick off the poll loop unless the caller opted out (`noPoll` with a
159
+ // custom `runCycle` is a valid test config — the loop is still needed).
160
+ if (options.noPoll !== true) {
161
+ void runPollLoop(runCycle, interval, controller.signal, pauseState, logger);
162
+ }
163
+ return { bus, release: () => releaseKey(expandedRef) };
164
+ }
165
+ function releaseKey(key) {
166
+ const sub = registry.get(key);
167
+ if (sub == null)
168
+ return;
169
+ sub.refCount -= 1;
170
+ if (sub.refCount > 0)
171
+ return;
172
+ sub.pausePoller();
173
+ sub.idleTimer = setTimeout(() => {
174
+ // Guarded: an acquire may have raced in during the tick.
175
+ const current = registry.get(key);
176
+ if (current == null || current !== sub)
177
+ return;
178
+ if (current.refCount > 0)
179
+ return;
180
+ current.stop();
181
+ registry.delete(key);
182
+ current.idleTimer = null;
183
+ current.logger.info?.(`event-bus: idle-TTL eviction of ${key}`);
184
+ }, sub.idleTtlMs);
185
+ if (sub.idleTimer.unref)
186
+ sub.idleTimer.unref();
187
+ }
188
+ async function expandRef(input, runner) {
189
+ const resolved = await resolveIssueContext({
190
+ issue: input,
191
+ ...(runner != null ? { runner } : {}),
192
+ });
193
+ return `${resolved.ref.nwo}#${resolved.ref.number}`;
194
+ }
195
+ function sleep(ms, signal) {
196
+ return new Promise((resolve) => {
197
+ if (signal.aborted) {
198
+ resolve();
199
+ return;
200
+ }
201
+ const timer = setTimeout(resolve, ms);
202
+ if (timer.unref)
203
+ timer.unref();
204
+ signal.addEventListener('abort', () => {
205
+ clearTimeout(timer);
206
+ resolve();
207
+ }, { once: true });
208
+ });
209
+ }
210
+ function waitForResume(pauseState, signal) {
211
+ return new Promise((resolve) => {
212
+ if (signal.aborted || !pauseState.paused) {
213
+ resolve();
214
+ return;
215
+ }
216
+ pauseState.resumeResolver = resolve;
217
+ signal.addEventListener('abort', () => {
218
+ if (pauseState.resumeResolver === resolve) {
219
+ pauseState.resumeResolver = null;
220
+ resolve();
221
+ }
222
+ }, { once: true });
223
+ });
224
+ }
225
+ async function runPollLoop(runCycle, interval, signal, pauseState, logger) {
226
+ while (!signal.aborted) {
227
+ if (pauseState.paused) {
228
+ await waitForResume(pauseState, signal);
229
+ if (signal.aborted)
230
+ break;
231
+ continue;
232
+ }
233
+ try {
234
+ await runCycle();
235
+ }
236
+ catch (err) {
237
+ logger.warn(`event-bus: poll error: ${err instanceof Error ? err.message : String(err)}`);
238
+ }
239
+ if (signal.aborted)
240
+ break;
241
+ if (pauseState.paused)
242
+ continue;
243
+ await sleep(interval, signal);
244
+ }
245
+ }
246
+ async function runRealCycle(bus, expandedRef, gh, state, logger) {
247
+ if (state.currentResolved == null) {
248
+ try {
249
+ state.currentResolved = await resolveEpic({ epicRef: expandedRef, gh, logger });
250
+ }
251
+ catch (err) {
252
+ if (err instanceof LoudResolverError) {
253
+ logger.warn(`event-bus: resolveEpic failed: ${err.message}`);
254
+ }
255
+ else {
256
+ logger.warn(`event-bus: resolveEpic failed: ${String(err)}`);
257
+ }
258
+ return;
259
+ }
260
+ }
261
+ const resolved = state.currentResolved;
262
+ const result = await runOnePoll(state.prev, {
263
+ gh,
264
+ refs: resolved.parsed.allRefs,
265
+ epicOwnerRepo: resolved.epic.repo,
266
+ logger,
267
+ });
268
+ for (const event of result.events) {
269
+ bus.emit({ ...event, type: 'issue-transition' });
270
+ }
271
+ const aggregateResult = computeAggregateEvents({
272
+ curr: result.curr,
273
+ parsed: resolved.parsed,
274
+ epicRepo: resolved.epic.repo,
275
+ epicNumber: resolved.epic.number,
276
+ prevState: state.aggState,
277
+ initial: state.firstPoll,
278
+ now: () => new Date().toISOString(),
279
+ });
280
+ for (const event of aggregateResult.events) {
281
+ bus.emit(event);
282
+ }
283
+ state.aggState = aggregateResult.nextState;
284
+ state.prev = result.curr;
285
+ state.firstPoll = false;
286
+ // Refresh the resolved epic for the next cycle (best effort).
287
+ try {
288
+ state.currentResolved = await resolveEpic({ epicRef: expandedRef, gh, logger });
289
+ }
290
+ catch (err) {
291
+ logger.warn(`event-bus: resolveEpic refresh failed: ${err instanceof Error ? err.message : String(err)}`);
292
+ }
293
+ }
294
+ /**
295
+ * Test-only: forcibly release all subscriptions. Use in test `afterEach`.
296
+ */
297
+ export function _resetRegistryForTests() {
298
+ for (const sub of registry.values()) {
299
+ if (sub.idleTimer != null)
300
+ clearTimeout(sub.idleTimer);
301
+ sub.stop();
302
+ }
303
+ registry.clear();
304
+ }
305
+ //# sourceMappingURL=event-bus-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus-registry.js","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/mcp/event-bus-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { CockpitStreamEvent } from '../watch/stream-event.js';
2
+ export interface EventBusEntry {
3
+ cursor: number;
4
+ event: CockpitStreamEvent;
5
+ emittedAt: number;
6
+ }
7
+ export interface WaitForInput {
8
+ sinceCursor: number;
9
+ maxWaitMs: number;
10
+ coalesceWindowMs: number;
11
+ maxBatchSize: number;
12
+ /** Optional clock injection for tests. */
13
+ now?: () => number;
14
+ }
15
+ export interface WaitForResult {
16
+ entries: EventBusEntry[];
17
+ resetFrom?: 'expired';
18
+ }
19
+ export type CursorParseResult = {
20
+ kind: 'valid';
21
+ position: number;
22
+ } | {
23
+ kind: 'expired';
24
+ requestedPosition: number;
25
+ } | {
26
+ kind: 'discarded';
27
+ reason: 'legacy' | 'cross-instance' | 'evicted';
28
+ } | {
29
+ kind: 'malformed';
30
+ } | {
31
+ kind: 'never-issued';
32
+ } | {
33
+ kind: 'wrong-epic';
34
+ requestedEpic: string;
35
+ boundEpic: string;
36
+ };
37
+ export interface EpicEventBusOptions {
38
+ epic: string;
39
+ retentionCount?: number;
40
+ retentionMs?: number;
41
+ now?: () => number;
42
+ /** Test seam: override the per-bus nonce. Defaults to a fresh random. */
43
+ nonce?: string;
44
+ }
45
+ /**
46
+ * Per-process nonce generated once at module load. Embedded in every cursor
47
+ * token so cross-instance cursors (server restart) classify as `discarded`
48
+ * rather than `never-issued`.
49
+ */
50
+ export declare const INSTANCE_NONCE: string;
51
+ export declare function encodeCursor(epic: string, position: number, pnonce: string, bnonce: string): string;
52
+ export declare function decodeCursor(str: string): {
53
+ epic: string;
54
+ position: number;
55
+ pnonce?: string;
56
+ bnonce?: string;
57
+ } | null;
58
+ export declare class EpicEventBus {
59
+ readonly epic: string;
60
+ readonly busNonce: string;
61
+ private buffer;
62
+ private nextCursor;
63
+ private waiters;
64
+ private readonly retentionCount;
65
+ private readonly retentionMs;
66
+ private readonly clock;
67
+ constructor(options: EpicEventBusOptions);
68
+ emit(event: CockpitStreamEvent): EventBusEntry;
69
+ parseCursor(str: string | undefined): CursorParseResult;
70
+ /**
71
+ * Drain entries with cursor > sinceCursor immediately (up to maxBatchSize);
72
+ * if empty, wait up to maxWaitMs for the first emit, then coalesce for
73
+ * coalesceWindowMs (or until maxBatchSize is reached).
74
+ */
75
+ waitFor(input: WaitForInput): Promise<WaitForResult>;
76
+ private waitForFirstEmit;
77
+ private flushWaiters;
78
+ private trim;
79
+ /** Test-only inspector. */
80
+ size(): number;
81
+ }
82
+ //# sourceMappingURL=event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/mcp/event-bus.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,gBAAgB,GAAG,SAAS,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAOD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,MAA8C,CAAC;AAI5E,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,MAAM,CAGR;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,GACV;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6B7E;AAED,qBAAa,YAAY;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;gBAEzB,OAAO,EAAE,mBAAmB;IAQxC,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa;IAa9C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB;IA0BvD;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA+C1D,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,IAAI;IAUZ,2BAA2B;IAC3B,IAAI,IAAI,MAAM;CAGf"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * In-process event bus for `cockpit_await_events`.
3
+ *
4
+ * Per-epic broadcaster subscribed to the same event source `cockpit watch`
5
+ * uses (poll loop + aggregate emits). Monotonic cursor; LRU buffer bounded
6
+ * by `retentionCount` AND `retentionMs` (whichever hits first).
7
+ *
8
+ * Cursor is base64-encoded JSON `{epic, position, pnonce, bnonce}` — opaque
9
+ * to callers. `pnonce` is a per-process instance nonce (16 hex chars);
10
+ * `bnonce` is a per-bus-instance nonce (16 hex chars). Distinct classes:
11
+ * - `valid` → normal path
12
+ * - `expired` → position below the low-watermark; return `resetFrom: "expired"`
13
+ * - `discarded` → nonce missing (legacy) or mismatched (cross-instance / evicted);
14
+ * reset to head with `resetFrom: "discarded"`
15
+ * - `malformed` → not base64 / not JSON / bad shape
16
+ * - `never-issued` → shape ok, nonces match, but position outside issued range
17
+ * - `wrong-epic` → cursor was issued for a different epic
18
+ *
19
+ * Retention env knobs: `COCKPIT_MCP_EVENT_RETENTION_COUNT` (default 10_000),
20
+ * `COCKPIT_MCP_EVENT_RETENTION_MS` (default 600_000).
21
+ */
22
+ import crypto from 'node:crypto';
23
+ /**
24
+ * Per-process nonce generated once at module load. Embedded in every cursor
25
+ * token so cross-instance cursors (server restart) classify as `discarded`
26
+ * rather than `never-issued`.
27
+ */
28
+ export const INSTANCE_NONCE = crypto.randomBytes(8).toString('hex');
29
+ const NONCE_SHAPE = /^[0-9a-f]{16}$/;
30
+ export function encodeCursor(epic, position, pnonce, bnonce) {
31
+ const json = JSON.stringify({ epic, position, pnonce, bnonce });
32
+ return Buffer.from(json, 'utf-8').toString('base64');
33
+ }
34
+ export function decodeCursor(str) {
35
+ let buf;
36
+ try {
37
+ buf = Buffer.from(str, 'base64');
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ const decoded = buf.toString('utf-8');
43
+ let parsed;
44
+ try {
45
+ parsed = JSON.parse(decoded);
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ if (parsed == null || typeof parsed !== 'object')
51
+ return null;
52
+ const record = parsed;
53
+ if (typeof record.epic !== 'string' || typeof record.position !== 'number')
54
+ return null;
55
+ if (!Number.isInteger(record.position) || record.position < 0)
56
+ return null;
57
+ const out = {
58
+ epic: record.epic,
59
+ position: record.position,
60
+ };
61
+ if (typeof record.pnonce === 'string' && NONCE_SHAPE.test(record.pnonce)) {
62
+ out.pnonce = record.pnonce;
63
+ }
64
+ if (typeof record.bnonce === 'string' && NONCE_SHAPE.test(record.bnonce)) {
65
+ out.bnonce = record.bnonce;
66
+ }
67
+ return out;
68
+ }
69
+ export class EpicEventBus {
70
+ epic;
71
+ busNonce;
72
+ buffer = [];
73
+ nextCursor = 1;
74
+ waiters = [];
75
+ retentionCount;
76
+ retentionMs;
77
+ clock;
78
+ constructor(options) {
79
+ this.epic = options.epic;
80
+ this.retentionCount = options.retentionCount ?? 10_000;
81
+ this.retentionMs = options.retentionMs ?? 600_000;
82
+ this.clock = options.now ?? Date.now;
83
+ this.busNonce = options.nonce ?? crypto.randomBytes(8).toString('hex');
84
+ }
85
+ emit(event) {
86
+ const entry = {
87
+ cursor: this.nextCursor,
88
+ event,
89
+ emittedAt: this.clock(),
90
+ };
91
+ this.nextCursor += 1;
92
+ this.buffer.push(entry);
93
+ this.trim();
94
+ this.flushWaiters();
95
+ return entry;
96
+ }
97
+ parseCursor(str) {
98
+ if (str == null)
99
+ return { kind: 'valid', position: 0 };
100
+ const decoded = decodeCursor(str);
101
+ if (decoded == null)
102
+ return { kind: 'malformed' };
103
+ if (decoded.pnonce == null || decoded.bnonce == null) {
104
+ return { kind: 'discarded', reason: 'legacy' };
105
+ }
106
+ if (decoded.epic !== this.epic) {
107
+ return { kind: 'wrong-epic', requestedEpic: decoded.epic, boundEpic: this.epic };
108
+ }
109
+ if (decoded.pnonce !== INSTANCE_NONCE) {
110
+ return { kind: 'discarded', reason: 'cross-instance' };
111
+ }
112
+ if (decoded.bnonce !== this.busNonce) {
113
+ return { kind: 'discarded', reason: 'evicted' };
114
+ }
115
+ if (decoded.position === 0)
116
+ return { kind: 'valid', position: 0 };
117
+ if (decoded.position >= this.nextCursor)
118
+ return { kind: 'never-issued' };
119
+ const lowWatermark = this.buffer.length === 0 ? this.nextCursor : this.buffer[0].cursor;
120
+ if (decoded.position < lowWatermark - 1) {
121
+ return { kind: 'expired', requestedPosition: decoded.position };
122
+ }
123
+ return { kind: 'valid', position: decoded.position };
124
+ }
125
+ /**
126
+ * Drain entries with cursor > sinceCursor immediately (up to maxBatchSize);
127
+ * if empty, wait up to maxWaitMs for the first emit, then coalesce for
128
+ * coalesceWindowMs (or until maxBatchSize is reached).
129
+ */
130
+ async waitFor(input) {
131
+ const now = input.now ?? this.clock;
132
+ const drainFrom = (since, cap) => {
133
+ const out = [];
134
+ for (const entry of this.buffer) {
135
+ if (entry.cursor <= since)
136
+ continue;
137
+ out.push(entry);
138
+ if (out.length >= cap)
139
+ break;
140
+ }
141
+ return out;
142
+ };
143
+ let batch = drainFrom(input.sinceCursor, input.maxBatchSize);
144
+ if (batch.length === 0) {
145
+ if (input.maxWaitMs === 0) {
146
+ return { entries: [] };
147
+ }
148
+ const first = await this.waitForFirstEmit(input.sinceCursor, input.maxWaitMs);
149
+ if (first == null)
150
+ return { entries: [] };
151
+ batch = [first];
152
+ }
153
+ if (batch.length >= input.maxBatchSize) {
154
+ return { entries: batch };
155
+ }
156
+ if (input.coalesceWindowMs > 0) {
157
+ const deadline = now() + input.coalesceWindowMs;
158
+ while (batch.length < input.maxBatchSize) {
159
+ const remaining = deadline - now();
160
+ if (remaining <= 0)
161
+ break;
162
+ const nextSince = batch[batch.length - 1].cursor;
163
+ const more = drainFrom(nextSince, input.maxBatchSize - batch.length);
164
+ if (more.length > 0) {
165
+ for (const entry of more)
166
+ batch.push(entry);
167
+ continue;
168
+ }
169
+ const next = await this.waitForFirstEmit(nextSince, remaining);
170
+ if (next == null)
171
+ break;
172
+ batch.push(next);
173
+ }
174
+ }
175
+ return { entries: batch };
176
+ }
177
+ waitForFirstEmit(sinceCursor, waitMs) {
178
+ return new Promise((resolve) => {
179
+ let settled = false;
180
+ const timer = setTimeout(() => {
181
+ if (settled)
182
+ return;
183
+ settled = true;
184
+ this.waiters = this.waiters.filter((w) => w !== waiter);
185
+ resolve(null);
186
+ }, waitMs);
187
+ if (timer.unref)
188
+ timer.unref();
189
+ const waiter = {
190
+ sinceCursor,
191
+ resolve: (entries) => {
192
+ if (settled)
193
+ return;
194
+ settled = true;
195
+ clearTimeout(timer);
196
+ resolve(entries[0] ?? null);
197
+ },
198
+ };
199
+ this.waiters.push(waiter);
200
+ });
201
+ }
202
+ flushWaiters() {
203
+ if (this.waiters.length === 0)
204
+ return;
205
+ const pending = this.waiters;
206
+ this.waiters = [];
207
+ for (const waiter of pending) {
208
+ const entries = [];
209
+ for (const entry of this.buffer) {
210
+ if (entry.cursor > waiter.sinceCursor)
211
+ entries.push(entry);
212
+ }
213
+ waiter.resolve(entries);
214
+ }
215
+ }
216
+ trim() {
217
+ const cutoff = this.clock() - this.retentionMs;
218
+ while (this.buffer.length > 0 && this.buffer[0].emittedAt < cutoff) {
219
+ this.buffer.shift();
220
+ }
221
+ while (this.buffer.length > this.retentionCount) {
222
+ this.buffer.shift();
223
+ }
224
+ }
225
+ /** Test-only inspector. */
226
+ size() {
227
+ return this.buffer.length;
228
+ }
229
+ }
230
+ //# sourceMappingURL=event-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/mcp/event-bus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `generacy cockpit mcp` command — Commander factory. Refuses to start on
3
+ * worker containers via `GENERACY_CLUSTER_ROLE` (Q2-A defense-in-depth).
4
+ * On orchestrator (or missing env), builds the MCP server and connects a
5
+ * stdio transport.
6
+ */
7
+ import { Command } from 'commander';
8
+ export interface CockpitMcpDeps {
9
+ /** Injection seam for tests — bypass real stdio transport. */
10
+ makeTransport?: () => unknown;
11
+ env?: NodeJS.ProcessEnv;
12
+ stderr?: (line: string) => void;
13
+ exit?: (code: number) => never;
14
+ }
15
+ export declare function cockpitMcpCommand(deps?: CockpitMcpDeps): Command;
16
+ export declare function runCockpitMcp(deps?: CockpitMcpDeps): Promise<void>;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/cockpit/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAChC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAUpE;AAED,wBAAsB,aAAa,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5E"}