@runcore-sh/runcore 0.4.0 → 0.5.1

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 (351) hide show
  1. package/dictionary.json +2 -2
  2. package/dist/activity/log.js +2 -2
  3. package/dist/activity/log.js.map +1 -1
  4. package/dist/agents/governed-spawn.d.ts.map +1 -1
  5. package/dist/cli.js +101 -11
  6. package/dist/cli.js.map +1 -1
  7. package/dist/extensions/cache.d.ts +57 -0
  8. package/dist/extensions/cache.d.ts.map +1 -0
  9. package/dist/extensions/cache.js +173 -0
  10. package/dist/extensions/cache.js.map +1 -0
  11. package/dist/extensions/client.d.ts +55 -0
  12. package/dist/extensions/client.d.ts.map +1 -0
  13. package/dist/extensions/client.js +120 -0
  14. package/dist/extensions/client.js.map +1 -0
  15. package/dist/extensions/index.d.ts +13 -0
  16. package/dist/extensions/index.d.ts.map +1 -0
  17. package/dist/extensions/index.js +12 -0
  18. package/dist/extensions/index.js.map +1 -0
  19. package/dist/extensions/loader.d.ts +50 -0
  20. package/dist/extensions/loader.d.ts.map +1 -0
  21. package/dist/extensions/loader.js +166 -0
  22. package/dist/extensions/loader.js.map +1 -0
  23. package/dist/extensions/manifest.d.ts +38 -0
  24. package/dist/extensions/manifest.d.ts.map +1 -0
  25. package/dist/extensions/manifest.js +17 -0
  26. package/dist/extensions/manifest.js.map +1 -0
  27. package/dist/extensions/stubs.d.ts +27 -0
  28. package/dist/extensions/stubs.d.ts.map +1 -0
  29. package/dist/extensions/stubs.js +45 -0
  30. package/dist/extensions/stubs.js.map +1 -0
  31. package/dist/lib/audit.js +2 -2
  32. package/dist/lib/audit.js.map +1 -1
  33. package/dist/lib/brain-migrate.d.ts +21 -0
  34. package/dist/lib/brain-migrate.d.ts.map +1 -0
  35. package/dist/lib/brain-migrate.js +137 -0
  36. package/dist/lib/brain-migrate.js.map +1 -0
  37. package/dist/lib/paths.d.ts +27 -0
  38. package/dist/lib/paths.d.ts.map +1 -1
  39. package/dist/lib/paths.js +65 -0
  40. package/dist/lib/paths.js.map +1 -1
  41. package/dist/llm/call-log.d.ts +40 -0
  42. package/dist/llm/call-log.d.ts.map +1 -0
  43. package/dist/llm/call-log.js +35 -0
  44. package/dist/llm/call-log.js.map +1 -0
  45. package/dist/llm/complete.d.ts +6 -0
  46. package/dist/llm/complete.d.ts.map +1 -1
  47. package/dist/llm/complete.js +27 -0
  48. package/dist/llm/complete.js.map +1 -1
  49. package/dist/mcp-server.js +118 -2
  50. package/dist/mcp-server.js.map +1 -1
  51. package/dist/memory/file-backed.d.ts +4 -0
  52. package/dist/memory/file-backed.d.ts.map +1 -1
  53. package/dist/memory/file-backed.js +4 -0
  54. package/dist/memory/file-backed.js.map +1 -1
  55. package/dist/memory/vector-index.d.ts +4 -12
  56. package/dist/memory/vector-index.d.ts.map +1 -1
  57. package/dist/memory/vector-index.js +11 -93
  58. package/dist/memory/vector-index.js.map +1 -1
  59. package/dist/search/brain-docs.d.ts +17 -7
  60. package/dist/search/brain-docs.d.ts.map +1 -1
  61. package/dist/search/brain-docs.js +170 -52
  62. package/dist/search/brain-docs.js.map +1 -1
  63. package/dist/search/brain-rag.d.ts +45 -0
  64. package/dist/search/brain-rag.d.ts.map +1 -0
  65. package/dist/search/brain-rag.js +275 -0
  66. package/dist/search/brain-rag.js.map +1 -0
  67. package/dist/search/chunker.d.ts +24 -0
  68. package/dist/search/chunker.d.ts.map +1 -0
  69. package/dist/search/chunker.js +95 -0
  70. package/dist/search/chunker.js.map +1 -0
  71. package/dist/search/embedder.d.ts +16 -0
  72. package/dist/search/embedder.d.ts.map +1 -0
  73. package/dist/search/embedder.js +108 -0
  74. package/dist/search/embedder.js.map +1 -0
  75. package/dist/search/file-watcher.d.ts +11 -0
  76. package/dist/search/file-watcher.d.ts.map +1 -0
  77. package/dist/search/file-watcher.js +86 -0
  78. package/dist/search/file-watcher.js.map +1 -0
  79. package/dist/server.d.ts.map +1 -1
  80. package/dist/server.js +814 -472
  81. package/dist/server.js.map +1 -1
  82. package/dist/sessions/store.d.ts +9 -0
  83. package/dist/sessions/store.d.ts.map +1 -1
  84. package/dist/sessions/store.js.map +1 -1
  85. package/dist/settings.d.ts +26 -0
  86. package/dist/settings.d.ts.map +1 -1
  87. package/dist/settings.js +78 -2
  88. package/dist/settings.js.map +1 -1
  89. package/dist/tracing/init.d.ts +1 -1
  90. package/dist/tracing/init.d.ts.map +1 -1
  91. package/dist/utils/logger.js +2 -2
  92. package/dist/utils/logger.js.map +1 -1
  93. package/module-tiers.json +164 -0
  94. package/package.json +9 -13
  95. package/public/avatar/cache/1184385ec5522b57.mp4 +0 -0
  96. package/public/avatar/cache/1f15f6a1ebd7e439.mp4 +0 -0
  97. package/public/avatar/cache/2c7e47ff0bdeb8d1.mp4 +0 -0
  98. package/public/avatar/cache/5f308566f7abb8f2.mp4 +0 -0
  99. package/public/avatar/cache/62f9cfba848d724e.mp4 +0 -0
  100. package/public/avatar/cache/6d64e657e6bf2aab.mp4 +0 -0
  101. package/public/avatar/cache/763ad0349e0b6f26.mp4 +0 -0
  102. package/public/avatar/cache/81a516cfd461b2b9.mp4 +0 -0
  103. package/public/avatar/cache/9366de15fd6910ca.mp4 +0 -0
  104. package/public/avatar/cache/ade41a846b283895.mp4 +0 -0
  105. package/public/avatar/cache/b6066e5c65383eec.mp4 +0 -0
  106. package/public/avatar/cache/edadb75d37891fc7.mp4 +0 -0
  107. package/public/avatar/cache/f0ae159640621dd9.mp4 +0 -0
  108. package/public/avatar/cache/fc2e5419adf29d96.mp4 +0 -0
  109. package/public/index.html +379 -59
  110. package/dist/agents/autonomous.js +0 -749
  111. package/dist/agents/autonomous.js.map +0 -1
  112. package/dist/agents/commit.js +0 -113
  113. package/dist/agents/commit.js.map +0 -1
  114. package/dist/agents/continue.js +0 -158
  115. package/dist/agents/continue.js.map +0 -1
  116. package/dist/agents/cooldown.js +0 -397
  117. package/dist/agents/cooldown.js.map +0 -1
  118. package/dist/agents/dedup-guard.js +0 -131
  119. package/dist/agents/dedup-guard.js.map +0 -1
  120. package/dist/agents/feed.js +0 -176
  121. package/dist/agents/feed.js.map +0 -1
  122. package/dist/agents/governance.js +0 -292
  123. package/dist/agents/governance.js.map +0 -1
  124. package/dist/agents/governed-spawn.js +0 -192
  125. package/dist/agents/governed-spawn.js.map +0 -1
  126. package/dist/agents/heartbeat.js +0 -324
  127. package/dist/agents/heartbeat.js.map +0 -1
  128. package/dist/agents/instance-manager.js +0 -850
  129. package/dist/agents/instance-manager.js.map +0 -1
  130. package/dist/agents/issue-reporter.js +0 -123
  131. package/dist/agents/issue-reporter.js.map +0 -1
  132. package/dist/agents/issues.js +0 -141
  133. package/dist/agents/issues.js.map +0 -1
  134. package/dist/agents/locks.js +0 -234
  135. package/dist/agents/locks.js.map +0 -1
  136. package/dist/agents/memory.js +0 -93
  137. package/dist/agents/memory.js.map +0 -1
  138. package/dist/agents/monitor.js +0 -235
  139. package/dist/agents/monitor.js.map +0 -1
  140. package/dist/agents/orchestration.js +0 -715
  141. package/dist/agents/orchestration.js.map +0 -1
  142. package/dist/agents/recover.js +0 -166
  143. package/dist/agents/recover.js.map +0 -1
  144. package/dist/agents/reflection.js +0 -199
  145. package/dist/agents/reflection.js.map +0 -1
  146. package/dist/agents/runtime/bus.js +0 -174
  147. package/dist/agents/runtime/bus.js.map +0 -1
  148. package/dist/agents/runtime/config.js +0 -101
  149. package/dist/agents/runtime/config.js.map +0 -1
  150. package/dist/agents/runtime/driver.js +0 -214
  151. package/dist/agents/runtime/driver.js.map +0 -1
  152. package/dist/agents/runtime/errors.js +0 -40
  153. package/dist/agents/runtime/errors.js.map +0 -1
  154. package/dist/agents/runtime/index.js +0 -54
  155. package/dist/agents/runtime/index.js.map +0 -1
  156. package/dist/agents/runtime/lifecycle.js +0 -116
  157. package/dist/agents/runtime/lifecycle.js.map +0 -1
  158. package/dist/agents/runtime/manager.js +0 -948
  159. package/dist/agents/runtime/manager.js.map +0 -1
  160. package/dist/agents/runtime/registry.js +0 -195
  161. package/dist/agents/runtime/registry.js.map +0 -1
  162. package/dist/agents/runtime/resources.js +0 -146
  163. package/dist/agents/runtime/resources.js.map +0 -1
  164. package/dist/agents/runtime/types.js +0 -24
  165. package/dist/agents/runtime/types.js.map +0 -1
  166. package/dist/agents/spawn-policy.js +0 -202
  167. package/dist/agents/spawn-policy.js.map +0 -1
  168. package/dist/agents/spawn.js +0 -970
  169. package/dist/agents/spawn.js.map +0 -1
  170. package/dist/agents/triage.js +0 -81
  171. package/dist/agents/triage.js.map +0 -1
  172. package/dist/agents/workflow.js +0 -543
  173. package/dist/agents/workflow.js.map +0 -1
  174. package/dist/avatar/client.js +0 -172
  175. package/dist/avatar/client.js.map +0 -1
  176. package/dist/avatar/sidecar.js +0 -125
  177. package/dist/avatar/sidecar.js.map +0 -1
  178. package/dist/browser/sessions.js +0 -122
  179. package/dist/browser/sessions.js.map +0 -1
  180. package/dist/capabilities/definitions/browser.js +0 -242
  181. package/dist/capabilities/definitions/browser.js.map +0 -1
  182. package/dist/channels/whatsapp.js +0 -200
  183. package/dist/channels/whatsapp.js.map +0 -1
  184. package/dist/credentials/store.js +0 -189
  185. package/dist/credentials/store.js.map +0 -1
  186. package/dist/files/deep-index.js +0 -337
  187. package/dist/files/deep-index.js.map +0 -1
  188. package/dist/files/extract.js +0 -33
  189. package/dist/files/extract.js.map +0 -1
  190. package/dist/files/gdrive.js +0 -246
  191. package/dist/files/gdrive.js.map +0 -1
  192. package/dist/github/client.js +0 -408
  193. package/dist/github/client.js.map +0 -1
  194. package/dist/github/commit-analysis.js +0 -276
  195. package/dist/github/commit-analysis.js.map +0 -1
  196. package/dist/github/contributor-stats.js +0 -119
  197. package/dist/github/contributor-stats.js.map +0 -1
  198. package/dist/github/issue-sla.js +0 -220
  199. package/dist/github/issue-sla.js.map +0 -1
  200. package/dist/github/issue-triage.js +0 -286
  201. package/dist/github/issue-triage.js.map +0 -1
  202. package/dist/github/pr-readiness.js +0 -197
  203. package/dist/github/pr-readiness.js.map +0 -1
  204. package/dist/github/pr-review.js +0 -410
  205. package/dist/github/pr-review.js.map +0 -1
  206. package/dist/github/release-notes.js +0 -227
  207. package/dist/github/release-notes.js.map +0 -1
  208. package/dist/github/repo-health.js +0 -303
  209. package/dist/github/repo-health.js.map +0 -1
  210. package/dist/github/retry.js +0 -117
  211. package/dist/github/retry.js.map +0 -1
  212. package/dist/github/types.js +0 -8
  213. package/dist/github/types.js.map +0 -1
  214. package/dist/github/webhooks.js +0 -153
  215. package/dist/github/webhooks.js.map +0 -1
  216. package/dist/google/auth.js +0 -325
  217. package/dist/google/auth.js.map +0 -1
  218. package/dist/google/calendar-timer.js +0 -91
  219. package/dist/google/calendar-timer.js.map +0 -1
  220. package/dist/google/calendar.js +0 -270
  221. package/dist/google/calendar.js.map +0 -1
  222. package/dist/google/docs.js +0 -309
  223. package/dist/google/docs.js.map +0 -1
  224. package/dist/google/gmail-send.js +0 -219
  225. package/dist/google/gmail-send.js.map +0 -1
  226. package/dist/google/gmail-timer.js +0 -223
  227. package/dist/google/gmail-timer.js.map +0 -1
  228. package/dist/google/gmail.js +0 -470
  229. package/dist/google/gmail.js.map +0 -1
  230. package/dist/google/plugin.js +0 -169
  231. package/dist/google/plugin.js.map +0 -1
  232. package/dist/google/tasks-timer.js +0 -107
  233. package/dist/google/tasks-timer.js.map +0 -1
  234. package/dist/google/tasks.js +0 -331
  235. package/dist/google/tasks.js.map +0 -1
  236. package/dist/google/temporal.js +0 -176
  237. package/dist/google/temporal.js.map +0 -1
  238. package/dist/integrations/gate.js +0 -100
  239. package/dist/integrations/gate.js.map +0 -1
  240. package/dist/integrations/github.js +0 -331
  241. package/dist/integrations/github.js.map +0 -1
  242. package/dist/integrations/google-tasks.js +0 -432
  243. package/dist/integrations/google-tasks.js.map +0 -1
  244. package/dist/mdns.js +0 -110
  245. package/dist/mdns.js.map +0 -1
  246. package/dist/notifications/channel.js +0 -83
  247. package/dist/notifications/channel.js.map +0 -1
  248. package/dist/notifications/channels/adapter.js +0 -55
  249. package/dist/notifications/channels/adapter.js.map +0 -1
  250. package/dist/notifications/channels/index.js +0 -6
  251. package/dist/notifications/channels/index.js.map +0 -1
  252. package/dist/notifications/channels/log.js +0 -29
  253. package/dist/notifications/channels/log.js.map +0 -1
  254. package/dist/notifications/email.js +0 -72
  255. package/dist/notifications/email.js.map +0 -1
  256. package/dist/notifications/engine.js +0 -198
  257. package/dist/notifications/engine.js.map +0 -1
  258. package/dist/notifications/index.js +0 -24
  259. package/dist/notifications/index.js.map +0 -1
  260. package/dist/notifications/phone.js +0 -48
  261. package/dist/notifications/phone.js.map +0 -1
  262. package/dist/notifications/sms.js +0 -65
  263. package/dist/notifications/sms.js.map +0 -1
  264. package/dist/notifications/types.js +0 -14
  265. package/dist/notifications/types.js.map +0 -1
  266. package/dist/notifications/webhook.js +0 -65
  267. package/dist/notifications/webhook.js.map +0 -1
  268. package/dist/resend/inbox.js +0 -199
  269. package/dist/resend/inbox.js.map +0 -1
  270. package/dist/resend/webhooks.js +0 -244
  271. package/dist/resend/webhooks.js.map +0 -1
  272. package/dist/search/browse.js +0 -225
  273. package/dist/search/browse.js.map +0 -1
  274. package/dist/search/perplexity.js +0 -41
  275. package/dist/search/perplexity.js.map +0 -1
  276. package/dist/slack/channels.js +0 -277
  277. package/dist/slack/channels.js.map +0 -1
  278. package/dist/slack/client.js +0 -468
  279. package/dist/slack/client.js.map +0 -1
  280. package/dist/slack/retry.js +0 -100
  281. package/dist/slack/retry.js.map +0 -1
  282. package/dist/slack/types.js +0 -52
  283. package/dist/slack/types.js.map +0 -1
  284. package/dist/slack/webhooks.js +0 -285
  285. package/dist/slack/webhooks.js.map +0 -1
  286. package/dist/stt/client.js +0 -66
  287. package/dist/stt/client.js.map +0 -1
  288. package/dist/stt/sidecar.js +0 -115
  289. package/dist/stt/sidecar.js.map +0 -1
  290. package/dist/tracing/bridge.js +0 -70
  291. package/dist/tracing/bridge.js.map +0 -1
  292. package/dist/tracing/correlation.js +0 -49
  293. package/dist/tracing/correlation.js.map +0 -1
  294. package/dist/tracing/index.js +0 -18
  295. package/dist/tracing/index.js.map +0 -1
  296. package/dist/tracing/init.js +0 -81
  297. package/dist/tracing/init.js.map +0 -1
  298. package/dist/tracing/instrument.js +0 -145
  299. package/dist/tracing/instrument.js.map +0 -1
  300. package/dist/tracing/middleware.js +0 -69
  301. package/dist/tracing/middleware.js.map +0 -1
  302. package/dist/tracing/tracer.js +0 -327
  303. package/dist/tracing/tracer.js.map +0 -1
  304. package/dist/tts/client.js +0 -48
  305. package/dist/tts/client.js.map +0 -1
  306. package/dist/tts/sidecar.js +0 -148
  307. package/dist/tts/sidecar.js.map +0 -1
  308. package/dist/twilio/call.js +0 -79
  309. package/dist/twilio/call.js.map +0 -1
  310. package/dist/vault/matcher.js +0 -197
  311. package/dist/vault/matcher.js.map +0 -1
  312. package/dist/vault/personal.js +0 -163
  313. package/dist/vault/personal.js.map +0 -1
  314. package/dist/vault/policy.js +0 -159
  315. package/dist/vault/policy.js.map +0 -1
  316. package/dist/vault/store.js +0 -122
  317. package/dist/vault/store.js.map +0 -1
  318. package/dist/vault/transfer.js +0 -188
  319. package/dist/vault/transfer.js.map +0 -1
  320. package/dist/volumes/index.js +0 -2
  321. package/dist/volumes/index.js.map +0 -1
  322. package/dist/volumes/manager.js +0 -462
  323. package/dist/volumes/manager.js.map +0 -1
  324. package/dist/volumes/types.js +0 -8
  325. package/dist/volumes/types.js.map +0 -1
  326. package/dist/webhooks/config.js +0 -214
  327. package/dist/webhooks/config.js.map +0 -1
  328. package/dist/webhooks/event-log.js +0 -132
  329. package/dist/webhooks/event-log.js.map +0 -1
  330. package/dist/webhooks/handler.js +0 -103
  331. package/dist/webhooks/handler.js.map +0 -1
  332. package/dist/webhooks/handlers.js +0 -231
  333. package/dist/webhooks/handlers.js.map +0 -1
  334. package/dist/webhooks/index.js +0 -33
  335. package/dist/webhooks/index.js.map +0 -1
  336. package/dist/webhooks/mount.js +0 -400
  337. package/dist/webhooks/mount.js.map +0 -1
  338. package/dist/webhooks/registry.js +0 -143
  339. package/dist/webhooks/registry.js.map +0 -1
  340. package/dist/webhooks/relay.js +0 -53
  341. package/dist/webhooks/relay.js.map +0 -1
  342. package/dist/webhooks/retry.js +0 -270
  343. package/dist/webhooks/retry.js.map +0 -1
  344. package/dist/webhooks/router.js +0 -290
  345. package/dist/webhooks/router.js.map +0 -1
  346. package/dist/webhooks/twilio.js +0 -129
  347. package/dist/webhooks/twilio.js.map +0 -1
  348. package/dist/webhooks/types.js +0 -8
  349. package/dist/webhooks/types.js.map +0 -1
  350. package/dist/webhooks/verify.js +0 -154
  351. package/dist/webhooks/verify.js.map +0 -1
@@ -1,276 +0,0 @@
1
- /**
2
- * Commit analysis — scan commits for patterns, quality metrics, and issues.
3
- *
4
- * Checks: conventional commit format, message quality, commit size,
5
- * co-authors, breaking changes, and common anti-patterns.
6
- */
7
- import { createLogger } from "../utils/logger.js";
8
- import { logActivity } from "../activity/log.js";
9
- import * as client from "./client.js";
10
- const log = createLogger("github.commit-analysis");
11
- // ── Conventional commit parsing ──────────────────────────────────────────────
12
- const CONVENTIONAL_PATTERN = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+?\))?(!)?:\s/;
13
- const PATTERN_MAP = {
14
- feat: "feature",
15
- fix: "bugfix",
16
- docs: "docs",
17
- style: "style",
18
- refactor: "refactor",
19
- perf: "perf",
20
- test: "test",
21
- build: "chore",
22
- ci: "ci",
23
- chore: "chore",
24
- revert: "revert",
25
- };
26
- // ── Analysis helpers ─────────────────────────────────────────────────────────
27
- function detectPatterns(message) {
28
- const lower = message.toLowerCase();
29
- const firstLine = message.split("\n")[0];
30
- const patterns = [];
31
- // Check conventional commit format first
32
- const match = firstLine.match(CONVENTIONAL_PATTERN);
33
- if (match) {
34
- const mapped = PATTERN_MAP[match[1]];
35
- if (mapped)
36
- patterns.push(mapped);
37
- return patterns;
38
- }
39
- // Merge commit
40
- if (lower.startsWith("merge ")) {
41
- patterns.push("merge");
42
- return patterns;
43
- }
44
- // Heuristic detection
45
- if (/\bwip\b/i.test(firstLine))
46
- patterns.push("wip");
47
- if (/\b(fix|bug|patch|hotfix)\b/i.test(firstLine))
48
- patterns.push("bugfix");
49
- if (/\b(add|feat|feature|implement|new)\b/i.test(firstLine))
50
- patterns.push("feature");
51
- if (/\b(refactor|restructure|reorganize|clean\s?up)\b/i.test(firstLine))
52
- patterns.push("refactor");
53
- if (/\b(test|spec|coverage)\b/i.test(firstLine))
54
- patterns.push("test");
55
- if (/\b(doc|readme|changelog)\b/i.test(firstLine))
56
- patterns.push("docs");
57
- if (/\b(ci|pipeline|workflow|github.actions)\b/i.test(firstLine))
58
- patterns.push("ci");
59
- if (/\b(perf|optimize|speed|fast)\b/i.test(firstLine))
60
- patterns.push("perf");
61
- if (/\brevert\b/i.test(firstLine))
62
- patterns.push("revert");
63
- if (patterns.length === 0)
64
- patterns.push("chore");
65
- return patterns;
66
- }
67
- function assessMessageQuality(message) {
68
- const firstLine = message.split("\n")[0].trim();
69
- // Poor: very short, no context
70
- if (firstLine.length < 10)
71
- return "poor";
72
- // Poor: generic messages
73
- if (/^(fix|update|change|wip|stuff|test|asdf|tmp)$/i.test(firstLine))
74
- return "poor";
75
- // Fair: decent length but no conventional format or structure
76
- if (firstLine.length < 30 && !CONVENTIONAL_PATTERN.test(firstLine))
77
- return "fair";
78
- // Good: conventional format or descriptive
79
- if (CONVENTIONAL_PATTERN.test(firstLine))
80
- return "good";
81
- if (firstLine.length >= 30)
82
- return "good";
83
- return "fair";
84
- }
85
- function categorizeSizeFromStats(additions, deletions) {
86
- const total = additions + deletions;
87
- if (total <= 10)
88
- return "tiny";
89
- if (total <= 50)
90
- return "small";
91
- if (total <= 200)
92
- return "medium";
93
- if (total <= 500)
94
- return "large";
95
- return "huge";
96
- }
97
- function detectIssues(message, additions, deletions) {
98
- const issues = [];
99
- const firstLine = message.split("\n")[0].trim();
100
- // Message quality issues
101
- if (firstLine.length < 5) {
102
- issues.push({ severity: "warning", message: "Commit message is too short to be meaningful." });
103
- }
104
- if (firstLine.length > 72) {
105
- issues.push({ severity: "info", message: "First line exceeds 72 characters (conventional limit)." });
106
- }
107
- if (/^[a-z]/.test(firstLine) && !CONVENTIONAL_PATTERN.test(firstLine)) {
108
- issues.push({ severity: "info", message: "First line starts with lowercase (not conventional format)." });
109
- }
110
- if (firstLine.endsWith(".")) {
111
- issues.push({ severity: "info", message: "Subject line ends with a period (convention says don't)." });
112
- }
113
- // Size issues
114
- const total = additions + deletions;
115
- if (total > 1000) {
116
- issues.push({ severity: "warning", message: `Very large commit (${total} lines). Consider smaller, atomic commits.` });
117
- }
118
- // WIP detection
119
- if (/\bwip\b/i.test(firstLine)) {
120
- issues.push({ severity: "warning", message: "Commit marked as WIP — should be squashed before merge." });
121
- }
122
- // Fixup detection
123
- if (/^(fixup|squash)!\s/.test(firstLine)) {
124
- issues.push({ severity: "info", message: "Fixup/squash commit detected — ensure it gets rebased." });
125
- }
126
- return issues;
127
- }
128
- // ── Public API ───────────────────────────────────────────────────────────────
129
- /**
130
- * Analyze a single commit by SHA.
131
- */
132
- export async function analyzeCommit(owner, repo, sha) {
133
- log.info(`Analyzing commit ${owner}/${repo}@${sha.slice(0, 8)}`);
134
- const commit = await client.getCommit(owner, repo, sha);
135
- if (!commit) {
136
- log.warn(`Failed to fetch commit ${sha}`);
137
- return null;
138
- }
139
- return analyzeCommitData(owner, repo, commit.sha, commit.message, commit.stats?.additions ?? 0, commit.stats?.deletions ?? 0);
140
- }
141
- /**
142
- * Analyze a commit from raw data (avoids API call when data is already available).
143
- */
144
- export function analyzeCommitData(owner, repo, sha, message, additions, deletions) {
145
- const patterns = detectPatterns(message);
146
- const messageQuality = assessMessageQuality(message);
147
- const sizeCategory = categorizeSizeFromStats(additions, deletions);
148
- const isConventional = CONVENTIONAL_PATTERN.test(message.split("\n")[0]);
149
- const hasCoAuthors = /co-authored-by:/i.test(message);
150
- const hasBreakingChange = /BREAKING.CHANGE/i.test(message) || /^.+!:/.test(message.split("\n")[0]);
151
- const quality = {
152
- score: computeQualityScore(messageQuality, isConventional, sizeCategory),
153
- messageQuality,
154
- hasCoAuthors,
155
- hasBreakingChange,
156
- isConventional,
157
- sizeCategory,
158
- };
159
- const issues = detectIssues(message, additions, deletions);
160
- return {
161
- sha,
162
- repo: `${owner}/${repo}`,
163
- quality,
164
- patterns,
165
- issues,
166
- analyzedAt: new Date().toISOString(),
167
- };
168
- }
169
- /**
170
- * Analyze recent commits in a repository.
171
- */
172
- export async function analyzeRecentCommits(owner, repo, opts) {
173
- log.info(`Analyzing recent commits for ${owner}/${repo}`);
174
- const commits = await client.listCommits(owner, repo, {
175
- per_page: opts?.count ?? 20,
176
- since: opts?.since,
177
- });
178
- if (!commits)
179
- return [];
180
- const results = [];
181
- for (const c of commits) {
182
- results.push(analyzeCommitData(owner, repo, c.sha, c.commit.message, 0, // List endpoint doesn't include stats
183
- 0));
184
- }
185
- const avgScore = results.length > 0
186
- ? Math.round(results.reduce((sum, r) => sum + r.quality.score, 0) / results.length)
187
- : 0;
188
- logActivity({
189
- source: "board",
190
- summary: `Commit analysis: ${results.length} commits in ${owner}/${repo}, avg quality ${avgScore}/100`,
191
- });
192
- return results;
193
- }
194
- // ── Helpers ──────────────────────────────────────────────────────────────────
195
- /**
196
- * Compute quality trend by comparing recent commits against older commits.
197
- * Fetches commits from the last 30 days and splits them into two halves.
198
- */
199
- export async function getQualityTrend(owner, repo, opts) {
200
- const days = opts?.days ?? 30;
201
- const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
202
- const commits = await client.listCommits(owner, repo, { since, per_page: 100 });
203
- if (!commits || commits.length === 0)
204
- return null;
205
- const analyses = commits.map((c) => analyzeCommitData(owner, repo, c.sha, c.commit.message, 0, 0));
206
- const midpoint = Math.floor(analyses.length / 2);
207
- const recent = analyses.slice(0, midpoint);
208
- const older = analyses.slice(midpoint);
209
- const avgScore = (items) => items.length === 0 ? 0 : Math.round(items.reduce((s, a) => s + a.quality.score, 0) / items.length);
210
- const recentAvg = avgScore(recent);
211
- const olderAvg = avgScore(older);
212
- const conventionalCount = analyses.filter((a) => a.quality.isConventional).length;
213
- const conventionalRate = Math.round((conventionalCount / analyses.length) * 100) / 100;
214
- // Author breakdown
215
- const authorMap = new Map();
216
- for (let i = 0; i < commits.length; i++) {
217
- const authorName = commits[i].commit.author?.name ?? "unknown";
218
- const entry = authorMap.get(authorName) ?? { scores: [], conventional: 0 };
219
- entry.scores.push(analyses[i].quality.score);
220
- if (analyses[i].quality.isConventional)
221
- entry.conventional++;
222
- authorMap.set(authorName, entry);
223
- }
224
- const authorBreakdown = [...authorMap.entries()]
225
- .map(([author, data]) => ({
226
- author,
227
- commitCount: data.scores.length,
228
- avgScore: Math.round(data.scores.reduce((s, v) => s + v, 0) / data.scores.length),
229
- conventionalRate: Math.round((data.conventional / data.scores.length) * 100) / 100,
230
- }))
231
- .sort((a, b) => b.commitCount - a.commitCount);
232
- let direction = "stable";
233
- if (recentAvg > olderAvg + 5)
234
- direction = "improving";
235
- else if (recentAvg < olderAvg - 5)
236
- direction = "declining";
237
- const trend = {
238
- repo: `${owner}/${repo}`,
239
- period: { from: since, to: new Date().toISOString() },
240
- recentAvgScore: recentAvg,
241
- olderAvgScore: olderAvg,
242
- direction,
243
- totalAnalyzed: analyses.length,
244
- conventionalCommitRate: conventionalRate,
245
- authorBreakdown,
246
- };
247
- logActivity({
248
- source: "board",
249
- summary: `Commit quality trend: ${owner}/${repo} → ${direction} (recent: ${recentAvg}, older: ${olderAvg})`,
250
- });
251
- return trend;
252
- }
253
- function computeQualityScore(messageQuality, isConventional, sizeCategory) {
254
- let score = 50;
255
- // Message quality: +20 good, +10 fair, -10 poor
256
- if (messageQuality === "good")
257
- score += 20;
258
- else if (messageQuality === "fair")
259
- score += 10;
260
- else
261
- score -= 10;
262
- // Conventional format: +15
263
- if (isConventional)
264
- score += 15;
265
- // Size: +15 tiny/small, +5 medium, -5 large, -15 huge
266
- if (sizeCategory === "tiny" || sizeCategory === "small")
267
- score += 15;
268
- else if (sizeCategory === "medium")
269
- score += 5;
270
- else if (sizeCategory === "large")
271
- score -= 5;
272
- else
273
- score -= 15;
274
- return Math.max(0, Math.min(100, score));
275
- }
276
- //# sourceMappingURL=commit-analysis.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commit-analysis.js","sourceRoot":"","sources":["../../src/github/commit-analysis.ts"],"names":[],"mappings":"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"}
@@ -1,119 +0,0 @@
1
- /**
2
- * Contributor stats — compute activity metrics for repository contributors.
3
- *
4
- * Tracks: commits per author, PRs opened/merged, reviews given,
5
- * lines added/removed.
6
- */
7
- import { createLogger } from "../utils/logger.js";
8
- import { logActivity } from "../activity/log.js";
9
- import * as client from "./client.js";
10
- const log = createLogger("github.contributor-stats");
11
- const MS_PER_DAY = 24 * 60 * 60 * 1000;
12
- // ── Public API ───────────────────────────────────────────────────────────────
13
- /**
14
- * Compute contributor stats for a repository over a given period.
15
- */
16
- export async function getContributorStats(owner, repo, opts) {
17
- const days = opts?.days ?? 30;
18
- const since = new Date(Date.now() - days * MS_PER_DAY).toISOString();
19
- log.info(`Computing contributor stats for ${owner}/${repo} (last ${days} days)`);
20
- // Fetch data in parallel
21
- const [commits, prs] = await Promise.all([
22
- client.listCommits(owner, repo, { since, per_page: 100 }),
23
- client.listPullRequests(owner, repo, { state: "all", per_page: 100 }),
24
- ]);
25
- if (!commits) {
26
- log.warn(`Failed to fetch data for ${owner}/${repo}`);
27
- return null;
28
- }
29
- // Filter PRs to the time period
30
- const periodPRs = (prs ?? []).filter((pr) => {
31
- const created = new Date(pr.created_at).getTime();
32
- return created >= new Date(since).getTime();
33
- });
34
- // Build contributor map keyed by login or email
35
- const profileMap = new Map();
36
- function getOrCreate(key) {
37
- let p = profileMap.get(key);
38
- if (!p) {
39
- p = {
40
- login: key,
41
- commits: 0,
42
- prsOpened: 0,
43
- prsMerged: 0,
44
- reviewsGiven: 0,
45
- linesAdded: 0,
46
- linesRemoved: 0,
47
- };
48
- profileMap.set(key, p);
49
- }
50
- return p;
51
- }
52
- // Aggregate commits
53
- for (const c of commits) {
54
- const authorKey = c.commit.author?.email ?? c.commit.author?.name ?? "unknown";
55
- const profile = getOrCreate(authorKey);
56
- profile.commits++;
57
- }
58
- // Aggregate PRs
59
- for (const pr of periodPRs) {
60
- const login = pr.user.login;
61
- const profile = getOrCreate(login);
62
- profile.prsOpened++;
63
- if (pr.merged) {
64
- profile.prsMerged++;
65
- profile.linesAdded += pr.additions;
66
- profile.linesRemoved += pr.deletions;
67
- }
68
- }
69
- // Fetch review counts for each PR (limited to first 20 PRs to avoid rate limits)
70
- const prsToCheck = periodPRs.slice(0, 20);
71
- for (const pr of prsToCheck) {
72
- const reviews = await client.getPRReviews(owner, repo, pr.number);
73
- if (!reviews)
74
- continue;
75
- for (const review of reviews) {
76
- if (review.state === "PENDING")
77
- continue;
78
- const profile = getOrCreate(review.user.login);
79
- profile.reviewsGiven++;
80
- }
81
- }
82
- const contributors = [...profileMap.values()]
83
- .sort((a, b) => b.commits - a.commits);
84
- const result = {
85
- repo: `${owner}/${repo}`,
86
- period: { from: since, to: new Date().toISOString() },
87
- contributors,
88
- generatedAt: new Date().toISOString(),
89
- };
90
- logActivity({
91
- source: "board",
92
- summary: `Contributor stats: ${owner}/${repo} — ${contributors.length} contributors, ${commits.length} commits`,
93
- });
94
- return result;
95
- }
96
- /**
97
- * Format contributor stats as a markdown table.
98
- */
99
- export function formatContributorStats(stats) {
100
- const lines = [];
101
- lines.push(`## Contributor Stats: ${stats.repo}`);
102
- lines.push("");
103
- lines.push(`*Period: ${new Date(stats.period.from).toLocaleDateString()} – ${new Date(stats.period.to).toLocaleDateString()}*`);
104
- lines.push("");
105
- if (stats.contributors.length === 0) {
106
- lines.push("No contributor activity in this period.");
107
- return lines.join("\n");
108
- }
109
- lines.push("| Contributor | Commits | PRs Opened | PRs Merged | Reviews | Lines +/- |");
110
- lines.push("|-------------|---------|------------|------------|---------|-----------|");
111
- for (const c of stats.contributors) {
112
- const linesChanged = c.linesAdded + c.linesRemoved > 0
113
- ? `+${c.linesAdded}/-${c.linesRemoved}`
114
- : "—";
115
- lines.push(`| ${c.login} | ${c.commits} | ${c.prsOpened} | ${c.prsMerged} | ${c.reviewsGiven} | ${linesChanged} |`);
116
- }
117
- return lines.join("\n");
118
- }
119
- //# sourceMappingURL=contributor-stats.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contributor-stats.js","sourceRoot":"","sources":["../../src/github/contributor-stats.ts"],"names":[],"mappings":"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"}
@@ -1,220 +0,0 @@
1
- /**
2
- * Issue SLA tracking — monitor response and resolution times against targets.
3
- *
4
- * Defines SLA targets by priority level (critical, high, medium, low).
5
- * Measures first-response time and resolution time.
6
- * Generates compliance reports with breach details.
7
- */
8
- import { createLogger } from "../utils/logger.js";
9
- import { logActivity } from "../activity/log.js";
10
- import * as client from "./client.js";
11
- import { triageFromIssue } from "./issue-triage.js";
12
- const log = createLogger("github.issue-sla");
13
- const MS_PER_HOUR = 60 * 60 * 1000;
14
- const MS_PER_DAY = 24 * MS_PER_HOUR;
15
- // ── Default SLA configuration ────────────────────────────────────────────────
16
- const DEFAULT_SLA = {
17
- targets: {
18
- critical: { responseHours: 4, resolutionHours: 24 },
19
- high: { responseHours: 8, resolutionHours: 72 },
20
- medium: { responseHours: 24, resolutionHours: 168 }, // 7 days
21
- low: { responseHours: 72, resolutionHours: 720 }, // 30 days
22
- },
23
- };
24
- let activeSLA = { ...DEFAULT_SLA };
25
- /**
26
- * Update the SLA configuration.
27
- */
28
- export function setSLAConfig(config) {
29
- activeSLA = {
30
- targets: {
31
- ...DEFAULT_SLA.targets,
32
- ...config.targets,
33
- },
34
- };
35
- }
36
- /** Get current SLA configuration. */
37
- export function getSLAConfig() {
38
- return activeSLA;
39
- }
40
- // ── SLA measurement ──────────────────────────────────────────────────────────
41
- function hoursBetween(a, b) {
42
- return Math.abs(new Date(b).getTime() - new Date(a).getTime()) / MS_PER_HOUR;
43
- }
44
- /**
45
- * Determine priority for an issue using the triage system.
46
- */
47
- function getIssuePriority(issue) {
48
- // Use the existing triage system to classify
49
- const triage = triageFromIssue("", "", issue);
50
- return triage.priority;
51
- }
52
- /**
53
- * Find first response time for an issue.
54
- * First response = first comment from someone other than the issue author.
55
- */
56
- async function getFirstResponseTime(owner, repo, issue) {
57
- const comments = await client.listIssueComments(owner, repo, issue.number, { per_page: 10 });
58
- if (!comments || comments.length === 0)
59
- return null;
60
- // Find first comment not from the issue author
61
- const firstResponse = comments.find((c) => c.user.login !== issue.user.login);
62
- if (!firstResponse)
63
- return null;
64
- return hoursBetween(issue.created_at, firstResponse.created_at);
65
- }
66
- /**
67
- * Get resolution time for a closed issue.
68
- */
69
- function getResolutionTime(issue) {
70
- if (issue.state !== "closed" || !issue.closed_at)
71
- return null;
72
- return hoursBetween(issue.created_at, issue.closed_at);
73
- }
74
- // ── Report generation ────────────────────────────────────────────────────────
75
- function emptyCompliance() {
76
- return { total: 0, withinSLA: 0, breached: 0, complianceRate: 100 };
77
- }
78
- /**
79
- * Generate an SLA compliance report for a repository.
80
- */
81
- export async function getSLAReport(owner, repo, opts) {
82
- const days = opts?.days ?? 30;
83
- const since = new Date(Date.now() - days * MS_PER_DAY).toISOString();
84
- log.info(`Generating SLA report for ${owner}/${repo} (last ${days} days)`);
85
- const issues = await client.listIssues(owner, repo, { state: "all", per_page: 100, since });
86
- if (!issues) {
87
- log.warn(`Failed to fetch issues for ${owner}/${repo}`);
88
- return null;
89
- }
90
- // Filter to actual issues (not PRs) created in the period
91
- const periodIssues = issues.filter((i) => !i.pull_request && new Date(i.created_at).getTime() >= new Date(since).getTime());
92
- const overall = emptyCompliance();
93
- const byPriority = {
94
- critical: emptyCompliance(),
95
- high: emptyCompliance(),
96
- medium: emptyCompliance(),
97
- low: emptyCompliance(),
98
- };
99
- const breaches = [];
100
- for (const issue of periodIssues) {
101
- const priority = getIssuePriority(issue);
102
- const target = activeSLA.targets[priority];
103
- overall.total++;
104
- byPriority[priority].total++;
105
- let isBreached = false;
106
- // Check resolution SLA for closed issues
107
- const resolutionHours = getResolutionTime(issue);
108
- if (resolutionHours !== null && resolutionHours > target.resolutionHours) {
109
- isBreached = true;
110
- breaches.push({
111
- issueNumber: issue.number,
112
- title: issue.title,
113
- priority,
114
- type: "resolution",
115
- targetHours: target.resolutionHours,
116
- actualHours: Math.round(resolutionHours * 10) / 10,
117
- url: issue.html_url,
118
- });
119
- }
120
- // Check response SLA — only if we can fetch first response
121
- const firstResponseHours = await getFirstResponseTime(owner, repo, issue);
122
- if (firstResponseHours !== null && firstResponseHours > target.responseHours) {
123
- isBreached = true;
124
- breaches.push({
125
- issueNumber: issue.number,
126
- title: issue.title,
127
- priority,
128
- type: "response",
129
- targetHours: target.responseHours,
130
- actualHours: Math.round(firstResponseHours * 10) / 10,
131
- url: issue.html_url,
132
- });
133
- }
134
- // For open issues past their resolution SLA, also flag them
135
- if (issue.state === "open") {
136
- const ageHours = hoursBetween(issue.created_at, new Date().toISOString());
137
- if (ageHours > target.resolutionHours) {
138
- isBreached = true;
139
- breaches.push({
140
- issueNumber: issue.number,
141
- title: issue.title,
142
- priority,
143
- type: "resolution",
144
- targetHours: target.resolutionHours,
145
- actualHours: Math.round(ageHours * 10) / 10,
146
- url: issue.html_url,
147
- });
148
- }
149
- }
150
- if (isBreached) {
151
- overall.breached++;
152
- byPriority[priority].breached++;
153
- }
154
- else {
155
- overall.withinSLA++;
156
- byPriority[priority].withinSLA++;
157
- }
158
- }
159
- // Compute compliance rates
160
- overall.complianceRate = overall.total > 0
161
- ? Math.round((overall.withinSLA / overall.total) * 100)
162
- : 100;
163
- for (const p of Object.keys(byPriority)) {
164
- const c = byPriority[p];
165
- c.complianceRate = c.total > 0
166
- ? Math.round((c.withinSLA / c.total) * 100)
167
- : 100;
168
- }
169
- // Sort breaches by priority (critical first)
170
- const priorityOrder = ["critical", "high", "medium", "low"];
171
- breaches.sort((a, b) => priorityOrder.indexOf(a.priority) - priorityOrder.indexOf(b.priority));
172
- const report = {
173
- repo: `${owner}/${repo}`,
174
- period: { from: since, to: new Date().toISOString() },
175
- generatedAt: new Date().toISOString(),
176
- overall,
177
- byPriority,
178
- breaches,
179
- };
180
- logActivity({
181
- source: "board",
182
- summary: `SLA report: ${owner}/${repo} — ${overall.complianceRate}% compliance (${overall.breached} breaches in ${overall.total} issues)`,
183
- });
184
- return report;
185
- }
186
- /**
187
- * Format an SLA report as markdown.
188
- */
189
- export function formatSLAReport(report) {
190
- const lines = [];
191
- lines.push(`## SLA Compliance Report: ${report.repo}`);
192
- lines.push("");
193
- lines.push(`*Period: ${new Date(report.period.from).toLocaleDateString()} – ${new Date(report.period.to).toLocaleDateString()}*`);
194
- lines.push("");
195
- lines.push(`**Overall Compliance: ${report.overall.complianceRate}%** (${report.overall.withinSLA}/${report.overall.total} within SLA)`);
196
- lines.push("");
197
- lines.push("### By Priority");
198
- lines.push("");
199
- lines.push("| Priority | Total | Within SLA | Breached | Rate |");
200
- lines.push("|----------|-------|------------|----------|------|");
201
- for (const p of ["critical", "high", "medium", "low"]) {
202
- const c = report.byPriority[p];
203
- lines.push(`| ${p} | ${c.total} | ${c.withinSLA} | ${c.breached} | ${c.complianceRate}% |`);
204
- }
205
- if (report.breaches.length > 0) {
206
- lines.push("");
207
- lines.push("### SLA Breaches");
208
- lines.push("");
209
- lines.push("| Issue | Priority | Type | Target | Actual |");
210
- lines.push("|-------|----------|------|--------|--------|");
211
- for (const b of report.breaches.slice(0, 20)) {
212
- lines.push(`| #${b.issueNumber} ${b.title.slice(0, 40)} | ${b.priority} | ${b.type} | ${b.targetHours}h | ${b.actualHours}h |`);
213
- }
214
- if (report.breaches.length > 20) {
215
- lines.push(`| *... and ${report.breaches.length - 20} more* | | | | |`);
216
- }
217
- }
218
- return lines.join("\n");
219
- }
220
- //# sourceMappingURL=issue-sla.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"issue-sla.js","sourceRoot":"","sources":["../../src/github/issue-sla.ts"],"names":[],"mappings":"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"}