project-logbook 1.2.0 → 1.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 (226) hide show
  1. package/README.md +2 -0
  2. package/dist/commands/answer.d.ts +1 -0
  3. package/dist/commands/answer.js +41 -0
  4. package/dist/commands/answer.js.map +1 -0
  5. package/dist/commands/answers.d.ts +6 -0
  6. package/dist/commands/answers.js +37 -0
  7. package/dist/commands/answers.js.map +1 -0
  8. package/dist/commands/ask.d.ts +1 -0
  9. package/dist/commands/ask.js +30 -0
  10. package/dist/commands/ask.js.map +1 -0
  11. package/dist/commands/build.js +25 -6
  12. package/dist/commands/build.js.map +1 -1
  13. package/dist/commands/deprecate-qna.d.ts +1 -0
  14. package/dist/commands/deprecate-qna.js +33 -0
  15. package/dist/commands/deprecate-qna.js.map +1 -0
  16. package/dist/commands/log.js +2 -0
  17. package/dist/commands/log.js.map +1 -1
  18. package/dist/commands/new-helpers.d.ts +0 -1
  19. package/dist/commands/new-helpers.js +6 -3
  20. package/dist/commands/new-helpers.js.map +1 -1
  21. package/dist/commands/release.js +2 -0
  22. package/dist/commands/release.js.map +1 -1
  23. package/dist/commands/start.js +90 -21
  24. package/dist/commands/start.js.map +1 -1
  25. package/dist/commands/status.js +6 -0
  26. package/dist/commands/status.js.map +1 -1
  27. package/dist/commands/unanswered.d.ts +1 -0
  28. package/dist/commands/unanswered.js +25 -0
  29. package/dist/commands/unanswered.js.map +1 -0
  30. package/dist/commands/watch.d.ts +15 -0
  31. package/dist/commands/watch.js +153 -0
  32. package/dist/commands/watch.js.map +1 -0
  33. package/dist/index.js +44 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/lib/autolink.d.ts +5 -0
  36. package/dist/lib/autolink.js +36 -2
  37. package/dist/lib/autolink.js.map +1 -1
  38. package/dist/lib/build-helpers.d.ts +10 -1
  39. package/dist/lib/build-helpers.js +27 -4
  40. package/dist/lib/build-helpers.js.map +1 -1
  41. package/dist/lib/build-steps.js +2 -1
  42. package/dist/lib/build-steps.js.map +1 -1
  43. package/dist/lib/config.d.ts +16 -0
  44. package/dist/lib/config.js +17 -0
  45. package/dist/lib/config.js.map +1 -1
  46. package/dist/lib/custom-card-renderer.js +2 -1
  47. package/dist/lib/custom-card-renderer.js.map +1 -1
  48. package/dist/lib/entry-href.d.ts +7 -0
  49. package/dist/lib/entry-href.js +8 -0
  50. package/dist/lib/entry-href.js.map +1 -0
  51. package/dist/lib/markdown-processors.d.ts +2 -1
  52. package/dist/lib/post-template.js +3 -3
  53. package/dist/lib/post-template.js.map +1 -1
  54. package/dist/lib/template-helpers.d.ts +2 -1
  55. package/dist/lib/template-helpers.js +32 -2
  56. package/dist/lib/template-helpers.js.map +1 -1
  57. package/dist/lib/template-types.d.ts +14 -0
  58. package/dist/lib/templates.js +14 -4
  59. package/dist/lib/templates.js.map +1 -1
  60. package/dist/linters/index.js +2 -0
  61. package/dist/linters/index.js.map +1 -1
  62. package/dist/linters/jira-prefix.js +32 -16
  63. package/dist/linters/jira-prefix.js.map +1 -1
  64. package/dist/linters/qna.d.ts +3 -0
  65. package/dist/linters/qna.js +120 -0
  66. package/dist/linters/qna.js.map +1 -0
  67. package/dist/templates/about-watch.md +29 -0
  68. package/dist/templates/hub.css +677 -0
  69. package/dist/templates/hub.js +743 -0
  70. package/dist/templates/qna.md +11 -0
  71. package/dist/templates/steer.txt +2 -0
  72. package/dist/templates/styles.css +53 -0
  73. package/dist/utils/id.d.ts +1 -1
  74. package/dist/utils/id.js +4 -1
  75. package/dist/utils/id.js.map +1 -1
  76. package/dist/utils/qna.d.ts +46 -0
  77. package/dist/utils/qna.js +157 -0
  78. package/dist/utils/qna.js.map +1 -0
  79. package/dist/watch/__tests__/git-utils.test.d.ts +1 -0
  80. package/dist/watch/__tests__/git-utils.test.js +17 -0
  81. package/dist/watch/__tests__/git-utils.test.js.map +1 -0
  82. package/dist/watch/collector.d.ts +14 -0
  83. package/dist/watch/collector.js +33 -0
  84. package/dist/watch/collector.js.map +1 -0
  85. package/dist/watch/collectors/acli.d.ts +15 -0
  86. package/dist/watch/collectors/acli.js +197 -0
  87. package/dist/watch/collectors/acli.js.map +1 -0
  88. package/dist/watch/collectors/entries.d.ts +9 -0
  89. package/dist/watch/collectors/entries.js +90 -0
  90. package/dist/watch/collectors/entries.js.map +1 -0
  91. package/dist/watch/collectors/git.d.ts +12 -0
  92. package/dist/watch/collectors/git.js +58 -0
  93. package/dist/watch/collectors/git.js.map +1 -0
  94. package/dist/watch/collectors/glab.d.ts +10 -0
  95. package/dist/watch/collectors/glab.js +273 -0
  96. package/dist/watch/collectors/glab.js.map +1 -0
  97. package/dist/watch/collectors/index.d.ts +10 -0
  98. package/dist/watch/collectors/index.js +21 -0
  99. package/dist/watch/collectors/index.js.map +1 -0
  100. package/dist/watch/collectors/jira.d.ts +3 -0
  101. package/dist/watch/collectors/jira.js +111 -0
  102. package/dist/watch/collectors/jira.js.map +1 -0
  103. package/dist/watch/collectors/type-guards.d.ts +17 -0
  104. package/dist/watch/collectors/type-guards.js +35 -0
  105. package/dist/watch/collectors/type-guards.js.map +1 -0
  106. package/dist/watch/collectors/types.d.ts +37 -0
  107. package/dist/watch/collectors/types.js +9 -0
  108. package/dist/watch/collectors/types.js.map +1 -0
  109. package/dist/watch/dashboard-html.d.ts +11 -0
  110. package/dist/watch/dashboard-html.js +81 -0
  111. package/dist/watch/dashboard-html.js.map +1 -0
  112. package/dist/watch/dashboard-script.d.ts +12 -0
  113. package/dist/watch/dashboard-script.js +20 -0
  114. package/dist/watch/dashboard-script.js.map +1 -0
  115. package/dist/watch/dashboard-styles.d.ts +12 -0
  116. package/dist/watch/dashboard-styles.js +20 -0
  117. package/dist/watch/dashboard-styles.js.map +1 -0
  118. package/dist/watch/dashboard.d.ts +12 -0
  119. package/dist/watch/dashboard.js +50 -0
  120. package/dist/watch/dashboard.js.map +1 -0
  121. package/dist/watch/git-utils.d.ts +36 -0
  122. package/dist/watch/git-utils.js +117 -0
  123. package/dist/watch/git-utils.js.map +1 -0
  124. package/dist/watch/hub-state.d.ts +39 -0
  125. package/dist/watch/hub-state.js +57 -0
  126. package/dist/watch/hub-state.js.map +1 -0
  127. package/dist/watch/hub.d.ts +2 -0
  128. package/dist/watch/hub.js +252 -0
  129. package/dist/watch/hub.js.map +1 -0
  130. package/dist/watch/log-utils.d.ts +13 -0
  131. package/dist/watch/log-utils.js +24 -0
  132. package/dist/watch/log-utils.js.map +1 -0
  133. package/dist/watch/notify.d.ts +18 -0
  134. package/dist/watch/notify.js +45 -0
  135. package/dist/watch/notify.js.map +1 -0
  136. package/dist/watch/state.d.ts +38 -0
  137. package/dist/watch/state.js +36 -0
  138. package/dist/watch/state.js.map +1 -0
  139. package/dist/watch/strategies/behind-default.d.ts +5 -0
  140. package/dist/watch/strategies/behind-default.js +21 -0
  141. package/dist/watch/strategies/behind-default.js.map +1 -0
  142. package/dist/watch/strategies/idle.d.ts +5 -0
  143. package/dist/watch/strategies/idle.js +21 -0
  144. package/dist/watch/strategies/idle.js.map +1 -0
  145. package/dist/watch/strategies/in-progress.d.ts +5 -0
  146. package/dist/watch/strategies/in-progress.js +21 -0
  147. package/dist/watch/strategies/in-progress.js.map +1 -0
  148. package/dist/watch/strategies/index.d.ts +34 -0
  149. package/dist/watch/strategies/index.js +148 -0
  150. package/dist/watch/strategies/index.js.map +1 -0
  151. package/dist/watch/strategies/jira-not-in-review.d.ts +2 -0
  152. package/dist/watch/strategies/jira-not-in-review.js +29 -0
  153. package/dist/watch/strategies/jira-not-in-review.js.map +1 -0
  154. package/dist/watch/strategies/jira-still-open.d.ts +2 -0
  155. package/dist/watch/strategies/jira-still-open.js +31 -0
  156. package/dist/watch/strategies/jira-still-open.js.map +1 -0
  157. package/dist/watch/strategies/mr-approval-optional.d.ts +5 -0
  158. package/dist/watch/strategies/mr-approval-optional.js +21 -0
  159. package/dist/watch/strategies/mr-approval-optional.js.map +1 -0
  160. package/dist/watch/strategies/mr-approved.d.ts +5 -0
  161. package/dist/watch/strategies/mr-approved.js +21 -0
  162. package/dist/watch/strategies/mr-approved.js.map +1 -0
  163. package/dist/watch/strategies/mr-conflicts.d.ts +5 -0
  164. package/dist/watch/strategies/mr-conflicts.js +21 -0
  165. package/dist/watch/strategies/mr-conflicts.js.map +1 -0
  166. package/dist/watch/strategies/mr-draft.d.ts +5 -0
  167. package/dist/watch/strategies/mr-draft.js +21 -0
  168. package/dist/watch/strategies/mr-draft.js.map +1 -0
  169. package/dist/watch/strategies/mr-open-comments.d.ts +5 -0
  170. package/dist/watch/strategies/mr-open-comments.js +21 -0
  171. package/dist/watch/strategies/mr-open-comments.js.map +1 -0
  172. package/dist/watch/strategies/narrative-missing.d.ts +5 -0
  173. package/dist/watch/strategies/narrative-missing.js +21 -0
  174. package/dist/watch/strategies/narrative-missing.js.map +1 -0
  175. package/dist/watch/strategies/no-mr.d.ts +5 -0
  176. package/dist/watch/strategies/no-mr.js +21 -0
  177. package/dist/watch/strategies/no-mr.js.map +1 -0
  178. package/dist/watch/strategies/pipeline-failed.d.ts +5 -0
  179. package/dist/watch/strategies/pipeline-failed.js +21 -0
  180. package/dist/watch/strategies/pipeline-failed.js.map +1 -0
  181. package/dist/watch/strategies/pipeline-running.d.ts +5 -0
  182. package/dist/watch/strategies/pipeline-running.js +21 -0
  183. package/dist/watch/strategies/pipeline-running.js.map +1 -0
  184. package/dist/watch/strategies/ready-for-release.d.ts +7 -0
  185. package/dist/watch/strategies/ready-for-release.js +35 -0
  186. package/dist/watch/strategies/ready-for-release.js.map +1 -0
  187. package/dist/watch/strategies/ready-to-commit.d.ts +5 -0
  188. package/dist/watch/strategies/ready-to-commit.js +21 -0
  189. package/dist/watch/strategies/ready-to-commit.js.map +1 -0
  190. package/dist/watch/strategies/ready-to-push.d.ts +5 -0
  191. package/dist/watch/strategies/ready-to-push.js +21 -0
  192. package/dist/watch/strategies/ready-to-push.js.map +1 -0
  193. package/dist/watch/strategies/released.d.ts +6 -0
  194. package/dist/watch/strategies/released.js +21 -0
  195. package/dist/watch/strategies/released.js.map +1 -0
  196. package/dist/watch/strategies/squash-merged.d.ts +6 -0
  197. package/dist/watch/strategies/squash-merged.js +21 -0
  198. package/dist/watch/strategies/squash-merged.js.map +1 -0
  199. package/dist/watch/strategies/types.d.ts +31 -0
  200. package/dist/watch/strategies/types.js +12 -0
  201. package/dist/watch/strategies/types.js.map +1 -0
  202. package/dist/watch/strategies/unstaged-changes.d.ts +5 -0
  203. package/dist/watch/strategies/unstaged-changes.js +21 -0
  204. package/dist/watch/strategies/unstaged-changes.js.map +1 -0
  205. package/dist/watch/strategies/wrong-branch.d.ts +6 -0
  206. package/dist/watch/strategies/wrong-branch.js +26 -0
  207. package/dist/watch/strategies/wrong-branch.js.map +1 -0
  208. package/dist/watch/types.d.ts +211 -0
  209. package/dist/watch/types.js +25 -0
  210. package/dist/watch/types.js.map +1 -0
  211. package/dist/watch/watcher-fs.d.ts +39 -0
  212. package/dist/watch/watcher-fs.js +105 -0
  213. package/dist/watch/watcher-fs.js.map +1 -0
  214. package/dist/watch/watcher-http.d.ts +19 -0
  215. package/dist/watch/watcher-http.js +47 -0
  216. package/dist/watch/watcher-http.js.map +1 -0
  217. package/dist/watch/watcher.d.ts +4 -0
  218. package/dist/watch/watcher.js +185 -0
  219. package/dist/watch/watcher.js.map +1 -0
  220. package/package.json +8 -2
  221. package/src/templates/about-watch.md +29 -0
  222. package/src/templates/hub.css +677 -0
  223. package/src/templates/hub.js +743 -0
  224. package/src/templates/qna.md +11 -0
  225. package/src/templates/steer.txt +2 -0
  226. package/src/templates/styles.css +53 -0
@@ -0,0 +1,35 @@
1
+ /** Type guards for GitLab and Jira API response types. */
2
+ export function isJiraIssue(value) {
3
+ if (!value || typeof value !== 'object')
4
+ return false;
5
+ if (!('key' in value) || !('fields' in value))
6
+ return false;
7
+ if (typeof value.key !== 'string')
8
+ return false;
9
+ const fields = value.fields;
10
+ if (!fields || typeof fields !== 'object')
11
+ return false;
12
+ if (!('summary' in fields) || !('status' in fields))
13
+ return false;
14
+ if (typeof fields.summary !== 'string')
15
+ return false;
16
+ const status = fields.status;
17
+ if (!status || typeof status !== 'object')
18
+ return false;
19
+ return 'name' in status && typeof status.name === 'string';
20
+ }
21
+ export function parsePipelineStatus(status) {
22
+ const lower = status.toLowerCase();
23
+ if (lower === 'running')
24
+ return 'running';
25
+ if (lower === 'passed' || lower === 'success')
26
+ return 'passed';
27
+ if (lower === 'failed')
28
+ return 'failed';
29
+ if (lower === 'pending')
30
+ return 'pending';
31
+ if (lower === 'canceled')
32
+ return 'canceled';
33
+ return 'none';
34
+ }
35
+ //# sourceMappingURL=type-guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-guards.js","sourceRoot":"","sources":["../../../src/watch/collectors/type-guards.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAY1D,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC/D,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Collector interface for logbook watch.
3
+ *
4
+ * A collector gathers a subset of metrics from a specific source (git, files,
5
+ * CLI tools, APIs). Each collector runs independently on its own schedule and
6
+ * writes its results into the shared WatcherState.
7
+ */
8
+ import type { WatcherState } from '../state.js';
9
+ /** Schedule type for a collector. */
10
+ export type CollectorSchedule =
11
+ /** Runs on file-system events (instant, debounced). */
12
+ {
13
+ type: 'fs';
14
+ patterns: string[];
15
+ }
16
+ /** Runs on a fixed interval. */
17
+ | {
18
+ type: 'interval';
19
+ ms: number;
20
+ };
21
+ /** A collector that gathers metrics from a specific source. */
22
+ export interface Collector {
23
+ /** Human-readable name for logging. */
24
+ name: string;
25
+ /** When this collector should run. */
26
+ schedule: CollectorSchedule;
27
+ /**
28
+ * Check if this collector is available (e.g., CLI tool installed).
29
+ * Returns false if prerequisites are missing — collector will be skipped.
30
+ */
31
+ available(cwd: string): Promise<boolean>;
32
+ /**
33
+ * Collect metrics and write them into the shared state.
34
+ * Must not throw — failures should result in undefined/default values.
35
+ */
36
+ collect(cwd: string, state: WatcherState): Promise<void>;
37
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Collector interface for logbook watch.
3
+ *
4
+ * A collector gathers a subset of metrics from a specific source (git, files,
5
+ * CLI tools, APIs). Each collector runs independently on its own schedule and
6
+ * writes its results into the shared WatcherState.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/watch/collectors/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Dashboard HTML structure for logbook watch hub.
3
+ *
4
+ * Provides the page skeleton with tab navigation and content areas.
5
+ */
6
+ /**
7
+ * Generate the HTML body structure with tab navigation.
8
+ *
9
+ * @param aboutHtml - Pre-rendered HTML content for the About tab.
10
+ */
11
+ export declare function dashboardHtml(aboutHtml: string): string;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Dashboard HTML structure for logbook watch hub.
3
+ *
4
+ * Provides the page skeleton with tab navigation and content areas.
5
+ */
6
+ /**
7
+ * Generate the HTML body structure with tab navigation.
8
+ *
9
+ * @param aboutHtml - Pre-rendered HTML content for the About tab.
10
+ */
11
+ export function dashboardHtml(aboutHtml) {
12
+ return `
13
+ <header>
14
+ <h1>Logbook Hub</h1>
15
+ </header>
16
+ <nav class="tab-bar">
17
+ <button class="tab-btn active" data-tab="projects">Local Projects <span class="tab-count" id="project-count">0</span></button>
18
+ <button class="tab-btn" data-tab="jira">Jira <span class="tab-count" id="jira-count">0</span></button>
19
+ <button class="tab-btn" data-tab="gitlab">GitLab <span class="tab-count" id="gitlab-count">0</span></button>
20
+ <button class="tab-btn" data-tab="workitems">GitLab Work Items <span class="tab-count" id="workitems-count">0</span></button>
21
+ <button class="tab-btn" data-tab="help">Help</button>
22
+ <button class="tab-btn" data-tab="about">About</button>
23
+ </nav>
24
+ <div class="container">
25
+ <div id="tab-projects" class="tab-content active">
26
+ <div class="tab-header-row" style="justify-content: flex-end;">
27
+ <button class="sort-toggle" id="sort-toggle">Sort (Newest)</button>
28
+ </div>
29
+ <div id="projects" class="projects">
30
+ <div class="empty">Waiting for projects to connect...</div>
31
+ </div>
32
+ </div>
33
+ <div id="tab-help" class="tab-content">
34
+ <h2 class="tab-heading">Status Badges Reference</h2>
35
+ <p class="tab-description">
36
+ These badges appear on project cards based on the current state of your code, merge requests, and Jira tickets.
37
+ Badges marked "blocked by" will not appear if the blocking badge is already active.
38
+ </p>
39
+ <table class="help-table">
40
+ <thead><tr><th>Badge</th><th>Source</th><th>Severity</th><th>Description</th><th>Blocked By</th></tr></thead>
41
+ <tbody id="help-table-body"><tr><td colspan="5" class="table-loading">Loading...</td></tr></tbody>
42
+ </table>
43
+ </div>
44
+ <div id="tab-about" class="tab-content">
45
+ <div class="about-content">${aboutHtml}</div>
46
+ </div>
47
+ <div id="tab-jira" class="tab-content">
48
+ <div class="tab-header-row">
49
+ <h2 class="tab-heading">Assigned Jira Issues</h2>
50
+ <button class="sort-toggle" id="jira-sort-toggle">Sort (Updated)</button>
51
+ </div>
52
+ <div id="jira-issues-content">
53
+ <div class="placeholder-msg">No assigned Jira issues found.<br>Set the <code>JIRA_API_TOKEN</code> environment variable and connect a project with <code>jiraBaseUrl</code> configured.</div>
54
+ </div>
55
+ <div class="tab-collector-footer" id="jira-tab-footer" style="display:none"></div>
56
+ </div>
57
+ <div id="tab-gitlab" class="tab-content">
58
+ <h2 class="tab-heading">Open Merge Requests</h2>
59
+ <div id="gitlab-mrs-content">
60
+ <div class="placeholder-msg">No open merge requests found.<br>Install the <code>glab</code> CLI and run <code>glab auth login</code> to connect.</div>
61
+ </div>
62
+ <div class="tab-collector-footer" id="gitlab-tab-footer" style="display:none"></div>
63
+ </div>
64
+ <div id="tab-workitems" class="tab-content">
65
+ <h2 class="tab-heading">Open GitLab Work Items</h2>
66
+ <div id="workitems-content">
67
+ <div class="placeholder-msg">No open work items found.<br>Install the <code>glab</code> CLI and run <code>glab auth login</code> to connect.</div>
68
+ </div>
69
+ <div class="tab-collector-footer" id="workitems-tab-footer" style="display:none"></div>
70
+ </div>
71
+ </div>
72
+ <div class="connection-status" id="conn-status">connected</div>
73
+ <div class="lightbox" id="lightbox">
74
+ <div class="lightbox-content">
75
+ <button class="lightbox-close" id="lightbox-close">&times;</button>
76
+ <div class="lightbox-title" id="lightbox-title"></div>
77
+ <div class="lightbox-body" id="lightbox-body"></div>
78
+ </div>
79
+ </div>`;
80
+ }
81
+ //# sourceMappingURL=dashboard-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-html.js","sourceRoot":"","sources":["../../src/watch/dashboard-html.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAiC0B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAkCnC,CAAC;AACV,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dashboard client-side JavaScript for logbook watch hub.
3
+ *
4
+ * Reads from the static hub.js template file instead of embedding JavaScript
5
+ * in a TypeScript string literal.
6
+ */
7
+ /**
8
+ * Read and return the Hub JavaScript wrapped in a script tag.
9
+ *
10
+ * @returns A `<script>` element string with the full dashboard JS.
11
+ */
12
+ export declare function dashboardScript(): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Dashboard client-side JavaScript for logbook watch hub.
3
+ *
4
+ * Reads from the static hub.js template file instead of embedding JavaScript
5
+ * in a TypeScript string literal.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { getTemplatesDir } from '../lib/migrations.js';
10
+ /**
11
+ * Read and return the Hub JavaScript wrapped in a script tag.
12
+ *
13
+ * @returns A `<script>` element string with the full dashboard JS.
14
+ */
15
+ export function dashboardScript() {
16
+ const jsPath = join(getTemplatesDir(), 'hub.js');
17
+ const js = readFileSync(jsPath, 'utf8');
18
+ return `<script>\n${js}\n</script>`;
19
+ }
20
+ //# sourceMappingURL=dashboard-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-script.js","sourceRoot":"","sources":["../../src/watch/dashboard-script.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,aAAa,EAAE,aAAa,CAAC;AACtC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dashboard CSS styles for logbook watch hub.
3
+ *
4
+ * Reads from the static hub.css template file instead of embedding CSS
5
+ * in a TypeScript string literal.
6
+ */
7
+ /**
8
+ * Read and return the Hub CSS wrapped in a style tag.
9
+ *
10
+ * @returns A `<style>` element string with the full dashboard CSS.
11
+ */
12
+ export declare function dashboardStyles(): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Dashboard CSS styles for logbook watch hub.
3
+ *
4
+ * Reads from the static hub.css template file instead of embedding CSS
5
+ * in a TypeScript string literal.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { getTemplatesDir } from '../lib/migrations.js';
10
+ /**
11
+ * Read and return the Hub CSS wrapped in a style tag.
12
+ *
13
+ * @returns A `<style>` element string with the full dashboard CSS.
14
+ */
15
+ export function dashboardStyles() {
16
+ const cssPath = join(getTemplatesDir(), 'hub.css');
17
+ const css = readFileSync(cssPath, 'utf8');
18
+ return `<style>\n${css}\n</style>`;
19
+ }
20
+ //# sourceMappingURL=dashboard-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-styles.js","sourceRoot":"","sources":["../../src/watch/dashboard-styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,YAAY,GAAG,YAAY,CAAC;AACrC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dashboard assembler for logbook watch hub.
3
+ *
4
+ * The "logbook Hub" is the web-based UI for `logbook watch` instances. It
5
+ * composes the full HTML page from separate style, script, and HTML modules.
6
+ */
7
+ /**
8
+ * Generate the full dashboard HTML document.
9
+ *
10
+ * @returns Complete HTML string for the dashboard page.
11
+ */
12
+ export declare function generateDashboardHtml(): Promise<string>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Dashboard assembler for logbook watch hub.
3
+ *
4
+ * The "logbook Hub" is the web-based UI for `logbook watch` instances. It
5
+ * composes the full HTML page from separate style, script, and HTML modules.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { dashboardStyles } from './dashboard-styles.js';
10
+ import { dashboardScript } from './dashboard-script.js';
11
+ import { dashboardHtml } from './dashboard-html.js';
12
+ import { getTemplatesDir } from '../lib/migrations.js';
13
+ import { mdToHtml } from '../lib/build-helpers.js';
14
+ /**
15
+ * Read the about-watch.md template and return raw markdown content.
16
+ * Falls back to a default message if the file is missing.
17
+ */
18
+ function readAboutMarkdown() {
19
+ try {
20
+ const templatePath = join(getTemplatesDir(), 'about-watch.md');
21
+ return readFileSync(templatePath, 'utf8');
22
+ }
23
+ catch {
24
+ return 'No about-watch.md template found.';
25
+ }
26
+ }
27
+ /**
28
+ * Generate the full dashboard HTML document.
29
+ *
30
+ * @returns Complete HTML string for the dashboard page.
31
+ */
32
+ export async function generateDashboardHtml() {
33
+ const aboutMd = readAboutMarkdown();
34
+ const aboutHtml = await mdToHtml(aboutMd);
35
+ return `<!DOCTYPE html>
36
+ <html lang="en">
37
+ <head>
38
+ <meta charset="utf-8">
39
+ <meta name="viewport" content="width=device-width, initial-scale=1">
40
+ <title>Logbook Hub</title>
41
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='18' fill='%232563eb'/%3E%3Ctext x='50' y='50' fill='%23fff' font-family='Arial,Helvetica,sans-serif' font-size='55' font-weight='700' text-anchor='middle' dominant-baseline='central'%3EHUB%3C/text%3E%3C/svg%3E">
42
+ ${dashboardStyles()}
43
+ </head>
44
+ <body>
45
+ ${dashboardHtml(aboutHtml)}
46
+ ${dashboardScript()}
47
+ </body>
48
+ </html>`;
49
+ }
50
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/watch/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC/D,OAAO,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mCAAmC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE1C,OAAO;;;;;;;IAOL,eAAe,EAAE;;;IAGjB,aAAa,CAAC,SAAS,CAAC;IACxB,eAAe,EAAE;;QAEb,CAAC;AACT,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared git utility helpers for logbook watch collectors.
3
+ *
4
+ * Provides a single `git()` runner and common git queries used by multiple
5
+ * collectors, eliminating duplication across collector files.
6
+ */
7
+ /**
8
+ * Parse `git status --porcelain` into staged and unstaged file counts.
9
+ */
10
+ export declare function parseGitStatus(cwd: string): {
11
+ staged: number;
12
+ unstaged: number;
13
+ };
14
+ /**
15
+ * Count commits ahead of the remote tracking branch.
16
+ */
17
+ export declare function commitsAheadOfRemote(cwd: string): number;
18
+ /**
19
+ * Count commits on the current branch vs the default branch.
20
+ */
21
+ export declare function commitsVsDefault(cwd: string, defaultBranch: string): number;
22
+ /**
23
+ * Extract a ticket ID from a branch name.
24
+ *
25
+ * Prefers the configured Jira prefix (e.g. "LB-34"), then falls back to a
26
+ * bare numeric GitLab work item segment when a gitlab prefix is configured
27
+ * (e.g. "feat/36-content-api" -> "#36").
28
+ */
29
+ export declare function extractTicketFromBranch(branch: string | undefined, jiraPrefix: string | undefined, gitlabPrefix?: string): string | undefined;
30
+ /**
31
+ * Resolve the active ticket ID. Checks lockfile first, then falls back to
32
+ * extracting it from the git branch name (Jira prefix or GitLab work item).
33
+ */
34
+ export declare function resolveActiveTicketId(cwd: string, branch: string | undefined, jiraPrefix: string | undefined, gitlabPrefix?: string): string | undefined;
35
+ /** Read the full active ticket slug from the lockfile (folder name). */
36
+ export declare function readActiveTicketSlug(cwd: string): string | undefined;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Shared git utility helpers for logbook watch collectors.
3
+ *
4
+ * Provides a single `git()` runner and common git queries used by multiple
5
+ * collectors, eliminating duplication across collector files.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ /**
11
+ * Run a git command and return trimmed stdout, or undefined on failure.
12
+ *
13
+ * @param cwd - Working directory.
14
+ * @param args - Git arguments (e.g., 'status --porcelain').
15
+ * @returns Trimmed output string, or undefined if the command fails or returns empty.
16
+ */
17
+ function git(cwd, args) {
18
+ try {
19
+ return (execSync(`git ${args}`, {
20
+ encoding: 'utf8',
21
+ cwd,
22
+ stdio: ['ignore', 'pipe', 'ignore'],
23
+ }).trim() || undefined);
24
+ }
25
+ catch {
26
+ return undefined;
27
+ }
28
+ }
29
+ /**
30
+ * Parse `git status --porcelain` into staged and unstaged file counts.
31
+ */
32
+ export function parseGitStatus(cwd) {
33
+ const output = git(cwd, 'status --porcelain') ?? '';
34
+ let staged = 0;
35
+ let unstaged = 0;
36
+ for (const line of output.split('\n').filter(Boolean)) {
37
+ const idx = line[0];
38
+ const wt = line[1];
39
+ if (idx && idx !== ' ' && idx !== '?')
40
+ staged++;
41
+ if (wt && wt !== ' ' && wt !== '?')
42
+ unstaged++;
43
+ if (idx === '?' && wt === '?')
44
+ unstaged++;
45
+ }
46
+ return { staged, unstaged };
47
+ }
48
+ /**
49
+ * Count commits ahead of the remote tracking branch.
50
+ */
51
+ export function commitsAheadOfRemote(cwd) {
52
+ const out = git(cwd, 'rev-list --count @{upstream}..HEAD');
53
+ return out ? parseInt(out, 10) : 0;
54
+ }
55
+ /**
56
+ * Count commits on the current branch vs the default branch.
57
+ */
58
+ export function commitsVsDefault(cwd, defaultBranch) {
59
+ const out = git(cwd, `rev-list --count ${defaultBranch}..HEAD`);
60
+ return out ? parseInt(out, 10) : 0;
61
+ }
62
+ /** Read the active ticket slug from the lockfile, if it exists. */
63
+ function readLockfileSlug(cwd) {
64
+ const lockPath = join(cwd, '.logbook-active');
65
+ if (!existsSync(lockPath))
66
+ return undefined;
67
+ try {
68
+ const data = JSON.parse(readFileSync(lockPath, 'utf8'));
69
+ return data.slug || undefined;
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ /** Extract a ticket ID (e.g. "IBB-558") from the first two dash-separated segments of a slug. */
76
+ function ticketIdFromSlug(slug) {
77
+ const parts = slug.split('-');
78
+ return parts.length >= 2 ? `${parts[0]}-${parts[1]}` : slug;
79
+ }
80
+ /**
81
+ * Extract a ticket ID from a branch name.
82
+ *
83
+ * Prefers the configured Jira prefix (e.g. "LB-34"), then falls back to a
84
+ * bare numeric GitLab work item segment when a gitlab prefix is configured
85
+ * (e.g. "feat/36-content-api" -> "#36").
86
+ */
87
+ export function extractTicketFromBranch(branch, jiraPrefix, gitlabPrefix) {
88
+ if (!branch)
89
+ return undefined;
90
+ const regex = jiraPrefix ? new RegExp(`\\b${jiraPrefix}-\\d+\\b`, 'i') : /\b[A-Z]+-\d+\b/;
91
+ const jira = branch.match(regex)?.[0]?.toUpperCase();
92
+ if (jira)
93
+ return jira;
94
+ // GitLab work items appear as a bare numeric branch segment after a slash or
95
+ // dash, e.g. "feat/36-content-api-garbage-endpoints" -> "#36".
96
+ if (gitlabPrefix) {
97
+ const gl = branch.match(/(?:^|[\/\\_#-])(\d+)(?:-|$)/);
98
+ if (gl)
99
+ return `${gitlabPrefix}${gl[1]}`;
100
+ }
101
+ return undefined;
102
+ }
103
+ /**
104
+ * Resolve the active ticket ID. Checks lockfile first, then falls back to
105
+ * extracting it from the git branch name (Jira prefix or GitLab work item).
106
+ */
107
+ export function resolveActiveTicketId(cwd, branch, jiraPrefix, gitlabPrefix) {
108
+ const slug = readLockfileSlug(cwd);
109
+ if (slug)
110
+ return ticketIdFromSlug(slug);
111
+ return extractTicketFromBranch(branch, jiraPrefix, gitlabPrefix);
112
+ }
113
+ /** Read the full active ticket slug from the lockfile (folder name). */
114
+ export function readActiveTicketSlug(cwd) {
115
+ return readLockfileSlug(cwd);
116
+ }
117
+ //# sourceMappingURL=git-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-utils.js","sourceRoot":"","sources":["../../src/watch/git-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Hub shared state and utilities for logbook watch.
3
+ *
4
+ * Contains the in-memory stores for projects, events, Jira issues, and GitLab
5
+ * MRs, plus HTTP helper functions used by the route handler.
6
+ */
7
+ import type { IncomingMessage, ServerResponse } from 'node:http';
8
+ import type { ActivityEvent, GitLabMr, GitLabWorkItem, JiraIssue, ProjectStatus } from './types.js';
9
+ /** Connected SSE clients. */
10
+ export declare const sseClients: Set<ServerResponse>;
11
+ /** Current state of all registered projects. */
12
+ export declare const projectStates: Map<string, ProjectStatus>;
13
+ /** Activity timeline per project (keyed by projectPath). Max 50 events per project. */
14
+ export declare const projectEvents: Map<string, ActivityEvent[]>;
15
+ /** Jira assigned issues, deduplicated by key+jiraBaseUrl. */
16
+ export declare const jiraIssues: Map<string, JiraIssue>;
17
+ /** GitLab open MRs, deduplicated by projectUrl+iid. */
18
+ export declare const gitlabMrs: Map<string, GitLabMr>;
19
+ /** GitLab open work items, deduplicated by projectUrl+iid. */
20
+ export declare const gitlabWorkItems: Map<string, GitLabWorkItem>;
21
+ /** Maximum number of events to keep per project. */
22
+ export declare const MAX_EVENTS_PER_PROJECT = 50;
23
+ /**
24
+ * Broadcast an SSE event to all connected clients.
25
+ *
26
+ * @param data - The data object to send as JSON.
27
+ */
28
+ export declare function broadcast(data: unknown): void;
29
+ /**
30
+ * Read the full request body as a string.
31
+ *
32
+ * @param req - The incoming HTTP request.
33
+ * @returns The request body string.
34
+ */
35
+ export declare function readBody(req: IncomingMessage): Promise<string>;
36
+ /**
37
+ * Send a JSON response.
38
+ */
39
+ export declare function jsonResponse(res: ServerResponse, status: number, data: unknown): void;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Hub shared state and utilities for logbook watch.
3
+ *
4
+ * Contains the in-memory stores for projects, events, Jira issues, and GitLab
5
+ * MRs, plus HTTP helper functions used by the route handler.
6
+ */
7
+ /** Connected SSE clients. */
8
+ export const sseClients = new Set();
9
+ /** Current state of all registered projects. */
10
+ export const projectStates = new Map();
11
+ /** Activity timeline per project (keyed by projectPath). Max 50 events per project. */
12
+ export const projectEvents = new Map();
13
+ /** Jira assigned issues, deduplicated by key+jiraBaseUrl. */
14
+ export const jiraIssues = new Map();
15
+ /** GitLab open MRs, deduplicated by projectUrl+iid. */
16
+ export const gitlabMrs = new Map();
17
+ /** GitLab open work items, deduplicated by projectUrl+iid. */
18
+ export const gitlabWorkItems = new Map();
19
+ /** Maximum number of events to keep per project. */
20
+ export const MAX_EVENTS_PER_PROJECT = 50;
21
+ /**
22
+ * Broadcast an SSE event to all connected clients.
23
+ *
24
+ * @param data - The data object to send as JSON.
25
+ */
26
+ export function broadcast(data) {
27
+ const payload = `data: ${JSON.stringify(data)}\n\n`;
28
+ for (const client of sseClients) {
29
+ client.write(payload);
30
+ }
31
+ }
32
+ /**
33
+ * Read the full request body as a string.
34
+ *
35
+ * @param req - The incoming HTTP request.
36
+ * @returns The request body string.
37
+ */
38
+ export function readBody(req) {
39
+ return new Promise((resolve, reject) => {
40
+ const chunks = [];
41
+ req.on('data', (chunk) => chunks.push(chunk));
42
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
43
+ req.on('error', reject);
44
+ });
45
+ }
46
+ /**
47
+ * Send a JSON response.
48
+ */
49
+ export function jsonResponse(res, status, data) {
50
+ const body = JSON.stringify(data);
51
+ res.writeHead(status, {
52
+ 'Content-Type': 'application/json',
53
+ 'Content-Length': Buffer.byteLength(body),
54
+ });
55
+ res.end(body);
56
+ }
57
+ //# sourceMappingURL=hub-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-state.js","sourceRoot":"","sources":["../../src/watch/hub-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,6BAA6B;AAC7B,MAAM,CAAC,MAAM,UAAU,GAAwB,IAAI,GAAG,EAAE,CAAC;AAEzD,gDAAgD;AAChD,MAAM,CAAC,MAAM,aAAa,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEnE,uFAAuF;AACvF,MAAM,CAAC,MAAM,aAAa,GAAiC,IAAI,GAAG,EAAE,CAAC;AAErE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,UAAU,GAA2B,IAAI,GAAG,EAAE,CAAC;AAE5D,uDAAuD;AACvD,MAAM,CAAC,MAAM,SAAS,GAA0B,IAAI,GAAG,EAAE,CAAC;AAE1D,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAgC,IAAI,GAAG,EAAE,CAAC;AAEtE,oDAAoD;AACpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,MAAM,OAAO,GAAG,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;IACpD,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAoB;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACrE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;KAC1C,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Hub server — serves the dashboard UI and bridges watchers ↔ SSE. */
2
+ export declare function startHub(port: number): Promise<string>;