@dxos/plugin-github 0.13.0 → 0.16.0-next-60712ab191a99ba90316cc4be753e9e11b17100a

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 (114) hide show
  1. package/dist/lib/GitHubCapabilities.mjs +1 -10
  2. package/dist/lib/GitHubEvents.mjs +1 -15
  3. package/dist/lib/GitHubOperation.mjs +1 -358
  4. package/dist/lib/GitHubPlugin.mjs +1 -16
  5. package/dist/lib/Walkthrough.mjs +1 -59
  6. package/dist/lib/capabilities.browser.mjs +1 -2
  7. package/dist/lib/capabilities.browser.mjs.map +1 -1
  8. package/dist/lib/capabilities.mjs +1 -2
  9. package/dist/lib/capabilities.mjs.map +1 -1
  10. package/dist/lib/capabilities.tauri.mjs +1 -2
  11. package/dist/lib/capabilities.tauri.mjs.map +1 -1
  12. package/dist/lib/chunk-Extensions.mjs +18 -0
  13. package/dist/lib/chunk-Extensions.mjs.map +1 -0
  14. package/dist/lib/chunk-GitHubCapabilities.mjs +10 -0
  15. package/dist/lib/chunk-GitHubCapabilities.mjs.map +1 -0
  16. package/dist/lib/chunk-GitHubEvents.mjs +15 -0
  17. package/dist/lib/chunk-GitHubEvents.mjs.map +1 -0
  18. package/dist/lib/chunk-GitHubOperation.mjs +386 -0
  19. package/dist/lib/chunk-GitHubOperation.mjs.map +1 -0
  20. package/dist/lib/chunk-GitHubPlugin.mjs +16 -0
  21. package/dist/lib/chunk-GitHubPlugin.mjs.map +1 -0
  22. package/dist/lib/chunk-ImportPullRequestDialog.mjs.map +1 -1
  23. package/dist/lib/chunk-PLUGIN.mjs +1 -1
  24. package/dist/lib/chunk-PullRequestArticle.mjs +64 -21
  25. package/dist/lib/chunk-PullRequestArticle.mjs.map +1 -1
  26. package/dist/lib/chunk-PullRequestArticle2.mjs +1 -2
  27. package/dist/lib/chunk-PullRequestCardMenu.mjs +1 -1
  28. package/dist/lib/chunk-PullRequestsArticle.mjs +3 -3
  29. package/dist/lib/chunk-PullRequestsArticle.mjs.map +1 -1
  30. package/dist/lib/chunk-Walkthrough.mjs +59 -0
  31. package/dist/lib/chunk-Walkthrough.mjs.map +1 -0
  32. package/dist/lib/chunk-WalkthroughArticle.mjs +1 -1
  33. package/dist/lib/chunk-add-pull-request-comment.mjs.map +1 -1
  34. package/dist/lib/chunk-add-pull-request-review-comment.mjs.map +1 -1
  35. package/dist/lib/chunk-connector.mjs.map +1 -1
  36. package/dist/lib/chunk-generate-walkthrough.mjs.map +1 -1
  37. package/dist/lib/chunk-get-pull-request-diff.mjs.map +1 -1
  38. package/dist/lib/chunk-get-pull-request-status.mjs.map +1 -1
  39. package/dist/lib/chunk-get-repositories.mjs.map +1 -1
  40. package/dist/lib/chunk-github-api.mjs +1 -0
  41. package/dist/lib/chunk-github-api.mjs.map +1 -1
  42. package/dist/lib/chunk-import-pull-request.mjs +78 -3
  43. package/dist/lib/chunk-import-pull-request.mjs.map +1 -1
  44. package/dist/lib/chunk-link-resolver.mjs.map +1 -1
  45. package/dist/lib/chunk-pull-request2.mjs +1 -0
  46. package/dist/lib/chunk-pull-request2.mjs.map +1 -1
  47. package/dist/lib/chunk-react-surface.mjs +4 -4
  48. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  49. package/dist/lib/chunk-refresh-pull-requests.mjs +49 -0
  50. package/dist/lib/chunk-refresh-pull-requests.mjs.map +1 -0
  51. package/dist/lib/chunk-submit-pull-request-approval.mjs.map +1 -1
  52. package/dist/lib/chunk-sync-pull-request.mjs +11 -9
  53. package/dist/lib/chunk-sync-pull-request.mjs.map +1 -1
  54. package/dist/lib/chunk-sync.mjs.map +1 -1
  55. package/dist/lib/index.mjs +2 -2
  56. package/dist/lib/meta.mjs.map +1 -1
  57. package/dist/lib/ns/Extensions.mjs +2 -16
  58. package/dist/lib/operations.mjs +2 -1
  59. package/dist/lib/operations.mjs.map +1 -1
  60. package/dist/lib/types.mjs +4 -4
  61. package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -1
  62. package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -1
  63. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  64. package/dist/types/src/cards/GitHubCard.d.ts.map +1 -1
  65. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +6 -3
  66. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -1
  67. package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts +2 -0
  68. package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts.map +1 -0
  69. package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts.map +1 -1
  70. package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts.map +1 -1
  71. package/dist/types/src/operations/import-pull-request.d.ts.map +1 -1
  72. package/dist/types/src/operations/index.d.ts.map +1 -1
  73. package/dist/types/src/operations/pull-request.d.ts.map +1 -1
  74. package/dist/types/src/operations/refresh-pull-requests.d.ts +5 -0
  75. package/dist/types/src/operations/refresh-pull-requests.d.ts.map +1 -0
  76. package/dist/types/src/operations/refresh.d.ts +37 -0
  77. package/dist/types/src/operations/refresh.d.ts.map +1 -0
  78. package/dist/types/src/operations/refresh.test.d.ts +2 -0
  79. package/dist/types/src/operations/refresh.test.d.ts.map +1 -0
  80. package/dist/types/src/operations/sync-pull-request.d.ts.map +1 -1
  81. package/dist/types/src/services/github-api.d.ts +1 -0
  82. package/dist/types/src/services/github-api.d.ts.map +1 -1
  83. package/dist/types/src/stories/PullRequestOverview.stories.d.ts +2 -0
  84. package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -1
  85. package/dist/types/src/types/GitHubOperation.d.ts +14 -0
  86. package/dist/types/src/types/GitHubOperation.d.ts.map +1 -1
  87. package/dist/types/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +47 -47
  89. package/src/capabilities/gen/browser.ts +1 -3
  90. package/src/capabilities/gen/tauri.ts +1 -3
  91. package/src/capabilities/index.ts +1 -4
  92. package/src/cards/GitHubCard.tsx +7 -3
  93. package/src/components/PullRequestOverview/ArtifactPill.tsx +1 -1
  94. package/src/components/PullRequestOverview/CheckRunList.test.ts +29 -0
  95. package/src/components/PullRequestOverview/CheckRunList.tsx +62 -13
  96. package/src/components/PullRequestOverview/PullRequestOverview.tsx +5 -1
  97. package/src/components/PullRequestStatus/PullRequestStatus.tsx +8 -5
  98. package/src/containers/PullRequestsArticle/PullRequestsArticle.tsx +12 -10
  99. package/src/operations/import-pull-request.ts +8 -0
  100. package/src/operations/index.ts +1 -0
  101. package/src/operations/pull-request.ts +1 -0
  102. package/src/operations/refresh-pull-requests.ts +69 -0
  103. package/src/operations/refresh.test.ts +112 -0
  104. package/src/operations/refresh.ts +111 -0
  105. package/src/operations/sync-pull-request.ts +10 -13
  106. package/src/services/github-api.ts +1 -0
  107. package/src/stories/PullRequestOverview.stories.tsx +22 -1
  108. package/src/types/GitHubOperation.ts +28 -0
  109. package/dist/lib/GitHubCapabilities.mjs.map +0 -1
  110. package/dist/lib/GitHubEvents.mjs.map +0 -1
  111. package/dist/lib/GitHubOperation.mjs.map +0 -1
  112. package/dist/lib/GitHubPlugin.mjs.map +0 -1
  113. package/dist/lib/Walkthrough.mjs.map +0 -1
  114. package/dist/lib/ns/Extensions.mjs.map +0 -1
@@ -0,0 +1,49 @@
1
+ import { n as githubToken } from "./chunk-pull-request2.mjs";
2
+ import { a as selectRefreshBatch, i as refreshPullRequest, n as ensureRefreshTrigger, r as queryInFlightPullRequests } from "./chunk-import-pull-request.mjs";
3
+ import { GitHubOperation } from "#types";
4
+ import * as Operation from "@dxos/compute/Operation";
5
+ import * as Effect from "effect/Effect";
6
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
7
+ import { log } from "@dxos/log";
8
+ import * as Clock from "effect/Clock";
9
+ //#region src/operations/refresh-pull-requests.ts
10
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-github/src/operations/refresh-pull-requests.ts";
11
+ /** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */
12
+ var REFRESH_CONCURRENCY = 2;
13
+ /** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */
14
+ var REFRESH_INTERVAL_MS = 36e5;
15
+ var handler = GitHubOperation.RefreshPullRequests.pipe(Operation.withHandler(Effect.fn(function* () {
16
+ yield* ensureRefreshTrigger();
17
+ const inFlight = yield* queryInFlightPullRequests();
18
+ if (inFlight.length === 0) return {
19
+ checked: 0,
20
+ updated: 0,
21
+ failed: 0
22
+ };
23
+ const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);
24
+ const pullRequests = selectRefreshBatch(inFlight, window);
25
+ const token = yield* githubToken();
26
+ const results = yield* Effect.forEach(pullRequests, (pullRequest) => refreshPullRequest(pullRequest, token).pipe(Effect.map((updated) => updated.length > 0 ? "updated" : "unchanged"), Effect.catchDefect((cause) => Effect.sync(() => {
27
+ log.warn("pull request refresh failed", {
28
+ owner: pullRequest.owner,
29
+ repo: pullRequest.repo,
30
+ number: pullRequest.number,
31
+ cause
32
+ }, {
33
+ "~LogMeta": "~LogMeta",
34
+ F: __dxlog_file,
35
+ L: 47,
36
+ S: this
37
+ });
38
+ return "failed";
39
+ }))), { concurrency: REFRESH_CONCURRENCY });
40
+ return {
41
+ checked: pullRequests.length,
42
+ updated: results.filter((result) => result === "updated").length,
43
+ failed: results.filter((result) => result === "failed").length
44
+ };
45
+ }, Effect.provide(FetchHttpClient.layer))));
46
+ //#endregion
47
+ export { handler as default };
48
+
49
+ //# sourceMappingURL=chunk-refresh-pull-requests.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-refresh-pull-requests.mjs","names":[],"sources":["../../src/operations/refresh-pull-requests.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Clock from 'effect/Clock';\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { log } from '@dxos/log';\n\nimport { GitHubOperation } from '#types';\n\nimport { githubToken } from './pull-request.ts';\nimport { ensureRefreshTrigger, queryInFlightPullRequests, refreshPullRequest, selectRefreshBatch } from './refresh.ts';\n\n/** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */\nconst REFRESH_CONCURRENCY = 2;\n\n/** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */\nconst REFRESH_INTERVAL_MS = 60 * 60 * 1000;\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests> =\n GitHubOperation.RefreshPullRequests.pipe(\n Operation.withHandler(\n Effect.fn(function* () {\n // Collapses any duplicate a racing peer created, so the space keeps one schedule.\n yield* ensureRefreshTrigger();\n const inFlight = yield* queryInFlightPullRequests();\n if (inFlight.length === 0) {\n return { checked: 0, updated: 0, failed: 0 };\n }\n\n const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);\n const pullRequests = selectRefreshBatch(inFlight, window);\n\n const token = yield* githubToken();\n const results = yield* Effect.forEach(\n pullRequests,\n (pullRequest) =>\n // One deleted or unreachable pull request must not fail the run: EDGE disables a trigger\n // after repeated failures, which would stop refreshing every other one.\n refreshPullRequest(pullRequest, token).pipe(\n Effect.map((updated) => (updated.length > 0 ? 'updated' : 'unchanged')),\n Effect.catchDefect((cause) =>\n Effect.sync(() => {\n log.warn('pull request refresh failed', {\n owner: pullRequest.owner,\n repo: pullRequest.repo,\n number: pullRequest.number,\n cause,\n });\n return 'failed' as const;\n }),\n ),\n ),\n { concurrency: REFRESH_CONCURRENCY },\n );\n\n return {\n checked: pullRequests.length,\n updated: results.filter((result) => result === 'updated').length,\n failed: results.filter((result) => result === 'failed').length,\n };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;AAiBA,IAAM,sBAAsB;;AAG5B,IAAM,sBAAsB;AAE5B,IAAM,UACJ,gBAAgB,oBAAoB,KAClC,UAAU,YACR,OAAO,GAAG,aAAa;CAErB,OAAO,qBAAqB;CAC5B,MAAM,WAAW,OAAO,0BAA0B;CAClD,IAAI,SAAS,WAAW,GACtB,OAAO;EAAE,SAAS;EAAG,SAAS;EAAG,QAAQ;CAAE;CAG7C,MAAM,SAAS,KAAK,OAAO,OAAO,MAAM,qBAAqB,mBAAmB;CAChF,MAAM,eAAe,mBAAmB,UAAU,MAAM;CAExD,MAAM,QAAQ,OAAO,YAAY;CACjC,MAAM,UAAU,OAAO,OAAO,QAC5B,eACC,gBAGC,mBAAmB,aAAa,KAAK,CAAC,CAAC,KACrC,OAAO,KAAK,YAAa,QAAQ,SAAS,IAAI,YAAY,WAAY,GACtE,OAAO,aAAa,UAClB,OAAO,WAAW;EAChB,IAAI,KAAK,+BAA+B;GACtC,OAAO,YAAY;GACnB,MAAM,YAAY;GAClB,QAAQ,YAAY;GACpB;EACF,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC;EACD,OAAO;CACT,CAAC,CACH,CACF,GACF,EAAE,aAAa,oBAAoB,CACrC;CAEA,OAAO;EACL,SAAS,aAAa;EACtB,SAAS,QAAQ,QAAQ,WAAW,WAAW,SAAS,CAAC,CAAC;EAC1D,QAAQ,QAAQ,QAAQ,WAAW,WAAW,QAAQ,CAAC,CAAC;CAC1D;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-submit-pull-request-approval.mjs","names":[],"sources":["../../src/approval.ts","../../src/operations/submit-pull-request-approval.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { GitHubApi } from './services/index.ts';\n\n/**\n * Machine-readable marker carried by an approval posted as a comment.\n *\n * An HTML comment renders as nothing on GitHub, so the marker is invisible to a human reader while\n * remaining an exact string for an agent polling the conversation — which is the point: a comment\n * fallback has to be as detectable as the review state it stands in for.\n */\nexport const APPROVAL_MARKER = '<!-- dxos:approval state=approved -->';\n\n/** Prose shown above the marker; states why the approval is a comment rather than a review. */\nconst APPROVAL_TEXT =\n 'Approved — good to land.\\n\\n' +\n '_GitHub declined an approving review from this connection (a pull request cannot be approved by ' +\n 'its own author, and some tokens carry no review permission), so the approval is recorded here._';\n\n/** Body of the fallback comment: the reviewer's own summary, the standing text, and the marker. */\nexport const approvalCommentBody = (body?: string): string =>\n [body?.trim(), APPROVAL_TEXT, APPROVAL_MARKER].filter(Boolean).join('\\n\\n');\n\n/** Whether a comment body records an approval — the detector an agent runs over a PR's comments. */\nexport const isApprovalComment = (body: string): boolean => body.includes(APPROVAL_MARKER);\n\n/**\n * Whether an approving review failed for a reason a comment can stand in for.\n *\n * `422` is GitHub's answer to approving one's own pull request, `403` to a token without review\n * permission on the repository. Anything else (a rejected credential, a deleted pull request, a\n * network fault) is a real failure and must surface rather than turn into a comment.\n */\nexport const isApprovalRefused = (error: unknown): boolean => {\n const status = GitHubApi.responseStatus(error);\n return status === 403 || status === 422;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Option from 'effect/Option';\n\nimport * as Operation from '@dxos/compute/Operation';\n\nimport { GitHubOperation } from '#types';\n\nimport { approvalCommentBody, isApprovalRefused } from '../approval.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SubmitPullRequestApproval> =\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const review = yield* GitHubApi.approvePullRequest(owner, repo, number, body).pipe(\n Effect.provide(credentials),\n Effect.asSome,\n // Only a refusal to review becomes a comment; every other failure stays a failure.\n Effect.catchIf(isApprovalRefused, () => Effect.succeedNone),\n );\n if (Option.isSome(review)) {\n return { reviewId: review.value.id, commented: false };\n }\n\n const comment = yield* GitHubApi.createIssueComment(owner, repo, number, approvalCommentBody(body)).pipe(\n Effect.provide(credentials),\n );\n return { commentId: comment.id, url: comment.html_url ?? undefined, commented: true };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;AAaA,IAAa,kBAAkB;;AAG/B,IAAM,gBACJ;;AAKF,IAAa,uBAAuB,SAClC;CAAC,MAAM,KAAK;CAAG;CAAe;AAAe,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM;;;;;;;;AAY5E,IAAa,qBAAqB,UAA4B;CAC5D,MAAM,SAAS,eAAyB,KAAK;CAC7C,OAAO,WAAW,OAAO,WAAW;AACtC;;;ACtBA,IAAM,UACJ,gBAAgB,0BAA0B,KACxC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,QAAQ;CAC/C,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,SAAS,OAAO,mBAA6B,OAAO,MAAM,QAAQ,IAAI,CAAC,CAAC,KAC5E,OAAO,QAAQ,WAAW,GAC1B,OAAO,QAEP,OAAO,QAAQ,yBAAyB,OAAO,WAAW,CAC5D;CACA,IAAI,OAAO,OAAO,MAAM,GACtB,OAAO;EAAE,UAAU,OAAO,MAAM;EAAI,WAAW;CAAM;CAGvD,MAAM,UAAU,OAAO,mBAA6B,OAAO,MAAM,QAAQ,oBAAoB,IAAI,CAAC,CAAC,CAAC,KAClG,OAAO,QAAQ,WAAW,CAC5B;CACA,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;EAAW,WAAW;CAAK;AACtF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-submit-pull-request-approval.mjs","names":["GitHubApi.responseStatus","GitHubApi.approvePullRequest","GitHubApi.createIssueComment"],"sources":["../../src/approval.ts","../../src/operations/submit-pull-request-approval.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { GitHubApi } from './services/index.ts';\n\n/**\n * Machine-readable marker carried by an approval posted as a comment.\n *\n * An HTML comment renders as nothing on GitHub, so the marker is invisible to a human reader while\n * remaining an exact string for an agent polling the conversation — which is the point: a comment\n * fallback has to be as detectable as the review state it stands in for.\n */\nexport const APPROVAL_MARKER = '<!-- dxos:approval state=approved -->';\n\n/** Prose shown above the marker; states why the approval is a comment rather than a review. */\nconst APPROVAL_TEXT =\n 'Approved — good to land.\\n\\n' +\n '_GitHub declined an approving review from this connection (a pull request cannot be approved by ' +\n 'its own author, and some tokens carry no review permission), so the approval is recorded here._';\n\n/** Body of the fallback comment: the reviewer's own summary, the standing text, and the marker. */\nexport const approvalCommentBody = (body?: string): string =>\n [body?.trim(), APPROVAL_TEXT, APPROVAL_MARKER].filter(Boolean).join('\\n\\n');\n\n/** Whether a comment body records an approval — the detector an agent runs over a PR's comments. */\nexport const isApprovalComment = (body: string): boolean => body.includes(APPROVAL_MARKER);\n\n/**\n * Whether an approving review failed for a reason a comment can stand in for.\n *\n * `422` is GitHub's answer to approving one's own pull request, `403` to a token without review\n * permission on the repository. Anything else (a rejected credential, a deleted pull request, a\n * network fault) is a real failure and must surface rather than turn into a comment.\n */\nexport const isApprovalRefused = (error: unknown): boolean => {\n const status = GitHubApi.responseStatus(error);\n return status === 403 || status === 422;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Option from 'effect/Option';\n\nimport * as Operation from '@dxos/compute/Operation';\n\nimport { GitHubOperation } from '#types';\n\nimport { approvalCommentBody, isApprovalRefused } from '../approval.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SubmitPullRequestApproval> =\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const review = yield* GitHubApi.approvePullRequest(owner, repo, number, body).pipe(\n Effect.provide(credentials),\n Effect.asSome,\n // Only a refusal to review becomes a comment; every other failure stays a failure.\n Effect.catchIf(isApprovalRefused, () => Effect.succeedNone),\n );\n if (Option.isSome(review)) {\n return { reviewId: review.value.id, commented: false };\n }\n\n const comment = yield* GitHubApi.createIssueComment(owner, repo, number, approvalCommentBody(body)).pipe(\n Effect.provide(credentials),\n );\n return { commentId: comment.id, url: comment.html_url ?? undefined, commented: true };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;AAaA,IAAa,kBAAkB;;AAG/B,IAAM,gBACJ;;AAKF,IAAa,uBAAuB,SAClC;CAAC,MAAM,KAAK;CAAG;CAAe;AAAe,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM;;;;;;;;AAY5E,IAAa,qBAAqB,UAA4B;CAC5D,MAAM,SAASA,eAAyB,KAAK;CAC7C,OAAO,WAAW,OAAO,WAAW;AACtC;;;ACtBA,IAAM,UACJ,gBAAgB,0BAA0B,KACxC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,QAAQ;CAC/C,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,SAAS,OAAOC,mBAA6B,OAAO,MAAM,QAAQ,IAAI,CAAC,CAAC,KAC5E,OAAO,QAAQ,WAAW,GAC1B,OAAO,QAEP,OAAO,QAAQ,yBAAyB,OAAO,WAAW,CAC5D;CACA,IAAI,OAAO,OAAO,MAAM,GACtB,OAAO;EAAE,UAAU,OAAO,MAAM;EAAI,WAAW;CAAM;CAGvD,MAAM,UAAU,OAAOC,mBAA6B,OAAO,MAAM,QAAQ,oBAAoB,IAAI,CAAC,CAAC,CAAC,KAClG,OAAO,QAAQ,WAAW,CAC5B;CACA,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;EAAW,WAAW;CAAK;AACtF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1,21 +1,23 @@
1
- import { t as pullRequestChanges } from "./chunk-pull-request.mjs";
2
1
  import { n as githubToken, r as resolvePullRequest } from "./chunk-pull-request2.mjs";
3
- import { fetchPullRequestWithFallback } from "./chunk-import-pull-request.mjs";
2
+ import { i as refreshPullRequest, n as ensureRefreshTrigger } from "./chunk-import-pull-request.mjs";
4
3
  import { GitHubOperation } from "#types";
5
4
  import * as Operation from "@dxos/compute/Operation";
6
5
  import * as Effect from "effect/Effect";
7
- import { Database, Obj } from "@dxos/echo";
6
+ import { Database } from "@dxos/echo";
8
7
  import * as FetchHttpClient from "effect/http/FetchHttpClient";
8
+ import { log } from "@dxos/log";
9
9
  //#region src/operations/sync-pull-request.ts
10
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-github/src/operations/sync-pull-request.ts";
10
11
  var handler = GitHubOperation.SyncPullRequest.pipe(Operation.withHandler(Effect.fn(function* ({ pullRequest: ref }) {
11
12
  const { pullRequest, db } = yield* resolvePullRequest(ref);
12
13
  const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));
13
- const pull = yield* fetchPullRequestWithFallback(pullRequest, token);
14
- const changes = pullRequestChanges(pullRequest, pull);
15
- const updated = Object.keys(changes);
16
- if (updated.length > 0) Obj.update(pullRequest, (pullRequest) => {
17
- Object.assign(pullRequest, changes);
18
- });
14
+ const updated = yield* refreshPullRequest(pullRequest, token);
15
+ yield* ensureRefreshTrigger().pipe(Effect.provide(Database.layer(db)), Effect.catchDefect((defect) => Effect.sync(() => log.warn("refresh trigger setup failed", { defect }, {
16
+ "~LogMeta": "~LogMeta",
17
+ F: __dxlog_file,
18
+ L: 27,
19
+ S: this
20
+ }))));
19
21
  return { updated };
20
22
  }, Effect.provide(FetchHttpClient.layer))));
21
23
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-sync-pull-request.mjs","names":[],"sources":["../../src/operations/sync-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Obj } from '@dxos/echo';\n\nimport { GitHubOperation } from '#types';\n\nimport { pullRequestChanges } from '../pull-request.ts';\nimport { fetchPullRequestWithFallback } from './import-pull-request.ts';\nimport { githubToken, resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncPullRequest> = GitHubOperation.SyncPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, db } = yield* resolvePullRequest(ref);\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n // With the anonymous fallback, so a public pull request still refreshes behind a revoked token.\n const pull = yield* fetchPullRequestWithFallback(pullRequest, token);\n const changes = pullRequestChanges(pullRequest, pull);\n const updated = Object.keys(changes);\n if (updated.length > 0) {\n Obj.update(pullRequest, (pullRequest) => {\n Object.assign(pullRequest, changes);\n });\n }\n\n return { updated };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;AAgBA,IAAM,UAAyE,gBAAgB,gBAAgB,KAC7G,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,OAAO,OAAO,mBAAmB,GAAG;CACzD,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAE1E,MAAM,OAAO,OAAO,6BAA6B,aAAa,KAAK;CACnE,MAAM,UAAU,mBAAmB,aAAa,IAAI;CACpD,MAAM,UAAU,OAAO,KAAK,OAAO;CACnC,IAAI,QAAQ,SAAS,GACnB,IAAI,OAAO,cAAc,gBAAgB;EACvC,OAAO,OAAO,aAAa,OAAO;CACpC,CAAC;CAGH,OAAO,EAAE,QAAQ;AACnB,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-sync-pull-request.mjs","names":[],"sources":["../../src/operations/sync-pull-request.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database } from '@dxos/echo';\nimport { log } from '@dxos/log';\n\nimport { GitHubOperation } from '#types';\n\nimport { githubToken, resolvePullRequest } from './pull-request.ts';\nimport { ensureRefreshTrigger, refreshPullRequest } from './refresh.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncPullRequest> = GitHubOperation.SyncPullRequest.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, db } = yield* resolvePullRequest(ref);\n const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));\n const updated = yield* refreshPullRequest(pullRequest, token);\n // Spaces that imported pull requests before the scheduled refresh existed get it on next open.\n yield* ensureRefreshTrigger().pipe(\n Effect.provide(Database.layer(db)),\n // The refresh already succeeded; the schedule is retried on the next open.\n Effect.catchDefect((defect) => Effect.sync(() => log.warn('refresh trigger setup failed', { defect }))),\n );\n return { updated };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;;AAgBA,IAAM,UAAyE,gBAAgB,gBAAgB,KAC7G,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,OAAO,OAAO,mBAAmB,GAAG;CACzD,MAAM,QAAQ,OAAO,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;CAC1E,MAAM,UAAU,OAAO,mBAAmB,aAAa,KAAK;CAE5D,OAAO,qBAAqB,CAAC,CAAC,KAC5B,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GAEjC,OAAO,aAAa,WAAW,OAAO,WAAW,IAAI,KAAK,gCAAgC,EAAE,OAAO,GAAA;EAAA,YAAA;EAAA,GAAA;EAAA,GAAA;EAAA,GAAA;CAAA,CAAC,CAAC,CAAC,CACxG;CACA,OAAO,EAAE,QAAQ;AACnB,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-sync.mjs","names":[],"sources":["../../src/operations/sync.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\nimport * as Semaphore from 'effect/Semaphore';\n\nimport * as ConnectorSync from '@dxos/app-toolkit/ConnectorSync';\nimport * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Filter, Obj, Query, Ref, Type } from '@dxos/echo';\nimport { Cursor } from '@dxos/link';\nimport { log } from '@dxos/log';\nimport * as Binding from '@dxos/plugin-connector/Binding';\nimport { Milestone, Organization, Person, Task, TaskSet } from '@dxos/types';\n\nimport { meta } from '#meta';\nimport { GitHubOperation } from '#types';\n\nimport { GITHUB_SOURCE } from '../constants.ts';\nimport {\n GitHubProjectMissingError,\n GitHubRepoInaccessibleError,\n GitHubRepoUnresolvedError,\n formatGitHubSyncFailure,\n} from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\n\nconst { mergeField, snapshotField } = ConnectorSync;\n\n//\n// Direction: bidirectional (pull-then-push) for projects and tasks.\n//\n// Each sync pass syncs one binding (one repo). It first pulls every reachable\n// Organization, Person, Project, and Task from GitHub into ECHO, then walks the\n// local mirrors and pushes any field that diverged from the snapshot taken at\n// the end of the previous pull. Snapshots live on the `Cursor` object's\n// `spec.snapshots[<github id>]` (where ids are the GitHub-issued numeric ids,\n// stringified for stable foreign-key matching).\n//\n// Mapped fields per object:\n// Project (repo): description (description-only — see updateRepo for why\n// `name` is intentionally not pushed)\n// Task (issue): title, description, status (open/closed)\n//\n// Conflict policy is remote-wins (mirrors Trello/Linear). Comments are NOT\n// synced (the chunked-yield rewrite is still pending; see TODO below).\n//\n// Attribution caveat: pushed edits are attributed to the GitHub App / OAuth\n// user that owns the connection token, not to the local user who made the\n// edit. This is unavoidable with the current token model — a write from\n// \"Person A in space\" appears on GitHub as a write from the App. Document\n// before enabling for shared spaces.\n//\n// New local objects (no GitHub foreign key) are NOT pushed in this pass —\n// creating a new GitHub issue requires (owner, repo) which we currently\n// don't surface from local Tasks unambiguously.\n//\n// Sync target shape: each binding's target is the local root Project for one\n// REPOSITORY. The repo's owning org (and org members) are auto-pulled.\n//\n\n//\n// Tunables\n//\n\n/** Per-repo issue parallelism. */\nconst ISSUE_CONCURRENCY = 4;\n\n//\n// Snapshot field shapes (stored on Cursor's `spec.snapshots`)\n//\n\n/**\n * Snapshot shapes. Fields are required (not `?`) because every snapshot is\n * written in one shot via {@link Cursor.writeSnapshot} after a pull; absence-of-\n * snapshot is modeled by `Cursor.readSnapshot` returning `undefined`. `name` on a\n * Project is recorded but not pushed — see {@link GitHubApi.updateRepo}.\n */\ntype ProjectSnapshot = {\n name: string;\n description: string;\n};\n\ntype TaskSnapshot = {\n title: string;\n description: string;\n status: 'todo' | 'done';\n};\n\n//\n// Foreign-key + lookup helpers\n//\n\nconst fkFor = (id: string | number) => ({ source: GITHUB_SOURCE, id: String(id) });\n\n/**\n * Generic foreign-key lookup. Type is forwarded to `Filter.foreignKeys`\n * untyped — the caller supplies the result type via the explicit `T` parameter\n * (mirrors how plugin-trello casts after `Database.query(...).run`).\n */\nconst findByForeignId = <T>(type: Type.AnyEntity, id: string | number) =>\n Effect.gen(function* () {\n const results = yield* Database.query(Query.select(Filter.foreignKeys(type as never, [fkFor(id)]))).run;\n return results.length > 0 ? (results[0] as T) : undefined;\n });\n\n//\n// Field mappers (GitHub ↔ DXOS)\n//\n\n/**\n * Maps GitHub issue state to a Task status. GitHub issues only have `open` /\n * `closed` — there's no \"in progress\" concept, so we collapse open→`todo` and\n * closed→`done`. PRs use the same mapping; merged PRs are reported as `closed`\n * by GitHub plus a non-null `pull_request.merged_at`.\n */\nconst issueStateToTaskStatus = (state: string): 'todo' | 'done' => (state === 'closed' ? 'done' : 'todo');\n\n/**\n * Reverse of {@link issueStateToTaskStatus}. `'started'` is collapsed to\n * `open` since GitHub has no equivalent state. Returns undefined when the\n * status is unrecognised so the caller can skip the push instead of failing.\n */\nconst taskStatusToIssueState = (status: string | undefined): 'open' | 'closed' | undefined => {\n switch (status) {\n case 'done':\n return 'closed';\n case 'todo':\n case 'started':\n return 'open';\n default:\n return undefined;\n }\n};\n\nconst sinceFromOptions = (options: GitHubOperation.SyncOptions | undefined): string | undefined => {\n const days = options?.maxDaysBack;\n if (typeof days !== 'number' || days <= 0) {\n return undefined;\n }\n return new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();\n};\n\n/** GitHub reports `due_on` as an ISO datetime; `Milestone.targetDate` is date-only. */\nconst dueOnToTargetDate = (dueOn: string | null | undefined): string | undefined => dueOn?.slice(0, 10) ?? undefined;\n\n/**\n * Move a task into `container`. Idempotent — sync runs repeatedly and must never append a second\n * ref for a task already in the set.\n */\nexport const setTaskContainer = Effect.fn('setTaskContainer')(function* (task: Task.Task, container: TaskSet.TaskSet) {\n const listed = container.tasks.some(Ref.hasEntityId(task.id));\n // A stale entry for a task now parented elsewhere is not membership; it still needs re-rooting.\n if (listed && Obj.getParent(task)?.id === container.id) {\n return;\n }\n // The reverse-ref index, not `Obj.getParent`: legacy sets may hold refs to tasks whose parent\n // edge has not yet been healed to the set, and every holder must drop its stale entry.\n const previous = yield* Database.query(\n Query.select(Filter.id(task.id)).referencedBy(TaskSet.TaskSet, 'tasks'),\n ).run.pipe(Effect.orElseSucceed(() => []));\n for (const set of previous) {\n if (set.id === container.id) {\n continue;\n }\n Obj.update(set, (set) => {\n TaskSet.removeRefsInPlace(set.tasks, new Set([task.id]));\n });\n }\n // A task filed as a sub-task is listed by its parent rather than a set; it leaves that list too.\n const parent = Task.getParentTask(task);\n if (parent) {\n Obj.update(parent, (parent) => {\n TaskSet.removeRefsInPlace(parent.subtasks ?? [], new Set([task.id]));\n });\n }\n if (!listed) {\n Obj.update(container, (container) => {\n container.tasks.push(Ref.make(task));\n });\n }\n // `tasks` claims only an unparented task, so a move between sets moves the edge itself.\n Obj.setParent(task, container);\n});\n\n//\n// Pull (snapshot-driven three-way merge for Project + Task; simple upsert for Org/Person)\n//\n\nconst upsertOrganization = Effect.fn('upsertOrganization')(function* (org: GitHubApi.GitHubOrg) {\n const existing = yield* findByForeignId<Organization.Organization>(Organization.Organization, org.id);\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.name = org.name ?? org.login;\n if (org.description != null) {\n existing.description = org.description;\n }\n if (org.blog) {\n existing.website = org.blog;\n }\n if (org.avatar_url) {\n existing.image = org.avatar_url;\n }\n });\n return existing;\n }\n const created = Obj.make(Organization.Organization, {\n [Obj.Meta]: { keys: [fkFor(org.id)] },\n name: org.name ?? org.login,\n description: org.description ?? undefined,\n website: org.blog ?? undefined,\n image: org.avatar_url ?? undefined,\n });\n return yield* Database.add(created);\n});\n\nconst upsertPerson = Effect.fn('upsertPerson')(function* (\n user: GitHubApi.GitHubUser,\n organization: Organization.Organization | undefined,\n) {\n const existing = yield* findByForeignId<Person.Person>(Person.Person, user.id);\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.fullName = user.name ?? user.login;\n if (user.avatar_url) {\n existing.image = user.avatar_url;\n }\n if (organization && !existing.organization) {\n existing.organization = Ref.make(organization);\n }\n // Add the GitHub login identity if not already present.\n const ids = existing.identities ?? [];\n if (!ids.some((entry: { value: string }) => entry.value === user.login)) {\n (existing.identities ??= []).push({ label: 'github', value: user.login });\n }\n });\n return existing;\n }\n const created = Person.make({\n [Obj.Meta]: { keys: [fkFor(user.id)] },\n fullName: user.name ?? user.login,\n image: user.avatar_url ?? undefined,\n organization: organization ? Ref.make(organization) : undefined,\n identities: [{ label: 'github', value: user.login }],\n });\n return yield* Database.add(created);\n});\n\n/**\n * Pull a GitHub repo into ECHO as a Project. Mapped fields go through\n * three-way merge against `binding.snapshots[<repo id>]`; the snapshot\n * is then refreshed to remote-current so the next push pass sees only\n * fields the user has edited locally. `name` is recorded in the snapshot\n * (so we can detect divergence) but is not pushed back — see\n * {@link GitHubApi.updateRepo}.\n */\nconst upsertProject = Effect.fn('upsertProject')(function* (\n binding: Cursor.ExternalCursor,\n repo: GitHubApi.GitHubRepo,\n) {\n const remoteFields: Required<ProjectSnapshot> = {\n name: repo.full_name,\n description: repo.description ?? '',\n };\n const fid = String(repo.id);\n const existing = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, repo.id);\n\n if (existing) {\n const snapshot = Cursor.readSnapshot<ProjectSnapshot>(binding, fid);\n const nameResult = mergeField<string | undefined>(\n existing.name,\n remoteFields.name,\n snapshotField(snapshot, 'name'),\n );\n const descriptionResult = mergeField<string | undefined>(\n existing.description,\n remoteFields.description,\n snapshotField(snapshot, 'description'),\n );\n const writeName = nameResult.source === 'remote' && existing.name !== nameResult.value;\n const writeDescription = descriptionResult.source === 'remote' && existing.description !== descriptionResult.value;\n if (writeName || writeDescription) {\n Obj.update(existing, (existing) => {\n if (writeName) {\n existing.name = nameResult.value;\n }\n if (writeDescription) {\n existing.description = descriptionResult.value;\n }\n });\n }\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return existing;\n }\n\n const created = TaskSet.make({\n [Obj.Meta]: { keys: [fkFor(repo.id)] },\n name: repo.full_name,\n description: repo.description ?? undefined,\n });\n const persisted = yield* Database.add(created);\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return persisted;\n});\n\n/**\n * Pull a GitHub milestone into ECHO. Mirrored remote-wins without a snapshot merge — milestones\n * are pull-only (nothing here pushes milestone edits back), so there is no local side to protect.\n */\nexport const upsertMilestone = Effect.fn('upsertMilestone')(function* (\n taskSet: TaskSet.TaskSet,\n remote: GitHubApi.GitHubMilestone,\n) {\n const name = remote.title;\n const description = remote.description ?? undefined;\n // GitHub's open/closed milestone state is deliberately not mapped: `Milestone` derives progress\n // from its tasks, so a stored status could contradict the work it contains.\n const targetDate = dueOnToTargetDate(remote.due_on);\n\n const existing = yield* findByForeignId<Milestone.Milestone>(Milestone.Milestone, remote.id);\n const milestone =\n existing ??\n (yield* Database.add(Milestone.make({ [Obj.Meta]: { keys: [fkFor(remote.id)] }, name, description, targetDate })));\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.name = name;\n existing.description = description;\n existing.targetDate = targetDate;\n });\n }\n // Sequence is the `milestones` array; the parent edge only carries deletion cascade.\n if (!taskSet.milestones.some(Ref.hasEntityId(milestone.id))) {\n Obj.update(taskSet, (taskSet) => {\n taskSet.milestones.push(Ref.make(milestone));\n });\n Obj.setParent(milestone, taskSet);\n }\n return milestone;\n});\n\n/**\n * Pull a GitHub issue into ECHO as a Task. Same merge shape as\n * {@link upsertProject}, against snapshot fields {title, description, status}.\n * Non-mapped fields (`Task.priority`, `Task.estimate`, etc.) are preserved.\n *\n * Set membership is NOT wired here: this runs concurrently per issue and `TaskSet.tasks` is a\n * shared array, so the caller applies {@link setTaskContainer} sequentially afterwards.\n *\n * `milestone` is the local mirror of `issue.milestone`, mirrored remote-wins outside the snapshot\n * merge (nothing pushes milestone edits back, so there is no local side to protect).\n */\nexport const upsertTask = Effect.fn('upsertTask')(function* (\n binding: Cursor.ExternalCursor,\n issue: GitHubApi.GitHubIssue,\n assignedPerson: Person.Person | undefined,\n milestone: Milestone.Milestone | undefined,\n) {\n const remoteFields: Required<TaskSnapshot> = {\n title: issue.title,\n description: issue.body ?? '',\n status: issueStateToTaskStatus(issue.state),\n };\n const fid = String(issue.id);\n const existing = yield* findByForeignId<Task.Task>(Task.Task, issue.id);\n\n if (existing) {\n const snapshot = Cursor.readSnapshot<TaskSnapshot>(binding, fid);\n // Task.title is required (non-optional) so the merge produces a string.\n const titleResult = mergeField<string>(existing.title, remoteFields.title, snapshotField(snapshot, 'title'));\n const descriptionResult = mergeField<string | undefined>(\n existing.description,\n remoteFields.description,\n snapshotField(snapshot, 'description'),\n );\n // existing.status is the full Task status union; the snapshot only ever holds GitHub's\n // collapsed shape ('todo' | 'done'). Widen the merge type so both sides typecheck and let\n // mergeField compare them as plain values.\n const statusResult = mergeField<Task.Task['status']>(\n existing.status,\n remoteFields.status,\n snapshotField(snapshot, 'status'),\n );\n const writeTitle = titleResult.source === 'remote' && existing.title !== titleResult.value;\n const writeDescription = descriptionResult.source === 'remote' && existing.description !== descriptionResult.value;\n const writeStatus = statusResult.source === 'remote' && existing.status !== statusResult.value;\n Obj.update(existing, (existing) => {\n if (writeTitle) {\n existing.title = titleResult.value;\n }\n if (writeDescription) {\n existing.description = descriptionResult.value;\n }\n if (writeStatus) {\n existing.status = statusResult.value;\n }\n if (assignedPerson && !existing.assignee?.contact) {\n existing.assignee = { contact: Ref.make(assignedPerson) };\n }\n if (milestone) {\n if (existing.milestone?.target?.id !== milestone.id) {\n existing.milestone = Ref.make(milestone);\n }\n // Clear only when GitHub itself reports no milestone; a merely unresolved one would\n // otherwise wipe a perfectly good local assignment.\n } else if (issue.milestone == null && existing.milestone !== undefined) {\n existing.milestone = undefined;\n }\n });\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return { task: existing, created: false };\n }\n\n const created = Task.make({\n [Obj.Meta]: { keys: [fkFor(issue.id)] },\n title: issue.title,\n description: issue.body ?? '',\n status: issueStateToTaskStatus(issue.state),\n assignee: assignedPerson ? { contact: Ref.make(assignedPerson) } : undefined,\n milestone: milestone ? Ref.make(milestone) : undefined,\n });\n const persisted = yield* Database.add(created);\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return { task: persisted, created: true };\n});\n\n//\n// Push (snapshot diff → GitHub mutations)\n//\n\nexport type GitHubPushResult = {\n projects: number;\n tasks: number;\n};\n\n/**\n * Push reconciler for one repo. Walks the locally-mirrored Project for the\n * given repo plus every Task whose foreign key matches one of the issues we\n * just pulled, diffs against the binding's snapshot, and PATCHes any diverged\n * field back to GitHub.\n *\n * Behaviour:\n * - Project description divergence → PATCH /repos/{owner}/{repo}.\n * `name` divergence is logged but NOT pushed (rename is destructive and\n * almost never desired from a sync mirror).\n * - Task title / description / status divergence → PATCH the issue.\n * - Tombstones (`Obj.isDeleted`) are skipped.\n *\n * After a successful push the snapshot is refreshed with the values just\n * sent so the next pass sees no divergence even before the next pull.\n *\n * The push callbacks' error type is generic. The reconciler doesn't inspect\n * or recover from those errors — it propagates so the outer `Effect.result`\n * at the call site can record the binding's `lastError`. Generic-`E` keeps\n * this module decoupled from the HTTP error hierarchy of `GitHubApi`.\n */\nexport const pushRepoUpdates: <E, R>(\n binding: Cursor.ExternalCursor,\n repo: GitHubApi.GitHubRepo,\n remoteIssuesById: ReadonlyMap<string, GitHubApi.GitHubIssue>,\n push: {\n /** Wraps `GitHubApi.updateIssue`. */\n updateIssue: (\n owner: string,\n repo: string,\n issueNumber: number,\n input: GitHubApi.IssueUpdateInput,\n ) => Effect.Effect<void, E, R>;\n /** Wraps `GitHubApi.updateRepo`. */\n updateRepo: (owner: string, repo: string, input: GitHubApi.RepoUpdateInput) => Effect.Effect<void, E, R>;\n },\n) => Effect.Effect<GitHubPushResult, E, Database.Service | R> = Effect.fn('pushRepoUpdates')(\n function* (binding, repo, remoteIssuesById, push) {\n let projects = 0;\n let tasks = 0;\n\n // Project (repo) push — description only.\n {\n const fid = String(repo.id);\n const local = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, repo.id);\n if (local && !Obj.isDeleted(local)) {\n const snapshot = Cursor.readSnapshot<ProjectSnapshot>(binding, fid);\n if (snapshot) {\n const localName = local.name ?? '';\n const localDescription = local.description ?? '';\n const input: GitHubApi.RepoUpdateInput = {};\n let diverged = false;\n if (snapshot.description !== undefined && snapshot.description !== localDescription) {\n input.description = localDescription;\n diverged = true;\n }\n if (snapshot.name !== undefined && snapshot.name !== localName) {\n // We deliberately don't push repo renames — see updateRepo above.\n // Log instead so the user can chase down via the audit channel.\n log.warn('github push: local repo name diverges from remote; rename push is intentionally disabled', {\n repoId: fid,\n localName,\n snapshotName: snapshot.name,\n });\n }\n if (diverged) {\n yield* push.updateRepo(repo.owner.login, repo.name, input);\n Cursor.writeSnapshot(binding, fid, {\n ...snapshot,\n description: localDescription,\n });\n projects++;\n }\n }\n }\n }\n\n // Task (issue) push — title / body / state.\n for (const [id, remoteIssue] of remoteIssuesById) {\n const local = yield* findByForeignId<Task.Task>(Task.Task, id);\n if (!local || Obj.isDeleted(local)) {\n continue;\n }\n const snapshot = Cursor.readSnapshot<TaskSnapshot>(binding, id);\n if (!snapshot) {\n continue;\n }\n const localTitle = local.title ?? '';\n const localDescription = local.description ?? '';\n const localStatus = local.status;\n const desiredStatusForSnapshot: 'todo' | 'done' | undefined =\n localStatus === 'done' ? 'done' : localStatus === 'todo' || localStatus === 'started' ? 'todo' : undefined;\n\n const input: GitHubApi.IssueUpdateInput = {};\n let diverged = false;\n if (snapshot.title !== undefined && snapshot.title !== localTitle) {\n input.title = localTitle;\n diverged = true;\n }\n if (snapshot.description !== undefined && snapshot.description !== localDescription) {\n input.body = localDescription;\n diverged = true;\n }\n // Status push is pull-only for PRs. GitHub uses the same /issues/{n}\n // endpoint for issues and PRs, but `state: 'closed'` on a PR rejects\n // it (the closed-without-merge red badge), and merging requires a\n // separate `PUT /pulls/{n}/merge` endpoint we don't support. The safe\n // default is to never push a status change for a PR — log if local\n // and snapshot diverge so the divergence is auditable.\n const isPullRequest = remoteIssue.pull_request != null;\n if (\n !isPullRequest &&\n snapshot.status !== undefined &&\n desiredStatusForSnapshot !== undefined &&\n snapshot.status !== desiredStatusForSnapshot\n ) {\n const issueState = taskStatusToIssueState(localStatus);\n if (issueState) {\n input.state = issueState;\n diverged = true;\n }\n } else if (\n isPullRequest &&\n snapshot.status !== undefined &&\n desiredStatusForSnapshot !== undefined &&\n snapshot.status !== desiredStatusForSnapshot\n ) {\n log.warn('github push: PR status diverged locally; pull-only for PRs (status will not be pushed)', {\n issueId: id,\n number: remoteIssue.number,\n localStatus,\n snapshotStatus: snapshot.status,\n });\n }\n if (!diverged) {\n continue;\n }\n\n yield* push.updateIssue(repo.owner.login, repo.name, remoteIssue.number, input);\n // Refresh the snapshot: title / description / status sent. Status only\n // gets refreshed when we actually pushed a state change (issues only) —\n // for PRs we keep the snapshot's previous status, so the warning above\n // keeps firing until either the user reverts locally or the PR's state\n // changes on GitHub and a pull catches up.\n Cursor.writeSnapshot(binding, id, {\n ...snapshot,\n title: localTitle,\n description: localDescription,\n status: input.state !== undefined ? (desiredStatusForSnapshot ?? snapshot.status) : snapshot.status,\n });\n tasks++;\n }\n\n return { projects, tasks };\n },\n);\n\n//\n// Main handler\n//\n\n/**\n * Per-binding sync body run by the account-level fan-out: reconcile the one repo the\n * binding targets, stamping success/failure onto the binding and toasting either way.\n */\nconst syncRepoBinding = Effect.fn('syncRepoBinding')(function* (binding: Cursor.ExternalCursor) {\n const project = yield* Database.load(binding.spec.target);\n const db = Obj.getDatabase(binding) ?? Obj.getDatabase(project);\n if (!db) {\n return yield* Effect.fail(new ConnectorSync.DatabaseMissingError());\n }\n\n // The repo's foreign id: prefer the binding's `externalId`, falling back\n // to the GitHub foreign key on the target object.\n const externalId =\n binding.spec.externalId ?? Obj.getMeta(project).keys.find((key) => key.source === GITHUB_SOURCE)?.id;\n\n const outcome = yield* Effect.result(\n Effect.gen(function* () {\n if (externalId === undefined) {\n return yield* Effect.fail(new GitHubRepoUnresolvedError());\n }\n\n // Fetch all repos visible to the token once so the binding can\n // resolve its remote `GitHubRepo`. The binding stores the numeric\n // repo id as `externalId` (a stringified integer).\n // TODO(wittjosiah): Switch to `fetchRepo(owner, name)` once the\n // binding carries `owner`/`name`. `fetchUserRepos()` walks every\n // repo the token can see and dominates large-account syncs.\n const allRepos = yield* GitHubApi.fetchUserRepos();\n const remoteRepo = allRepos.find((repo) => String(repo.id) === externalId);\n if (!remoteRepo) {\n return yield* Effect.fail(new GitHubRepoInaccessibleError());\n }\n\n const options = (binding.spec.options ?? undefined) as GitHubOperation.SyncOptions | undefined;\n\n // Upsert the local Project for this repo (three-way merge).\n yield* upsertProject(binding, remoteRepo);\n\n // Cross-issue dedup for Person upserts: parallel per-issue work can\n // race two upserts for the same login (same assignee on multiple\n // issues, or org members). Without serialization both fibers find no\n // foreign-key match, both insert, leaving duplicate Person rows. The\n // semaphore + cache pair gives us a single in-flight upsert per login;\n // subsequent callers read from `personByLogin`.\n const personByLogin = new Map<string, Person.Person>();\n const personSemaphore = yield* Semaphore.make(1);\n const ensurePerson = (user: GitHubApi.GitHubUser, organization: Organization.Organization | undefined) =>\n personSemaphore.withPermits(1)(\n Effect.gen(function* () {\n const cached = personByLogin.get(user.login);\n if (cached) {\n return cached;\n }\n const person = yield* upsertPerson(user, organization);\n personByLogin.set(user.login, person);\n return person;\n }),\n );\n\n // Auto-pull the owning org + members for this repo's owner.\n // `/orgs/{owner}` returns 404 for user-owned repos (personal\n // accounts are not orgs). Treat that as \"no org to sync\" and\n // continue — the Project just won't have a parent organization.\n let pulledOrganizations = 0;\n const owner = remoteRepo.owner.login;\n const orgResult = yield* Effect.result(GitHubApi.fetchOrg(owner));\n if (orgResult._tag === 'Success') {\n const organization = yield* upsertOrganization(orgResult.success);\n pulledOrganizations++;\n const members = yield* GitHubApi.fetchOrgMembers(owner);\n for (const member of members) {\n yield* ensurePerson(member, organization);\n }\n } else {\n log.info('github sync: owner is not an org, skipping org/member pull', { owner });\n }\n\n // Re-resolve the local Project after upsert so issue upserts and\n // pushes operate on the persisted record.\n const localProject = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, remoteRepo.id);\n if (!localProject) {\n return yield* Effect.fail(new GitHubProjectMissingError());\n }\n\n // Milestones before issues: an issue's `milestone` has to resolve to a local mirror, and the\n // repo endpoint also surfaces milestones no open issue points at yet.\n const milestoneByRemoteId = new Map<number, Milestone.Milestone>();\n const remoteMilestones = yield* GitHubApi.fetchRepoMilestones(remoteRepo.owner.login, remoteRepo.name);\n for (const remoteMilestone of remoteMilestones) {\n milestoneByRemoteId.set(remoteMilestone.id, yield* upsertMilestone(localProject, remoteMilestone));\n }\n\n let pulledTasks = 0;\n const since = sinceFromOptions(options);\n const issues = yield* GitHubApi.fetchRepoIssues(remoteRepo.owner.login, remoteRepo.name, { since });\n const remoteIssuesById = new Map<string, GitHubApi.GitHubIssue>();\n const pulled = yield* Effect.forEach(\n issues,\n (issue) =>\n Effect.gen(function* () {\n // Resolve assignee — first assignee only for v1. External\n // (non-org) assignees are upserted lazily; the semaphored\n // `ensurePerson` dedups across fibers.\n const assigneeUser = issue.assignees?.[0];\n const assignedPerson = assigneeUser ? yield* ensurePerson(assigneeUser, undefined) : undefined;\n const milestone = issue.milestone ? milestoneByRemoteId.get(issue.milestone.id) : undefined;\n\n const { task, created } = yield* upsertTask(binding, issue, assignedPerson, milestone);\n remoteIssuesById.set(String(issue.id), issue);\n if (created) {\n pulledTasks++;\n }\n\n // TODO(wittjosiah): Comments sync disabled — re-enable once\n // chunked/yielded to avoid automerge_wasm crash when upserting\n // many comments in one tick.\n return task;\n }),\n { concurrency: ISSUE_CONCURRENCY },\n );\n\n // Sequential: `TaskSet.tasks` is one shared array, so concurrent appends would drop entries.\n // `Effect.forEach` preserves input order, so the set's order mirrors GitHub's.\n for (const task of pulled) {\n yield* setTaskContainer(task, localProject);\n }\n\n // Push: snapshot-diff the local Project + Tasks for this repo and\n // PATCH only the diverged fields.\n //\n // TODO(wittjosiah): `remoteIssuesById` is built from\n // `fetchRepoIssues(..., { since })`, so when `maxDaysBack` is set\n // this push pass cannot see locally-edited tasks whose remote issue\n // is older than the window. Switch the candidate set to the local\n // mirror (every Task with a GITHUB_SOURCE fk under this repo) once\n // we store `number` per task so we don't need the remote payload to PATCH.\n const pushResult = yield* pushRepoUpdates(binding, remoteRepo, remoteIssuesById, {\n updateIssue: (owner, repoName, issueNumber, input) =>\n GitHubApi.updateIssue(owner, repoName, issueNumber, input).pipe(Effect.map(() => undefined)),\n updateRepo: (owner, repoName, input) =>\n GitHubApi.updateRepo(owner, repoName, input).pipe(Effect.map(() => undefined)),\n });\n\n return {\n pulled: {\n organizations: pulledOrganizations,\n people: personByLogin.size,\n projects: 1,\n tasks: pulledTasks,\n comments: 0,\n },\n pushed: pushResult,\n };\n }).pipe(Effect.provide(Layer.provideMerge(Database.layer(db), GitHubApi.fromAccessToken(binding.spec.source)))),\n );\n\n // Write sync state onto the binding.\n if (outcome._tag === 'Success') {\n Cursor.advance(binding);\n yield* Effect.ignore(\n Operation.invoke(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.sync-success`,\n icon: 'ph--check--regular',\n title: ['sync-toast.success.label', { ns: meta.profile.key }],\n }),\n );\n return { pulled: outcome.success.pulled };\n } else {\n const message = formatGitHubSyncFailure(outcome.failure);\n Cursor.recordError(binding, message);\n log.warn('github sync: binding failed', { error: outcome.failure });\n yield* Effect.ignore(\n Operation.invoke(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.sync-error`,\n icon: 'ph--warning--regular',\n title: ['sync-toast.error.label', { ns: meta.profile.key }],\n description: message,\n }),\n );\n return yield* Effect.fail(outcome.failure);\n }\n}, Effect.provide(FetchHttpClient.layer));\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncGitHubRepositories> =\n GitHubOperation.SyncGitHubRepositories.pipe(\n Operation.withHandler(({ connection, priority }) =>\n Binding.syncAll({\n connection,\n priority,\n sync: (binding) => syncRepoBinding(binding),\n }).pipe(\n Effect.map(({ outputs }) => ({\n pulled: outputs.reduce(\n (total, { pulled }) => ({\n organizations: total.organizations + pulled.organizations,\n people: total.people + pulled.people,\n projects: total.projects + pulled.projects,\n tasks: total.tasks + pulled.tasks,\n comments: total.comments + pulled.comments,\n }),\n { organizations: 0, people: 0, projects: 0, tasks: 0, comments: 0 },\n ),\n })),\n ),\n ),\n );\n\nexport default handler;\n"],"mappings":"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"}
1
+ {"version":3,"file":"chunk-sync.mjs","names":["GitHubApi.fetchUserRepos","GitHubApi.fetchOrg","GitHubApi.fetchOrgMembers","GitHubApi.fetchRepoMilestones","GitHubApi.fetchRepoIssues","GitHubApi.updateIssue","GitHubApi.updateRepo","GitHubApi.fromAccessToken"],"sources":["../../src/operations/sync.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\nimport * as Semaphore from 'effect/Semaphore';\n\nimport * as ConnectorSync from '@dxos/app-toolkit/ConnectorSync';\nimport * as LayoutOperation from '@dxos/app-toolkit/LayoutOperation';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Filter, Obj, Query, Ref, Type } from '@dxos/echo';\nimport { Cursor } from '@dxos/link';\nimport { log } from '@dxos/log';\nimport * as Binding from '@dxos/plugin-connector/Binding';\nimport { Milestone, Organization, Person, Task, TaskSet } from '@dxos/types';\n\nimport { meta } from '#meta';\nimport { GitHubOperation } from '#types';\n\nimport { GITHUB_SOURCE } from '../constants.ts';\nimport {\n GitHubProjectMissingError,\n GitHubRepoInaccessibleError,\n GitHubRepoUnresolvedError,\n formatGitHubSyncFailure,\n} from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\n\nconst { mergeField, snapshotField } = ConnectorSync;\n\n//\n// Direction: bidirectional (pull-then-push) for projects and tasks.\n//\n// Each sync pass syncs one binding (one repo). It first pulls every reachable\n// Organization, Person, Project, and Task from GitHub into ECHO, then walks the\n// local mirrors and pushes any field that diverged from the snapshot taken at\n// the end of the previous pull. Snapshots live on the `Cursor` object's\n// `spec.snapshots[<github id>]` (where ids are the GitHub-issued numeric ids,\n// stringified for stable foreign-key matching).\n//\n// Mapped fields per object:\n// Project (repo): description (description-only — see updateRepo for why\n// `name` is intentionally not pushed)\n// Task (issue): title, description, status (open/closed)\n//\n// Conflict policy is remote-wins (mirrors Trello/Linear). Comments are NOT\n// synced (the chunked-yield rewrite is still pending; see TODO below).\n//\n// Attribution caveat: pushed edits are attributed to the GitHub App / OAuth\n// user that owns the connection token, not to the local user who made the\n// edit. This is unavoidable with the current token model — a write from\n// \"Person A in space\" appears on GitHub as a write from the App. Document\n// before enabling for shared spaces.\n//\n// New local objects (no GitHub foreign key) are NOT pushed in this pass —\n// creating a new GitHub issue requires (owner, repo) which we currently\n// don't surface from local Tasks unambiguously.\n//\n// Sync target shape: each binding's target is the local root Project for one\n// REPOSITORY. The repo's owning org (and org members) are auto-pulled.\n//\n\n//\n// Tunables\n//\n\n/** Per-repo issue parallelism. */\nconst ISSUE_CONCURRENCY = 4;\n\n//\n// Snapshot field shapes (stored on Cursor's `spec.snapshots`)\n//\n\n/**\n * Snapshot shapes. Fields are required (not `?`) because every snapshot is\n * written in one shot via {@link Cursor.writeSnapshot} after a pull; absence-of-\n * snapshot is modeled by `Cursor.readSnapshot` returning `undefined`. `name` on a\n * Project is recorded but not pushed — see {@link GitHubApi.updateRepo}.\n */\ntype ProjectSnapshot = {\n name: string;\n description: string;\n};\n\ntype TaskSnapshot = {\n title: string;\n description: string;\n status: 'todo' | 'done';\n};\n\n//\n// Foreign-key + lookup helpers\n//\n\nconst fkFor = (id: string | number) => ({ source: GITHUB_SOURCE, id: String(id) });\n\n/**\n * Generic foreign-key lookup. Type is forwarded to `Filter.foreignKeys`\n * untyped — the caller supplies the result type via the explicit `T` parameter\n * (mirrors how plugin-trello casts after `Database.query(...).run`).\n */\nconst findByForeignId = <T>(type: Type.AnyEntity, id: string | number) =>\n Effect.gen(function* () {\n const results = yield* Database.query(Query.select(Filter.foreignKeys(type as never, [fkFor(id)]))).run;\n return results.length > 0 ? (results[0] as T) : undefined;\n });\n\n//\n// Field mappers (GitHub ↔ DXOS)\n//\n\n/**\n * Maps GitHub issue state to a Task status. GitHub issues only have `open` /\n * `closed` — there's no \"in progress\" concept, so we collapse open→`todo` and\n * closed→`done`. PRs use the same mapping; merged PRs are reported as `closed`\n * by GitHub plus a non-null `pull_request.merged_at`.\n */\nconst issueStateToTaskStatus = (state: string): 'todo' | 'done' => (state === 'closed' ? 'done' : 'todo');\n\n/**\n * Reverse of {@link issueStateToTaskStatus}. `'started'` is collapsed to\n * `open` since GitHub has no equivalent state. Returns undefined when the\n * status is unrecognised so the caller can skip the push instead of failing.\n */\nconst taskStatusToIssueState = (status: string | undefined): 'open' | 'closed' | undefined => {\n switch (status) {\n case 'done':\n return 'closed';\n case 'todo':\n case 'started':\n return 'open';\n default:\n return undefined;\n }\n};\n\nconst sinceFromOptions = (options: GitHubOperation.SyncOptions | undefined): string | undefined => {\n const days = options?.maxDaysBack;\n if (typeof days !== 'number' || days <= 0) {\n return undefined;\n }\n return new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();\n};\n\n/** GitHub reports `due_on` as an ISO datetime; `Milestone.targetDate` is date-only. */\nconst dueOnToTargetDate = (dueOn: string | null | undefined): string | undefined => dueOn?.slice(0, 10) ?? undefined;\n\n/**\n * Move a task into `container`. Idempotent — sync runs repeatedly and must never append a second\n * ref for a task already in the set.\n */\nexport const setTaskContainer = Effect.fn('setTaskContainer')(function* (task: Task.Task, container: TaskSet.TaskSet) {\n const listed = container.tasks.some(Ref.hasEntityId(task.id));\n // A stale entry for a task now parented elsewhere is not membership; it still needs re-rooting.\n if (listed && Obj.getParent(task)?.id === container.id) {\n return;\n }\n // The reverse-ref index, not `Obj.getParent`: legacy sets may hold refs to tasks whose parent\n // edge has not yet been healed to the set, and every holder must drop its stale entry.\n const previous = yield* Database.query(\n Query.select(Filter.id(task.id)).referencedBy(TaskSet.TaskSet, 'tasks'),\n ).run.pipe(Effect.orElseSucceed(() => []));\n for (const set of previous) {\n if (set.id === container.id) {\n continue;\n }\n Obj.update(set, (set) => {\n TaskSet.removeRefsInPlace(set.tasks, new Set([task.id]));\n });\n }\n // A task filed as a sub-task is listed by its parent rather than a set; it leaves that list too.\n const parent = Task.getParentTask(task);\n if (parent) {\n Obj.update(parent, (parent) => {\n TaskSet.removeRefsInPlace(parent.subtasks ?? [], new Set([task.id]));\n });\n }\n if (!listed) {\n Obj.update(container, (container) => {\n container.tasks.push(Ref.make(task));\n });\n }\n // `tasks` claims only an unparented task, so a move between sets moves the edge itself.\n Obj.setParent(task, container);\n});\n\n//\n// Pull (snapshot-driven three-way merge for Project + Task; simple upsert for Org/Person)\n//\n\nconst upsertOrganization = Effect.fn('upsertOrganization')(function* (org: GitHubApi.GitHubOrg) {\n const existing = yield* findByForeignId<Organization.Organization>(Organization.Organization, org.id);\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.name = org.name ?? org.login;\n if (org.description != null) {\n existing.description = org.description;\n }\n if (org.blog) {\n existing.website = org.blog;\n }\n if (org.avatar_url) {\n existing.image = org.avatar_url;\n }\n });\n return existing;\n }\n const created = Obj.make(Organization.Organization, {\n [Obj.Meta]: { keys: [fkFor(org.id)] },\n name: org.name ?? org.login,\n description: org.description ?? undefined,\n website: org.blog ?? undefined,\n image: org.avatar_url ?? undefined,\n });\n return yield* Database.add(created);\n});\n\nconst upsertPerson = Effect.fn('upsertPerson')(function* (\n user: GitHubApi.GitHubUser,\n organization: Organization.Organization | undefined,\n) {\n const existing = yield* findByForeignId<Person.Person>(Person.Person, user.id);\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.fullName = user.name ?? user.login;\n if (user.avatar_url) {\n existing.image = user.avatar_url;\n }\n if (organization && !existing.organization) {\n existing.organization = Ref.make(organization);\n }\n // Add the GitHub login identity if not already present.\n const ids = existing.identities ?? [];\n if (!ids.some((entry: { value: string }) => entry.value === user.login)) {\n (existing.identities ??= []).push({ label: 'github', value: user.login });\n }\n });\n return existing;\n }\n const created = Person.make({\n [Obj.Meta]: { keys: [fkFor(user.id)] },\n fullName: user.name ?? user.login,\n image: user.avatar_url ?? undefined,\n organization: organization ? Ref.make(organization) : undefined,\n identities: [{ label: 'github', value: user.login }],\n });\n return yield* Database.add(created);\n});\n\n/**\n * Pull a GitHub repo into ECHO as a Project. Mapped fields go through\n * three-way merge against `binding.snapshots[<repo id>]`; the snapshot\n * is then refreshed to remote-current so the next push pass sees only\n * fields the user has edited locally. `name` is recorded in the snapshot\n * (so we can detect divergence) but is not pushed back — see\n * {@link GitHubApi.updateRepo}.\n */\nconst upsertProject = Effect.fn('upsertProject')(function* (\n binding: Cursor.ExternalCursor,\n repo: GitHubApi.GitHubRepo,\n) {\n const remoteFields: Required<ProjectSnapshot> = {\n name: repo.full_name,\n description: repo.description ?? '',\n };\n const fid = String(repo.id);\n const existing = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, repo.id);\n\n if (existing) {\n const snapshot = Cursor.readSnapshot<ProjectSnapshot>(binding, fid);\n const nameResult = mergeField<string | undefined>(\n existing.name,\n remoteFields.name,\n snapshotField(snapshot, 'name'),\n );\n const descriptionResult = mergeField<string | undefined>(\n existing.description,\n remoteFields.description,\n snapshotField(snapshot, 'description'),\n );\n const writeName = nameResult.source === 'remote' && existing.name !== nameResult.value;\n const writeDescription = descriptionResult.source === 'remote' && existing.description !== descriptionResult.value;\n if (writeName || writeDescription) {\n Obj.update(existing, (existing) => {\n if (writeName) {\n existing.name = nameResult.value;\n }\n if (writeDescription) {\n existing.description = descriptionResult.value;\n }\n });\n }\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return existing;\n }\n\n const created = TaskSet.make({\n [Obj.Meta]: { keys: [fkFor(repo.id)] },\n name: repo.full_name,\n description: repo.description ?? undefined,\n });\n const persisted = yield* Database.add(created);\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return persisted;\n});\n\n/**\n * Pull a GitHub milestone into ECHO. Mirrored remote-wins without a snapshot merge — milestones\n * are pull-only (nothing here pushes milestone edits back), so there is no local side to protect.\n */\nexport const upsertMilestone = Effect.fn('upsertMilestone')(function* (\n taskSet: TaskSet.TaskSet,\n remote: GitHubApi.GitHubMilestone,\n) {\n const name = remote.title;\n const description = remote.description ?? undefined;\n // GitHub's open/closed milestone state is deliberately not mapped: `Milestone` derives progress\n // from its tasks, so a stored status could contradict the work it contains.\n const targetDate = dueOnToTargetDate(remote.due_on);\n\n const existing = yield* findByForeignId<Milestone.Milestone>(Milestone.Milestone, remote.id);\n const milestone =\n existing ??\n (yield* Database.add(Milestone.make({ [Obj.Meta]: { keys: [fkFor(remote.id)] }, name, description, targetDate })));\n if (existing) {\n Obj.update(existing, (existing) => {\n existing.name = name;\n existing.description = description;\n existing.targetDate = targetDate;\n });\n }\n // Sequence is the `milestones` array; the parent edge only carries deletion cascade.\n if (!taskSet.milestones.some(Ref.hasEntityId(milestone.id))) {\n Obj.update(taskSet, (taskSet) => {\n taskSet.milestones.push(Ref.make(milestone));\n });\n Obj.setParent(milestone, taskSet);\n }\n return milestone;\n});\n\n/**\n * Pull a GitHub issue into ECHO as a Task. Same merge shape as\n * {@link upsertProject}, against snapshot fields {title, description, status}.\n * Non-mapped fields (`Task.priority`, `Task.estimate`, etc.) are preserved.\n *\n * Set membership is NOT wired here: this runs concurrently per issue and `TaskSet.tasks` is a\n * shared array, so the caller applies {@link setTaskContainer} sequentially afterwards.\n *\n * `milestone` is the local mirror of `issue.milestone`, mirrored remote-wins outside the snapshot\n * merge (nothing pushes milestone edits back, so there is no local side to protect).\n */\nexport const upsertTask = Effect.fn('upsertTask')(function* (\n binding: Cursor.ExternalCursor,\n issue: GitHubApi.GitHubIssue,\n assignedPerson: Person.Person | undefined,\n milestone: Milestone.Milestone | undefined,\n) {\n const remoteFields: Required<TaskSnapshot> = {\n title: issue.title,\n description: issue.body ?? '',\n status: issueStateToTaskStatus(issue.state),\n };\n const fid = String(issue.id);\n const existing = yield* findByForeignId<Task.Task>(Task.Task, issue.id);\n\n if (existing) {\n const snapshot = Cursor.readSnapshot<TaskSnapshot>(binding, fid);\n // Task.title is required (non-optional) so the merge produces a string.\n const titleResult = mergeField<string>(existing.title, remoteFields.title, snapshotField(snapshot, 'title'));\n const descriptionResult = mergeField<string | undefined>(\n existing.description,\n remoteFields.description,\n snapshotField(snapshot, 'description'),\n );\n // existing.status is the full Task status union; the snapshot only ever holds GitHub's\n // collapsed shape ('todo' | 'done'). Widen the merge type so both sides typecheck and let\n // mergeField compare them as plain values.\n const statusResult = mergeField<Task.Task['status']>(\n existing.status,\n remoteFields.status,\n snapshotField(snapshot, 'status'),\n );\n const writeTitle = titleResult.source === 'remote' && existing.title !== titleResult.value;\n const writeDescription = descriptionResult.source === 'remote' && existing.description !== descriptionResult.value;\n const writeStatus = statusResult.source === 'remote' && existing.status !== statusResult.value;\n Obj.update(existing, (existing) => {\n if (writeTitle) {\n existing.title = titleResult.value;\n }\n if (writeDescription) {\n existing.description = descriptionResult.value;\n }\n if (writeStatus) {\n existing.status = statusResult.value;\n }\n if (assignedPerson && !existing.assignee?.contact) {\n existing.assignee = { contact: Ref.make(assignedPerson) };\n }\n if (milestone) {\n if (existing.milestone?.target?.id !== milestone.id) {\n existing.milestone = Ref.make(milestone);\n }\n // Clear only when GitHub itself reports no milestone; a merely unresolved one would\n // otherwise wipe a perfectly good local assignment.\n } else if (issue.milestone == null && existing.milestone !== undefined) {\n existing.milestone = undefined;\n }\n });\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return { task: existing, created: false };\n }\n\n const created = Task.make({\n [Obj.Meta]: { keys: [fkFor(issue.id)] },\n title: issue.title,\n description: issue.body ?? '',\n status: issueStateToTaskStatus(issue.state),\n assignee: assignedPerson ? { contact: Ref.make(assignedPerson) } : undefined,\n milestone: milestone ? Ref.make(milestone) : undefined,\n });\n const persisted = yield* Database.add(created);\n Cursor.writeSnapshot(binding, fid, remoteFields);\n return { task: persisted, created: true };\n});\n\n//\n// Push (snapshot diff → GitHub mutations)\n//\n\nexport type GitHubPushResult = {\n projects: number;\n tasks: number;\n};\n\n/**\n * Push reconciler for one repo. Walks the locally-mirrored Project for the\n * given repo plus every Task whose foreign key matches one of the issues we\n * just pulled, diffs against the binding's snapshot, and PATCHes any diverged\n * field back to GitHub.\n *\n * Behaviour:\n * - Project description divergence → PATCH /repos/{owner}/{repo}.\n * `name` divergence is logged but NOT pushed (rename is destructive and\n * almost never desired from a sync mirror).\n * - Task title / description / status divergence → PATCH the issue.\n * - Tombstones (`Obj.isDeleted`) are skipped.\n *\n * After a successful push the snapshot is refreshed with the values just\n * sent so the next pass sees no divergence even before the next pull.\n *\n * The push callbacks' error type is generic. The reconciler doesn't inspect\n * or recover from those errors — it propagates so the outer `Effect.result`\n * at the call site can record the binding's `lastError`. Generic-`E` keeps\n * this module decoupled from the HTTP error hierarchy of `GitHubApi`.\n */\nexport const pushRepoUpdates: <E, R>(\n binding: Cursor.ExternalCursor,\n repo: GitHubApi.GitHubRepo,\n remoteIssuesById: ReadonlyMap<string, GitHubApi.GitHubIssue>,\n push: {\n /** Wraps `GitHubApi.updateIssue`. */\n updateIssue: (\n owner: string,\n repo: string,\n issueNumber: number,\n input: GitHubApi.IssueUpdateInput,\n ) => Effect.Effect<void, E, R>;\n /** Wraps `GitHubApi.updateRepo`. */\n updateRepo: (owner: string, repo: string, input: GitHubApi.RepoUpdateInput) => Effect.Effect<void, E, R>;\n },\n) => Effect.Effect<GitHubPushResult, E, Database.Service | R> = Effect.fn('pushRepoUpdates')(\n function* (binding, repo, remoteIssuesById, push) {\n let projects = 0;\n let tasks = 0;\n\n // Project (repo) push — description only.\n {\n const fid = String(repo.id);\n const local = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, repo.id);\n if (local && !Obj.isDeleted(local)) {\n const snapshot = Cursor.readSnapshot<ProjectSnapshot>(binding, fid);\n if (snapshot) {\n const localName = local.name ?? '';\n const localDescription = local.description ?? '';\n const input: GitHubApi.RepoUpdateInput = {};\n let diverged = false;\n if (snapshot.description !== undefined && snapshot.description !== localDescription) {\n input.description = localDescription;\n diverged = true;\n }\n if (snapshot.name !== undefined && snapshot.name !== localName) {\n // We deliberately don't push repo renames — see updateRepo above.\n // Log instead so the user can chase down via the audit channel.\n log.warn('github push: local repo name diverges from remote; rename push is intentionally disabled', {\n repoId: fid,\n localName,\n snapshotName: snapshot.name,\n });\n }\n if (diverged) {\n yield* push.updateRepo(repo.owner.login, repo.name, input);\n Cursor.writeSnapshot(binding, fid, {\n ...snapshot,\n description: localDescription,\n });\n projects++;\n }\n }\n }\n }\n\n // Task (issue) push — title / body / state.\n for (const [id, remoteIssue] of remoteIssuesById) {\n const local = yield* findByForeignId<Task.Task>(Task.Task, id);\n if (!local || Obj.isDeleted(local)) {\n continue;\n }\n const snapshot = Cursor.readSnapshot<TaskSnapshot>(binding, id);\n if (!snapshot) {\n continue;\n }\n const localTitle = local.title ?? '';\n const localDescription = local.description ?? '';\n const localStatus = local.status;\n const desiredStatusForSnapshot: 'todo' | 'done' | undefined =\n localStatus === 'done' ? 'done' : localStatus === 'todo' || localStatus === 'started' ? 'todo' : undefined;\n\n const input: GitHubApi.IssueUpdateInput = {};\n let diverged = false;\n if (snapshot.title !== undefined && snapshot.title !== localTitle) {\n input.title = localTitle;\n diverged = true;\n }\n if (snapshot.description !== undefined && snapshot.description !== localDescription) {\n input.body = localDescription;\n diverged = true;\n }\n // Status push is pull-only for PRs. GitHub uses the same /issues/{n}\n // endpoint for issues and PRs, but `state: 'closed'` on a PR rejects\n // it (the closed-without-merge red badge), and merging requires a\n // separate `PUT /pulls/{n}/merge` endpoint we don't support. The safe\n // default is to never push a status change for a PR — log if local\n // and snapshot diverge so the divergence is auditable.\n const isPullRequest = remoteIssue.pull_request != null;\n if (\n !isPullRequest &&\n snapshot.status !== undefined &&\n desiredStatusForSnapshot !== undefined &&\n snapshot.status !== desiredStatusForSnapshot\n ) {\n const issueState = taskStatusToIssueState(localStatus);\n if (issueState) {\n input.state = issueState;\n diverged = true;\n }\n } else if (\n isPullRequest &&\n snapshot.status !== undefined &&\n desiredStatusForSnapshot !== undefined &&\n snapshot.status !== desiredStatusForSnapshot\n ) {\n log.warn('github push: PR status diverged locally; pull-only for PRs (status will not be pushed)', {\n issueId: id,\n number: remoteIssue.number,\n localStatus,\n snapshotStatus: snapshot.status,\n });\n }\n if (!diverged) {\n continue;\n }\n\n yield* push.updateIssue(repo.owner.login, repo.name, remoteIssue.number, input);\n // Refresh the snapshot: title / description / status sent. Status only\n // gets refreshed when we actually pushed a state change (issues only) —\n // for PRs we keep the snapshot's previous status, so the warning above\n // keeps firing until either the user reverts locally or the PR's state\n // changes on GitHub and a pull catches up.\n Cursor.writeSnapshot(binding, id, {\n ...snapshot,\n title: localTitle,\n description: localDescription,\n status: input.state !== undefined ? (desiredStatusForSnapshot ?? snapshot.status) : snapshot.status,\n });\n tasks++;\n }\n\n return { projects, tasks };\n },\n);\n\n//\n// Main handler\n//\n\n/**\n * Per-binding sync body run by the account-level fan-out: reconcile the one repo the\n * binding targets, stamping success/failure onto the binding and toasting either way.\n */\nconst syncRepoBinding = Effect.fn('syncRepoBinding')(function* (binding: Cursor.ExternalCursor) {\n const project = yield* Database.load(binding.spec.target);\n const db = Obj.getDatabase(binding) ?? Obj.getDatabase(project);\n if (!db) {\n return yield* Effect.fail(new ConnectorSync.DatabaseMissingError());\n }\n\n // The repo's foreign id: prefer the binding's `externalId`, falling back\n // to the GitHub foreign key on the target object.\n const externalId =\n binding.spec.externalId ?? Obj.getMeta(project).keys.find((key) => key.source === GITHUB_SOURCE)?.id;\n\n const outcome = yield* Effect.result(\n Effect.gen(function* () {\n if (externalId === undefined) {\n return yield* Effect.fail(new GitHubRepoUnresolvedError());\n }\n\n // Fetch all repos visible to the token once so the binding can\n // resolve its remote `GitHubRepo`. The binding stores the numeric\n // repo id as `externalId` (a stringified integer).\n // TODO(wittjosiah): Switch to `fetchRepo(owner, name)` once the\n // binding carries `owner`/`name`. `fetchUserRepos()` walks every\n // repo the token can see and dominates large-account syncs.\n const allRepos = yield* GitHubApi.fetchUserRepos();\n const remoteRepo = allRepos.find((repo) => String(repo.id) === externalId);\n if (!remoteRepo) {\n return yield* Effect.fail(new GitHubRepoInaccessibleError());\n }\n\n const options = (binding.spec.options ?? undefined) as GitHubOperation.SyncOptions | undefined;\n\n // Upsert the local Project for this repo (three-way merge).\n yield* upsertProject(binding, remoteRepo);\n\n // Cross-issue dedup for Person upserts: parallel per-issue work can\n // race two upserts for the same login (same assignee on multiple\n // issues, or org members). Without serialization both fibers find no\n // foreign-key match, both insert, leaving duplicate Person rows. The\n // semaphore + cache pair gives us a single in-flight upsert per login;\n // subsequent callers read from `personByLogin`.\n const personByLogin = new Map<string, Person.Person>();\n const personSemaphore = yield* Semaphore.make(1);\n const ensurePerson = (user: GitHubApi.GitHubUser, organization: Organization.Organization | undefined) =>\n personSemaphore.withPermits(1)(\n Effect.gen(function* () {\n const cached = personByLogin.get(user.login);\n if (cached) {\n return cached;\n }\n const person = yield* upsertPerson(user, organization);\n personByLogin.set(user.login, person);\n return person;\n }),\n );\n\n // Auto-pull the owning org + members for this repo's owner.\n // `/orgs/{owner}` returns 404 for user-owned repos (personal\n // accounts are not orgs). Treat that as \"no org to sync\" and\n // continue — the Project just won't have a parent organization.\n let pulledOrganizations = 0;\n const owner = remoteRepo.owner.login;\n const orgResult = yield* Effect.result(GitHubApi.fetchOrg(owner));\n if (orgResult._tag === 'Success') {\n const organization = yield* upsertOrganization(orgResult.success);\n pulledOrganizations++;\n const members = yield* GitHubApi.fetchOrgMembers(owner);\n for (const member of members) {\n yield* ensurePerson(member, organization);\n }\n } else {\n log.info('github sync: owner is not an org, skipping org/member pull', { owner });\n }\n\n // Re-resolve the local Project after upsert so issue upserts and\n // pushes operate on the persisted record.\n const localProject = yield* findByForeignId<TaskSet.TaskSet>(TaskSet.TaskSet, remoteRepo.id);\n if (!localProject) {\n return yield* Effect.fail(new GitHubProjectMissingError());\n }\n\n // Milestones before issues: an issue's `milestone` has to resolve to a local mirror, and the\n // repo endpoint also surfaces milestones no open issue points at yet.\n const milestoneByRemoteId = new Map<number, Milestone.Milestone>();\n const remoteMilestones = yield* GitHubApi.fetchRepoMilestones(remoteRepo.owner.login, remoteRepo.name);\n for (const remoteMilestone of remoteMilestones) {\n milestoneByRemoteId.set(remoteMilestone.id, yield* upsertMilestone(localProject, remoteMilestone));\n }\n\n let pulledTasks = 0;\n const since = sinceFromOptions(options);\n const issues = yield* GitHubApi.fetchRepoIssues(remoteRepo.owner.login, remoteRepo.name, { since });\n const remoteIssuesById = new Map<string, GitHubApi.GitHubIssue>();\n const pulled = yield* Effect.forEach(\n issues,\n (issue) =>\n Effect.gen(function* () {\n // Resolve assignee — first assignee only for v1. External\n // (non-org) assignees are upserted lazily; the semaphored\n // `ensurePerson` dedups across fibers.\n const assigneeUser = issue.assignees?.[0];\n const assignedPerson = assigneeUser ? yield* ensurePerson(assigneeUser, undefined) : undefined;\n const milestone = issue.milestone ? milestoneByRemoteId.get(issue.milestone.id) : undefined;\n\n const { task, created } = yield* upsertTask(binding, issue, assignedPerson, milestone);\n remoteIssuesById.set(String(issue.id), issue);\n if (created) {\n pulledTasks++;\n }\n\n // TODO(wittjosiah): Comments sync disabled — re-enable once\n // chunked/yielded to avoid automerge_wasm crash when upserting\n // many comments in one tick.\n return task;\n }),\n { concurrency: ISSUE_CONCURRENCY },\n );\n\n // Sequential: `TaskSet.tasks` is one shared array, so concurrent appends would drop entries.\n // `Effect.forEach` preserves input order, so the set's order mirrors GitHub's.\n for (const task of pulled) {\n yield* setTaskContainer(task, localProject);\n }\n\n // Push: snapshot-diff the local Project + Tasks for this repo and\n // PATCH only the diverged fields.\n //\n // TODO(wittjosiah): `remoteIssuesById` is built from\n // `fetchRepoIssues(..., { since })`, so when `maxDaysBack` is set\n // this push pass cannot see locally-edited tasks whose remote issue\n // is older than the window. Switch the candidate set to the local\n // mirror (every Task with a GITHUB_SOURCE fk under this repo) once\n // we store `number` per task so we don't need the remote payload to PATCH.\n const pushResult = yield* pushRepoUpdates(binding, remoteRepo, remoteIssuesById, {\n updateIssue: (owner, repoName, issueNumber, input) =>\n GitHubApi.updateIssue(owner, repoName, issueNumber, input).pipe(Effect.map(() => undefined)),\n updateRepo: (owner, repoName, input) =>\n GitHubApi.updateRepo(owner, repoName, input).pipe(Effect.map(() => undefined)),\n });\n\n return {\n pulled: {\n organizations: pulledOrganizations,\n people: personByLogin.size,\n projects: 1,\n tasks: pulledTasks,\n comments: 0,\n },\n pushed: pushResult,\n };\n }).pipe(Effect.provide(Layer.provideMerge(Database.layer(db), GitHubApi.fromAccessToken(binding.spec.source)))),\n );\n\n // Write sync state onto the binding.\n if (outcome._tag === 'Success') {\n Cursor.advance(binding);\n yield* Effect.ignore(\n Operation.invoke(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.sync-success`,\n icon: 'ph--check--regular',\n title: ['sync-toast.success.label', { ns: meta.profile.key }],\n }),\n );\n return { pulled: outcome.success.pulled };\n } else {\n const message = formatGitHubSyncFailure(outcome.failure);\n Cursor.recordError(binding, message);\n log.warn('github sync: binding failed', { error: outcome.failure });\n yield* Effect.ignore(\n Operation.invoke(LayoutOperation.AddToast, {\n id: `${meta.profile.key}.sync-error`,\n icon: 'ph--warning--regular',\n title: ['sync-toast.error.label', { ns: meta.profile.key }],\n description: message,\n }),\n );\n return yield* Effect.fail(outcome.failure);\n }\n}, Effect.provide(FetchHttpClient.layer));\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.SyncGitHubRepositories> =\n GitHubOperation.SyncGitHubRepositories.pipe(\n Operation.withHandler(({ connection, priority }) =>\n Binding.syncAll({\n connection,\n priority,\n sync: (binding) => syncRepoBinding(binding),\n }).pipe(\n Effect.map(({ outputs }) => ({\n pulled: outputs.reduce(\n (total, { pulled }) => ({\n organizations: total.organizations + pulled.organizations,\n people: total.people + pulled.people,\n projects: total.projects + pulled.projects,\n tasks: total.tasks + pulled.tasks,\n comments: total.comments + pulled.comments,\n }),\n { organizations: 0, people: 0, projects: 0, tasks: 0, comments: 0 },\n ),\n })),\n ),\n ),\n );\n\nexport default handler;\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as Extensions_exports } from "./ns/Extensions.mjs";
2
- import { t as GitHubPlugin_exports } from "./GitHubPlugin.mjs";
1
+ import { t as Extensions_exports } from "./chunk-Extensions.mjs";
2
+ import { t as GitHubPlugin_exports } from "./chunk-GitHubPlugin.mjs";
3
3
  export * from "#types";
4
4
  export { Extensions_exports as Extensions, GitHubPlugin_exports as GitHubPlugin };
@@ -1 +1 @@
1
- {"version":3,"file":"meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.github',\n name: 'GitHub',\n author: 'DXOS',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-github',\n spec: 'PLUGIN.mdl',\n description: trim`\n Connect GitHub to your Composer workspace so organizations, repositories,\n issues, and pull requests stay available alongside everything else you're\n working on.\n\n Authenticate with a GitHub OAuth App or GitHub App and select the\n repositories you want to track. On each sync pass the plugin pulls\n organizations and their members into ECHO as Organization and Person\n objects, and mirrors every repository as a Project and every issue or\n pull request as a Task — with open mapping to \"todo\" and closed mapping\n to \"done\".\n\n Edits made locally to issue title, description, or open/closed status\n are pushed back to GitHub via a snapshot-diff reconciliation step, so\n changes flow in both directions. Pull request status is deliberately\n pull-only to avoid accidental closes; repo renames are similarly guarded.\n\n All GitHub data is stored in ECHO and replicated to other peers in the\n space, giving the whole team a shared, local-first view of the project\n without requiring each member to hold their own GitHub token.\n `,\n icon: { key: 'ph--github-logo--regular', hue: 'purple' },\n tags: ['labs', 'connector'],\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport { DXN } from '@dxos/keys';\n\nimport config from '../dx.config.ts';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n\n/** The dialog behind the \"Import pull request\" command. */\nexport const IMPORT_PULL_REQUEST_DIALOG = DXN.make(`${meta.profile.key}.importPullRequestDialog`);\n"],"mappings":";;;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,aAAa,IAAI;;;;;;;;;;;;;;;;;;;;;CAqBjB,MAAM;EAAE,KAAK;EAA4B,KAAK;CAAS;CACvD,MAAM,CAAC,QAAQ,WAAW;AAC5B,EACF,CAAC;;;AC7BD,IAAa,OAAO,OAAO,kBAAkB,iBAAM;;AAGnD,IAAa,6BAA6B,IAAI,KAAK,GAAG,KAAK,QAAQ,IAAI,yBAAyB"}
1
+ {"version":3,"file":"meta.mjs","names":["config"],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.github',\n name: 'GitHub',\n author: 'DXOS',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-github',\n spec: 'PLUGIN.mdl',\n description: trim`\n Connect GitHub to your Composer workspace so organizations, repositories,\n issues, and pull requests stay available alongside everything else you're\n working on.\n\n Authenticate with a GitHub OAuth App or GitHub App and select the\n repositories you want to track. On each sync pass the plugin pulls\n organizations and their members into ECHO as Organization and Person\n objects, and mirrors every repository as a Project and every issue or\n pull request as a Task — with open mapping to \"todo\" and closed mapping\n to \"done\".\n\n Edits made locally to issue title, description, or open/closed status\n are pushed back to GitHub via a snapshot-diff reconciliation step, so\n changes flow in both directions. Pull request status is deliberately\n pull-only to avoid accidental closes; repo renames are similarly guarded.\n\n All GitHub data is stored in ECHO and replicated to other peers in the\n space, giving the whole team a shared, local-first view of the project\n without requiring each member to hold their own GitHub token.\n `,\n icon: { key: 'ph--github-logo--regular', hue: 'purple' },\n tags: ['labs', 'connector'],\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport { DXN } from '@dxos/keys';\n\nimport config from '../dx.config.ts';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n\n/** The dialog behind the \"Import pull request\" command. */\nexport const IMPORT_PULL_REQUEST_DIALOG = DXN.make(`${meta.profile.key}.importPullRequestDialog`);\n"],"mappings":";;;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,aAAa,IAAI;;;;;;;;;;;;;;;;;;;;;CAqBjB,MAAM;EAAE,KAAK;EAA4B,KAAK;CAAS;CACvD,MAAM,CAAC,QAAQ,WAAW;AAC5B,EACF,CAAC;;;AC7BD,IAAa,OAAO,OAAO,kBAAkBA,iBAAM;;AAGnD,IAAa,6BAA6B,IAAI,KAAK,GAAG,KAAK,QAAQ,IAAI,yBAAyB"}
@@ -1,18 +1,4 @@
1
- import { t as __exportAll } from "../chunk-rolldown-runtime.mjs";
2
1
  import { n as parseGitHubLink, r as parsePullRequestReference, t as GITHUB_LINK } from "../chunk-github-link.mjs";
3
2
  import { PULL_REQUEST_ICON, githubLinkIcon, githubLinks, githubReferences, referenceUrl } from "../extensions.mjs";
4
- //#region src/Extensions.ts
5
- var Extensions_exports = /* @__PURE__ */ __exportAll({
6
- GITHUB_LINK: () => GITHUB_LINK,
7
- PULL_REQUEST_ICON: () => PULL_REQUEST_ICON,
8
- githubLinkIcon: () => githubLinkIcon,
9
- githubLinks: () => githubLinks,
10
- githubReferences: () => githubReferences,
11
- parseGitHubLink: () => parseGitHubLink,
12
- parsePullRequestReference: () => parsePullRequestReference,
13
- referenceUrl: () => referenceUrl
14
- });
15
- //#endregion
16
- export { GITHUB_LINK, PULL_REQUEST_ICON, githubLinkIcon, githubLinks, githubReferences, parseGitHubLink, parsePullRequestReference, referenceUrl, Extensions_exports as t };
17
-
18
- //# sourceMappingURL=Extensions.mjs.map
3
+ import "../chunk-Extensions.mjs";
4
+ export { GITHUB_LINK, PULL_REQUEST_ICON, githubLinkIcon, githubLinks, githubReferences, parseGitHubLink, parsePullRequestReference, referenceUrl };
@@ -7,13 +7,14 @@ var GitHubOperationHandlerSet = OperationHandlerSet.lazy([
7
7
  GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import("./chunk-materialize-target.mjs"))),
8
8
  GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import("./chunk-sync.mjs"))),
9
9
  GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import("./chunk-generate-walkthrough.mjs"))),
10
- GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request.mjs"))),
10
+ GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request.mjs").then((n) => n.t))),
11
11
  GitHubOperation.ImportPullRequestFromSnapshot.pipe(Operation.lazyHandler(() => import("./chunk-import-pull-request-from-snapshot.mjs"))),
12
12
  GitHubOperation.SubmitPullRequestApproval.pipe(Operation.lazyHandler(() => import("./chunk-submit-pull-request-approval.mjs"))),
13
13
  GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import("./chunk-add-pull-request-comment.mjs"))),
14
14
  GitHubOperation.AddPullRequestReviewComment.pipe(Operation.lazyHandler(() => import("./chunk-add-pull-request-review-comment.mjs"))),
15
15
  GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import("./chunk-get-pull-request-status.mjs"))),
16
16
  GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import("./chunk-sync-pull-request.mjs"))),
17
+ GitHubOperation.RefreshPullRequests.pipe(Operation.lazyHandler(() => import("./chunk-refresh-pull-requests.mjs"))),
17
18
  GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import("./chunk-get-pull-request-diff.mjs")))
18
19
  ]);
19
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { GitHubOperation } from '#types';\n\nexport const GitHubOperationHandlerSet = OperationHandlerSet.lazy([\n GitHubOperation.GetGitHubRepositories.pipe(Operation.lazyHandler(() => import('./get-repositories.ts'))),\n GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import('./materialize-target.ts'))),\n GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import('./sync.ts'))),\n GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import('./generate-walkthrough.ts'))),\n GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import('./import-pull-request.ts'))),\n GitHubOperation.ImportPullRequestFromSnapshot.pipe(\n Operation.lazyHandler(() => import('./import-pull-request-from-snapshot.ts')),\n ),\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.lazyHandler(() => import('./submit-pull-request-approval.ts')),\n ),\n GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import('./add-pull-request-comment.ts'))),\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.lazyHandler(() => import('./add-pull-request-review-comment.ts')),\n ),\n GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import('./get-pull-request-status.ts'))),\n GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import('./sync-pull-request.ts'))),\n GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import('./get-pull-request-diff.ts'))),\n]);\n"],"mappings":";;;;AASA,IAAa,4BAA4B,oBAAoB,KAAK;CAChE,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,+BAAwB,CAAC;CACvG,gBAAgB,wBAAwB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;CAC3G,gBAAgB,uBAAuB,KAAK,UAAU,kBAAkB,OAAO,mBAAY,CAAC;CAC5F,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,mCAA4B,CAAC;CACzG,gBAAgB,kBAAkB,KAAK,UAAU,kBAAkB,OAAO,kCAA2B,CAAC;CACtG,gBAAgB,8BAA8B,KAC5C,UAAU,kBAAkB,OAAO,gDAAyC,CAC9E;CACA,gBAAgB,0BAA0B,KACxC,UAAU,kBAAkB,OAAO,2CAAoC,CACzE;CACA,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,uCAAgC,CAAC;CAC/G,gBAAgB,4BAA4B,KAC1C,UAAU,kBAAkB,OAAO,8CAAuC,CAC5E;CACA,gBAAgB,qBAAqB,KAAK,UAAU,kBAAkB,OAAO,sCAA+B,CAAC;CAC7G,gBAAgB,gBAAgB,KAAK,UAAU,kBAAkB,OAAO,gCAAyB,CAAC;CAClG,gBAAgB,mBAAmB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;AAC3G,CAAC"}
1
+ {"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { GitHubOperation } from '#types';\n\nexport const GitHubOperationHandlerSet = OperationHandlerSet.lazy([\n GitHubOperation.GetGitHubRepositories.pipe(Operation.lazyHandler(() => import('./get-repositories.ts'))),\n GitHubOperation.MaterializeGitHubTarget.pipe(Operation.lazyHandler(() => import('./materialize-target.ts'))),\n GitHubOperation.SyncGitHubRepositories.pipe(Operation.lazyHandler(() => import('./sync.ts'))),\n GitHubOperation.GenerateWalkthrough.pipe(Operation.lazyHandler(() => import('./generate-walkthrough.ts'))),\n GitHubOperation.ImportPullRequest.pipe(Operation.lazyHandler(() => import('./import-pull-request.ts'))),\n GitHubOperation.ImportPullRequestFromSnapshot.pipe(\n Operation.lazyHandler(() => import('./import-pull-request-from-snapshot.ts')),\n ),\n GitHubOperation.SubmitPullRequestApproval.pipe(\n Operation.lazyHandler(() => import('./submit-pull-request-approval.ts')),\n ),\n GitHubOperation.AddPullRequestComment.pipe(Operation.lazyHandler(() => import('./add-pull-request-comment.ts'))),\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.lazyHandler(() => import('./add-pull-request-review-comment.ts')),\n ),\n GitHubOperation.GetPullRequestStatus.pipe(Operation.lazyHandler(() => import('./get-pull-request-status.ts'))),\n GitHubOperation.SyncPullRequest.pipe(Operation.lazyHandler(() => import('./sync-pull-request.ts'))),\n GitHubOperation.RefreshPullRequests.pipe(Operation.lazyHandler(() => import('./refresh-pull-requests.ts'))),\n GitHubOperation.GetPullRequestDiff.pipe(Operation.lazyHandler(() => import('./get-pull-request-diff.ts'))),\n]);\n"],"mappings":";;;;AASA,IAAa,4BAA4B,oBAAoB,KAAK;CAChE,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,+BAAwB,CAAC;CACvG,gBAAgB,wBAAwB,KAAK,UAAU,kBAAkB,OAAO,iCAA0B,CAAC;CAC3G,gBAAgB,uBAAuB,KAAK,UAAU,kBAAkB,OAAO,mBAAY,CAAC;CAC5F,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,mCAA4B,CAAC;CACzG,gBAAgB,kBAAkB,KAAK,UAAU,kBAAkB,OAAO,kCAA2B,CAAA,MAAA,MAAA,EAAA,CAAA,CAAA,CAAC;CACtG,gBAAgB,8BAA8B,KAC5C,UAAU,kBAAkB,OAAO,gDAAyC,CAC9E;CACA,gBAAgB,0BAA0B,KACxC,UAAU,kBAAkB,OAAO,2CAAoC,CACzE;CACA,gBAAgB,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,uCAAgC,CAAC;CAC/G,gBAAgB,4BAA4B,KAC1C,UAAU,kBAAkB,OAAO,8CAAuC,CAC5E;CACA,gBAAgB,qBAAqB,KAAK,UAAU,kBAAkB,OAAO,sCAA+B,CAAC;CAC7G,gBAAgB,gBAAgB,KAAK,UAAU,kBAAkB,OAAO,gCAAyB,CAAC;CAClG,gBAAgB,oBAAoB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;CAC1G,gBAAgB,mBAAmB,KAAK,UAAU,kBAAkB,OAAO,oCAA6B,CAAC;AAC3G,CAAC"}
@@ -1,5 +1,5 @@
1
- import { t as GitHubCapabilities_exports } from "./GitHubCapabilities.mjs";
2
- import { t as GitHubEvents_exports } from "./GitHubEvents.mjs";
3
- import { t as Walkthrough_exports } from "./Walkthrough.mjs";
4
- import { t as GitHubOperation_exports } from "./GitHubOperation.mjs";
1
+ import { t as GitHubCapabilities_exports } from "./chunk-GitHubCapabilities.mjs";
2
+ import { t as GitHubEvents_exports } from "./chunk-GitHubEvents.mjs";
3
+ import { n as Walkthrough_exports } from "./chunk-Walkthrough.mjs";
4
+ import { d as GitHubOperation_exports } from "./chunk-GitHubOperation.mjs";
5
5
  export { GitHubCapabilities_exports as GitHubCapabilities, GitHubEvents_exports as GitHubEvents, GitHubOperation_exports as GitHubOperation, Walkthrough_exports as Walkthrough };
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/browser.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAgB7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAGF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AAEF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAIF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AAEH,eAAO,MAAM,MAAM,yBAAqD,CAAC;AAEzE,eAAO,MAAM,eAAe,yBAAwE,CAAC;AAErG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AAEH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AAEH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/browser.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAc7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAGF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AAEF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAIF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AAEH,eAAO,MAAM,MAAM,yBAAqD,CAAC;AAEzE,eAAO,MAAM,eAAe,yBAAwE,CAAC;AAErG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AAEH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AAEH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tauri.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/tauri.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAgB7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAGF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AAEF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAIF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AAEH,eAAO,MAAM,MAAM,yBAAqD,CAAC;AAEzE,eAAO,MAAM,eAAe,yBAAwE,CAAC;AAErG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AAEH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AAEH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
1
+ {"version":3,"file":"tauri.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/tauri.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAc7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAGF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AAEF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAIF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AAEH,eAAO,MAAM,MAAM,yBAAqD,CAAC;AAEzE,eAAO,MAAM,eAAe,yBAAwE,CAAC;AAErG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AAEH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AAEH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAiB7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AACF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAGF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AACH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AACF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AACH,eAAO,MAAM,MAAM,yBAAoD,CAAC;AACxE,eAAO,MAAM,eAAe,yBAAuE,CAAC;AACpG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AACH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AACH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/capabilities/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,UAAU,MAAM,gCAAgC,CAAC;AAc7D,eAAO,MAAM,SAAS,yBAIrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AACF,eAAO,MAAM,YAAY,yBAQxB,CAAC;AAGF,eAAO,MAAM,eAAe,yBAE1B,CAAC;AACH,eAAO,MAAM,kBAAkB,yBAI9B,CAAC;AACF,eAAO,MAAM,gBAAgB,yBAE3B,CAAC;AACH,eAAO,MAAM,MAAM,yBAAoD,CAAC;AACxE,eAAO,MAAM,eAAe,yBAAuE,CAAC;AACpG,eAAO,MAAM,YAAY,yBAEvB,CAAC;AACH,eAAO,MAAM,WAAW,yBAKtB,CAAC;AACH,eAAO,MAAM,YAAY,yBAA2C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubCard.d.ts","sourceRoot":"","sources":["../../../../src/cards/GitHubCard.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAKhE,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAItE,KAAK,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC;AAyBjE;;;GAGG;AACH,eAAO,MAAM,UAAU,gBAAiB,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,sBAgD1E,CAAC"}
1
+ {"version":3,"file":"GitHubCard.d.ts","sourceRoot":"","sources":["../../../../src/cards/GitHubCard.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,KAAK,UAAU,MAAM,8BAA8B,CAAC;AAMhE,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAItE,KAAK,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC;AA2BjE;;;GAGG;AACH,eAAO,MAAM,UAAU,gBAAiB,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,sBAiD1E,CAAC"}
@@ -1,14 +1,17 @@
1
1
  import React from 'react';
2
2
  import { type GitHubOperation } from '#types';
3
- /** `4m 12s`, or undefined for a run that has not both started and finished. */
4
- export declare const formatDuration: (startedAt?: string, completedAt?: string) => string | undefined;
3
+ /**
4
+ * `4m 12s` from start to finish, or to `now` for a run still in progress;
5
+ * undefined for a run that has not started, or has not finished when no `now` is given.
6
+ */
7
+ export declare const formatDuration: (startedAt?: string, completedAt?: string, now?: number) => string | undefined;
5
8
  /** Sorts runs by what needs attention, then by name so shards read in order. */
6
9
  export declare const sortCheckRuns: (runs: readonly GitHubOperation.CheckRun[]) => GitHubOperation.CheckRun[];
7
10
  export type CheckRunListProps = {
8
11
  /** Undefined while the status is loading. */
9
12
  runs?: readonly GitHubOperation.CheckRun[];
10
13
  };
11
- /** Every check on the head commit: its outcome, how long it took, and its logs a click away. */
14
+ /** Every check on the head commit: its outcome, how long it took, and a button to its logs. */
12
15
  export declare const CheckRunList: ({ runs }: CheckRunListProps) => React.JSX.Element;
13
16
  /** The label the checks section carries: the counts once there are runs to count. */
14
17
  export declare const useCheckSummary: (runs?: readonly GitHubOperation.CheckRun[]) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"CheckRunList.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAOvC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAa9C,+EAA+E;AAC/E,eAAO,MAAM,cAAc,eAAgB,MAAM,gBAAgB,MAAM,KAAG,MAAM,GAAG,SAUlF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,aAAa,SAAU,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,eAAe,CAAC,QAAQ,EAK/F,CAAC;AAEJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,YAAY,aAAc,iBAAiB,sBA0CvD,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,eAAe,UAAW,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,MAuB5E,CAAC"}
1
+ {"version":3,"file":"CheckRunList.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAQ5D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAa9C;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAgB,MAAM,gBAAgB,MAAM,QAAQ,MAAM,KAAG,MAAM,GAAG,SAWhG,CAAC;AAoBF,gFAAgF;AAChF,eAAO,MAAM,aAAa,SAAU,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,eAAe,CAAC,QAAQ,EAK/F,CAAC;AAEJ,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,YAAY,aAAc,iBAAiB,sBAoEvD,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,eAAe,UAAW,SAAS,eAAe,CAAC,QAAQ,EAAE,KAAG,MAuB5E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CheckRunList.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckRunList.test.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/CheckRunList.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"PullRequestOverview.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/PullRequestOverview.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAYvC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAK9C,OAAO,EAA4B,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,MAAM,MAAM,wBAAwB,GAAG;IACrC,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,wBAAwB,CAAC;IAClC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,4BAA6B,wBAAwB,sBAiCpF,CAAC"}
1
+ {"version":3,"file":"PullRequestOverview.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestOverview/PullRequestOverview.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAavC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAK9C,OAAO,EAA4B,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAGnG,MAAM,MAAM,wBAAwB,GAAG;IACrC,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,wBAAwB,CAAC;IAClC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,SAAS,eAAe,CAAC,QAAQ,EAAE,CAAC;CAC5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,4BAA6B,wBAAwB,sBAoCpF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PullRequestStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestStatus/PullRequestStatus.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAsB9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;IAC1B,mGAAmG;IACnG,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,EAAE,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;KAAE,CAAC;CAC9E,CAAC;AAEF,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,4CAA6C,sBAAsB,sBAsChG,CAAC"}
1
+ {"version":3,"file":"PullRequestStatus.d.ts","sourceRoot":"","sources":["../../../../../src/components/PullRequestStatus/PullRequestStatus.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAsB9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;IAC1B,mGAAmG;IACnG,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,WAAW,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,EAAE,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;KAAE,CAAC;CAC9E,CAAC;AAEF,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,4CAA6C,sBAAsB,sBAwChG,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/import-pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAKrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,EAAE,KAAK,oBAAoB,EAA6B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAkBjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,4BACd,oBAAoB,SACtC,MAAM,UACN,CACL,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDA6C/C,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,iBAAiB,CA8B5E,CAAC;eAEa,OAAO"}
1
+ {"version":3,"file":"import-pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/import-pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAMrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,EAAE,KAAK,oBAAoB,EAA6B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAmBjD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,4BACd,oBAAoB,SACtC,MAAM,UACN,CACL,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDA6C/C,CAAC;AAEL;;;;;GAKG;AACH,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,iBAAiB,CAoC5E,CAAC;eAEa,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,mBAAmB,MAAM,mCAAmC,CAAC;AAIzE,eAAO,MAAM,yBAAyB,yCAmBpC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/operations/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,mBAAmB,MAAM,mCAAmC,CAAC;AAIzE,eAAO,MAAM,yBAAyB,yCAoBpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAI9C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;gFAczB,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,WAAW,+FAAiF,CAAC;AAE1G;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC;;;;yDASpE,CAAC;AAYL,8GAA8G;AAC9G,eAAO,MAAM,UAAU,QAAS,SAAS,CAAC,cAAc,KAAG,eAAe,CAAC,QAoB1E,CAAC;AAEF,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,SACvB,SAAS,SAAS,CAAC,cAAc,EAAE,KACxC;IAAE,EAAE,EAAE,eAAe,CAAC,OAAO,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;CAepE,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAClB,SAAS,SAAS,CAAC,qBAAqB,EAAE,KAClD;IAAE,MAAM,EAAE,eAAe,CAAC,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAiB1D,CAAC"}
1
+ {"version":3,"file":"pull-request.d.ts","sourceRoot":"","sources":["../../../../src/operations/pull-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAI9C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;gFAczB,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,WAAW,+FAAiF,CAAC;AAE1G;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC;;;;yDASpE,CAAC;AAYL,8GAA8G;AAC9G,eAAO,MAAM,UAAU,QAAS,SAAS,CAAC,cAAc,KAAG,eAAe,CAAC,QAqB1E,CAAC;AAEF,2GAA2G;AAC3G,eAAO,MAAM,kBAAkB,SACvB,SAAS,SAAS,CAAC,cAAc,EAAE,KACxC;IAAE,EAAE,EAAE,eAAe,CAAC,OAAO,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC,WAAW,CAAA;CAepE,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAClB,SAAS,SAAS,CAAC,qBAAqB,EAAE,KAClD;IAAE,MAAM,EAAE,eAAe,CAAC,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAiB1D,CAAC"}
@@ -0,0 +1,5 @@
1
+ import * as Operation from '@dxos/compute/Operation';
2
+ import { GitHubOperation } from '#types';
3
+ declare const handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests>;
4
+ export default handler;
5
+ //# sourceMappingURL=refresh-pull-requests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-pull-requests.d.ts","sourceRoot":"","sources":["../../../../src/operations/refresh-pull-requests.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAWzC,QAAA,MAAM,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,eAAe,CAAC,mBAAmB,CA4C5E,CAAC;eAEW,OAAO"}