hippo-memory 1.2.1 → 1.3.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 (108) hide show
  1. package/README.md +17 -0
  2. package/dist/cli.js +10 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/connectors/github/backfill.d.ts +48 -0
  5. package/dist/connectors/github/backfill.d.ts.map +1 -0
  6. package/dist/connectors/github/backfill.js +272 -0
  7. package/dist/connectors/github/backfill.js.map +1 -0
  8. package/dist/connectors/github/cli-impl.d.ts +24 -0
  9. package/dist/connectors/github/cli-impl.d.ts.map +1 -0
  10. package/dist/connectors/github/cli-impl.js +192 -0
  11. package/dist/connectors/github/cli-impl.js.map +1 -0
  12. package/dist/connectors/github/deletion.d.ts +43 -0
  13. package/dist/connectors/github/deletion.d.ts.map +1 -0
  14. package/dist/connectors/github/deletion.js +83 -0
  15. package/dist/connectors/github/deletion.js.map +1 -0
  16. package/dist/connectors/github/dlq.d.ts +108 -0
  17. package/dist/connectors/github/dlq.d.ts.map +1 -0
  18. package/dist/connectors/github/dlq.js +182 -0
  19. package/dist/connectors/github/dlq.js.map +1 -0
  20. package/dist/connectors/github/idempotency.d.ts +19 -0
  21. package/dist/connectors/github/idempotency.d.ts.map +1 -0
  22. package/dist/connectors/github/idempotency.js +25 -0
  23. package/dist/connectors/github/idempotency.js.map +1 -0
  24. package/dist/connectors/github/ingest.d.ts +67 -0
  25. package/dist/connectors/github/ingest.d.ts.map +1 -0
  26. package/dist/connectors/github/ingest.js +138 -0
  27. package/dist/connectors/github/ingest.js.map +1 -0
  28. package/dist/connectors/github/octokit-client.d.ts +36 -0
  29. package/dist/connectors/github/octokit-client.d.ts.map +1 -0
  30. package/dist/connectors/github/octokit-client.js +65 -0
  31. package/dist/connectors/github/octokit-client.js.map +1 -0
  32. package/dist/connectors/github/ratelimit.d.ts +20 -0
  33. package/dist/connectors/github/ratelimit.d.ts.map +1 -0
  34. package/dist/connectors/github/ratelimit.js +31 -0
  35. package/dist/connectors/github/ratelimit.js.map +1 -0
  36. package/dist/connectors/github/scope.d.ts +8 -0
  37. package/dist/connectors/github/scope.d.ts.map +1 -0
  38. package/dist/connectors/github/scope.js +13 -0
  39. package/dist/connectors/github/scope.js.map +1 -0
  40. package/dist/connectors/github/signature.d.ts +47 -0
  41. package/dist/connectors/github/signature.d.ts.map +1 -0
  42. package/dist/connectors/github/signature.js +58 -0
  43. package/dist/connectors/github/signature.js.map +1 -0
  44. package/dist/connectors/github/tenant-routing.d.ts +33 -0
  45. package/dist/connectors/github/tenant-routing.d.ts.map +1 -0
  46. package/dist/connectors/github/tenant-routing.js +61 -0
  47. package/dist/connectors/github/tenant-routing.js.map +1 -0
  48. package/dist/connectors/github/transform.d.ts +7 -0
  49. package/dist/connectors/github/transform.d.ts.map +1 -0
  50. package/dist/connectors/github/transform.js +103 -0
  51. package/dist/connectors/github/transform.js.map +1 -0
  52. package/dist/connectors/github/types.d.ts +87 -0
  53. package/dist/connectors/github/types.d.ts.map +1 -0
  54. package/dist/connectors/github/types.js +94 -0
  55. package/dist/connectors/github/types.js.map +1 -0
  56. package/dist/db.d.ts.map +1 -1
  57. package/dist/db.js +94 -1
  58. package/dist/db.js.map +1 -1
  59. package/dist/mcp/server.d.ts.map +1 -1
  60. package/dist/mcp/server.js +5 -4
  61. package/dist/mcp/server.js.map +1 -1
  62. package/dist/server.d.ts.map +1 -1
  63. package/dist/server.js +313 -2
  64. package/dist/server.js.map +1 -1
  65. package/dist/src/cli.js +10 -0
  66. package/dist/src/cli.js.map +1 -1
  67. package/dist/src/connectors/github/backfill.js +272 -0
  68. package/dist/src/connectors/github/backfill.js.map +1 -0
  69. package/dist/src/connectors/github/cli-impl.js +192 -0
  70. package/dist/src/connectors/github/cli-impl.js.map +1 -0
  71. package/dist/src/connectors/github/deletion.js +83 -0
  72. package/dist/src/connectors/github/deletion.js.map +1 -0
  73. package/dist/src/connectors/github/dlq.js +182 -0
  74. package/dist/src/connectors/github/dlq.js.map +1 -0
  75. package/dist/src/connectors/github/idempotency.js +25 -0
  76. package/dist/src/connectors/github/idempotency.js.map +1 -0
  77. package/dist/src/connectors/github/ingest.js +138 -0
  78. package/dist/src/connectors/github/ingest.js.map +1 -0
  79. package/dist/src/connectors/github/octokit-client.js +65 -0
  80. package/dist/src/connectors/github/octokit-client.js.map +1 -0
  81. package/dist/src/connectors/github/ratelimit.js +31 -0
  82. package/dist/src/connectors/github/ratelimit.js.map +1 -0
  83. package/dist/src/connectors/github/scope.js +13 -0
  84. package/dist/src/connectors/github/scope.js.map +1 -0
  85. package/dist/src/connectors/github/signature.js +58 -0
  86. package/dist/src/connectors/github/signature.js.map +1 -0
  87. package/dist/src/connectors/github/tenant-routing.js +61 -0
  88. package/dist/src/connectors/github/tenant-routing.js.map +1 -0
  89. package/dist/src/connectors/github/transform.js +103 -0
  90. package/dist/src/connectors/github/transform.js.map +1 -0
  91. package/dist/src/connectors/github/types.js +94 -0
  92. package/dist/src/connectors/github/types.js.map +1 -0
  93. package/dist/src/db.js +94 -1
  94. package/dist/src/db.js.map +1 -1
  95. package/dist/src/mcp/server.js +5 -4
  96. package/dist/src/mcp/server.js.map +1 -1
  97. package/dist/src/server.js +313 -2
  98. package/dist/src/server.js.map +1 -1
  99. package/dist/src/version.js +35 -0
  100. package/dist/src/version.js.map +1 -0
  101. package/dist/version.d.ts +25 -0
  102. package/dist/version.d.ts.map +1 -0
  103. package/dist/version.js +35 -0
  104. package/dist/version.js.map +1 -0
  105. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  106. package/extensions/openclaw-plugin/package.json +1 -1
  107. package/openclaw.plugin.json +1 -1
  108. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../../src/connectors/github/ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Octokit-shaped HTTP fetcher for the GitHub connector backfill.
3
+ *
4
+ * Production uses `realGitHubFetcher` against `https://api.github.com`.
5
+ * Tests inject a fake `GitHubFetcher` so they never hit the network.
6
+ *
7
+ * Codex P1 #4 mandate: any non-200 response that is NOT a recognized
8
+ * rate-limit pause MUST throw `GitHubFetchError`. Silently turning
9
+ * 401/403/404/500 into empty pages produced empty backfills with no
10
+ * operator signal, so this code path is now load-bearing.
11
+ */
12
+ import { type RateLimitInfo } from './ratelimit.js';
13
+ export declare class GitHubFetchError extends Error {
14
+ readonly status: number;
15
+ readonly bodyExcerpt: string;
16
+ readonly url: string;
17
+ constructor(status: number, bodyExcerpt: string, url: string);
18
+ }
19
+ export interface GitHubBackfillPage {
20
+ readonly items: ReadonlyArray<unknown>;
21
+ readonly next: string | null;
22
+ readonly rateLimit: RateLimitInfo;
23
+ }
24
+ export type GitHubFetcher = (args: {
25
+ url: string;
26
+ token: string;
27
+ }) => Promise<GitHubBackfillPage>;
28
+ /**
29
+ * Parse the rel="next" URL from an RFC 5988 `Link` header.
30
+ *
31
+ * Header format: `<url1>; rel="next", <url2>; rel="last"`.
32
+ * Returns the URL whose rel parameter is exactly `"next"`, or null.
33
+ */
34
+ export declare function parseNextLink(linkHeader: string): string | null;
35
+ export declare const realGitHubFetcher: GitHubFetcher;
36
+ //# sourceMappingURL=octokit-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"octokit-client.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/octokit-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM;gBAFX,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM;CAKvB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;CACnC;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK/D;AAUD,eAAO,MAAM,iBAAiB,EAAE,aAsB/B,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Octokit-shaped HTTP fetcher for the GitHub connector backfill.
3
+ *
4
+ * Production uses `realGitHubFetcher` against `https://api.github.com`.
5
+ * Tests inject a fake `GitHubFetcher` so they never hit the network.
6
+ *
7
+ * Codex P1 #4 mandate: any non-200 response that is NOT a recognized
8
+ * rate-limit pause MUST throw `GitHubFetchError`. Silently turning
9
+ * 401/403/404/500 into empty pages produced empty backfills with no
10
+ * operator signal, so this code path is now load-bearing.
11
+ */
12
+ import { parseRateLimit } from './ratelimit.js';
13
+ export class GitHubFetchError extends Error {
14
+ status;
15
+ bodyExcerpt;
16
+ url;
17
+ constructor(status, bodyExcerpt, url) {
18
+ super(`GitHub ${status} on ${url}: ${bodyExcerpt}`);
19
+ this.status = status;
20
+ this.bodyExcerpt = bodyExcerpt;
21
+ this.url = url;
22
+ this.name = 'GitHubFetchError';
23
+ }
24
+ }
25
+ /**
26
+ * Parse the rel="next" URL from an RFC 5988 `Link` header.
27
+ *
28
+ * Header format: `<url1>; rel="next", <url2>; rel="last"`.
29
+ * Returns the URL whose rel parameter is exactly `"next"`, or null.
30
+ */
31
+ export function parseNextLink(linkHeader) {
32
+ if (!linkHeader)
33
+ return null;
34
+ const re = /<([^>]+)>\s*;\s*rel="next"/;
35
+ const m = linkHeader.match(re);
36
+ return m ? m[1] : null;
37
+ }
38
+ function headersToRecord(h) {
39
+ const out = {};
40
+ h.forEach((v, k) => {
41
+ out[k.toLowerCase()] = v;
42
+ });
43
+ return out;
44
+ }
45
+ export const realGitHubFetcher = async ({ url, token }) => {
46
+ const res = await fetch(url, {
47
+ headers: {
48
+ Authorization: `Bearer ${token}`,
49
+ Accept: 'application/vnd.github+json',
50
+ 'X-GitHub-Api-Version': '2022-11-28',
51
+ },
52
+ });
53
+ const headers = headersToRecord(res.headers);
54
+ const rateLimit = parseRateLimit(headers, res.status);
55
+ // Codex P1 #4: don't silently turn 401/403/404/500 into empty pages.
56
+ if (res.status !== 200 && rateLimit.reason === 'none') {
57
+ const body = await res.text().catch(() => '');
58
+ throw new GitHubFetchError(res.status, body.slice(0, 256), url);
59
+ }
60
+ const items = res.status === 200 ? (await res.json()) : [];
61
+ const link = res.headers.get('link') ?? '';
62
+ const next = parseNextLink(link);
63
+ return { items, next, rateLimit };
64
+ };
65
+ //# sourceMappingURL=octokit-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"octokit-client.js","sourceRoot":"","sources":["../../../src/connectors/github/octokit-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAsB,MAAM,gBAAgB,CAAC;AAEpE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAE9B;IACA;IACA;IAHX,YACW,MAAc,EACd,WAAmB,EACnB,GAAW;QAEpB,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,KAAK,WAAW,EAAE,CAAC,CAAC;QAJ3C,WAAM,GAAN,MAAM,CAAQ;QACd,gBAAW,GAAX,WAAW,CAAQ;QACnB,QAAG,GAAH,GAAG,CAAQ;QAGpB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAaD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,EAAE,GAAG,4BAA4B,CAAC;IACxC,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,CAAU;IACjC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjB,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAkB,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;IACvE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,MAAM,EAAE,6BAA6B;YACrC,sBAAsB,EAAE,YAAY;SACrC;KACF,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAEtD,qEAAqE;IACrE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,KAAK,GACT,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AACpC,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * GitHub rate-limit header parser.
3
+ *
4
+ * GitHub returns 403 for primary rate-limit (with `X-RateLimit-Remaining: 0`
5
+ * and `X-RateLimit-Reset: <epoch>`) and 429 + `Retry-After: <seconds>` for
6
+ * secondary rate-limit. Backfill must pause and resume rather than error.
7
+ */
8
+ export interface RateLimitInfo {
9
+ readonly sleepSeconds: number;
10
+ readonly reason: 'primary' | 'secondary' | 'none';
11
+ }
12
+ /**
13
+ * Parse rate-limit signal from a GitHub HTTP response.
14
+ *
15
+ * @param headers Lower-cased HTTP response headers.
16
+ * @param status HTTP status code.
17
+ * @param now Optional current epoch seconds (for deterministic tests).
18
+ */
19
+ export declare function parseRateLimit(headers: Record<string, string | undefined>, status: number, now?: number): RateLimitInfo;
20
+ //# sourceMappingURL=ratelimit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratelimit.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/ratelimit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC3C,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,aAAa,CAkBf"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * GitHub rate-limit header parser.
3
+ *
4
+ * GitHub returns 403 for primary rate-limit (with `X-RateLimit-Remaining: 0`
5
+ * and `X-RateLimit-Reset: <epoch>`) and 429 + `Retry-After: <seconds>` for
6
+ * secondary rate-limit. Backfill must pause and resume rather than error.
7
+ */
8
+ /**
9
+ * Parse rate-limit signal from a GitHub HTTP response.
10
+ *
11
+ * @param headers Lower-cased HTTP response headers.
12
+ * @param status HTTP status code.
13
+ * @param now Optional current epoch seconds (for deterministic tests).
14
+ */
15
+ export function parseRateLimit(headers, status, now) {
16
+ const _now = now ?? Math.floor(Date.now() / 1000);
17
+ if (status === 429) {
18
+ const retry = Number(headers['retry-after'] ?? '60');
19
+ return {
20
+ sleepSeconds: Number.isFinite(retry) && retry >= 0 ? retry : 60,
21
+ reason: 'secondary',
22
+ };
23
+ }
24
+ if (status === 403 && Number(headers['x-ratelimit-remaining'] ?? '1') === 0) {
25
+ const reset = Number(headers['x-ratelimit-reset'] ?? '0');
26
+ const diff = reset - _now;
27
+ return { sleepSeconds: Math.max(diff, 1), reason: 'primary' };
28
+ }
29
+ return { sleepSeconds: 0, reason: 'none' };
30
+ }
31
+ //# sourceMappingURL=ratelimit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratelimit.js","sourceRoot":"","sources":["../../../src/connectors/github/ratelimit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,OAA2C,EAC3C,MAAc,EACd,GAAY;IAEZ,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAElD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,CAAC;QACrD,OAAO;YACL,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YAC/D,MAAM,EAAE,WAAW;SACpB,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC;QAC1B,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAChE,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { GitHubRepository } from './types.js';
2
+ /**
3
+ * Map a GitHub repository to a hippo scope string. Default-private when
4
+ * privacy is undetermined: cost of leaking public into private (recall returns
5
+ * nothing) << cost of leaking private into public (data exposure).
6
+ */
7
+ export declare function scopeFromRepository(repo: GitHubRepository | undefined): string;
8
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,MAAM,CAI9E"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Map a GitHub repository to a hippo scope string. Default-private when
3
+ * privacy is undetermined: cost of leaking public into private (recall returns
4
+ * nothing) << cost of leaking private into public (data exposure).
5
+ */
6
+ export function scopeFromRepository(repo) {
7
+ if (!repo)
8
+ return 'github:private:unknown';
9
+ if (repo.private === false)
10
+ return `github:public:${repo.full_name}`;
11
+ return `github:private:${repo.full_name}`;
12
+ }
13
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../../src/connectors/github/scope.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAkC;IACpE,IAAI,CAAC,IAAI;QAAE,OAAO,wBAAwB,CAAC;IAC3C,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,iBAAiB,IAAI,CAAC,SAAS,EAAE,CAAC;IACrE,OAAO,kBAAkB,IAAI,CAAC,SAAS,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,47 @@
1
+ export interface VerifyOpts {
2
+ rawBody: string;
3
+ /** Value of X-Hub-Signature-256, e.g. 'sha256=ab12...' */
4
+ signature: string;
5
+ webhookSecret: string;
6
+ /** Previous secret for rotation parity with Slack. Optional. */
7
+ previousSecret?: string;
8
+ }
9
+ export declare function verifyGitHubSignature(opts: VerifyOpts): boolean;
10
+ /**
11
+ * Source-aware idempotency key. v1.3.1 hotfix (codex round 1 P0 #3 + claude
12
+ * round 2 P0 #3).
13
+ *
14
+ * Round 1 design: sha256(eventName + ':' + rawBody) so an attacker rotating
15
+ * X-GitHub-Delivery cannot bypass dedupe.
16
+ *
17
+ * Round 2 found that key produced different hashes for the SAME source event
18
+ * delivered via webhook vs via REST backfill, because backfill rawBody is the
19
+ * REST list-item shape while webhook rawBody is the envelope. Result:
20
+ * backfill + later webhook of the same issue created two `kind='raw'` rows
21
+ * with the same artifact_ref. Combined with the deletion bug, deletion could
22
+ * not archive both.
23
+ *
24
+ * v1.3.1 fix: key from the SOURCE-NORMALIZED identifier — artifact_ref plus
25
+ * the source-side updated_at timestamp. Same artifact + same revision = same
26
+ * key, regardless of which path delivered it. Different revisions of the same
27
+ * issue (an edit) get different keys, which is correct: each edit IS a new
28
+ * memory revision.
29
+ *
30
+ * Both inputs are upstream-derived from the parsed event, not from the
31
+ * unsigned delivery header — replay attacks still cannot bypass dedupe.
32
+ *
33
+ * Inputs:
34
+ * - artifactRef: e.g. 'github://acme/repo/issue/42' or
35
+ * 'github://acme/repo/issue/42/comment/123'.
36
+ * - updatedAt: source-side ISO timestamp (issue.updated_at,
37
+ * comment.updated_at, pull_request.updated_at). Empty string when the
38
+ * payload omits it (rare; older REST shapes).
39
+ *
40
+ * Migration note for v1.3.0 → v1.3.1: existing github_event_log rows from
41
+ * v1.3.0 used the round-1 key shape and will not collide with v1.3.1 keys.
42
+ * The first webhook delivery after upgrading creates a new log row with the
43
+ * new key. This is acceptable for a hotfix (no production users on v1.3.0)
44
+ * and correct semantics going forward.
45
+ */
46
+ export declare function computeIdempotencyKey(artifactRef: string, updatedAt: string | null | undefined): string;
47
+ //# sourceMappingURL=signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/signature.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAWD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAI/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEvG"}
@@ -0,0 +1,58 @@
1
+ import { createHmac, createHash, timingSafeEqual } from 'crypto';
2
+ function verifyOne(rawBody, signature, secret) {
3
+ if (!signature.startsWith('sha256='))
4
+ return false;
5
+ const expected = `sha256=${createHmac('sha256', secret).update(rawBody).digest('hex')}`;
6
+ const a = Buffer.from(signature, 'utf8');
7
+ const b = Buffer.from(expected, 'utf8');
8
+ if (a.length !== b.length)
9
+ return false;
10
+ return timingSafeEqual(a, b);
11
+ }
12
+ export function verifyGitHubSignature(opts) {
13
+ if (verifyOne(opts.rawBody, opts.signature, opts.webhookSecret))
14
+ return true;
15
+ if (opts.previousSecret && verifyOne(opts.rawBody, opts.signature, opts.previousSecret))
16
+ return true;
17
+ return false;
18
+ }
19
+ /**
20
+ * Source-aware idempotency key. v1.3.1 hotfix (codex round 1 P0 #3 + claude
21
+ * round 2 P0 #3).
22
+ *
23
+ * Round 1 design: sha256(eventName + ':' + rawBody) so an attacker rotating
24
+ * X-GitHub-Delivery cannot bypass dedupe.
25
+ *
26
+ * Round 2 found that key produced different hashes for the SAME source event
27
+ * delivered via webhook vs via REST backfill, because backfill rawBody is the
28
+ * REST list-item shape while webhook rawBody is the envelope. Result:
29
+ * backfill + later webhook of the same issue created two `kind='raw'` rows
30
+ * with the same artifact_ref. Combined with the deletion bug, deletion could
31
+ * not archive both.
32
+ *
33
+ * v1.3.1 fix: key from the SOURCE-NORMALIZED identifier — artifact_ref plus
34
+ * the source-side updated_at timestamp. Same artifact + same revision = same
35
+ * key, regardless of which path delivered it. Different revisions of the same
36
+ * issue (an edit) get different keys, which is correct: each edit IS a new
37
+ * memory revision.
38
+ *
39
+ * Both inputs are upstream-derived from the parsed event, not from the
40
+ * unsigned delivery header — replay attacks still cannot bypass dedupe.
41
+ *
42
+ * Inputs:
43
+ * - artifactRef: e.g. 'github://acme/repo/issue/42' or
44
+ * 'github://acme/repo/issue/42/comment/123'.
45
+ * - updatedAt: source-side ISO timestamp (issue.updated_at,
46
+ * comment.updated_at, pull_request.updated_at). Empty string when the
47
+ * payload omits it (rare; older REST shapes).
48
+ *
49
+ * Migration note for v1.3.0 → v1.3.1: existing github_event_log rows from
50
+ * v1.3.0 used the round-1 key shape and will not collide with v1.3.1 keys.
51
+ * The first webhook delivery after upgrading creates a new log row with the
52
+ * new key. This is acceptable for a hotfix (no production users on v1.3.0)
53
+ * and correct semantics going forward.
54
+ */
55
+ export function computeIdempotencyKey(artifactRef, updatedAt) {
56
+ return createHash('sha256').update(`${artifactRef}:${updatedAt ?? ''}`).digest('hex');
57
+ }
58
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../src/connectors/github/signature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAWjE,SAAS,SAAS,CAAC,OAAe,EAAE,SAAiB,EAAE,MAAc;IACnE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,MAAM,QAAQ,GAAG,UAAU,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACxF,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAgB;IACpD,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IACrG,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAmB,EAAE,SAAoC;IAC7F,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,WAAW,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxF,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { DatabaseSyncLike } from '../../db.js';
2
+ export interface ResolveArgs {
3
+ /** String form of `installation.id`. `null`/`undefined` means "no installation field" (PAT-mode webhook). */
4
+ installationId?: string | null;
5
+ /** `repository.full_name` from the webhook envelope, used for PAT-mode multi-tenant routing. */
6
+ repoFullName?: string | null;
7
+ }
8
+ /**
9
+ * Resolve the tenant_id for a GitHub webhook envelope.
10
+ *
11
+ * Returns:
12
+ * - mapped tenant_id when `github_installations` has a row for `installationId`
13
+ * (App-mode multi-tenant — primary path)
14
+ * - mapped tenant_id when `installation` is absent, `repository.full_name`
15
+ * matches a `github_repositories` row (PAT-mode multi-tenant)
16
+ * - the deployment's HIPPO_TENANT fallback (or 'default') when BOTH routing
17
+ * tables are empty (single-tenant deployment — env fallback is safe)
18
+ * - null when:
19
+ * - `installationId` is present but unknown AND `github_installations`
20
+ * is non-empty (multi-tenant install with foreign installation)
21
+ * - `installationId` is missing AND either routing table is non-empty
22
+ * AND no `repository.full_name` match (PAT-mode webhook from a foreign
23
+ * account — codex P0 #4 regression target)
24
+ *
25
+ * Escape hatch: `GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1` restores the
26
+ * env fallback for emergency rollback only. Mirrors the Slack equivalent
27
+ * (`SLACK_ALLOW_UNKNOWN_TEAM_FALLBACK`).
28
+ *
29
+ * The fail-closed contract lives here so every caller (route handler, CLI
30
+ * replay, future MCP) gets identical protection.
31
+ */
32
+ export declare function resolveTenantForGitHub(db: DatabaseSyncLike, args: ResolveArgs): string | null;
33
+ //# sourceMappingURL=tenant-routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-routing.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/tenant-routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,6GAA6G;IAC7G,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,IAAI,EAAE,WAAW,GAChB,MAAM,GAAG,IAAI,CAsCf"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Resolve the tenant_id for a GitHub webhook envelope.
3
+ *
4
+ * Returns:
5
+ * - mapped tenant_id when `github_installations` has a row for `installationId`
6
+ * (App-mode multi-tenant — primary path)
7
+ * - mapped tenant_id when `installation` is absent, `repository.full_name`
8
+ * matches a `github_repositories` row (PAT-mode multi-tenant)
9
+ * - the deployment's HIPPO_TENANT fallback (or 'default') when BOTH routing
10
+ * tables are empty (single-tenant deployment — env fallback is safe)
11
+ * - null when:
12
+ * - `installationId` is present but unknown AND `github_installations`
13
+ * is non-empty (multi-tenant install with foreign installation)
14
+ * - `installationId` is missing AND either routing table is non-empty
15
+ * AND no `repository.full_name` match (PAT-mode webhook from a foreign
16
+ * account — codex P0 #4 regression target)
17
+ *
18
+ * Escape hatch: `GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK=1` restores the
19
+ * env fallback for emergency rollback only. Mirrors the Slack equivalent
20
+ * (`SLACK_ALLOW_UNKNOWN_TEAM_FALLBACK`).
21
+ *
22
+ * The fail-closed contract lives here so every caller (route handler, CLI
23
+ * replay, future MCP) gets identical protection.
24
+ */
25
+ export function resolveTenantForGitHub(db, args) {
26
+ const envFallback = () => process.env.HIPPO_TENANT?.trim() || 'default';
27
+ const escapeHatch = process.env.GITHUB_ALLOW_UNKNOWN_INSTALLATION_FALLBACK === '1';
28
+ const instCount = db
29
+ .prepare(`SELECT COUNT(*) AS c FROM github_installations`)
30
+ .get().c;
31
+ const repoCount = db
32
+ .prepare(`SELECT COUNT(*) AS c FROM github_repositories`)
33
+ .get().c;
34
+ if (args.installationId) {
35
+ const row = db
36
+ .prepare(`SELECT tenant_id FROM github_installations WHERE installation_id = ?`)
37
+ .get(args.installationId);
38
+ if (row?.tenant_id)
39
+ return row.tenant_id;
40
+ if (Number(instCount) === 0) {
41
+ // Single-tenant install (table empty); env fallback is safe.
42
+ return envFallback();
43
+ }
44
+ // Multi-tenant install with unknown installation_id — fail closed.
45
+ return escapeHatch ? envFallback() : null;
46
+ }
47
+ // No installation.id (PAT-mode webhook).
48
+ if (Number(instCount) === 0 && Number(repoCount) === 0) {
49
+ // Single-tenant deployment with no routing tables populated.
50
+ return envFallback();
51
+ }
52
+ if (args.repoFullName) {
53
+ const row = db
54
+ .prepare(`SELECT tenant_id FROM github_repositories WHERE repo_full_name = ? ORDER BY added_at, tenant_id LIMIT 1`)
55
+ .get(args.repoFullName);
56
+ if (row?.tenant_id)
57
+ return row.tenant_id;
58
+ }
59
+ return escapeHatch ? envFallback() : null;
60
+ }
61
+ //# sourceMappingURL=tenant-routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-routing.js","sourceRoot":"","sources":["../../../src/connectors/github/tenant-routing.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,sBAAsB,CACpC,EAAoB,EACpB,IAAiB;IAEjB,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAChF,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,0CAA0C,KAAK,GAAG,CAAC;IAEnF,MAAM,SAAS,GAAI,EAAE;SAClB,OAAO,CAAC,gDAAgD,CAAC;SACzD,GAAG,EAA6B,CAAC,CAAC,CAAC;IACtC,MAAM,SAAS,GAAI,EAAE;SAClB,OAAO,CAAC,+CAA+C,CAAC;SACxD,GAAG,EAA6B,CAAC,CAAC,CAAC;IAEtC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CAAC,sEAAsE,CAAC;aAC/E,GAAG,CAAC,IAAI,CAAC,cAAc,CAAuC,CAAC;QAClE,IAAI,GAAG,EAAE,SAAS;YAAE,OAAO,GAAG,CAAC,SAAS,CAAC;QACzC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,6DAA6D;YAC7D,OAAO,WAAW,EAAE,CAAC;QACvB,CAAC;QACD,mEAAmE;QACnE,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;IAED,yCAAyC;IACzC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,6DAA6D;QAC7D,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CACN,yGAAyG,CAC1G;aACA,GAAG,CAAC,IAAI,CAAC,YAAY,CAAuC,CAAC;QAChE,IAAI,GAAG,EAAE,SAAS;YAAE,OAAO,GAAG,CAAC,SAAS,CAAC;IAC3C,CAAC;IACD,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { RememberOpts } from '../../api.js';
2
+ import type { GitHubIssueEvent, GitHubIssueCommentEvent, GitHubPullRequestEvent, GitHubPullRequestReviewCommentEvent } from './types.js';
3
+ export declare function issueEventToRememberOpts(evt: GitHubIssueEvent): RememberOpts | null;
4
+ export declare function issueCommentEventToRememberOpts(evt: GitHubIssueCommentEvent): RememberOpts | null;
5
+ export declare function pullRequestEventToRememberOpts(evt: GitHubPullRequestEvent): RememberOpts | null;
6
+ export declare function prReviewCommentEventToRememberOpts(evt: GitHubPullRequestReviewCommentEvent): RememberOpts | null;
7
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/connectors/github/transform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,mCAAmC,EACpC,MAAM,YAAY,CAAC;AAqBpB,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,gBAAgB,GACpB,YAAY,GAAG,IAAI,CAoBrB;AAED,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,uBAAuB,GAC3B,YAAY,GAAG,IAAI,CAkBrB;AAED,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,sBAAsB,GAC1B,YAAY,GAAG,IAAI,CAoBrB;AAED,wBAAgB,kCAAkC,CAChD,GAAG,EAAE,mCAAmC,GACvC,YAAY,GAAG,IAAI,CAkBrB"}
@@ -0,0 +1,103 @@
1
+ import { scopeFromRepository } from './scope.js';
2
+ /**
3
+ * Convert GitHub webhook events into RememberOpts for api.remember(). Each
4
+ * function returns null when the event has no usable body so the webhook
5
+ * caller can mark the delivery seen for idempotency and skip the insert.
6
+ *
7
+ * Contract (mirrors src/connectors/slack/transform.ts):
8
+ * - kind is the literal 'raw' (E1.x connector boundary, see src/importers.ts).
9
+ * - artifact_ref formats are stable; deletion paths look up by these strings.
10
+ * - issue: github://<owner/repo>/issue/<number>
11
+ * - issue_comment: github://<owner/repo>/issue/<number>/comment/<id>
12
+ * - pull_request: github://<owner/repo>/pull/<number>
13
+ * - pr_review_comment: github://<owner/repo>/pull/<number>/review_comment/<id>
14
+ * - owner is `user:github:<login>`. Required by the v0.40.0 provenance gate.
15
+ * - scope is derived from repository.private via scopeFromRepository (default
16
+ * private when undetermined).
17
+ */
18
+ const UNKNOWN_REPO = 'unknown/unknown';
19
+ export function issueEventToRememberOpts(evt) {
20
+ const body = evt.issue.body?.trim();
21
+ const title = evt.issue.title?.trim();
22
+ const text = [title, body].filter(Boolean).join('\n\n');
23
+ if (!text)
24
+ return null;
25
+ const repoFull = evt.repository?.full_name ?? UNKNOWN_REPO;
26
+ const login = evt.issue.user.login;
27
+ return {
28
+ content: text,
29
+ kind: 'raw',
30
+ scope: scopeFromRepository(evt.repository),
31
+ artifactRef: `github://${repoFull}/issue/${evt.issue.number}`,
32
+ owner: `user:github:${login}`,
33
+ tags: [
34
+ 'source:github',
35
+ `repo:${repoFull}`,
36
+ `event:issues.${evt.action}`,
37
+ `user:github:${login}`,
38
+ ],
39
+ };
40
+ }
41
+ export function issueCommentEventToRememberOpts(evt) {
42
+ const text = evt.comment.body?.trim();
43
+ if (!text)
44
+ return null;
45
+ const repoFull = evt.repository?.full_name ?? UNKNOWN_REPO;
46
+ const login = evt.comment.user.login;
47
+ return {
48
+ content: text,
49
+ kind: 'raw',
50
+ scope: scopeFromRepository(evt.repository),
51
+ artifactRef: `github://${repoFull}/issue/${evt.issue.number}/comment/${evt.comment.id}`,
52
+ owner: `user:github:${login}`,
53
+ tags: [
54
+ 'source:github',
55
+ `repo:${repoFull}`,
56
+ `event:issue_comment.${evt.action}`,
57
+ `user:github:${login}`,
58
+ ],
59
+ };
60
+ }
61
+ export function pullRequestEventToRememberOpts(evt) {
62
+ const body = evt.pull_request.body?.trim();
63
+ const title = evt.pull_request.title?.trim();
64
+ const text = [title, body].filter(Boolean).join('\n\n');
65
+ if (!text)
66
+ return null;
67
+ const repoFull = evt.repository?.full_name ?? UNKNOWN_REPO;
68
+ const login = evt.pull_request.user.login;
69
+ return {
70
+ content: text,
71
+ kind: 'raw',
72
+ scope: scopeFromRepository(evt.repository),
73
+ artifactRef: `github://${repoFull}/pull/${evt.pull_request.number}`,
74
+ owner: `user:github:${login}`,
75
+ tags: [
76
+ 'source:github',
77
+ `repo:${repoFull}`,
78
+ `event:pull_request.${evt.action}`,
79
+ `user:github:${login}`,
80
+ ],
81
+ };
82
+ }
83
+ export function prReviewCommentEventToRememberOpts(evt) {
84
+ const text = evt.comment.body?.trim();
85
+ if (!text)
86
+ return null;
87
+ const repoFull = evt.repository?.full_name ?? UNKNOWN_REPO;
88
+ const login = evt.comment.user.login;
89
+ return {
90
+ content: text,
91
+ kind: 'raw',
92
+ scope: scopeFromRepository(evt.repository),
93
+ artifactRef: `github://${repoFull}/pull/${evt.pull_request.number}/review_comment/${evt.comment.id}`,
94
+ owner: `user:github:${login}`,
95
+ tags: [
96
+ 'source:github',
97
+ `repo:${repoFull}`,
98
+ `event:pull_request_review_comment.${evt.action}`,
99
+ `user:github:${login}`,
100
+ ],
101
+ };
102
+ }
103
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/connectors/github/transform.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQjD;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAEvC,MAAM,UAAU,wBAAwB,CACtC,GAAqB;IAErB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,SAAS,IAAI,YAAY,CAAC;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IACnC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,WAAW,EAAE,YAAY,QAAQ,UAAU,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE;QAC7D,KAAK,EAAE,eAAe,KAAK,EAAE;QAC7B,IAAI,EAAE;YACJ,eAAe;YACf,QAAQ,QAAQ,EAAE;YAClB,gBAAgB,GAAG,CAAC,MAAM,EAAE;YAC5B,eAAe,KAAK,EAAE;SACvB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,GAA4B;IAE5B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,SAAS,IAAI,YAAY,CAAC;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,WAAW,EAAE,YAAY,QAAQ,UAAU,GAAG,CAAC,KAAK,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE;QACvF,KAAK,EAAE,eAAe,KAAK,EAAE;QAC7B,IAAI,EAAE;YACJ,eAAe;YACf,QAAQ,QAAQ,EAAE;YAClB,uBAAuB,GAAG,CAAC,MAAM,EAAE;YACnC,eAAe,KAAK,EAAE;SACvB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,GAA2B;IAE3B,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,SAAS,IAAI,YAAY,CAAC;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1C,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,WAAW,EAAE,YAAY,QAAQ,SAAS,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE;QACnE,KAAK,EAAE,eAAe,KAAK,EAAE;QAC7B,IAAI,EAAE;YACJ,eAAe;YACf,QAAQ,QAAQ,EAAE;YAClB,sBAAsB,GAAG,CAAC,MAAM,EAAE;YAClC,eAAe,KAAK,EAAE;SACvB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,GAAwC;IAExC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,SAAS,IAAI,YAAY,CAAC;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,WAAW,EAAE,YAAY,QAAQ,SAAS,GAAG,CAAC,YAAY,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE;QACpG,KAAK,EAAE,eAAe,KAAK,EAAE;QAC7B,IAAI,EAAE;YACJ,eAAe;YACf,QAAQ,QAAQ,EAAE;YAClB,qCAAqC,GAAG,CAAC,MAAM,EAAE;YACjD,eAAe,KAAK,EAAE;SACvB;KACF,CAAC;AACJ,CAAC"}