@aligndottech/connector-core 0.1.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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/dist/fetchers/confluence.d.ts +9 -0
  3. package/dist/fetchers/confluence.d.ts.map +1 -0
  4. package/dist/fetchers/confluence.js +89 -0
  5. package/dist/fetchers/confluence.js.map +1 -0
  6. package/dist/fetchers/errors.d.ts +11 -0
  7. package/dist/fetchers/errors.d.ts.map +1 -0
  8. package/dist/fetchers/errors.js +15 -0
  9. package/dist/fetchers/errors.js.map +1 -0
  10. package/dist/fetchers/git.d.ts +23 -0
  11. package/dist/fetchers/git.d.ts.map +1 -0
  12. package/dist/fetchers/git.js +27 -0
  13. package/dist/fetchers/git.js.map +1 -0
  14. package/dist/fetchers/github.d.ts +9 -0
  15. package/dist/fetchers/github.d.ts.map +1 -0
  16. package/dist/fetchers/github.js +53 -0
  17. package/dist/fetchers/github.js.map +1 -0
  18. package/dist/fetchers/gitlab.d.ts +9 -0
  19. package/dist/fetchers/gitlab.d.ts.map +1 -0
  20. package/dist/fetchers/gitlab.js +33 -0
  21. package/dist/fetchers/gitlab.js.map +1 -0
  22. package/dist/fetchers/index.d.ts +20 -0
  23. package/dist/fetchers/index.d.ts.map +1 -0
  24. package/dist/fetchers/index.js +38 -0
  25. package/dist/fetchers/index.js.map +1 -0
  26. package/dist/fetchers/jira.d.ts +9 -0
  27. package/dist/fetchers/jira.d.ts.map +1 -0
  28. package/dist/fetchers/jira.js +73 -0
  29. package/dist/fetchers/jira.js.map +1 -0
  30. package/dist/fetchers/linear.d.ts +9 -0
  31. package/dist/fetchers/linear.d.ts.map +1 -0
  32. package/dist/fetchers/linear.js +71 -0
  33. package/dist/fetchers/linear.js.map +1 -0
  34. package/dist/fetchers/notion.d.ts +9 -0
  35. package/dist/fetchers/notion.d.ts.map +1 -0
  36. package/dist/fetchers/notion.js +85 -0
  37. package/dist/fetchers/notion.js.map +1 -0
  38. package/dist/fetchers/slack.d.ts +10 -0
  39. package/dist/fetchers/slack.d.ts.map +1 -0
  40. package/dist/fetchers/slack.js +103 -0
  41. package/dist/fetchers/slack.js.map +1 -0
  42. package/dist/fetchers/teams.d.ts +10 -0
  43. package/dist/fetchers/teams.d.ts.map +1 -0
  44. package/dist/fetchers/teams.js +76 -0
  45. package/dist/fetchers/teams.js.map +1 -0
  46. package/dist/fetchers/util/git.d.ts +22 -0
  47. package/dist/fetchers/util/git.d.ts.map +1 -0
  48. package/dist/fetchers/util/git.js +50 -0
  49. package/dist/fetchers/util/git.js.map +1 -0
  50. package/dist/fetchers/zoom.d.ts +9 -0
  51. package/dist/fetchers/zoom.d.ts.map +1 -0
  52. package/dist/fetchers/zoom.js +72 -0
  53. package/dist/fetchers/zoom.js.map +1 -0
  54. package/dist/index.d.ts +25 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +33 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/parsers/CommandParser.d.ts +69 -0
  59. package/dist/parsers/CommandParser.d.ts.map +1 -0
  60. package/dist/parsers/CommandParser.js +233 -0
  61. package/dist/parsers/CommandParser.js.map +1 -0
  62. package/dist/services/GatewayClient.d.ts +147 -0
  63. package/dist/services/GatewayClient.d.ts.map +1 -0
  64. package/dist/services/GatewayClient.js +411 -0
  65. package/dist/services/GatewayClient.js.map +1 -0
  66. package/dist/services/StreamingResponseConsumer.d.ts +28 -0
  67. package/dist/services/StreamingResponseConsumer.d.ts.map +1 -0
  68. package/dist/services/StreamingResponseConsumer.js +58 -0
  69. package/dist/services/StreamingResponseConsumer.js.map +1 -0
  70. package/dist/services/TelemetryClient.d.ts +116 -0
  71. package/dist/services/TelemetryClient.d.ts.map +1 -0
  72. package/dist/services/TelemetryClient.js +234 -0
  73. package/dist/services/TelemetryClient.js.map +1 -0
  74. package/dist/testing/MockGatewayClient.d.ts +51 -0
  75. package/dist/testing/MockGatewayClient.d.ts.map +1 -0
  76. package/dist/testing/MockGatewayClient.js +84 -0
  77. package/dist/testing/MockGatewayClient.js.map +1 -0
  78. package/dist/testing/fixtures.d.ts +49 -0
  79. package/dist/testing/fixtures.d.ts.map +1 -0
  80. package/dist/testing/fixtures.js +59 -0
  81. package/dist/testing/fixtures.js.map +1 -0
  82. package/dist/tiers/capabilities.d.ts +18 -0
  83. package/dist/tiers/capabilities.d.ts.map +1 -0
  84. package/dist/tiers/capabilities.js +99 -0
  85. package/dist/tiers/capabilities.js.map +1 -0
  86. package/dist/types/fetcher.d.ts +59 -0
  87. package/dist/types/fetcher.d.ts.map +1 -0
  88. package/dist/types/fetcher.js +15 -0
  89. package/dist/types/fetcher.js.map +1 -0
  90. package/dist/types/flow.d.ts +190 -0
  91. package/dist/types/flow.d.ts.map +1 -0
  92. package/dist/types/flow.js +24 -0
  93. package/dist/types/flow.js.map +1 -0
  94. package/dist/types/index.d.ts +707 -0
  95. package/dist/types/index.d.ts.map +1 -0
  96. package/dist/types/index.js +13 -0
  97. package/dist/types/index.js.map +1 -0
  98. package/dist/utils/requestContext.d.ts +42 -0
  99. package/dist/utils/requestContext.d.ts.map +1 -0
  100. package/dist/utils/requestContext.js +56 -0
  101. package/dist/utils/requestContext.js.map +1 -0
  102. package/dist/utils/validation.d.ts +25 -0
  103. package/dist/utils/validation.d.ts.map +1 -0
  104. package/dist/utils/validation.js +31 -0
  105. package/dist/utils/validation.js.map +1 -0
  106. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Align Technologies Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ /**
3
+ * Read-only personal Confluence fetcher (API v2): pages the token can read.
4
+ * OAuth (cloudId) or basic-auth (domain+email). Author = the page author.
5
+ */
6
+ export declare class ConfluenceFetcher implements ConnectorFetcher {
7
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
8
+ }
9
+ //# sourceMappingURL=confluence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confluence.d.ts","sourceRoot":"","sources":["../../src/fetchers/confluence.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAuClG;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,gBAAgB;IAClD,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CA0DnE"}
@@ -0,0 +1,89 @@
1
+ import { fetch } from 'undici';
2
+ import { FetcherAuthError } from './errors.js';
3
+ function stripHtml(html) {
4
+ return html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
5
+ }
6
+ /** Resolve a Confluence accountId to a display name (cached). Degrades to undefined
7
+ * if the token lacks read:confluence-user or the lookup fails. */
8
+ function makeConfluenceUserResolver(base, headers) {
9
+ const cache = new Map();
10
+ return async (accountId) => {
11
+ if (!accountId)
12
+ return undefined;
13
+ if (cache.has(accountId))
14
+ return cache.get(accountId) ?? undefined;
15
+ try {
16
+ const res = await fetch(`${base}/rest/api/user?accountId=${encodeURIComponent(accountId)}`, { headers });
17
+ if (!res.ok) {
18
+ cache.set(accountId, null);
19
+ return undefined;
20
+ }
21
+ const u = (await res.json());
22
+ const name = u.displayName || u.publicName;
23
+ const resolved = name ? { name, ...(u.email ? { email: u.email } : {}) } : null;
24
+ cache.set(accountId, resolved);
25
+ return resolved ?? undefined;
26
+ }
27
+ catch {
28
+ cache.set(accountId, null);
29
+ return undefined;
30
+ }
31
+ };
32
+ }
33
+ /**
34
+ * Read-only personal Confluence fetcher (API v2): pages the token can read.
35
+ * OAuth (cloudId) or basic-auth (domain+email). Author = the page author.
36
+ */
37
+ export class ConfluenceFetcher {
38
+ async fetch(opts) {
39
+ const cloudId = opts.cloudId;
40
+ const siteBase = opts.siteBase;
41
+ const email = opts.email;
42
+ const domain = opts.domain;
43
+ const isOAuth = Boolean(cloudId);
44
+ const base = isOAuth
45
+ ? `https://api.atlassian.com/ex/confluence/${cloudId}/wiki`
46
+ : `https://${domain}/wiki`;
47
+ const headers = isOAuth
48
+ ? { Authorization: `Bearer ${opts.token}`, Accept: 'application/json' }
49
+ : {
50
+ Authorization: `Basic ${Buffer.from(`${email}:${opts.token}`).toString('base64')}`,
51
+ Accept: 'application/json',
52
+ };
53
+ const limit = opts.limit ?? 50;
54
+ const url = `${base}/api/v2/pages?limit=${limit}&body-format=storage`;
55
+ const res = await fetch(url, { headers });
56
+ if (!res.ok) {
57
+ if (res.status === 401)
58
+ throw new FetcherAuthError('Confluence');
59
+ if (res.status === 403) {
60
+ throw new Error('Confluence access denied (403): the token lacks Confluence scopes or this site has no Confluence. ' +
61
+ "Re-auth won't help - check the Atlassian app's Confluence API permissions (or skip Confluence).");
62
+ }
63
+ throw new Error(`Confluence API failed (${res.status}). ${isOAuth ? 'Check your OAuth token.' : 'Check your email, token, and domain.'}`);
64
+ }
65
+ const data = (await res.json());
66
+ const humanBase = isOAuth
67
+ ? (siteBase ?? `https://api.atlassian.com/ex/confluence/${cloudId}`)
68
+ : `https://${domain}`;
69
+ const linkBase = data._links?.base ?? `${humanBase}/wiki`;
70
+ const resolveUser = makeConfluenceUserResolver(base, headers);
71
+ const items = [];
72
+ for (const page of data.results ?? []) {
73
+ const bodyHtml = page.body?.storage?.value ?? '';
74
+ const bodyText = stripHtml(bodyHtml).slice(0, 2000);
75
+ const webui = page._links?.webui ?? '';
76
+ const pageUrl = webui.startsWith('http') ? webui : `${linkBase}${webui}`;
77
+ const author = await resolveUser(page.authorId);
78
+ items.push({
79
+ source_url: pageUrl,
80
+ platform: 'confluence',
81
+ raw_text: [page.title, bodyText].filter(Boolean).join('\n\n'),
82
+ title: page.title,
83
+ ...(author ? { author } : {}),
84
+ });
85
+ }
86
+ return items;
87
+ }
88
+ }
89
+ //# sourceMappingURL=confluence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confluence.js","sourceRoot":"","sources":["../../src/fetchers/confluence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Thrown by a fetcher when the provider returns 401 (token expired/revoked) -
3
+ * i.e. re-authenticating would help. Callers (e.g. the CLI) can catch this to
4
+ * trigger a reconnect flow, vs. a generic Error (403 / lacking scopes) where
5
+ * re-auth won't help.
6
+ */
7
+ export declare class FetcherAuthError extends Error {
8
+ readonly connector: string;
9
+ constructor(connector: string);
10
+ }
11
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/fetchers/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aACb,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAI9C"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Thrown by a fetcher when the provider returns 401 (token expired/revoked) -
3
+ * i.e. re-authenticating would help. Callers (e.g. the CLI) can catch this to
4
+ * trigger a reconnect flow, vs. a generic Error (403 / lacking scopes) where
5
+ * re-auth won't help.
6
+ */
7
+ export class FetcherAuthError extends Error {
8
+ connector;
9
+ constructor(connector) {
10
+ super(`${connector} authentication expired or revoked`);
11
+ this.connector = connector;
12
+ this.name = 'FetcherAuthError';
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/fetchers/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACb;IAA5B,YAA4B,SAAiB;QAC3C,KAAK,CAAC,GAAG,SAAS,oCAAoC,CAAC,CAAC;QAD9B,cAAS,GAAT,SAAS,CAAQ;QAE3C,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ import { type GitCommit } from './util/git.js';
3
+ export type { GitCommit } from './util/git.js';
4
+ /**
5
+ * The git I/O the {@link GitFetcher} needs, injected by the caller (e.g. the CLI
6
+ * wraps `git log` / `git remote` via execa). Keeps connector-core process-free.
7
+ */
8
+ export interface GitCommitSource {
9
+ getCommitHistory(opts: {
10
+ limit: number;
11
+ }): Promise<GitCommit[]>;
12
+ getRemoteUrl(): Promise<string | null | undefined>;
13
+ }
14
+ /**
15
+ * Read-only local-git fetcher: maps decision-relevant commits to FetcherItems.
16
+ * Author = the commit author ("who to talk to"). `token` is unused (local).
17
+ */
18
+ export declare class GitFetcher implements ConnectorFetcher {
19
+ private readonly source;
20
+ constructor(source: GitCommitSource);
21
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
22
+ }
23
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/fetchers/git.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAEnF,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAChE,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACpD;AAED;;;GAGG;AACH,qBAAa,UAAW,YAAW,gBAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAE9C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAenE"}
@@ -0,0 +1,27 @@
1
+ import { buildCommitUrl, formatCommitAsText } from './util/git.js';
2
+ /**
3
+ * Read-only local-git fetcher: maps decision-relevant commits to FetcherItems.
4
+ * Author = the commit author ("who to talk to"). `token` is unused (local).
5
+ */
6
+ export class GitFetcher {
7
+ source;
8
+ constructor(source) {
9
+ this.source = source;
10
+ }
11
+ async fetch(opts) {
12
+ const limit = opts.limit ?? 100;
13
+ const commits = await this.source.getCommitHistory({ limit });
14
+ const remoteUrl = await this.source.getRemoteUrl();
15
+ return commits.map((c) => {
16
+ const url = buildCommitUrl(remoteUrl, c.sha);
17
+ return {
18
+ source_url: url,
19
+ platform: 'git',
20
+ raw_text: formatCommitAsText(c, url),
21
+ title: c.subject,
22
+ ...(c.author ? { author: { name: c.author } } : {}),
23
+ };
24
+ });
25
+ }
26
+ }
27
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/fetchers/git.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAkB,MAAM,eAAe,CAAC;AAanF;;;GAGG;AACH,MAAM,OAAO,UAAU;IACQ;IAA7B,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD,KAAK,CAAC,KAAK,CAAC,IAA6B;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACvB,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;YAC7C,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,QAAQ,EAAE,KAAK;gBACf,QAAQ,EAAE,kBAAkB,CAAC,CAAC,EAAE,GAAG,CAAC;gBACpC,KAAK,EAAE,CAAC,CAAC,OAAO;gBAChB,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9B,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ /**
3
+ * Read-only personal GitHub fetcher: the caller's merged PRs and issues they
4
+ * commented on. Author = the PR/issue user ("who to talk to").
5
+ */
6
+ export declare class GitHubFetcher implements ConnectorFetcher {
7
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
8
+ }
9
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/fetchers/github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWlG;;;GAGG;AACH,qBAAa,aAAc,YAAW,gBAAgB;IAC9C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAwDnE"}
@@ -0,0 +1,53 @@
1
+ import { fetch } from 'undici';
2
+ /**
3
+ * Read-only personal GitHub fetcher: the caller's merged PRs and issues they
4
+ * commented on. Author = the PR/issue user ("who to talk to").
5
+ */
6
+ export class GitHubFetcher {
7
+ async fetch(opts) {
8
+ const headers = {
9
+ Authorization: `Bearer ${opts.token}`,
10
+ Accept: 'application/vnd.github+json',
11
+ 'X-GitHub-Api-Version': '2022-11-28',
12
+ };
13
+ const userRes = await fetch('https://api.github.com/user', { headers });
14
+ if (!userRes.ok) {
15
+ throw new Error(`GitHub auth failed (${userRes.status}). Check your token has 'repo' scope.`);
16
+ }
17
+ const user = (await userRes.json());
18
+ const limit = opts.limit ?? 100;
19
+ const items = [];
20
+ const prRes = await fetch(`https://api.github.com/search/issues?q=author:${user.login}+type:pr+is:merged&sort=updated&per_page=${Math.min(limit, 50)}`, { headers });
21
+ if (prRes.ok) {
22
+ const data = (await prRes.json());
23
+ for (const pr of data.items) {
24
+ const repo = (pr.repository_url ?? '').replace('https://api.github.com/repos/', '');
25
+ items.push({
26
+ source_url: pr.html_url,
27
+ platform: 'github',
28
+ raw_text: `${pr.title}\n\n${pr.body ?? ''}\n\nStatus: ${pr.state}\nRepo: ${repo}`.trim(),
29
+ title: pr.title,
30
+ ...(pr.user ? { author: { name: pr.user.login, handle: pr.user.login, url: pr.user.html_url } } : {}),
31
+ });
32
+ }
33
+ }
34
+ if (items.length < limit) {
35
+ const remaining = Math.min(limit - items.length, 50);
36
+ const issueRes = await fetch(`https://api.github.com/search/issues?q=commenter:${user.login}+type:issue&sort=updated&per_page=${remaining}`, { headers });
37
+ if (issueRes.ok) {
38
+ const data = (await issueRes.json());
39
+ for (const issue of data.items) {
40
+ items.push({
41
+ source_url: issue.html_url,
42
+ platform: 'github',
43
+ raw_text: `${issue.title}\n\n${issue.body ?? ''}\n\nStatus: ${issue.state}`.trim(),
44
+ title: issue.title,
45
+ ...(issue.user ? { author: { name: issue.user.login, handle: issue.user.login, url: issue.user.html_url } } : {}),
46
+ });
47
+ }
48
+ }
49
+ }
50
+ return items.slice(0, limit);
51
+ }
52
+ }
53
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/fetchers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAY/B;;;GAGG;AACH,MAAM,OAAO,aAAa;IACxB,KAAK,CAAC,KAAK,CAAC,IAA6B;QACvC,MAAM,OAAO,GAAG;YACd,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;YACrC,MAAM,EAAE,6BAA6B;YACrC,sBAAsB,EAAE,YAAY;SACrC,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,6BAA6B,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,CAAC,MAAM,uCAAuC,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAsB,CAAC;QAEzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;QAChC,MAAM,KAAK,GAAkB,EAAE,CAAC;QAEhC,MAAM,KAAK,GAAG,MAAM,KAAK,CACvB,iDAAiD,IAAI,CAAC,KAAK,4CAA4C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,EAC5H,EAAE,OAAO,EAAE,CACZ,CAAC;QACF,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAkC,CAAC;YACnE,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;gBACpF,KAAK,CAAC,IAAI,CAAC;oBACT,UAAU,EAAE,EAAE,CAAC,QAAQ;oBACvB,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,IAAI,IAAI,EAAE,eAAe,EAAE,CAAC,KAAK,WAAW,IAAI,EAAE,CAAC,IAAI,EAAE;oBACxF,KAAK,EAAE,EAAE,CAAC,KAAK;oBACf,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtG,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACrD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,oDAAoD,IAAI,CAAC,KAAK,qCAAqC,SAAS,EAAE,EAC9G,EAAE,OAAO,EAAE,CACZ,CAAC;YACF,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkC,CAAC;gBACtE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC;wBACT,UAAU,EAAE,KAAK,CAAC,QAAQ;wBAC1B,QAAQ,EAAE,QAAQ;wBAClB,QAAQ,EAAE,GAAG,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,IAAI,IAAI,EAAE,eAAe,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE;wBAClF,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAClH,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ /**
3
+ * Read-only personal GitLab fetcher: the caller's merged merge requests.
4
+ * `domain` (default gitlab.com) rides on the options index signature.
5
+ */
6
+ export declare class GitLabFetcher implements ConnectorFetcher {
7
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
8
+ }
9
+ //# sourceMappingURL=gitlab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/fetchers/gitlab.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASlG;;;GAGG;AACH,qBAAa,aAAc,YAAW,gBAAgB;IAC9C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAgCnE"}
@@ -0,0 +1,33 @@
1
+ import { fetch } from 'undici';
2
+ /**
3
+ * Read-only personal GitLab fetcher: the caller's merged merge requests.
4
+ * `domain` (default gitlab.com) rides on the options index signature.
5
+ */
6
+ export class GitLabFetcher {
7
+ async fetch(opts) {
8
+ const domain = opts.domain ?? 'gitlab.com';
9
+ const base = `https://${domain}/api/v4`;
10
+ const headers = { Authorization: `Bearer ${opts.token}` };
11
+ const userRes = await fetch(`${base}/user`, { headers });
12
+ if (!userRes.ok) {
13
+ throw new Error(`GitLab auth failed (${userRes.status}). Check your token has 'read_api' scope.`);
14
+ }
15
+ const user = (await userRes.json());
16
+ const limit = opts.limit ?? 100;
17
+ const items = [];
18
+ const mrRes = await fetch(`${base}/merge_requests?author_id=${user.id}&state=merged&per_page=${Math.min(limit, 50)}&order_by=updated_at`, { headers });
19
+ if (mrRes.ok) {
20
+ const mrs = (await mrRes.json());
21
+ for (const mr of mrs) {
22
+ items.push({
23
+ source_url: mr.web_url,
24
+ platform: 'gitlab',
25
+ raw_text: `${mr.title}\n\n${mr.description ?? ''}\n\nStatus: ${mr.state}`.trim(),
26
+ title: mr.title,
27
+ });
28
+ }
29
+ }
30
+ return items.slice(0, limit);
31
+ }
32
+ }
33
+ //# sourceMappingURL=gitlab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/fetchers/gitlab.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAU/B;;;GAGG;AACH,MAAM,OAAO,aAAa;IACxB,KAAK,CAAC,KAAK,CAAC,IAA6B;QACvC,MAAM,MAAM,GAAI,IAAI,CAAC,MAA6B,IAAI,YAAY,CAAC;QACnE,MAAM,IAAI,GAAG,WAAW,MAAM,SAAS,CAAC;QACxC,MAAM,OAAO,GAAG,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QAE1D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,CAAC,MAAM,2CAA2C,CAAC,CAAC;QACpG,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAmB,CAAC;QAEtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;QAChC,MAAM,KAAK,GAAkB,EAAE,CAAC;QAEhC,MAAM,KAAK,GAAG,MAAM,KAAK,CACvB,GAAG,IAAI,6BAA6B,IAAI,CAAC,EAAE,0BAA0B,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,EAC9G,EAAE,OAAO,EAAE,CACZ,CAAC;QACF,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAyB,CAAC;YACzD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC;oBACT,UAAU,EAAE,EAAE,CAAC,OAAO;oBACtB,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,WAAW,IAAI,EAAE,eAAe,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE;oBAChF,KAAK,EAAE,EAAE,CAAC,KAAK;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { ConnectorFetcher } from '../types/fetcher.js';
2
+ export { GitHubFetcher } from './github.js';
3
+ export { GitLabFetcher } from './gitlab.js';
4
+ export { JiraFetcher } from './jira.js';
5
+ export { ConfluenceFetcher } from './confluence.js';
6
+ export { SlackFetcher } from './slack.js';
7
+ export { TeamsFetcher } from './teams.js';
8
+ export { ZoomFetcher } from './zoom.js';
9
+ export { LinearFetcher } from './linear.js';
10
+ export { NotionFetcher } from './notion.js';
11
+ export { GitFetcher, type GitCommitSource, type GitCommit } from './git.js';
12
+ export { buildCommitUrl, formatCommitAsText } from './util/git.js';
13
+ export { FetcherAuthError } from './errors.js';
14
+ /**
15
+ * Registry of token-based read-only fetchers, keyed by platform. The CLI and the
16
+ * gateway discover scan both resolve fetchers from here. `git` is not registered
17
+ * because it needs an injected {@link GitCommitSource} (local process I/O).
18
+ */
19
+ export declare const FETCHERS: Record<string, () => ConnectorFetcher>;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fetchers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAW5D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,gBAAgB,CAU3D,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { GitHubFetcher } from './github.js';
2
+ import { GitLabFetcher } from './gitlab.js';
3
+ import { JiraFetcher } from './jira.js';
4
+ import { ConfluenceFetcher } from './confluence.js';
5
+ import { SlackFetcher } from './slack.js';
6
+ import { TeamsFetcher } from './teams.js';
7
+ import { ZoomFetcher } from './zoom.js';
8
+ import { LinearFetcher } from './linear.js';
9
+ import { NotionFetcher } from './notion.js';
10
+ export { GitHubFetcher } from './github.js';
11
+ export { GitLabFetcher } from './gitlab.js';
12
+ export { JiraFetcher } from './jira.js';
13
+ export { ConfluenceFetcher } from './confluence.js';
14
+ export { SlackFetcher } from './slack.js';
15
+ export { TeamsFetcher } from './teams.js';
16
+ export { ZoomFetcher } from './zoom.js';
17
+ export { LinearFetcher } from './linear.js';
18
+ export { NotionFetcher } from './notion.js';
19
+ export { GitFetcher } from './git.js';
20
+ export { buildCommitUrl, formatCommitAsText } from './util/git.js';
21
+ export { FetcherAuthError } from './errors.js';
22
+ /**
23
+ * Registry of token-based read-only fetchers, keyed by platform. The CLI and the
24
+ * gateway discover scan both resolve fetchers from here. `git` is not registered
25
+ * because it needs an injected {@link GitCommitSource} (local process I/O).
26
+ */
27
+ export const FETCHERS = {
28
+ github: () => new GitHubFetcher(),
29
+ gitlab: () => new GitLabFetcher(),
30
+ jira: () => new JiraFetcher(),
31
+ confluence: () => new ConfluenceFetcher(),
32
+ slack: () => new SlackFetcher(),
33
+ teams: () => new TeamsFetcher(),
34
+ zoom: () => new ZoomFetcher(),
35
+ linear: () => new LinearFetcher(),
36
+ notion: () => new NotionFetcher(),
37
+ };
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fetchers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwC,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAA2C;IAC9D,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;IACjC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;IACjC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,EAAE;IAC7B,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IACzC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;IAC/B,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;IAC/B,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,EAAE;IAC7B,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;IACjC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,aAAa,EAAE;CAClC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ /**
3
+ * Read-only personal Jira fetcher: issues assigned to or reported by the caller.
4
+ * OAuth (cloudId) or basic-auth (domain+email). Author = the issue reporter.
5
+ */
6
+ export declare class JiraFetcher implements ConnectorFetcher {
7
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
8
+ }
9
+ //# sourceMappingURL=jira.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/fetchers/jira.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAuBlG;;;GAGG;AACH,qBAAa,WAAY,YAAW,gBAAgB;IAC5C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CA8DnE"}
@@ -0,0 +1,73 @@
1
+ import { fetch } from 'undici';
2
+ import { FetcherAuthError } from './errors.js';
3
+ function extractAdfText(adf) {
4
+ if (!adf)
5
+ return '';
6
+ return (adf.content ?? [])
7
+ .flatMap((block) => (block.content ?? []).map((inline) => inline.text ?? ''))
8
+ .join(' ')
9
+ .trim();
10
+ }
11
+ /**
12
+ * Read-only personal Jira fetcher: issues assigned to or reported by the caller.
13
+ * OAuth (cloudId) or basic-auth (domain+email). Author = the issue reporter.
14
+ */
15
+ export class JiraFetcher {
16
+ async fetch(opts) {
17
+ const cloudId = opts.cloudId;
18
+ const siteBase = opts.siteBase;
19
+ const email = opts.email;
20
+ const domain = opts.domain;
21
+ const isOAuth = Boolean(cloudId);
22
+ const base = isOAuth ? `https://api.atlassian.com/ex/jira/${cloudId}` : `https://${domain}`;
23
+ const headers = isOAuth
24
+ ? { Authorization: `Bearer ${opts.token}`, Accept: 'application/json' }
25
+ : {
26
+ Authorization: `Basic ${Buffer.from(`${email}:${opts.token}`).toString('base64')}`,
27
+ Accept: 'application/json',
28
+ };
29
+ const limit = opts.limit ?? 100;
30
+ const jql = 'assignee = currentUser() OR reporter = currentUser() ORDER BY updated DESC';
31
+ const res = await fetch(`${base}/rest/api/3/search/jql`, {
32
+ method: 'POST',
33
+ headers: { ...headers, 'Content-Type': 'application/json' },
34
+ body: JSON.stringify({ jql, maxResults: limit, fields: ['summary', 'description', 'status', 'key', 'reporter'] }),
35
+ });
36
+ if (!res.ok) {
37
+ if (res.status === 401)
38
+ throw new FetcherAuthError('Jira');
39
+ if (res.status === 403) {
40
+ throw new Error("Jira access denied (403): the token lacks Jira scopes or access. Re-auth won't help - " +
41
+ "check the Atlassian app's Jira API permissions.");
42
+ }
43
+ const text = await res.text();
44
+ throw new Error(`Jira API failed (${res.status}): ${text.slice(0, 200)}`);
45
+ }
46
+ const data = (await res.json());
47
+ const browseBase = isOAuth ? (siteBase ?? `https://api.atlassian.com/ex/jira/${cloudId}`) : base;
48
+ return data.issues.map((issue) => {
49
+ const desc = extractAdfText(issue.fields.description);
50
+ return {
51
+ source_url: `${browseBase}/browse/${issue.key}`,
52
+ platform: 'jira',
53
+ raw_text: [
54
+ `[${issue.key}] ${issue.fields.summary}`,
55
+ desc,
56
+ issue.fields.status?.name ? `Status: ${issue.fields.status.name}` : '',
57
+ ]
58
+ .filter(Boolean)
59
+ .join('\n\n'),
60
+ title: `[${issue.key}] ${issue.fields.summary}`,
61
+ ...(issue.fields.reporter?.displayName
62
+ ? {
63
+ author: {
64
+ name: issue.fields.reporter.displayName,
65
+ ...(issue.fields.reporter.emailAddress ? { email: issue.fields.reporter.emailAddress } : {}),
66
+ },
67
+ }
68
+ : {}),
69
+ };
70
+ });
71
+ }
72
+ }
73
+ //# sourceMappingURL=jira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../src/fetchers/jira.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ConnectorFetcher, ConnectorFetcherOptions, FetcherItem } from '../types/fetcher.js';
2
+ /**
3
+ * Read-only personal Linear fetcher: the caller's assigned + created issues.
4
+ * Author = the issue creator ("who to talk to").
5
+ */
6
+ export declare class LinearFetcher implements ConnectorFetcher {
7
+ fetch(opts: ConnectorFetcherOptions): Promise<FetcherItem[]>;
8
+ }
9
+ //# sourceMappingURL=linear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/fetchers/linear.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiClG;;;GAGG;AACH,qBAAa,aAAc,YAAW,gBAAgB;IAC9C,KAAK,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAgDnE"}
@@ -0,0 +1,71 @@
1
+ import { fetch } from 'undici';
2
+ const LINEAR_GQL = 'https://api.linear.app/graphql';
3
+ const ISSUES_QUERY = `
4
+ query PersonalIssues($first: Int!) {
5
+ viewer {
6
+ assignedIssues(first: $first, orderBy: updatedAt) {
7
+ nodes {
8
+ id title description url
9
+ state { name }
10
+ team { name }
11
+ creator { name email }
12
+ comments { nodes { body user { name } } }
13
+ }
14
+ }
15
+ createdIssues(first: $first, orderBy: updatedAt) {
16
+ nodes { id title description url state { name } team { name } creator { name email } }
17
+ }
18
+ }
19
+ }`;
20
+ /**
21
+ * Read-only personal Linear fetcher: the caller's assigned + created issues.
22
+ * Author = the issue creator ("who to talk to").
23
+ */
24
+ export class LinearFetcher {
25
+ async fetch(opts) {
26
+ const limit = opts.limit ?? 50;
27
+ const res = await fetch(LINEAR_GQL, {
28
+ method: 'POST',
29
+ headers: { Authorization: `Bearer ${opts.token}`, 'Content-Type': 'application/json' },
30
+ body: JSON.stringify({ query: ISSUES_QUERY, variables: { first: limit } }),
31
+ });
32
+ if (!res.ok)
33
+ throw new Error(`Linear API failed (${res.status}). Check your personal API token.`);
34
+ const data = (await res.json());
35
+ if (data.errors?.length)
36
+ throw new Error(data.errors[0].message);
37
+ const seen = new Set();
38
+ const items = [];
39
+ const allIssues = [
40
+ ...(data.data.viewer.assignedIssues?.nodes ?? []),
41
+ ...(data.data.viewer.createdIssues?.nodes ?? []),
42
+ ];
43
+ for (const issue of allIssues) {
44
+ if (seen.has(issue.id))
45
+ continue;
46
+ seen.add(issue.id);
47
+ const comments = (issue.comments?.nodes ?? [])
48
+ .map((c) => `${c.user?.name ?? 'Unknown'}: ${c.body}`)
49
+ .join('\n');
50
+ items.push({
51
+ source_url: issue.url,
52
+ platform: 'linear',
53
+ raw_text: [
54
+ issue.title,
55
+ issue.description ?? '',
56
+ issue.team?.name ? `Team: ${issue.team.name}` : '',
57
+ issue.state?.name ? `Status: ${issue.state.name}` : '',
58
+ comments ? `Comments:\n${comments}` : '',
59
+ ]
60
+ .filter(Boolean)
61
+ .join('\n\n'),
62
+ title: issue.title,
63
+ ...(issue.creator?.name
64
+ ? { author: { name: issue.creator.name, ...(issue.creator.email ? { email: issue.creator.email } : {}) } }
65
+ : {}),
66
+ });
67
+ }
68
+ return items.slice(0, limit);
69
+ }
70
+ }
71
+ //# sourceMappingURL=linear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear.js","sourceRoot":"","sources":["../../src/fetchers/linear.ts"],"names":[],"mappings":"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"}