@cat-factory/integrations 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +68 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +84 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/modules/datadog/DatadogClient.d.ts +54 -0
  7. package/dist/modules/datadog/DatadogClient.d.ts.map +1 -0
  8. package/dist/modules/datadog/DatadogClient.js +132 -0
  9. package/dist/modules/datadog/DatadogClient.js.map +1 -0
  10. package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts +30 -0
  11. package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts.map +1 -0
  12. package/dist/modules/datadog/DatadogReleaseHealthProvider.js +101 -0
  13. package/dist/modules/datadog/DatadogReleaseHealthProvider.js.map +1 -0
  14. package/dist/modules/datadog/datadog.logic.d.ts +37 -0
  15. package/dist/modules/datadog/datadog.logic.d.ts.map +1 -0
  16. package/dist/modules/datadog/datadog.logic.js +90 -0
  17. package/dist/modules/datadog/datadog.logic.js.map +1 -0
  18. package/dist/modules/documents/ConfluenceProvider.d.ts +29 -0
  19. package/dist/modules/documents/ConfluenceProvider.d.ts.map +1 -0
  20. package/dist/modules/documents/ConfluenceProvider.js +180 -0
  21. package/dist/modules/documents/ConfluenceProvider.js.map +1 -0
  22. package/dist/modules/documents/DocumentConnectionService.d.ts +30 -0
  23. package/dist/modules/documents/DocumentConnectionService.d.ts.map +1 -0
  24. package/dist/modules/documents/DocumentConnectionService.js +69 -0
  25. package/dist/modules/documents/DocumentConnectionService.js.map +1 -0
  26. package/dist/modules/documents/DocumentImportService.d.ts +34 -0
  27. package/dist/modules/documents/DocumentImportService.d.ts.map +1 -0
  28. package/dist/modules/documents/DocumentImportService.js +83 -0
  29. package/dist/modules/documents/DocumentImportService.js.map +1 -0
  30. package/dist/modules/documents/DocumentLinkService.d.ts +31 -0
  31. package/dist/modules/documents/DocumentLinkService.d.ts.map +1 -0
  32. package/dist/modules/documents/DocumentLinkService.js +75 -0
  33. package/dist/modules/documents/DocumentLinkService.js.map +1 -0
  34. package/dist/modules/documents/DocumentPlannerService.d.ts +23 -0
  35. package/dist/modules/documents/DocumentPlannerService.d.ts.map +1 -0
  36. package/dist/modules/documents/DocumentPlannerService.js +96 -0
  37. package/dist/modules/documents/DocumentPlannerService.js.map +1 -0
  38. package/dist/modules/documents/GitHubDocsProvider.d.ts +42 -0
  39. package/dist/modules/documents/GitHubDocsProvider.d.ts.map +1 -0
  40. package/dist/modules/documents/GitHubDocsProvider.js +86 -0
  41. package/dist/modules/documents/GitHubDocsProvider.js.map +1 -0
  42. package/dist/modules/documents/NotionProvider.d.ts +32 -0
  43. package/dist/modules/documents/NotionProvider.d.ts.map +1 -0
  44. package/dist/modules/documents/NotionProvider.js +221 -0
  45. package/dist/modules/documents/NotionProvider.js.map +1 -0
  46. package/dist/modules/documents/confluence.logic.d.ts +37 -0
  47. package/dist/modules/documents/confluence.logic.d.ts.map +1 -0
  48. package/dist/modules/documents/confluence.logic.js +133 -0
  49. package/dist/modules/documents/confluence.logic.js.map +1 -0
  50. package/dist/modules/documents/documents.logic.d.ts +22 -0
  51. package/dist/modules/documents/documents.logic.d.ts.map +1 -0
  52. package/dist/modules/documents/documents.logic.js +138 -0
  53. package/dist/modules/documents/documents.logic.js.map +1 -0
  54. package/dist/modules/documents/github-docs.logic.d.ts +52 -0
  55. package/dist/modules/documents/github-docs.logic.d.ts.map +1 -0
  56. package/dist/modules/documents/github-docs.logic.js +94 -0
  57. package/dist/modules/documents/github-docs.logic.js.map +1 -0
  58. package/dist/modules/documents/notion.logic.d.ts +31 -0
  59. package/dist/modules/documents/notion.logic.d.ts.map +1 -0
  60. package/dist/modules/documents/notion.logic.js +142 -0
  61. package/dist/modules/documents/notion.logic.js.map +1 -0
  62. package/dist/modules/email/EmailConnectionService.d.ts +34 -0
  63. package/dist/modules/email/EmailConnectionService.d.ts.map +1 -0
  64. package/dist/modules/email/EmailConnectionService.js +82 -0
  65. package/dist/modules/email/EmailConnectionService.js.map +1 -0
  66. package/dist/modules/email/adapters.d.ts +39 -0
  67. package/dist/modules/email/adapters.d.ts.map +1 -0
  68. package/dist/modules/email/adapters.js +79 -0
  69. package/dist/modules/email/adapters.js.map +1 -0
  70. package/dist/modules/environments/EnvironmentConnectionService.d.ts +42 -0
  71. package/dist/modules/environments/EnvironmentConnectionService.d.ts.map +1 -0
  72. package/dist/modules/environments/EnvironmentConnectionService.js +120 -0
  73. package/dist/modules/environments/EnvironmentConnectionService.js.map +1 -0
  74. package/dist/modules/environments/EnvironmentProvisioningService.d.ts +56 -0
  75. package/dist/modules/environments/EnvironmentProvisioningService.d.ts.map +1 -0
  76. package/dist/modules/environments/EnvironmentProvisioningService.js +153 -0
  77. package/dist/modules/environments/EnvironmentProvisioningService.js.map +1 -0
  78. package/dist/modules/environments/EnvironmentTeardownService.d.ts +24 -0
  79. package/dist/modules/environments/EnvironmentTeardownService.d.ts.map +1 -0
  80. package/dist/modules/environments/EnvironmentTeardownService.js +54 -0
  81. package/dist/modules/environments/EnvironmentTeardownService.js.map +1 -0
  82. package/dist/modules/environments/HttpEnvironmentProvider.d.ts +30 -0
  83. package/dist/modules/environments/HttpEnvironmentProvider.d.ts.map +1 -0
  84. package/dist/modules/environments/HttpEnvironmentProvider.js +316 -0
  85. package/dist/modules/environments/HttpEnvironmentProvider.js.map +1 -0
  86. package/dist/modules/environments/environments.logic.d.ts +50 -0
  87. package/dist/modules/environments/environments.logic.d.ts.map +1 -0
  88. package/dist/modules/environments/environments.logic.js +257 -0
  89. package/dist/modules/environments/environments.logic.js.map +1 -0
  90. package/dist/modules/github/GitHubInstallationService.d.ts +66 -0
  91. package/dist/modules/github/GitHubInstallationService.d.ts.map +1 -0
  92. package/dist/modules/github/GitHubInstallationService.js +143 -0
  93. package/dist/modules/github/GitHubInstallationService.js.map +1 -0
  94. package/dist/modules/github/GitHubService.d.ts +29 -0
  95. package/dist/modules/github/GitHubService.d.ts.map +1 -0
  96. package/dist/modules/github/GitHubService.js +61 -0
  97. package/dist/modules/github/GitHubService.js.map +1 -0
  98. package/dist/modules/github/GitHubSyncService.d.ts +97 -0
  99. package/dist/modules/github/GitHubSyncService.d.ts.map +1 -0
  100. package/dist/modules/github/GitHubSyncService.js +241 -0
  101. package/dist/modules/github/GitHubSyncService.js.map +1 -0
  102. package/dist/modules/github/RepoProvisioningService.d.ts +26 -0
  103. package/dist/modules/github/RepoProvisioningService.d.ts.map +1 -0
  104. package/dist/modules/github/RepoProvisioningService.js +36 -0
  105. package/dist/modules/github/RepoProvisioningService.js.map +1 -0
  106. package/dist/modules/github/WebhookService.d.ts +28 -0
  107. package/dist/modules/github/WebhookService.d.ts.map +1 -0
  108. package/dist/modules/github/WebhookService.js +156 -0
  109. package/dist/modules/github/WebhookService.js.map +1 -0
  110. package/dist/modules/github/projection.logic.d.ts +95 -0
  111. package/dist/modules/github/projection.logic.d.ts.map +1 -0
  112. package/dist/modules/github/projection.logic.js +94 -0
  113. package/dist/modules/github/projection.logic.js.map +1 -0
  114. package/dist/modules/github/provisioning.logic.d.ts +11 -0
  115. package/dist/modules/github/provisioning.logic.d.ts.map +1 -0
  116. package/dist/modules/github/provisioning.logic.js +18 -0
  117. package/dist/modules/github/provisioning.logic.js.map +1 -0
  118. package/dist/modules/incident/incident.logic.d.ts +16 -0
  119. package/dist/modules/incident/incident.logic.d.ts.map +1 -0
  120. package/dist/modules/incident/incident.logic.js +23 -0
  121. package/dist/modules/incident/incident.logic.js.map +1 -0
  122. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts +26 -0
  123. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts.map +1 -0
  124. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js +84 -0
  125. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js.map +1 -0
  126. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts +27 -0
  127. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts.map +1 -0
  128. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js +65 -0
  129. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js.map +1 -0
  130. package/dist/modules/providers/ApiKeyService.d.ts +73 -0
  131. package/dist/modules/providers/ApiKeyService.d.ts.map +1 -0
  132. package/dist/modules/providers/ApiKeyService.js +122 -0
  133. package/dist/modules/providers/ApiKeyService.js.map +1 -0
  134. package/dist/modules/providers/LocalModelEndpointService.d.ts +52 -0
  135. package/dist/modules/providers/LocalModelEndpointService.d.ts.map +1 -0
  136. package/dist/modules/providers/LocalModelEndpointService.js +131 -0
  137. package/dist/modules/providers/LocalModelEndpointService.js.map +1 -0
  138. package/dist/modules/providers/PersonalSubscriptionService.d.ts +94 -0
  139. package/dist/modules/providers/PersonalSubscriptionService.d.ts.map +1 -0
  140. package/dist/modules/providers/PersonalSubscriptionService.js +218 -0
  141. package/dist/modules/providers/PersonalSubscriptionService.js.map +1 -0
  142. package/dist/modules/providers/ProviderSubscriptionService.d.ts +75 -0
  143. package/dist/modules/providers/ProviderSubscriptionService.d.ts.map +1 -0
  144. package/dist/modules/providers/ProviderSubscriptionService.js +130 -0
  145. package/dist/modules/providers/ProviderSubscriptionService.js.map +1 -0
  146. package/dist/modules/providers/localModelUrl.d.ts +7 -0
  147. package/dist/modules/providers/localModelUrl.d.ts.map +1 -0
  148. package/dist/modules/providers/localModelUrl.js +67 -0
  149. package/dist/modules/providers/localModelUrl.js.map +1 -0
  150. package/dist/modules/providers/providers.logic.d.ts +23 -0
  151. package/dist/modules/providers/providers.logic.d.ts.map +1 -0
  152. package/dist/modules/providers/providers.logic.js +46 -0
  153. package/dist/modules/providers/providers.logic.js.map +1 -0
  154. package/dist/modules/runners/HttpRunnerPoolProvider.d.ts +51 -0
  155. package/dist/modules/runners/HttpRunnerPoolProvider.d.ts.map +1 -0
  156. package/dist/modules/runners/HttpRunnerPoolProvider.js +304 -0
  157. package/dist/modules/runners/HttpRunnerPoolProvider.js.map +1 -0
  158. package/dist/modules/runners/RunnerPoolConnectionService.d.ts +47 -0
  159. package/dist/modules/runners/RunnerPoolConnectionService.d.ts.map +1 -0
  160. package/dist/modules/runners/RunnerPoolConnectionService.js +98 -0
  161. package/dist/modules/runners/RunnerPoolConnectionService.js.map +1 -0
  162. package/dist/modules/runners/RunnerPoolTransport.d.ts +11 -0
  163. package/dist/modules/runners/RunnerPoolTransport.d.ts.map +1 -0
  164. package/dist/modules/runners/RunnerPoolTransport.js +61 -0
  165. package/dist/modules/runners/RunnerPoolTransport.js.map +1 -0
  166. package/dist/modules/runners/runners.logic.d.ts +16 -0
  167. package/dist/modules/runners/runners.logic.d.ts.map +1 -0
  168. package/dist/modules/runners/runners.logic.js +52 -0
  169. package/dist/modules/runners/runners.logic.js.map +1 -0
  170. package/dist/modules/slack/SlackApiClient.d.ts +67 -0
  171. package/dist/modules/slack/SlackApiClient.d.ts.map +1 -0
  172. package/dist/modules/slack/SlackApiClient.js +132 -0
  173. package/dist/modules/slack/SlackApiClient.js.map +1 -0
  174. package/dist/modules/slack/SlackConnectionService.d.ts +41 -0
  175. package/dist/modules/slack/SlackConnectionService.d.ts.map +1 -0
  176. package/dist/modules/slack/SlackConnectionService.js +136 -0
  177. package/dist/modules/slack/SlackConnectionService.js.map +1 -0
  178. package/dist/modules/slack/SlackMemberMappingService.d.ts +17 -0
  179. package/dist/modules/slack/SlackMemberMappingService.d.ts.map +1 -0
  180. package/dist/modules/slack/SlackMemberMappingService.js +28 -0
  181. package/dist/modules/slack/SlackMemberMappingService.js.map +1 -0
  182. package/dist/modules/slack/SlackNotificationChannel.d.ts +45 -0
  183. package/dist/modules/slack/SlackNotificationChannel.d.ts.map +1 -0
  184. package/dist/modules/slack/SlackNotificationChannel.js +84 -0
  185. package/dist/modules/slack/SlackNotificationChannel.js.map +1 -0
  186. package/dist/modules/slack/SlackSettingsService.d.ts +16 -0
  187. package/dist/modules/slack/SlackSettingsService.d.ts.map +1 -0
  188. package/dist/modules/slack/SlackSettingsService.js +41 -0
  189. package/dist/modules/slack/SlackSettingsService.js.map +1 -0
  190. package/dist/modules/slack/slack.logic.d.ts +55 -0
  191. package/dist/modules/slack/slack.logic.d.ts.map +1 -0
  192. package/dist/modules/slack/slack.logic.js +149 -0
  193. package/dist/modules/slack/slack.logic.js.map +1 -0
  194. package/dist/modules/tasks/GitHubIssuesProvider.d.ts +50 -0
  195. package/dist/modules/tasks/GitHubIssuesProvider.d.ts.map +1 -0
  196. package/dist/modules/tasks/GitHubIssuesProvider.js +92 -0
  197. package/dist/modules/tasks/GitHubIssuesProvider.js.map +1 -0
  198. package/dist/modules/tasks/JiraProvider.d.ts +29 -0
  199. package/dist/modules/tasks/JiraProvider.d.ts.map +1 -0
  200. package/dist/modules/tasks/JiraProvider.js +114 -0
  201. package/dist/modules/tasks/JiraProvider.js.map +1 -0
  202. package/dist/modules/tasks/TaskConnectionService.d.ts +30 -0
  203. package/dist/modules/tasks/TaskConnectionService.d.ts.map +1 -0
  204. package/dist/modules/tasks/TaskConnectionService.js +69 -0
  205. package/dist/modules/tasks/TaskConnectionService.js.map +1 -0
  206. package/dist/modules/tasks/TaskImportService.d.ts +34 -0
  207. package/dist/modules/tasks/TaskImportService.d.ts.map +1 -0
  208. package/dist/modules/tasks/TaskImportService.js +96 -0
  209. package/dist/modules/tasks/TaskImportService.js.map +1 -0
  210. package/dist/modules/tasks/TaskLinkService.d.ts +30 -0
  211. package/dist/modules/tasks/TaskLinkService.d.ts.map +1 -0
  212. package/dist/modules/tasks/TaskLinkService.js +56 -0
  213. package/dist/modules/tasks/TaskLinkService.js.map +1 -0
  214. package/dist/modules/tasks/github-issues.logic.d.ts +35 -0
  215. package/dist/modules/tasks/github-issues.logic.d.ts.map +1 -0
  216. package/dist/modules/tasks/github-issues.logic.js +67 -0
  217. package/dist/modules/tasks/github-issues.logic.js.map +1 -0
  218. package/dist/modules/tasks/jira.logic.d.ts +28 -0
  219. package/dist/modules/tasks/jira.logic.d.ts.map +1 -0
  220. package/dist/modules/tasks/jira.logic.js +151 -0
  221. package/dist/modules/tasks/jira.logic.js.map +1 -0
  222. package/dist/modules/tasks/tasks.logic.d.ts +12 -0
  223. package/dist/modules/tasks/tasks.logic.d.ts.map +1 -0
  224. package/dist/modules/tasks/tasks.logic.js +17 -0
  225. package/dist/modules/tasks/tasks.logic.js.map +1 -0
  226. package/dist/modules/tracker/TicketTrackerService.d.ts +45 -0
  227. package/dist/modules/tracker/TicketTrackerService.d.ts.map +1 -0
  228. package/dist/modules/tracker/TicketTrackerService.js +52 -0
  229. package/dist/modules/tracker/TicketTrackerService.js.map +1 -0
  230. package/dist/modules/tracker/base64.d.ts +2 -0
  231. package/dist/modules/tracker/base64.d.ts.map +1 -0
  232. package/dist/modules/tracker/base64.js +18 -0
  233. package/dist/modules/tracker/base64.js.map +1 -0
  234. package/dist/modules/tracker/github.create.logic.d.ts +16 -0
  235. package/dist/modules/tracker/github.create.logic.d.ts.map +1 -0
  236. package/dist/modules/tracker/github.create.logic.js +25 -0
  237. package/dist/modules/tracker/github.create.logic.js.map +1 -0
  238. package/dist/modules/tracker/jira.create.logic.d.ts +31 -0
  239. package/dist/modules/tracker/jira.create.logic.d.ts.map +1 -0
  240. package/dist/modules/tracker/jira.create.logic.js +59 -0
  241. package/dist/modules/tracker/jira.create.logic.js.map +1 -0
  242. package/package.json +36 -0
@@ -0,0 +1,69 @@
1
+ import { ConflictError, ValidationError } from '@cat-factory/kernel';
2
+ import { requireWorkspace } from '@cat-factory/kernel';
3
+ function toConnection(record) {
4
+ return {
5
+ source: record.source,
6
+ label: record.label,
7
+ connectedAt: record.createdAt,
8
+ };
9
+ }
10
+ export class TaskConnectionService {
11
+ deps;
12
+ constructor(deps) {
13
+ this.deps = deps;
14
+ }
15
+ /** The descriptors of every configured source (drives the connect UI). */
16
+ listSources() {
17
+ return this.deps.registry.list().map((p) => p.descriptor);
18
+ }
19
+ /** Resolve a provider for a source or throw if that source isn't configured. */
20
+ requireProvider(source) {
21
+ const provider = this.deps.registry.get(source);
22
+ if (!provider)
23
+ throw new ValidationError(`Unknown or unconfigured task source '${source}'`);
24
+ return provider;
25
+ }
26
+ /** Connect (or re-connect) a workspace to a task source. */
27
+ async connect(workspaceId, source, credentials) {
28
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
29
+ const provider = this.requireProvider(source);
30
+ const normalized = provider.normalizeConnection(credentials);
31
+ const existing = await this.deps.taskConnectionRepository.getByWorkspace(workspaceId, source);
32
+ const record = {
33
+ workspaceId,
34
+ source,
35
+ credentials: normalized.credentials,
36
+ label: normalized.label,
37
+ createdAt: existing?.createdAt ?? this.deps.clock.now(),
38
+ deletedAt: null,
39
+ };
40
+ await this.deps.taskConnectionRepository.upsert(record);
41
+ return toConnection(record);
42
+ }
43
+ /** The workspace's current connection for a source, or null if not connected. */
44
+ async getConnection(workspaceId, source) {
45
+ const record = await this.deps.taskConnectionRepository.getByWorkspace(workspaceId, source);
46
+ return record ? toConnection(record) : null;
47
+ }
48
+ /** Every live connection the workspace holds, across sources. */
49
+ async listConnections(workspaceId) {
50
+ const records = await this.deps.taskConnectionRepository.listByWorkspace(workspaceId);
51
+ return records.map(toConnection);
52
+ }
53
+ /** Resolve the live connection (with credentials) or throw if not connected. */
54
+ async requireConnection(workspaceId, source) {
55
+ const record = await this.deps.taskConnectionRepository.getByWorkspace(workspaceId, source);
56
+ if (!record) {
57
+ throw new ConflictError(`Workspace '${workspaceId}' is not connected to ${source}`);
58
+ }
59
+ return record;
60
+ }
61
+ /** Disconnect a workspace from a source (tombstones the binding). */
62
+ async disconnect(workspaceId, source) {
63
+ const record = await this.deps.taskConnectionRepository.getByWorkspace(workspaceId, source);
64
+ if (!record)
65
+ return;
66
+ await this.deps.taskConnectionRepository.softDelete(workspaceId, source, this.deps.clock.now());
67
+ }
68
+ }
69
+ //# sourceMappingURL=TaskConnectionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskConnectionService.js","sourceRoot":"","sources":["../../../src/modules/tasks/TaskConnectionService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAgBtD,SAAS,YAAY,CAAC,MAA4B;IAChD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,WAAW,EAAE,MAAM,CAAC,SAAS;KAC9B,CAAA;AACH,CAAC;AAED,MAAM,OAAO,qBAAqB;IACH,IAAI;IAAjC,YAA6B,IAAuC;oBAAvC,IAAI;IAAsC,CAAC;IAExE,0EAA0E;IAC1E,WAAW;QACT,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;IAC3D,CAAC;IAED,gFAAgF;IACxE,eAAe,CAAC,MAAsB;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAC/C,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,eAAe,CAAC,wCAAwC,MAAM,GAAG,CAAC,CAAA;QAC3F,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,4DAA4D;IAC5D,KAAK,CAAC,OAAO,CACX,WAAmB,EACnB,MAAsB,EACtB,WAAmC;QAEnC,MAAM,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC7C,MAAM,UAAU,GAAG,QAAQ,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAA;QAC5D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC7F,MAAM,MAAM,GAAyB;YACnC,WAAW;YACX,MAAM;YACN,WAAW,EAAE,UAAU,CAAC,WAAW;YACnC,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YACvD,SAAS,EAAE,IAAI;SAChB,CAAA;QACD,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACvD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,MAAsB;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC3F,OAAO,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7C,CAAC;IAED,iEAAiE;IACjE,KAAK,CAAC,eAAe,CAAC,WAAmB;QACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;QACrF,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAClC,CAAC;IAED,gFAAgF;IAChF,KAAK,CAAC,iBAAiB,CACrB,WAAmB,EACnB,MAAsB;QAEtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC3F,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,aAAa,CAAC,cAAc,WAAW,yBAAyB,MAAM,EAAE,CAAC,CAAA;QACrF,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,UAAU,CAAC,WAAmB,EAAE,MAAsB;QAC1D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAC3F,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAA;IACjG,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import type { Clock } from '@cat-factory/kernel';
2
+ import type { TaskSourceRegistry } from '@cat-factory/kernel';
3
+ import type { TaskRecord, TaskRepository } from '@cat-factory/kernel';
4
+ import type { SourceTask, TaskSearchResult, TaskSourceKind } from '@cat-factory/kernel';
5
+ import type { WorkspaceRepository } from '@cat-factory/kernel';
6
+ import type { TaskConnectionService } from './TaskConnectionService.js';
7
+ export interface TaskImportServiceDependencies {
8
+ registry: TaskSourceRegistry;
9
+ taskRepository: TaskRepository;
10
+ connectionService: TaskConnectionService;
11
+ workspaceRepository: WorkspaceRepository;
12
+ clock: Clock;
13
+ }
14
+ /** Project a stored task record onto the wire shape (drops the tombstone). */
15
+ export declare function toSourceTask(record: TaskRecord): SourceTask;
16
+ export declare class TaskImportService {
17
+ private readonly deps;
18
+ constructor(deps: TaskImportServiceDependencies);
19
+ private requireProvider;
20
+ /** Fetch an issue (by key or URL) and upsert its projection; returns the issue. */
21
+ import(workspaceId: string, source: TaskSourceKind, ref: string): Promise<SourceTask>;
22
+ /**
23
+ * Search a tracker by free text, returning lean hits (not yet imported). The
24
+ * provider authenticates with the workspace's stored credentials and builds/
25
+ * parses the source-specific query. Throws if the source can't search (no
26
+ * provider `search`), so the controller can answer cleanly.
27
+ */
28
+ search(workspaceId: string, source: TaskSourceKind, query: string): Promise<TaskSearchResult[]>;
29
+ /** Every issue imported into the workspace, across sources, as wire shapes. */
30
+ listTasks(workspaceId: string): Promise<SourceTask[]>;
31
+ /** Resolve a stored task record or throw if not imported. */
32
+ requireTask(workspaceId: string, source: TaskSourceKind, externalId: string): Promise<TaskRecord>;
33
+ }
34
+ //# sourceMappingURL=TaskImportService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskImportService.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/TaskImportService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AASvE,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,cAAc,EAAE,cAAc,CAAA;IAC9B,iBAAiB,EAAE,qBAAqB,CAAA;IACxC,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,KAAK,EAAE,KAAK,CAAA;CACb;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAiB3D;AAED,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,6BAA6B,EAAI;IAEpE,OAAO,CAAC,eAAe;IAMvB,mFAAmF;IAC7E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAgC1F;IAED;;;;;OAKG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAQ7B;IAED,+EAA+E;IACzE,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAG1D;IAED,6DAA6D;IACvD,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAMrB;CACF"}
@@ -0,0 +1,96 @@
1
+ import { ValidationError } from '@cat-factory/kernel';
2
+ import { requireWorkspace } from '@cat-factory/kernel';
3
+ import { buildTaskExcerpt } from './tasks.logic.js';
4
+ /** Project a stored task record onto the wire shape (drops the tombstone). */
5
+ export function toSourceTask(record) {
6
+ return {
7
+ source: record.source,
8
+ externalId: record.externalId,
9
+ title: record.title,
10
+ url: record.url,
11
+ status: record.status,
12
+ type: record.type,
13
+ assignee: record.assignee,
14
+ priority: record.priority,
15
+ labels: record.labels,
16
+ description: record.description,
17
+ comments: record.comments,
18
+ excerpt: record.excerpt,
19
+ linkedBlockId: record.linkedBlockId,
20
+ syncedAt: record.syncedAt,
21
+ };
22
+ }
23
+ export class TaskImportService {
24
+ deps;
25
+ constructor(deps) {
26
+ this.deps = deps;
27
+ }
28
+ requireProvider(source) {
29
+ const provider = this.deps.registry.get(source);
30
+ if (!provider)
31
+ throw new ValidationError(`Unknown or unconfigured task source '${source}'`);
32
+ return provider;
33
+ }
34
+ /** Fetch an issue (by key or URL) and upsert its projection; returns the issue. */
35
+ async import(workspaceId, source, ref) {
36
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
37
+ const provider = this.requireProvider(source);
38
+ const externalId = provider.parseRef(ref);
39
+ if (!externalId) {
40
+ throw new ValidationError(`Could not resolve a ${source} issue key from '${ref}'`);
41
+ }
42
+ const connection = await this.deps.connectionService.requireConnection(workspaceId, source);
43
+ const content = await provider.fetchTask(connection.credentials, externalId);
44
+ // Preserve any existing block link across a re-import.
45
+ const existing = await this.deps.taskRepository.get(workspaceId, source, content.externalId);
46
+ const record = {
47
+ workspaceId,
48
+ source,
49
+ externalId: content.externalId,
50
+ title: content.title,
51
+ url: content.url,
52
+ status: content.status,
53
+ type: content.type,
54
+ assignee: content.assignee,
55
+ priority: content.priority,
56
+ labels: content.labels,
57
+ description: content.description,
58
+ comments: content.comments,
59
+ excerpt: buildTaskExcerpt(content),
60
+ linkedBlockId: existing?.linkedBlockId ?? null,
61
+ syncedAt: this.deps.clock.now(),
62
+ deletedAt: null,
63
+ };
64
+ await this.deps.taskRepository.upsert(record);
65
+ return toSourceTask(record);
66
+ }
67
+ /**
68
+ * Search a tracker by free text, returning lean hits (not yet imported). The
69
+ * provider authenticates with the workspace's stored credentials and builds/
70
+ * parses the source-specific query. Throws if the source can't search (no
71
+ * provider `search`), so the controller can answer cleanly.
72
+ */
73
+ async search(workspaceId, source, query) {
74
+ await requireWorkspace(this.deps.workspaceRepository, workspaceId);
75
+ const provider = this.requireProvider(source);
76
+ if (!provider.search) {
77
+ throw new ValidationError(`The ${source} source does not support search`);
78
+ }
79
+ const connection = await this.deps.connectionService.requireConnection(workspaceId, source);
80
+ return provider.search(connection.credentials, query, workspaceId);
81
+ }
82
+ /** Every issue imported into the workspace, across sources, as wire shapes. */
83
+ async listTasks(workspaceId) {
84
+ const records = await this.deps.taskRepository.listByWorkspace(workspaceId);
85
+ return records.map(toSourceTask);
86
+ }
87
+ /** Resolve a stored task record or throw if not imported. */
88
+ async requireTask(workspaceId, source, externalId) {
89
+ const record = await this.deps.taskRepository.get(workspaceId, source, externalId);
90
+ if (!record) {
91
+ throw new ValidationError(`${source} issue '${externalId}' has not been imported`);
92
+ }
93
+ return record;
94
+ }
95
+ }
96
+ //# sourceMappingURL=TaskImportService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskImportService.js","sourceRoot":"","sources":["../../../src/modules/tasks/TaskImportService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { Block, SourceTask, TaskSourceKind } from '@cat-factory/kernel';
2
+ import type { BlockRepository } from '@cat-factory/kernel';
3
+ import type { BoardWritePort } from '@cat-factory/kernel';
4
+ import type { TaskRepository } from '@cat-factory/kernel';
5
+ export interface TaskLinkServiceDependencies {
6
+ boardService: BoardWritePort;
7
+ blockRepository: BlockRepository;
8
+ taskRepository: TaskRepository;
9
+ }
10
+ /** A board task created from an imported issue, plus the now-linked issue. */
11
+ export interface TaskFromIssue {
12
+ block: Block;
13
+ task: SourceTask;
14
+ }
15
+ export declare class TaskLinkService {
16
+ private readonly deps;
17
+ constructor(deps: TaskLinkServiceDependencies);
18
+ /** Attach an imported issue to a board block as extra agent context. */
19
+ linkToBlock(workspaceId: string, blockId: string, source: TaskSourceKind, externalId: string): Promise<SourceTask>;
20
+ /**
21
+ * Create a new board task from an already-imported issue, inside a container
22
+ * (service frame or module), and link the issue to the new task for context.
23
+ * The title/description are seeded from the issue; the issue stays the source
24
+ * of truth (re-importing refreshes it) and is fed to every agent step via the
25
+ * link. Reuses BoardService.addTask so scope/placement rules stay in one place.
26
+ * `createdBy` (the signed-in user) flows onto the new task for notification routing.
27
+ */
28
+ createTaskFromIssue(workspaceId: string, containerId: string, source: TaskSourceKind, externalId: string, createdBy?: string | null): Promise<TaskFromIssue>;
29
+ }
30
+ //# sourceMappingURL=TaskLinkService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskLinkService.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/TaskLinkService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAc,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAExF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAUzD,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,cAAc,CAAA;IAC5B,eAAe,EAAE,eAAe,CAAA;IAChC,cAAc,EAAE,cAAc,CAAA;CAC/B;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,2BAA2B,EAAI;IAElE,wEAAwE;IAClE,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAarB;IAED;;;;;;;OAOG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,aAAa,CAAC,CAgCxB;CACF"}
@@ -0,0 +1,56 @@
1
+ import { assertFound, ConflictError } from '@cat-factory/kernel';
2
+ import { toSourceTask } from './TaskImportService.js';
3
+ export class TaskLinkService {
4
+ deps;
5
+ constructor(deps) {
6
+ this.deps = deps;
7
+ }
8
+ /** Attach an imported issue to a board block as extra agent context. */
9
+ async linkToBlock(workspaceId, blockId, source, externalId) {
10
+ const block = assertFound(await this.deps.blockRepository.get(workspaceId, blockId), 'Block', blockId);
11
+ const task = assertFound(await this.deps.taskRepository.get(workspaceId, source, externalId), 'Task', externalId);
12
+ await this.deps.taskRepository.linkBlock(workspaceId, source, externalId, block.id);
13
+ return toSourceTask({ ...task, linkedBlockId: block.id });
14
+ }
15
+ /**
16
+ * Create a new board task from an already-imported issue, inside a container
17
+ * (service frame or module), and link the issue to the new task for context.
18
+ * The title/description are seeded from the issue; the issue stays the source
19
+ * of truth (re-importing refreshes it) and is fed to every agent step via the
20
+ * link. Reuses BoardService.addTask so scope/placement rules stay in one place.
21
+ * `createdBy` (the signed-in user) flows onto the new task for notification routing.
22
+ */
23
+ async createTaskFromIssue(workspaceId, containerId, source, externalId, createdBy) {
24
+ const issue = assertFound(await this.deps.taskRepository.get(workspaceId, source, externalId), 'Task', externalId);
25
+ // An issue carries a single `linkedBlockId`, so creating a second task from it
26
+ // would silently re-point the link and orphan the first task's issue context.
27
+ // Refuse rather than lose the existing link (the issue is the source of truth).
28
+ if (issue.linkedBlockId) {
29
+ throw new ConflictError(`Issue ${externalId} is already linked to task ${issue.linkedBlockId}; unlink it first`);
30
+ }
31
+ // Resolve the container in the REQUEST workspace (like linkToBlock) so the new
32
+ // block and the issue projection share a workspace — the issue link is workspace-
33
+ // scoped, so creating the task in a service mounted from another workspace would
34
+ // leave the link unresolvable at execution time. A foreign/unknown container 404s.
35
+ assertFound(await this.deps.blockRepository.get(workspaceId, containerId), 'Block', containerId);
36
+ const block = await this.deps.boardService.addTask(workspaceId, containerId, {
37
+ title: issueTaskTitle(issue),
38
+ description: issueTaskDescription(issue),
39
+ }, createdBy ?? null);
40
+ // Link the issue to the new task so agents get the full issue (description,
41
+ // comments, metadata) as context — and the task carries the back-reference.
42
+ await this.deps.taskRepository.linkBlock(workspaceId, source, externalId, block.id);
43
+ return { block, task: toSourceTask({ ...issue, linkedBlockId: block.id }) };
44
+ }
45
+ }
46
+ /** Seed the new task's title from the issue (keyed for traceability). */
47
+ function issueTaskTitle(issue) {
48
+ return `${issue.externalId}: ${issue.title}`;
49
+ }
50
+ /** Seed the new task's description: a source reference line + the issue body. */
51
+ function issueTaskDescription(issue) {
52
+ const reference = `Imported from ${issue.url}`;
53
+ const body = issue.description.trim() || issue.excerpt.trim();
54
+ return body ? `${reference}\n\n${body}` : reference;
55
+ }
56
+ //# sourceMappingURL=TaskLinkService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskLinkService.js","sourceRoot":"","sources":["../../../src/modules/tasks/TaskLinkService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { TaskSourceDescriptor } from '@cat-factory/kernel';
2
+ /**
3
+ * What the connect UI renders. GitHub issues piggyback on the workspace's
4
+ * existing GitHub App installation, so there are NO credential fields — the
5
+ * connect form is just a confirmation, and `normalizeConnection` accepts an empty
6
+ * bag.
7
+ */
8
+ export declare const GITHUB_ISSUES_DESCRIPTOR: TaskSourceDescriptor;
9
+ /** The canonical `owner/repo#number` external id for an issue's parts. */
10
+ export declare function githubIssueExternalId(id: GitHubIssueExternalId): string;
11
+ /**
12
+ * Resolve a GitHub issue reference from raw user input into the canonical
13
+ * `owner/repo#number` external id. Accepts:
14
+ * - a full issue URL: `https://github.com/octo/repo/issues/123`
15
+ * - the `octo/repo/issues/123` path form
16
+ * - the shorthand `octo/repo#123`
17
+ * Returns null when nothing parses. The owner/repo are kept verbatim (GitHub repo
18
+ * names are case-preserving); only surrounding whitespace is trimmed.
19
+ */
20
+ export declare function parseGitHubIssueRef(input: string): string | null;
21
+ /** The parts of a GitHub issue external id (`owner/repo#number`). */
22
+ export interface GitHubIssueExternalId {
23
+ owner: string;
24
+ repo: string;
25
+ number: number;
26
+ }
27
+ /**
28
+ * Split a stored `owner/repo#number` external id back into its parts. Returns
29
+ * null if the id is malformed (defensive — ids are produced by
30
+ * {@link parseGitHubIssueRef}, but a stale/hand-edited row should not throw).
31
+ */
32
+ export declare function parseGitHubIssueExternalId(externalId: string): GitHubIssueExternalId | null;
33
+ /** The canonical web URL for an issue external id. */
34
+ export declare function githubIssueUrl(id: GitHubIssueExternalId): string;
35
+ //# sourceMappingURL=github-issues.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-issues.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/github-issues.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAU/D;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,oBAQtC,CAAA;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,qBAAqB,GAAG,MAAM,CAEvE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAShE;AAED,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAI3F;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,EAAE,EAAE,qBAAqB,GAAG,MAAM,CAEhE"}
@@ -0,0 +1,67 @@
1
+ // GitHub-issues task-source pure logic, kept out of the worker so it is
2
+ // unit-testable without a live API: parsing an issue reference out of user input
3
+ // and round-tripping the `owner/repo#number` external id the provider stores. The
4
+ // fetch itself lives in the worker's GitHubIssuesProvider, which reuses the
5
+ // workspace's installed GitHub App (so this source needs no credentials of its
6
+ // own — unlike Jira). GitHub issue bodies are already Markdown, so there is no
7
+ // body-conversion step here.
8
+ /**
9
+ * What the connect UI renders. GitHub issues piggyback on the workspace's
10
+ * existing GitHub App installation, so there are NO credential fields — the
11
+ * connect form is just a confirmation, and `normalizeConnection` accepts an empty
12
+ * bag.
13
+ */
14
+ export const GITHUB_ISSUES_DESCRIPTOR = {
15
+ source: 'github',
16
+ label: 'GitHub Issues',
17
+ icon: 'i-lucide-github',
18
+ credentialFields: [],
19
+ refLabel: 'Issue URL or owner/repo#number',
20
+ refPlaceholder: 'octo/repo#123 or https://github.com/octo/repo/issues/123',
21
+ searchable: true,
22
+ };
23
+ /** The canonical `owner/repo#number` external id for an issue's parts. */
24
+ export function githubIssueExternalId(id) {
25
+ return `${id.owner}/${id.repo}#${id.number}`;
26
+ }
27
+ // A GitHub owner/repo segment: letters, digits, '.', '_' and '-'. Deliberately
28
+ // permissive but bounded so a stray path can't masquerade as a ref.
29
+ const SEG = '[A-Za-z0-9._-]+';
30
+ /**
31
+ * Resolve a GitHub issue reference from raw user input into the canonical
32
+ * `owner/repo#number` external id. Accepts:
33
+ * - a full issue URL: `https://github.com/octo/repo/issues/123`
34
+ * - the `octo/repo/issues/123` path form
35
+ * - the shorthand `octo/repo#123`
36
+ * Returns null when nothing parses. The owner/repo are kept verbatim (GitHub repo
37
+ * names are case-preserving); only surrounding whitespace is trimmed.
38
+ */
39
+ export function parseGitHubIssueRef(input) {
40
+ const trimmed = input.trim();
41
+ const url = trimmed.match(new RegExp(`github\\.com/(${SEG})/(${SEG})/issues/(\\d+)`));
42
+ if (url)
43
+ return `${url[1]}/${url[2]}#${url[3]}`;
44
+ const path = trimmed.match(new RegExp(`^(${SEG})/(${SEG})/issues/(\\d+)$`));
45
+ if (path)
46
+ return `${path[1]}/${path[2]}#${path[3]}`;
47
+ const short = trimmed.match(new RegExp(`^(${SEG})/(${SEG})#(\\d+)$`));
48
+ if (short)
49
+ return `${short[1]}/${short[2]}#${short[3]}`;
50
+ return null;
51
+ }
52
+ /**
53
+ * Split a stored `owner/repo#number` external id back into its parts. Returns
54
+ * null if the id is malformed (defensive — ids are produced by
55
+ * {@link parseGitHubIssueRef}, but a stale/hand-edited row should not throw).
56
+ */
57
+ export function parseGitHubIssueExternalId(externalId) {
58
+ const m = externalId.match(new RegExp(`^(${SEG})/(${SEG})#(\\d+)$`));
59
+ if (!m)
60
+ return null;
61
+ return { owner: m[1], repo: m[2], number: Number(m[3]) };
62
+ }
63
+ /** The canonical web URL for an issue external id. */
64
+ export function githubIssueUrl(id) {
65
+ return `https://github.com/${id.owner}/${id.repo}/issues/${id.number}`;
66
+ }
67
+ //# sourceMappingURL=github-issues.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-issues.logic.js","sourceRoot":"","sources":["../../../src/modules/tasks/github-issues.logic.ts"],"names":[],"mappings":"AAEA,wEAAwE;AACxE,iFAAiF;AACjF,kFAAkF;AAClF,4EAA4E;AAC5E,+EAA+E;AAC/E,+EAA+E;AAC/E,6BAA6B;AAE7B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAyB;IAC5D,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,eAAe;IACtB,IAAI,EAAE,iBAAiB;IACvB,gBAAgB,EAAE,EAAE;IACpB,QAAQ,EAAE,gCAAgC;IAC1C,cAAc,EAAE,4DAA4D;IAC5E,UAAU,EAAE,IAAI;CACjB,CAAA;AAED,0EAA0E;AAC1E,MAAM,UAAU,qBAAqB,CAAC,EAAyB;IAC7D,OAAO,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,MAAM,EAAE,CAAA;AAC9C,CAAC;AAED,+EAA+E;AAC/E,oEAAoE;AACpE,MAAM,GAAG,GAAG,iBAAiB,CAAA;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,iBAAiB,GAAG,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAA;IACrF,IAAI,GAAG;QAAE,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAA;IAC3E,IAAI,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAA;IACrE,IAAI,KAAK;QAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACvD,OAAO,IAAI,CAAA;AACb,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,UAAkB;IAC3D,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAA;IACpE,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAC5D,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,cAAc,CAAC,EAAyB;IACtD,OAAO,sBAAsB,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,EAAE,CAAA;AACxE,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { TaskSearchResult, TaskSourceDescriptor } from '@cat-factory/kernel';
2
+ /** What the connect UI renders, and which credentials the provider needs. */
3
+ export declare const JIRA_DESCRIPTOR: TaskSourceDescriptor;
4
+ /**
5
+ * Build the JQL for a free-text issue search: match the term across summary and
6
+ * body (`text ~`), newest first. A bare key typed into the box still matches via
7
+ * `text ~`, so the search box doubles as a quick "jump to issue".
8
+ */
9
+ export declare function buildJiraSearchJql(query: string): string;
10
+ /** Map a Jira search response into lean hits; URLs are the canonical `/browse/KEY`. */
11
+ export declare function parseJiraSearchResults(json: unknown, base: string): TaskSearchResult[];
12
+ /**
13
+ * Resolve a Jira issue key from raw user input: a bare key (`PROJ-123`), a
14
+ * `/browse/PROJ-123` URL, or the `selectedIssue=PROJ-123` / `/issues/PROJ-123`
15
+ * board URL forms. The key is upper-cased (Jira keys are case-insensitive on
16
+ * input but canonically upper-case). Returns null when nothing parses.
17
+ */
18
+ export declare function parseJiraRef(input: string): string | null;
19
+ /**
20
+ * Convert an Atlassian Document Format node tree into lightweight Markdown: the
21
+ * same `#`/`##`/`###` headings, `- ` list items and blank-line block boundaries
22
+ * the generic excerpt/prompt logic consumes. ADF is a JSON document
23
+ * (`{ type: 'doc', content: [...] }`); we walk it defensively so a missing or
24
+ * unexpected node yields '' rather than throwing — Jira fields are sometimes
25
+ * null or a plain string on older issues.
26
+ */
27
+ export declare function adfToMarkdown(node: unknown): string;
28
+ //# sourceMappingURL=jira.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/jira.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AASjF,6EAA6E;AAC7E,eAAO,MAAM,eAAe,EAAE,oBAuB7B,CAAA;AAOD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AASD,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAgBtF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWzD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAUnD"}
@@ -0,0 +1,151 @@
1
+ // Jira-specific pure logic, kept out of the worker so it is unit-testable
2
+ // without a live site: parsing an issue key out of user input and converting an
3
+ // issue's Atlassian Document Format (ADF) body into the lightweight Markdown the
4
+ // generic excerpt/prompt logic consumes. The base-URL guard is shared with
5
+ // Confluence (see ../../shared/atlassian.logic); the fetch itself lives in the
6
+ // worker's JiraProvider.
7
+ /** What the connect UI renders, and which credentials the provider needs. */
8
+ export const JIRA_DESCRIPTOR = {
9
+ source: 'jira',
10
+ label: 'Jira',
11
+ icon: 'i-lucide-square-check',
12
+ credentialFields: [
13
+ {
14
+ key: 'baseUrl',
15
+ label: 'Site URL',
16
+ placeholder: 'https://your-team.atlassian.net',
17
+ help: 'e.g. https://your-team.atlassian.net',
18
+ },
19
+ { key: 'accountEmail', label: 'Account email', placeholder: 'you@company.com' },
20
+ {
21
+ key: 'apiToken',
22
+ label: 'API token',
23
+ secret: true,
24
+ placeholder: 'Paste a Jira API token',
25
+ help: 'Create one at id.atlassian.com → Security → API tokens',
26
+ },
27
+ ],
28
+ refLabel: 'Issue key or URL',
29
+ refPlaceholder: 'PROJ-123 or https://…/browse/PROJ-123',
30
+ searchable: true,
31
+ };
32
+ /** Escape a user string for embedding inside a JQL double-quoted literal. */
33
+ function escapeJql(query) {
34
+ return query.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
35
+ }
36
+ /**
37
+ * Build the JQL for a free-text issue search: match the term across summary and
38
+ * body (`text ~`), newest first. A bare key typed into the box still matches via
39
+ * `text ~`, so the search box doubles as a quick "jump to issue".
40
+ */
41
+ export function buildJiraSearchJql(query) {
42
+ return `text ~ "${escapeJql(query.trim())}" ORDER BY updated DESC`;
43
+ }
44
+ /** Map a Jira search response into lean hits; URLs are the canonical `/browse/KEY`. */
45
+ export function parseJiraSearchResults(json, base) {
46
+ const body = (json ?? {});
47
+ const cleanBase = base.replace(/\/+$/, '');
48
+ const out = [];
49
+ for (const issue of Array.isArray(body.issues) ? body.issues : []) {
50
+ if (!issue.key)
51
+ continue;
52
+ out.push({
53
+ source: 'jira',
54
+ externalId: issue.key,
55
+ title: issue.fields?.summary ?? '(untitled)',
56
+ url: `${cleanBase}/browse/${issue.key}`,
57
+ status: issue.fields?.status?.name ?? '',
58
+ excerpt: '',
59
+ });
60
+ }
61
+ return out;
62
+ }
63
+ /**
64
+ * Resolve a Jira issue key from raw user input: a bare key (`PROJ-123`), a
65
+ * `/browse/PROJ-123` URL, or the `selectedIssue=PROJ-123` / `/issues/PROJ-123`
66
+ * board URL forms. The key is upper-cased (Jira keys are case-insensitive on
67
+ * input but canonically upper-case). Returns null when nothing parses.
68
+ */
69
+ export function parseJiraRef(input) {
70
+ const trimmed = input.trim();
71
+ const KEY = /[A-Za-z][A-Za-z0-9]+-\d+/;
72
+ if (new RegExp(`^${KEY.source}$`).test(trimmed))
73
+ return trimmed.toUpperCase();
74
+ const browse = trimmed.match(new RegExp(`/browse/(${KEY.source})`));
75
+ if (browse)
76
+ return browse[1].toUpperCase();
77
+ const selected = trimmed.match(new RegExp(`[?&]selectedIssue=(${KEY.source})`));
78
+ if (selected)
79
+ return selected[1].toUpperCase();
80
+ const issues = trimmed.match(new RegExp(`/issues/(${KEY.source})`));
81
+ if (issues)
82
+ return issues[1].toUpperCase();
83
+ return null;
84
+ }
85
+ /**
86
+ * Convert an Atlassian Document Format node tree into lightweight Markdown: the
87
+ * same `#`/`##`/`###` headings, `- ` list items and blank-line block boundaries
88
+ * the generic excerpt/prompt logic consumes. ADF is a JSON document
89
+ * (`{ type: 'doc', content: [...] }`); we walk it defensively so a missing or
90
+ * unexpected node yields '' rather than throwing — Jira fields are sometimes
91
+ * null or a plain string on older issues.
92
+ */
93
+ export function adfToMarkdown(node) {
94
+ if (node == null)
95
+ return '';
96
+ // Older issues / some fields come back as a plain string already.
97
+ if (typeof node === 'string')
98
+ return node.trim();
99
+ if (typeof node !== 'object')
100
+ return '';
101
+ const out = renderNode(node);
102
+ return out
103
+ .replace(/[ \t]+\n/g, '\n')
104
+ .replace(/\n{3,}/g, '\n\n')
105
+ .trim();
106
+ }
107
+ /** Render a node's children, concatenated. */
108
+ function renderChildren(node) {
109
+ if (!Array.isArray(node.content))
110
+ return '';
111
+ return node.content.map((child) => renderNode(child)).join('');
112
+ }
113
+ /** Render the inline text of a node (no block markers), for headings/list items. */
114
+ function renderInline(node) {
115
+ if (node.type === 'text')
116
+ return node.text ?? '';
117
+ if (node.type === 'hardBreak')
118
+ return ' ';
119
+ return Array.isArray(node.content)
120
+ ? node.content.map((child) => renderInline(child)).join('')
121
+ : '';
122
+ }
123
+ function renderNode(node) {
124
+ if (typeof node !== 'object' || node === null)
125
+ return '';
126
+ switch (node.type) {
127
+ case 'text':
128
+ return node.text ?? '';
129
+ case 'hardBreak':
130
+ return '\n';
131
+ case 'paragraph':
132
+ return `${renderChildren(node)}\n\n`;
133
+ case 'heading': {
134
+ const level = Math.min(Math.max(Number(node.attrs?.level ?? 1) || 1, 1), 3);
135
+ return `${'#'.repeat(level)} ${renderInline(node).trim()}\n\n`;
136
+ }
137
+ case 'bulletList':
138
+ case 'orderedList':
139
+ return `${renderChildren(node)}\n`;
140
+ case 'listItem':
141
+ return `- ${renderInline(node).trim()}\n`;
142
+ case 'codeBlock':
143
+ return `\`\`\`\n${renderInline(node)}\n\`\`\`\n\n`;
144
+ case 'blockquote':
145
+ return renderChildren(node);
146
+ default:
147
+ // 'doc', 'mediaGroup', panels, tables, unknown marks: recurse into content.
148
+ return renderChildren(node);
149
+ }
150
+ }
151
+ //# sourceMappingURL=jira.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.logic.js","sourceRoot":"","sources":["../../../src/modules/tasks/jira.logic.ts"],"names":[],"mappings":"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"}