@dxos/plugin-github 0.7.4 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +102 -5
- package/PLUGIN.mdl +784 -0
- package/dist/lib/GitHubCapabilities.mjs +10 -0
- package/dist/lib/GitHubCapabilities.mjs.map +1 -0
- package/dist/lib/GitHubEvents.mjs +15 -0
- package/dist/lib/GitHubEvents.mjs.map +1 -0
- package/dist/lib/GitHubOperation.mjs +384 -0
- package/dist/lib/GitHubOperation.mjs.map +1 -0
- package/dist/lib/GitHubPlugin.mjs +16 -0
- package/dist/lib/GitHubPlugin.mjs.map +1 -0
- package/dist/lib/Walkthrough.mjs +59 -0
- package/dist/lib/Walkthrough.mjs.map +1 -0
- package/dist/lib/capabilities.browser.mjs +54 -0
- package/dist/lib/capabilities.browser.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +54 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/capabilities.node.mjs +30 -0
- package/dist/lib/capabilities.node.mjs.map +1 -0
- package/dist/lib/capabilities.tauri.mjs +54 -0
- package/dist/lib/capabilities.tauri.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs +30 -0
- package/dist/lib/capabilities.workerd.mjs.map +1 -0
- package/dist/lib/chunk-ImportPullRequestDialog.mjs +116 -0
- package/dist/lib/chunk-ImportPullRequestDialog.mjs.map +1 -0
- package/dist/lib/chunk-PLUGIN.mjs +6 -0
- package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
- package/dist/lib/chunk-PullRequestArticle.mjs +1506 -0
- package/dist/lib/chunk-PullRequestArticle.mjs.map +1 -0
- package/dist/lib/chunk-PullRequestArticle2.mjs +2 -0
- package/dist/lib/chunk-PullRequestCardMenu.mjs +123 -0
- package/dist/lib/chunk-PullRequestCardMenu.mjs.map +1 -0
- package/dist/lib/chunk-PullRequestsArticle.mjs +594 -0
- package/dist/lib/chunk-PullRequestsArticle.mjs.map +1 -0
- package/dist/lib/chunk-WalkthroughArticle.mjs +26 -0
- package/dist/lib/chunk-WalkthroughArticle.mjs.map +1 -0
- package/dist/lib/chunk-add-pull-request-comment.mjs +19 -0
- package/dist/lib/chunk-add-pull-request-comment.mjs.map +1 -0
- package/dist/lib/chunk-add-pull-request-review-comment.mjs +25 -0
- package/dist/lib/chunk-add-pull-request-review-comment.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +39 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-connector.mjs +70 -0
- package/dist/lib/chunk-connector.mjs.map +1 -0
- package/dist/lib/chunk-constants.mjs +11 -0
- package/dist/lib/chunk-constants.mjs.map +1 -0
- package/dist/lib/chunk-errors.mjs +29 -0
- package/dist/lib/chunk-errors.mjs.map +1 -0
- package/dist/lib/chunk-generate-walkthrough.mjs +86 -0
- package/dist/lib/chunk-generate-walkthrough.mjs.map +1 -0
- package/dist/lib/chunk-generate.mjs +719 -0
- package/dist/lib/chunk-generate.mjs.map +1 -0
- package/dist/lib/chunk-get-pull-request-diff.mjs +25 -0
- package/dist/lib/chunk-get-pull-request-diff.mjs.map +1 -0
- package/dist/lib/chunk-get-pull-request-status.mjs +29 -0
- package/dist/lib/chunk-get-pull-request-status.mjs.map +1 -0
- package/dist/lib/chunk-get-repositories.mjs +32 -0
- package/dist/lib/chunk-get-repositories.mjs.map +1 -0
- package/dist/lib/chunk-github-api.mjs +375 -0
- package/dist/lib/chunk-github-api.mjs.map +1 -0
- package/dist/lib/chunk-github-link.mjs +59 -0
- package/dist/lib/chunk-github-link.mjs.map +1 -0
- package/dist/lib/chunk-import-pull-request-from-snapshot.mjs +25 -0
- package/dist/lib/chunk-import-pull-request-from-snapshot.mjs.map +1 -0
- package/dist/lib/chunk-import-pull-request.mjs +171 -0
- package/dist/lib/chunk-import-pull-request.mjs.map +1 -0
- package/dist/lib/chunk-link-resolver.mjs +109 -0
- package/dist/lib/chunk-link-resolver.mjs.map +1 -0
- package/dist/lib/chunk-markdown-extension.mjs +92 -0
- package/dist/lib/chunk-markdown-extension.mjs.map +1 -0
- package/dist/lib/chunk-materialize-target.mjs +36 -0
- package/dist/lib/chunk-materialize-target.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +12 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-page-action.mjs +22 -0
- package/dist/lib/chunk-page-action.mjs.map +1 -0
- package/dist/lib/chunk-pull-request.mjs +58 -0
- package/dist/lib/chunk-pull-request.mjs.map +1 -0
- package/dist/lib/chunk-pull-request2.mjs +110 -0
- package/dist/lib/chunk-pull-request2.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +233 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-refresh-pull-requests.mjs +49 -0
- package/dist/lib/chunk-refresh-pull-requests.mjs.map +1 -0
- package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
- package/dist/lib/chunk-schema.mjs +15 -0
- package/dist/lib/chunk-schema.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +10 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-submit-pull-request-approval.mjs +56 -0
- package/dist/lib/chunk-submit-pull-request-approval.mjs.map +1 -0
- package/dist/lib/chunk-sync-pull-request.mjs +26 -0
- package/dist/lib/chunk-sync-pull-request.mjs.map +1 -0
- package/dist/lib/chunk-sync.mjs +481 -0
- package/dist/lib/chunk-sync.mjs.map +1 -0
- package/dist/lib/chunk-useOpenObject.mjs +43 -0
- package/dist/lib/chunk-useOpenObject.mjs.map +1 -0
- package/dist/lib/extensions.mjs +132 -0
- package/dist/lib/extensions.mjs.map +1 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/meta.mjs +47 -0
- package/dist/lib/meta.mjs.map +1 -0
- package/dist/lib/ns/Extensions.mjs +18 -0
- package/dist/lib/ns/Extensions.mjs.map +1 -0
- package/dist/lib/operations.mjs +23 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/skills.mjs +44 -0
- package/dist/lib/skills.mjs.map +1 -0
- package/dist/lib/testing.mjs +189 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +136 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +5 -0
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/Extensions.d.ts +2 -0
- package/dist/types/src/Extensions.d.ts.map +1 -0
- package/dist/types/src/GitHubPlugin.d.ts +37 -0
- package/dist/types/src/GitHubPlugin.d.ts.map +1 -0
- package/dist/types/src/GitHubPlugin.workerd.test.d.ts +2 -0
- package/dist/types/src/GitHubPlugin.workerd.test.d.ts.map +1 -0
- package/dist/types/src/approval.d.ts +21 -0
- package/dist/types/src/approval.d.ts.map +1 -0
- package/dist/types/src/approval.test.d.ts +2 -0
- package/dist/types/src/approval.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/connector.d.ts +17 -0
- package/dist/types/src/capabilities/connector.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/browser.d.ts +13 -0
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/node.d.ts +13 -0
- package/dist/types/src/capabilities/gen/node.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts +13 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts +13 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +13 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/link-resolver.d.ts +10 -0
- package/dist/types/src/capabilities/link-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/markdown-extension.d.ts +14 -0
- package/dist/types/src/capabilities/markdown-extension.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +5 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/page-action.d.ts +5 -0
- package/dist/types/src/capabilities/page-action.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/schema.d.ts +12 -0
- package/dist/types/src/capabilities/schema.d.ts.map +1 -0
- package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
- package/dist/types/src/cards/GitHubCard.d.ts +11 -0
- package/dist/types/src/cards/GitHubCard.d.ts.map +1 -0
- package/dist/types/src/cards/GitHubCard.stories.d.ts +45 -0
- package/dist/types/src/cards/GitHubCard.stories.d.ts.map +1 -0
- package/dist/types/src/cards/PullRequestCard.d.ts +9 -0
- package/dist/types/src/cards/PullRequestCard.d.ts.map +1 -0
- package/dist/types/src/cards/index.d.ts +3 -0
- package/dist/types/src/cards/index.d.ts.map +1 -0
- package/dist/types/src/components/CommentComposer/CommentComposer.d.ts +30 -0
- package/dist/types/src/components/CommentComposer/CommentComposer.d.ts.map +1 -0
- package/dist/types/src/components/CommentComposer/index.d.ts +2 -0
- package/dist/types/src/components/CommentComposer/index.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/DiffStat.d.ts +8 -0
- package/dist/types/src/components/PullRequestFiles/DiffStat.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/FileTree.d.ts +17 -0
- package/dist/types/src/components/PullRequestFiles/FileTree.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/PullRequestFiles.d.ts +23 -0
- package/dist/types/src/components/PullRequestFiles/PullRequestFiles.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/files.d.ts +39 -0
- package/dist/types/src/components/PullRequestFiles/files.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/files.test.d.ts +2 -0
- package/dist/types/src/components/PullRequestFiles/files.test.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestFiles/index.d.ts +5 -0
- package/dist/types/src/components/PullRequestFiles/index.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/ArtifactPill.d.ts +21 -0
- package/dist/types/src/components/PullRequestOverview/ArtifactPill.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +18 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts +2 -0
- package/dist/types/src/components/PullRequestOverview/CheckRunList.test.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestDetails.d.ts +10 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestDetails.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts +16 -0
- package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/RelatedCards.d.ts +28 -0
- package/dist/types/src/components/PullRequestOverview/RelatedCards.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestOverview/index.d.ts +6 -0
- package/dist/types/src/components/PullRequestOverview/index.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts +20 -0
- package/dist/types/src/components/PullRequestStatus/PullRequestStatus.d.ts.map +1 -0
- package/dist/types/src/components/PullRequestStatus/index.d.ts +2 -0
- package/dist/types/src/components/PullRequestStatus/index.d.ts.map +1 -0
- package/dist/types/src/components/WalkthroughView/WalkthroughView.d.ts +18 -0
- package/dist/types/src/components/WalkthroughView/WalkthroughView.d.ts.map +1 -0
- package/dist/types/src/components/WalkthroughView/extensions.d.ts +16 -0
- package/dist/types/src/components/WalkthroughView/extensions.d.ts.map +1 -0
- package/dist/types/src/components/WalkthroughView/index.d.ts +3 -0
- package/dist/types/src/components/WalkthroughView/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +5 -8
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/constants.d.ts +7 -0
- package/dist/types/src/constants.d.ts.map +1 -0
- package/dist/types/src/containers/ImportPullRequestDialog/ImportPullRequestDialog.d.ts +6 -0
- package/dist/types/src/containers/ImportPullRequestDialog/ImportPullRequestDialog.d.ts.map +1 -0
- package/dist/types/src/containers/ImportPullRequestDialog/index.d.ts +3 -0
- package/dist/types/src/containers/ImportPullRequestDialog/index.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestArticle/PullRequestArticle.d.ts +15 -0
- package/dist/types/src/containers/PullRequestArticle/PullRequestArticle.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestArticle/failure.d.ts +10 -0
- package/dist/types/src/containers/PullRequestArticle/failure.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestArticle/failure.test.d.ts +2 -0
- package/dist/types/src/containers/PullRequestArticle/failure.test.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestArticle/index.d.ts +2 -0
- package/dist/types/src/containers/PullRequestArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestCardMenu/PullRequestCardMenu.d.ts +14 -0
- package/dist/types/src/containers/PullRequestCardMenu/PullRequestCardMenu.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestCardMenu/index.d.ts +2 -0
- package/dist/types/src/containers/PullRequestCardMenu/index.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestsArticle/PullRequestsArticle.d.ts +13 -0
- package/dist/types/src/containers/PullRequestsArticle/PullRequestsArticle.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestsArticle/arrange.d.ts +44 -0
- package/dist/types/src/containers/PullRequestsArticle/arrange.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestsArticle/arrange.test.d.ts +2 -0
- package/dist/types/src/containers/PullRequestsArticle/arrange.test.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestsArticle/format.d.ts +3 -0
- package/dist/types/src/containers/PullRequestsArticle/format.d.ts.map +1 -0
- package/dist/types/src/containers/PullRequestsArticle/index.d.ts +2 -0
- package/dist/types/src/containers/PullRequestsArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/WalkthroughArticle/WalkthroughArticle.d.ts +13 -0
- package/dist/types/src/containers/WalkthroughArticle/WalkthroughArticle.d.ts.map +1 -0
- package/dist/types/src/containers/WalkthroughArticle/index.d.ts +2 -0
- package/dist/types/src/containers/WalkthroughArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +7 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +157 -0
- package/dist/types/src/errors.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +3 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/extensions/links.d.ts +21 -0
- package/dist/types/src/extensions/links.d.ts.map +1 -0
- package/dist/types/src/extensions/links.test.d.ts +2 -0
- package/dist/types/src/extensions/links.test.d.ts.map +1 -0
- package/dist/types/src/extensions/references.d.ts +23 -0
- package/dist/types/src/extensions/references.d.ts.map +1 -0
- package/dist/types/src/extensions/references.test.d.ts +2 -0
- package/dist/types/src/extensions/references.test.d.ts.map +1 -0
- package/dist/types/src/github-link.d.ts +29 -0
- package/dist/types/src/github-link.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +5 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useOpenObject.d.ts +9 -0
- package/dist/types/src/hooks/useOpenObject.d.ts.map +1 -0
- package/dist/types/src/hooks/usePullRequestChecks.d.ts +10 -0
- package/dist/types/src/hooks/usePullRequestChecks.d.ts.map +1 -0
- package/dist/types/src/hooks/usePullRequestDiff.d.ts +12 -0
- package/dist/types/src/hooks/usePullRequestDiff.d.ts.map +1 -0
- package/dist/types/src/hooks/usePullRequestFiles.d.ts +22 -0
- package/dist/types/src/hooks/usePullRequestFiles.d.ts.map +1 -0
- package/dist/types/src/hooks/useSyncPullRequest.d.ts +10 -0
- package/dist/types/src/hooks/useSyncPullRequest.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +34 -11
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/add-pull-request-comment.d.ts +5 -0
- package/dist/types/src/operations/add-pull-request-comment.d.ts.map +1 -0
- package/dist/types/src/operations/add-pull-request-review-comment.d.ts +5 -0
- package/dist/types/src/operations/add-pull-request-review-comment.d.ts.map +1 -0
- package/dist/types/src/operations/generate-walkthrough.d.ts +11 -0
- package/dist/types/src/operations/generate-walkthrough.d.ts.map +1 -0
- package/dist/types/src/operations/get-pull-request-diff.d.ts +5 -0
- package/dist/types/src/operations/get-pull-request-diff.d.ts.map +1 -0
- package/dist/types/src/operations/get-pull-request-status.d.ts +5 -0
- package/dist/types/src/operations/get-pull-request-status.d.ts.map +1 -0
- package/dist/types/src/operations/get-repositories.d.ts +13 -0
- package/dist/types/src/operations/get-repositories.d.ts.map +1 -0
- package/dist/types/src/operations/import-pull-request-from-snapshot.d.ts +12 -0
- package/dist/types/src/operations/import-pull-request-from-snapshot.d.ts.map +1 -0
- package/dist/types/src/operations/import-pull-request.d.ts +63 -0
- package/dist/types/src/operations/import-pull-request.d.ts.map +1 -0
- package/dist/types/src/operations/import-pull-request.test.d.ts +2 -0
- package/dist/types/src/operations/import-pull-request.test.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/materialize-target.d.ts +12 -0
- package/dist/types/src/operations/materialize-target.d.ts.map +1 -0
- package/dist/types/src/operations/pull-request.d.ts +48 -0
- package/dist/types/src/operations/pull-request.d.ts.map +1 -0
- package/dist/types/src/operations/pull-request.test.d.ts +2 -0
- package/dist/types/src/operations/pull-request.test.d.ts.map +1 -0
- package/dist/types/src/operations/refresh-pull-requests.d.ts +5 -0
- package/dist/types/src/operations/refresh-pull-requests.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.d.ts +37 -0
- package/dist/types/src/operations/refresh.d.ts.map +1 -0
- package/dist/types/src/operations/refresh.test.d.ts +2 -0
- package/dist/types/src/operations/refresh.test.d.ts.map +1 -0
- package/dist/types/src/operations/submit-pull-request-approval.d.ts +5 -0
- package/dist/types/src/operations/submit-pull-request-approval.d.ts.map +1 -0
- package/dist/types/src/operations/sync-pull-request.d.ts +5 -0
- package/dist/types/src/operations/sync-pull-request.d.ts.map +1 -0
- package/dist/types/src/operations/sync.d.ts +123 -0
- package/dist/types/src/operations/sync.d.ts.map +1 -0
- package/dist/types/src/operations/sync.test.d.ts +2 -0
- package/dist/types/src/operations/sync.test.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/plugin.test.d.ts +2 -0
- package/dist/types/src/plugin.test.d.ts.map +1 -0
- package/dist/types/src/pull-request-body.d.ts +37 -0
- package/dist/types/src/pull-request-body.d.ts.map +1 -0
- package/dist/types/src/pull-request-body.test.d.ts +2 -0
- package/dist/types/src/pull-request-body.test.d.ts.map +1 -0
- package/dist/types/src/pull-request.d.ts +28 -0
- package/dist/types/src/pull-request.d.ts.map +1 -0
- package/dist/types/src/pull-request.test.d.ts +2 -0
- package/dist/types/src/pull-request.test.d.ts.map +1 -0
- package/dist/types/src/services/github-api.d.ts +332 -0
- package/dist/types/src/services/github-api.d.ts.map +1 -0
- package/dist/types/src/services/index.d.ts +2 -0
- package/dist/types/src/services/index.d.ts.map +1 -0
- package/dist/types/src/skills/GitHubSkill.d.ts +12 -0
- package/dist/types/src/skills/GitHubSkill.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +2 -0
- package/dist/types/src/skills/index.d.ts.map +1 -0
- package/dist/types/src/stories/Generate.stories.d.ts +27 -0
- package/dist/types/src/stories/Generate.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Links.stories.d.ts +23 -0
- package/dist/types/src/stories/Links.stories.d.ts.map +1 -0
- package/dist/types/src/stories/PullRequestArticle.stories.d.ts +359 -0
- package/dist/types/src/stories/PullRequestArticle.stories.d.ts.map +1 -0
- package/dist/types/src/stories/PullRequestFiles.stories.d.ts +365 -0
- package/dist/types/src/stories/PullRequestFiles.stories.d.ts.map +1 -0
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts +367 -0
- package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -0
- package/dist/types/src/stories/PullRequestsArticle.stories.d.ts +357 -0
- package/dist/types/src/stories/PullRequestsArticle.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Walkthrough.stories.d.ts +380 -0
- package/dist/types/src/stories/Walkthrough.stories.d.ts.map +1 -0
- package/dist/types/src/stories/github.d.ts +23 -0
- package/dist/types/src/stories/github.d.ts.map +1 -0
- package/dist/types/src/stories/github.test.d.ts +2 -0
- package/dist/types/src/stories/github.test.d.ts.map +1 -0
- package/dist/types/src/stories/walkthrough-fixture.d.ts +8 -0
- package/dist/types/src/stories/walkthrough-fixture.d.ts.map +1 -0
- package/dist/types/src/testing/fixtures.d.ts +14 -0
- package/dist/types/src/testing/fixtures.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +4 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/plugin.d.ts +4 -0
- package/dist/types/src/testing/plugin.d.ts.map +1 -0
- package/dist/types/src/testing/pull-request-13348.d.ts +6 -0
- package/dist/types/src/testing/pull-request-13348.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +339 -53
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/GitHubCapabilities.d.ts +13 -0
- package/dist/types/src/types/GitHubCapabilities.d.ts.map +1 -0
- package/dist/types/src/types/GitHubEvents.d.ts +8 -0
- package/dist/types/src/types/GitHubEvents.d.ts.map +1 -0
- package/dist/types/src/types/GitHubOperation.d.ts +281 -0
- package/dist/types/src/types/GitHubOperation.d.ts.map +1 -0
- package/dist/types/src/types/PullRequestsView.d.ts +35 -0
- package/dist/types/src/types/PullRequestsView.d.ts.map +1 -0
- package/dist/types/src/types/Walkthrough.d.ts +31 -0
- package/dist/types/src/types/Walkthrough.d.ts.map +1 -0
- package/dist/types/src/types/Walkthrough.test.d.ts +2 -0
- package/dist/types/src/types/Walkthrough.test.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +5 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/walkthrough/fill.d.ts +28 -0
- package/dist/types/src/walkthrough/fill.d.ts.map +1 -0
- package/dist/types/src/walkthrough/fill.test.d.ts +2 -0
- package/dist/types/src/walkthrough/fill.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/generate.d.ts +67 -0
- package/dist/types/src/walkthrough/generate.d.ts.map +1 -0
- package/dist/types/src/walkthrough/generate.test.d.ts +2 -0
- package/dist/types/src/walkthrough/generate.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/generated.d.ts +20 -0
- package/dist/types/src/walkthrough/generated.d.ts.map +1 -0
- package/dist/types/src/walkthrough/generated.test.d.ts +2 -0
- package/dist/types/src/walkthrough/generated.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/headings.d.ts +8 -0
- package/dist/types/src/walkthrough/headings.d.ts.map +1 -0
- package/dist/types/src/walkthrough/headings.test.d.ts +2 -0
- package/dist/types/src/walkthrough/headings.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/index.d.ts +9 -0
- package/dist/types/src/walkthrough/index.d.ts.map +1 -0
- package/dist/types/src/walkthrough/patch.d.ts +48 -0
- package/dist/types/src/walkthrough/patch.d.ts.map +1 -0
- package/dist/types/src/walkthrough/plan.d.ts +55 -0
- package/dist/types/src/walkthrough/plan.d.ts.map +1 -0
- package/dist/types/src/walkthrough/plan.test.d.ts +2 -0
- package/dist/types/src/walkthrough/plan.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/prompt.d.ts +33 -0
- package/dist/types/src/walkthrough/prompt.d.ts.map +1 -0
- package/dist/types/src/walkthrough/prompt.test.d.ts +2 -0
- package/dist/types/src/walkthrough/prompt.test.d.ts.map +1 -0
- package/dist/types/src/walkthrough/score.d.ts +43 -0
- package/dist/types/src/walkthrough/score.d.ts.map +1 -0
- package/dist/types/src/walkthrough/score.test.d.ts +2 -0
- package/dist/types/src/walkthrough/score.test.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dx.config.ts +39 -0
- package/package.json +167 -48
- package/src/Extensions.ts +7 -0
- package/src/GitHubPlugin.ts +15 -0
- package/src/GitHubPlugin.workerd.test.ts +23 -0
- package/src/approval.test.ts +40 -0
- package/src/approval.ts +39 -0
- package/src/capabilities/app-graph-builder.ts +47 -0
- package/src/capabilities/connector.ts +95 -0
- package/src/capabilities/gen/browser.ts +82 -0
- package/src/capabilities/gen/node.ts +43 -0
- package/src/capabilities/gen/tauri.ts +82 -0
- package/src/capabilities/gen/workerd.ts +43 -0
- package/src/capabilities/index.ts +71 -0
- package/src/capabilities/link-resolver.ts +137 -0
- package/src/capabilities/markdown-extension.ts +146 -0
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/page-action.ts +32 -0
- package/src/capabilities/react-surface.ts +98 -0
- package/src/capabilities/schema.ts +16 -0
- package/src/capabilities/skill-definition.ts +14 -0
- package/src/cards/GitHubCard.stories.tsx +165 -0
- package/src/cards/GitHubCard.tsx +93 -0
- package/src/cards/PullRequestCard.tsx +23 -0
- package/src/cards/index.ts +6 -0
- package/src/components/CommentComposer/CommentComposer.tsx +109 -0
- package/src/components/CommentComposer/index.ts +5 -0
- package/src/components/PullRequestFiles/DiffStat.tsx +15 -0
- package/src/components/PullRequestFiles/FileTree.tsx +102 -0
- package/src/components/PullRequestFiles/PullRequestFiles.tsx +87 -0
- package/src/components/PullRequestFiles/files.test.ts +59 -0
- package/src/components/PullRequestFiles/files.ts +115 -0
- package/src/components/PullRequestFiles/index.ts +8 -0
- package/src/components/PullRequestOverview/ArtifactPill.tsx +82 -0
- package/src/components/PullRequestOverview/CheckRunList.test.ts +29 -0
- package/src/components/PullRequestOverview/CheckRunList.tsx +141 -0
- package/src/components/PullRequestOverview/PullRequestDetails.tsx +15 -0
- package/src/components/PullRequestOverview/PullRequestOverview.tsx +110 -0
- package/src/components/PullRequestOverview/RelatedCards.tsx +147 -0
- package/src/components/PullRequestOverview/index.ts +9 -0
- package/src/components/PullRequestStatus/PullRequestStatus.tsx +84 -0
- package/src/components/PullRequestStatus/index.ts +5 -0
- package/src/components/WalkthroughView/WalkthroughView.tsx +62 -0
- package/src/components/WalkthroughView/extensions.ts +53 -0
- package/src/components/WalkthroughView/index.ts +6 -0
- package/src/components/index.ts +6 -9
- package/src/constants.ts +12 -0
- package/src/containers/ImportPullRequestDialog/ImportPullRequestDialog.tsx +160 -0
- package/src/containers/ImportPullRequestDialog/index.ts +7 -0
- package/src/containers/PullRequestArticle/PullRequestArticle.tsx +573 -0
- package/src/containers/PullRequestArticle/failure.test.ts +42 -0
- package/src/containers/PullRequestArticle/failure.ts +16 -0
- package/src/containers/PullRequestArticle/index.ts +5 -0
- package/src/containers/PullRequestCardMenu/PullRequestCardMenu.tsx +134 -0
- package/src/containers/PullRequestCardMenu/index.ts +5 -0
- package/src/containers/PullRequestsArticle/PullRequestsArticle.tsx +361 -0
- package/src/containers/PullRequestsArticle/arrange.test.ts +122 -0
- package/src/containers/PullRequestsArticle/arrange.ts +245 -0
- package/src/containers/PullRequestsArticle/format.ts +31 -0
- package/src/containers/PullRequestsArticle/index.ts +5 -0
- package/src/containers/WalkthroughArticle/WalkthroughArticle.tsx +31 -0
- package/src/containers/WalkthroughArticle/index.ts +5 -0
- package/src/containers/index.ts +11 -0
- package/src/errors.ts +61 -0
- package/src/extensions/index.ts +6 -0
- package/src/extensions/links.test.ts +133 -0
- package/src/extensions/links.ts +91 -0
- package/src/extensions/references.test.ts +83 -0
- package/src/extensions/references.ts +100 -0
- package/src/github-link.ts +70 -0
- package/src/hooks/index.ts +6 -3
- package/src/hooks/useOpenObject.ts +48 -0
- package/src/hooks/usePullRequestChecks.ts +81 -0
- package/src/hooks/usePullRequestDiff.ts +57 -0
- package/src/hooks/usePullRequestFiles.ts +98 -0
- package/src/hooks/useSyncPullRequest.ts +51 -0
- package/src/index.ts +4 -6
- package/src/meta.ts +8 -13
- package/src/operations/add-pull-request-comment.ts +31 -0
- package/src/operations/add-pull-request-review-comment.ts +32 -0
- package/src/operations/generate-walkthrough.ts +124 -0
- package/src/operations/get-pull-request-diff.ts +37 -0
- package/src/operations/get-pull-request-status.ts +44 -0
- package/src/operations/get-repositories.ts +53 -0
- package/src/operations/import-pull-request-from-snapshot.ts +48 -0
- package/src/operations/import-pull-request.test.ts +151 -0
- package/src/operations/import-pull-request.ts +149 -0
- package/src/operations/index.ts +30 -0
- package/src/operations/materialize-target.ts +60 -0
- package/src/operations/pull-request.test.ts +120 -0
- package/src/operations/pull-request.ts +141 -0
- package/src/operations/refresh-pull-requests.ts +69 -0
- package/src/operations/refresh.test.ts +112 -0
- package/src/operations/refresh.ts +111 -0
- package/src/operations/submit-pull-request-approval.ts +41 -0
- package/src/operations/sync-pull-request.ts +34 -0
- package/src/operations/sync.test.ts +453 -0
- package/src/operations/sync.ts +807 -0
- package/src/plugin.test.ts +40 -0
- package/src/plugin.ts +37 -0
- package/src/pull-request-body.test.ts +61 -0
- package/src/pull-request-body.ts +144 -0
- package/src/pull-request.test.ts +67 -0
- package/src/pull-request.ts +80 -0
- package/src/services/github-api.ts +735 -0
- package/src/services/index.ts +5 -0
- package/src/skills/GitHubSkill.ts +46 -0
- package/src/skills/index.ts +5 -0
- package/src/stories/Generate.stories.tsx +152 -0
- package/src/stories/Links.stories.tsx +153 -0
- package/src/stories/PullRequestArticle.stories.tsx +107 -0
- package/src/stories/PullRequestFiles.stories.tsx +69 -0
- package/src/stories/PullRequestOverview.stories.tsx +114 -0
- package/src/stories/PullRequestsArticle.stories.tsx +170 -0
- package/src/stories/Walkthrough.stories.tsx +110 -0
- package/src/stories/github.test.ts +65 -0
- package/src/stories/github.ts +70 -0
- package/src/stories/walkthrough-fixture.ts +115 -0
- package/src/testing/fixtures.ts +99 -0
- package/src/testing/index.ts +7 -0
- package/src/testing/plugin.ts +25 -0
- package/src/testing/pull-request-13348.ts +104 -0
- package/src/testing/pull-request-13363.patch +2981 -0
- package/src/translations.ts +135 -63
- package/src/types/GitHubCapabilities.ts +27 -0
- package/src/types/GitHubEvents.ts +16 -0
- package/src/types/GitHubOperation.ts +397 -0
- package/src/types/PullRequestsView.ts +45 -0
- package/src/types/Walkthrough.test.ts +75 -0
- package/src/types/Walkthrough.ts +66 -0
- package/src/types/index.ts +8 -0
- package/src/vite-env.d.ts +15 -0
- package/src/walkthrough/fill.test.ts +337 -0
- package/src/walkthrough/fill.ts +246 -0
- package/src/walkthrough/generate.test.ts +219 -0
- package/src/walkthrough/generate.ts +248 -0
- package/src/walkthrough/generated.test.ts +70 -0
- package/src/walkthrough/generated.ts +70 -0
- package/src/walkthrough/headings.test.ts +40 -0
- package/src/walkthrough/headings.ts +39 -0
- package/src/walkthrough/index.ts +12 -0
- package/src/walkthrough/patch.ts +154 -0
- package/src/walkthrough/plan.test.ts +178 -0
- package/src/walkthrough/plan.ts +251 -0
- package/src/walkthrough/prompt.test.ts +100 -0
- package/src/walkthrough/prompt.ts +147 -0
- package/src/walkthrough/score.test.ts +272 -0
- package/src/walkthrough/score.ts +430 -0
- package/README.md +0 -15
- package/dist/lib/browser/chunk-S4MPSBA5.mjs +0 -21
- package/dist/lib/browser/chunk-S4MPSBA5.mjs.map +0 -7
- package/dist/lib/browser/index.css +0 -7
- package/dist/lib/browser/index.css.map +0 -7
- package/dist/lib/browser/index.mjs +0 -1535
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/meta.mjs +0 -11
- package/dist/lib/browser/meta.mjs.map +0 -7
- package/dist/types/src/GithubPlugin.d.ts +0 -4
- package/dist/types/src/GithubPlugin.d.ts.map +0 -1
- package/dist/types/src/components/EmbeddedMain/EmbeddedMain.d.ts +0 -4
- package/dist/types/src/components/EmbeddedMain/EmbeddedMain.d.ts.map +0 -1
- package/dist/types/src/components/EmbeddedMain/GfmPreview.d.ts +0 -9
- package/dist/types/src/components/EmbeddedMain/GfmPreview.d.ts.map +0 -1
- package/dist/types/src/components/EmbeddedMain/index.d.ts +0 -2
- package/dist/types/src/components/EmbeddedMain/index.d.ts.map +0 -1
- package/dist/types/src/components/ExportDialog.d.ts +0 -8
- package/dist/types/src/components/ExportDialog.d.ts.map +0 -1
- package/dist/types/src/components/GithubApiProviders/GitHubSettings.d.ts +0 -3
- package/dist/types/src/components/GithubApiProviders/GitHubSettings.d.ts.map +0 -1
- package/dist/types/src/components/GithubApiProviders/OctokitProvider.d.ts +0 -15
- package/dist/types/src/components/GithubApiProviders/OctokitProvider.d.ts.map +0 -1
- package/dist/types/src/components/GithubApiProviders/index.d.ts +0 -3
- package/dist/types/src/components/GithubApiProviders/index.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/DocumentTreeItem.d.ts +0 -6
- package/dist/types/src/components/GithubEchoResolverProviders/DocumentTreeItem.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverContext.d.ts +0 -7
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverContext.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverDialog.d.ts +0 -6
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverDialog.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverProps.d.ts +0 -16
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverProps.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverTree.d.ts +0 -3
- package/dist/types/src/components/GithubEchoResolverProviders/ResolverTree.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.d.ts +0 -11
- package/dist/types/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/index.d.ts +0 -3
- package/dist/types/src/components/GithubEchoResolverProviders/index.d.ts.map +0 -1
- package/dist/types/src/components/GithubEchoResolverProviders/spaceResolvers.d.ts +0 -6
- package/dist/types/src/components/GithubEchoResolverProviders/spaceResolvers.d.ts.map +0 -1
- package/dist/types/src/components/ImportDialog.d.ts +0 -7
- package/dist/types/src/components/ImportDialog.d.ts.map +0 -1
- package/dist/types/src/components/Issue.d.ts +0 -5
- package/dist/types/src/components/Issue.d.ts.map +0 -1
- package/dist/types/src/components/Loading/Loading.d.ts +0 -15
- package/dist/types/src/components/Loading/Loading.d.ts.map +0 -1
- package/dist/types/src/components/Loading/Loading.stories.d.ts +0 -40
- package/dist/types/src/components/Loading/Loading.stories.d.ts.map +0 -1
- package/dist/types/src/components/Loading/index.d.ts +0 -2
- package/dist/types/src/components/Loading/index.d.ts.map +0 -1
- package/dist/types/src/components/MarkdownActions.d.ts +0 -7
- package/dist/types/src/components/MarkdownActions.d.ts.map +0 -1
- package/dist/types/src/components/UrlDialog.d.ts +0 -6
- package/dist/types/src/components/UrlDialog.d.ts.map +0 -1
- package/dist/types/src/hooks/useDocGhId.d.ts +0 -6
- package/dist/types/src/hooks/useDocGhId.d.ts.map +0 -1
- package/dist/types/src/hooks/useGhIdFromUrl.d.ts +0 -2
- package/dist/types/src/hooks/useGhIdFromUrl.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -30
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/GithubPlugin.tsx +0 -127
- package/src/components/EmbeddedMain/EmbeddedMain.tsx +0 -294
- package/src/components/EmbeddedMain/GfmPreview.tsx +0 -110
- package/src/components/EmbeddedMain/embedded.css +0 -3
- package/src/components/EmbeddedMain/index.ts +0 -5
- package/src/components/ExportDialog.tsx +0 -157
- package/src/components/GithubApiProviders/GitHubSettings.tsx +0 -72
- package/src/components/GithubApiProviders/OctokitProvider.tsx +0 -60
- package/src/components/GithubApiProviders/index.ts +0 -6
- package/src/components/GithubEchoResolverProviders/DocumentTreeItem.tsx +0 -26
- package/src/components/GithubEchoResolverProviders/ResolverContext.tsx +0 -137
- package/src/components/GithubEchoResolverProviders/ResolverDialog.tsx +0 -34
- package/src/components/GithubEchoResolverProviders/ResolverProps.ts +0 -23
- package/src/components/GithubEchoResolverProviders/ResolverTree.tsx +0 -86
- package/src/components/GithubEchoResolverProviders/SpacePickerTreeItem.tsx +0 -105
- package/src/components/GithubEchoResolverProviders/index.ts +0 -6
- package/src/components/GithubEchoResolverProviders/spaceResolvers.ts +0 -86
- package/src/components/ImportDialog.tsx +0 -72
- package/src/components/Issue.tsx +0 -62
- package/src/components/Loading/Loading.stories.tsx +0 -32
- package/src/components/Loading/Loading.tsx +0 -70
- package/src/components/Loading/index.ts +0 -5
- package/src/components/MarkdownActions.tsx +0 -136
- package/src/components/UrlDialog.tsx +0 -52
- package/src/hooks/useDocGhId.ts +0 -38
- package/src/hooks/useGhIdFromUrl.ts +0 -26
- package/src/types.ts +0 -51
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import * as Operation from '@dxos/compute/Operation';
|
|
8
|
+
import { Database, Filter, Obj, Query, Ref } from '@dxos/echo';
|
|
9
|
+
import { TaskSet } from '@dxos/types';
|
|
10
|
+
|
|
11
|
+
import { GitHubOperation } from '#types';
|
|
12
|
+
|
|
13
|
+
import { GITHUB_SOURCE } from '../constants.ts';
|
|
14
|
+
|
|
15
|
+
const fkFor = (id: string) => ({ source: GITHUB_SOURCE, id });
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Find-or-create the empty local root Project for a GitHub repo so a `Cursor`
|
|
19
|
+
* can reference it as its `spec.target`. Idempotent: keyed by the repo's
|
|
20
|
+
* GitHub foreign id (`remoteTarget.id`), it returns the existing Project
|
|
21
|
+
* when one already carries that key. The repo's data is filled in lazily by the
|
|
22
|
+
* sync operation; here we only stamp the foreign key + a display name.
|
|
23
|
+
*/
|
|
24
|
+
const handler: Operation.WithHandler<typeof GitHubOperation.MaterializeGitHubTarget> =
|
|
25
|
+
GitHubOperation.MaterializeGitHubTarget.pipe(
|
|
26
|
+
Operation.withHandler(
|
|
27
|
+
Effect.fnUntraced(function* ({ connection, remoteTarget }) {
|
|
28
|
+
if (!remoteTarget) {
|
|
29
|
+
return yield* Effect.die(new Error('GitHub materializeTarget requires a remoteTarget (repo descriptor).'));
|
|
30
|
+
}
|
|
31
|
+
// TODO(wittjosiah): the operation should just depend on `Database.Service` and
|
|
32
|
+
// have it provided by the OperationInvoker — composer's invoker is wired
|
|
33
|
+
// without a `databaseResolver`, so we derive the db from the connection ref's
|
|
34
|
+
// target and provide `Database.layer(db)` ourselves.
|
|
35
|
+
const db = connection.target ? Obj.getDatabase(connection.target) : undefined;
|
|
36
|
+
if (!db) {
|
|
37
|
+
return yield* Effect.die(new Error('No database for connection ref.'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return yield* Effect.gen(function* () {
|
|
41
|
+
const existing = yield* Database.query(
|
|
42
|
+
Query.select(Filter.foreignKeys(TaskSet.TaskSet, [fkFor(remoteTarget.id)])),
|
|
43
|
+
).run;
|
|
44
|
+
if (existing.length > 0) {
|
|
45
|
+
return { target: Ref.make(existing[0]) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const created = yield* Database.add(
|
|
49
|
+
TaskSet.make({
|
|
50
|
+
[Obj.Meta]: { keys: [fkFor(remoteTarget.id)] },
|
|
51
|
+
name: remoteTarget.name,
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
return { target: Ref.make(created) };
|
|
55
|
+
}).pipe(Effect.provide(Database.layer(db)));
|
|
56
|
+
}),
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export default handler;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { summarizeCheckRuns, summarizeReviews, toCheckRun } from './pull-request.ts';
|
|
8
|
+
|
|
9
|
+
describe('summarizeCheckRuns', () => {
|
|
10
|
+
test('no runs is none', () => {
|
|
11
|
+
expect(summarizeCheckRuns([])).toEqual({ ci: 'none', checks: { total: 0, passed: 0, failed: 0, pending: 0 } });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('all completed without failure is success, skipped and neutral included', () => {
|
|
15
|
+
const { ci, checks } = summarizeCheckRuns([
|
|
16
|
+
{ name: 'build', status: 'completed', conclusion: 'success' },
|
|
17
|
+
{ name: 'lint', status: 'completed', conclusion: 'skipped' },
|
|
18
|
+
{ name: 'docs', status: 'completed', conclusion: 'neutral' },
|
|
19
|
+
]);
|
|
20
|
+
expect(ci).toEqual('success');
|
|
21
|
+
expect(checks).toEqual({ total: 3, passed: 3, failed: 0, pending: 0 });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('an unfinished run is pending', () => {
|
|
25
|
+
const { ci } = summarizeCheckRuns([
|
|
26
|
+
{ name: 'build', status: 'completed', conclusion: 'success' },
|
|
27
|
+
{ name: 'test', status: 'in_progress', conclusion: null },
|
|
28
|
+
]);
|
|
29
|
+
expect(ci).toEqual('pending');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('a stale run does not count as passed', () => {
|
|
33
|
+
const { ci, checks } = summarizeCheckRuns([
|
|
34
|
+
{ name: 'build', status: 'completed', conclusion: 'success' },
|
|
35
|
+
{ name: 'test', status: 'completed', conclusion: 'stale' },
|
|
36
|
+
]);
|
|
37
|
+
expect(ci).toEqual('failure');
|
|
38
|
+
expect(checks).toEqual({ total: 2, passed: 1, failed: 1, pending: 0 });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('a failure wins over pending runs', () => {
|
|
42
|
+
const { ci, checks } = summarizeCheckRuns([
|
|
43
|
+
{ name: 'build', status: 'completed', conclusion: 'timed_out' },
|
|
44
|
+
{ name: 'test', status: 'queued' },
|
|
45
|
+
]);
|
|
46
|
+
expect(ci).toEqual('failure');
|
|
47
|
+
expect(checks).toEqual({ total: 2, passed: 0, failed: 1, pending: 1 });
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('toCheckRun', () => {
|
|
52
|
+
test('folds a conclusion into the outcome the list shows', () => {
|
|
53
|
+
expect(toCheckRun({ name: 'test', status: 'completed', conclusion: 'timed_out' }).outcome).toEqual('failure');
|
|
54
|
+
expect(toCheckRun({ name: 'cli', status: 'completed', conclusion: 'skipped' }).outcome).toEqual('skipped');
|
|
55
|
+
expect(toCheckRun({ name: 'e2e', status: 'in_progress', conclusion: null }).outcome).toEqual('pending');
|
|
56
|
+
expect(toCheckRun({ name: 'build', status: 'completed', conclusion: 'success' }).outcome).toEqual('success');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("links the provider's page over GitHub's", () => {
|
|
60
|
+
const run = toCheckRun({
|
|
61
|
+
name: 'Check / check',
|
|
62
|
+
status: 'completed',
|
|
63
|
+
conclusion: 'success',
|
|
64
|
+
html_url: 'https://github.com/dxos/dxos/runs/1',
|
|
65
|
+
details_url: 'https://depot.dev/orgs/acme/workflows/abc?job=1',
|
|
66
|
+
started_at: '2026-09-23T12:47:05Z',
|
|
67
|
+
completed_at: '2026-09-23T12:51:13Z',
|
|
68
|
+
});
|
|
69
|
+
expect(run).toEqual({
|
|
70
|
+
name: 'Check / check',
|
|
71
|
+
outcome: 'success',
|
|
72
|
+
conclusion: 'success',
|
|
73
|
+
url: 'https://depot.dev/orgs/acme/workflows/abc?job=1',
|
|
74
|
+
startedAt: '2026-09-23T12:47:05Z',
|
|
75
|
+
completedAt: '2026-09-23T12:51:13Z',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('summarizeReviews', () => {
|
|
81
|
+
const review = (id: number, login: string, state: string) => ({ id, state, user: { login } });
|
|
82
|
+
|
|
83
|
+
test('no reviews is none', () => {
|
|
84
|
+
expect(summarizeReviews([])).toEqual({ review: 'none', approvals: 0 });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('a comment alone is no verdict', () => {
|
|
88
|
+
expect(summarizeReviews([review(1, 'alice', 'COMMENTED')])).toEqual({ review: 'none', approvals: 0 });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('approvals are counted per reviewer', () => {
|
|
92
|
+
expect(
|
|
93
|
+
summarizeReviews([review(1, 'alice', 'APPROVED'), review(2, 'alice', 'APPROVED'), review(3, 'bob', 'APPROVED')]),
|
|
94
|
+
).toEqual({ review: 'approved', approvals: 2 });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('an outstanding request for changes outweighs approvals', () => {
|
|
98
|
+
expect(summarizeReviews([review(1, 'alice', 'APPROVED'), review(2, 'bob', 'CHANGES_REQUESTED')])).toEqual({
|
|
99
|
+
review: 'changes_requested',
|
|
100
|
+
approvals: 1,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("a reviewer's later approval clears their request, and a later comment does not undo it", () => {
|
|
105
|
+
expect(
|
|
106
|
+
summarizeReviews([
|
|
107
|
+
review(1, 'bob', 'CHANGES_REQUESTED'),
|
|
108
|
+
review(2, 'bob', 'APPROVED'),
|
|
109
|
+
review(3, 'bob', 'COMMENTED'),
|
|
110
|
+
]),
|
|
111
|
+
).toEqual({ review: 'approved', approvals: 1 });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('a dismissed review withdraws the verdict', () => {
|
|
115
|
+
expect(summarizeReviews([review(1, 'bob', 'APPROVED'), review(2, 'bob', 'DISMISSED')])).toEqual({
|
|
116
|
+
review: 'none',
|
|
117
|
+
approvals: 0,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Layer from 'effect/Layer';
|
|
7
|
+
|
|
8
|
+
import { Database, Filter, Obj, type Ref } from '@dxos/echo';
|
|
9
|
+
import { Connection } from '@dxos/link';
|
|
10
|
+
import { type PullRequest } from '@dxos/types';
|
|
11
|
+
|
|
12
|
+
import { type GitHubOperation } from '#types';
|
|
13
|
+
|
|
14
|
+
import { GITHUB_PROVIDER_ID } from '../constants.ts';
|
|
15
|
+
import { GitHubPullRequestUnstoredError } from '../errors.ts';
|
|
16
|
+
import { GitHubApi } from '../services/index.ts';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The GitHub connection whose token requests are sent with: the first one holding a token. Shared by
|
|
20
|
+
* the handlers and by the UI that sends the user to reconnect, so both name the same connection.
|
|
21
|
+
*/
|
|
22
|
+
export const githubConnection = () =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const connections = yield* Database.query(Filter.type(Connection.Connection)).run;
|
|
25
|
+
for (const connection of connections) {
|
|
26
|
+
if (connection.connectorId !== GITHUB_PROVIDER_ID) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const accessToken = yield* Database.load(connection.accessToken);
|
|
30
|
+
if (accessToken.token) {
|
|
31
|
+
return { connection, token: accessToken.token };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return undefined;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The token of {@link githubConnection}, or empty for anonymous — which reaches any public pull
|
|
40
|
+
* request, and is the only option in a space that has not connected GitHub.
|
|
41
|
+
*/
|
|
42
|
+
export const githubToken = () => githubConnection().pipe(Effect.map((selected) => selected?.token ?? ''));
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The stored pull request behind an operation's input and credentials for its space.
|
|
46
|
+
*
|
|
47
|
+
* The invoker carries no database resolver, so handlers derive one from the pull request itself; a
|
|
48
|
+
* preview card's in-memory pull request has none and cannot be acted on.
|
|
49
|
+
*/
|
|
50
|
+
export const resolvePullRequest = (ref: Ref.Ref<PullRequest.PullRequest>) =>
|
|
51
|
+
Effect.gen(function* () {
|
|
52
|
+
const pullRequest = ref.target;
|
|
53
|
+
const db = pullRequest ? Obj.getDatabase(pullRequest) : undefined;
|
|
54
|
+
if (!pullRequest || !db) {
|
|
55
|
+
return yield* Effect.die(new GitHubPullRequestUnstoredError());
|
|
56
|
+
}
|
|
57
|
+
const token = yield* githubToken().pipe(Effect.provide(Database.layer(db)));
|
|
58
|
+
return { pullRequest, db, credentials: Layer.succeed(GitHubApi.GitHubCredentials, { token }) };
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// `stale` is a completed run GitHub never re-ran, which branch protection does not count as passing.
|
|
62
|
+
const FAILED_CONCLUSIONS = new Set([
|
|
63
|
+
'failure',
|
|
64
|
+
'cancelled',
|
|
65
|
+
'timed_out',
|
|
66
|
+
'action_required',
|
|
67
|
+
'startup_failure',
|
|
68
|
+
'stale',
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
/** One check run as the article lists it: its outcome folded the way {@link summarizeCheckRuns} counts it. */
|
|
72
|
+
export const toCheckRun = (run: GitHubApi.GitHubCheckRun): GitHubOperation.CheckRun => {
|
|
73
|
+
const outcome: GitHubOperation.CheckOutcome =
|
|
74
|
+
run.status !== 'completed'
|
|
75
|
+
? 'pending'
|
|
76
|
+
: run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)
|
|
77
|
+
? 'failure'
|
|
78
|
+
: run.conclusion === 'skipped'
|
|
79
|
+
? 'skipped'
|
|
80
|
+
: run.conclusion === 'neutral'
|
|
81
|
+
? 'neutral'
|
|
82
|
+
: 'success';
|
|
83
|
+
const url = run.details_url ?? run.html_url;
|
|
84
|
+
return {
|
|
85
|
+
name: run.name,
|
|
86
|
+
outcome,
|
|
87
|
+
...(run.conclusion ? { conclusion: run.conclusion } : {}),
|
|
88
|
+
...(url ? { url } : {}),
|
|
89
|
+
...(run.started_at ? { startedAt: run.started_at } : {}),
|
|
90
|
+
...(run.completed_at ? { completedAt: run.completed_at } : {}),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** Folds a commit's check runs into one outcome: any failure fails, then any unfinished run is pending. */
|
|
95
|
+
export const summarizeCheckRuns = (
|
|
96
|
+
runs: readonly GitHubApi.GitHubCheckRun[],
|
|
97
|
+
): { ci: GitHubOperation.CiState; checks: GitHubOperation.CheckCounts } => {
|
|
98
|
+
const checks = { total: runs.length, passed: 0, failed: 0, pending: 0 };
|
|
99
|
+
for (const run of runs) {
|
|
100
|
+
if (run.status !== 'completed') {
|
|
101
|
+
checks.pending++;
|
|
102
|
+
} else if (run.conclusion && FAILED_CONCLUSIONS.has(run.conclusion)) {
|
|
103
|
+
checks.failed++;
|
|
104
|
+
} else {
|
|
105
|
+
checks.passed++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const ci: GitHubOperation.CiState =
|
|
110
|
+
checks.total === 0 ? 'none' : checks.failed > 0 ? 'failure' : checks.pending > 0 ? 'pending' : 'success';
|
|
111
|
+
return { ci, checks };
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/** Review states that set a reviewer's standing verdict; a comment leaves the previous one in place. */
|
|
115
|
+
const VERDICT_STATES = new Set(['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED']);
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Folds a pull request's reviews into where they stand, from each reviewer's latest verdict — the
|
|
119
|
+
* way GitHub reads them: a later approval clears that reviewer's request for changes, and a dismissal
|
|
120
|
+
* withdraws whichever verdict it replaced.
|
|
121
|
+
*/
|
|
122
|
+
export const summarizeReviews = (
|
|
123
|
+
reviews: readonly GitHubApi.GitHubSubmittedReview[],
|
|
124
|
+
): { review: GitHubOperation.ReviewState; approvals: number } => {
|
|
125
|
+
const verdicts = new Map<string, string>();
|
|
126
|
+
for (const review of reviews) {
|
|
127
|
+
const login = review.user?.login;
|
|
128
|
+
if (login && VERDICT_STATES.has(review.state)) {
|
|
129
|
+
verdicts.set(login, review.state);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const states = [...verdicts.values()];
|
|
134
|
+
const approvals = states.filter((state) => state === 'APPROVED').length;
|
|
135
|
+
const review: GitHubOperation.ReviewState = states.includes('CHANGES_REQUESTED')
|
|
136
|
+
? 'changes_requested'
|
|
137
|
+
: approvals > 0
|
|
138
|
+
? 'approved'
|
|
139
|
+
: 'none';
|
|
140
|
+
return { review, approvals };
|
|
141
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Clock from 'effect/Clock';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as FetchHttpClient from 'effect/http/FetchHttpClient';
|
|
8
|
+
|
|
9
|
+
import * as Operation from '@dxos/compute/Operation';
|
|
10
|
+
import { log } from '@dxos/log';
|
|
11
|
+
|
|
12
|
+
import { GitHubOperation } from '#types';
|
|
13
|
+
|
|
14
|
+
import { githubToken } from './pull-request.ts';
|
|
15
|
+
import { ensureRefreshTrigger, queryInFlightPullRequests, refreshPullRequest, selectRefreshBatch } from './refresh.ts';
|
|
16
|
+
|
|
17
|
+
/** Bounded so a space with many open pull requests does not burst GitHub's secondary rate limit. */
|
|
18
|
+
const REFRESH_CONCURRENCY = 2;
|
|
19
|
+
|
|
20
|
+
/** The hourly `REFRESH_CRON` period, so each scheduled run lands in its own batch window. */
|
|
21
|
+
const REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
22
|
+
|
|
23
|
+
const handler: Operation.WithHandler<typeof GitHubOperation.RefreshPullRequests> =
|
|
24
|
+
GitHubOperation.RefreshPullRequests.pipe(
|
|
25
|
+
Operation.withHandler(
|
|
26
|
+
Effect.fn(function* () {
|
|
27
|
+
// Collapses any duplicate a racing peer created, so the space keeps one schedule.
|
|
28
|
+
yield* ensureRefreshTrigger();
|
|
29
|
+
const inFlight = yield* queryInFlightPullRequests();
|
|
30
|
+
if (inFlight.length === 0) {
|
|
31
|
+
return { checked: 0, updated: 0, failed: 0 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const window = Math.floor((yield* Clock.currentTimeMillis) / REFRESH_INTERVAL_MS);
|
|
35
|
+
const pullRequests = selectRefreshBatch(inFlight, window);
|
|
36
|
+
|
|
37
|
+
const token = yield* githubToken();
|
|
38
|
+
const results = yield* Effect.forEach(
|
|
39
|
+
pullRequests,
|
|
40
|
+
(pullRequest) =>
|
|
41
|
+
// One deleted or unreachable pull request must not fail the run: EDGE disables a trigger
|
|
42
|
+
// after repeated failures, which would stop refreshing every other one.
|
|
43
|
+
refreshPullRequest(pullRequest, token).pipe(
|
|
44
|
+
Effect.map((updated) => (updated.length > 0 ? 'updated' : 'unchanged')),
|
|
45
|
+
Effect.catchDefect((cause) =>
|
|
46
|
+
Effect.sync(() => {
|
|
47
|
+
log.warn('pull request refresh failed', {
|
|
48
|
+
owner: pullRequest.owner,
|
|
49
|
+
repo: pullRequest.repo,
|
|
50
|
+
number: pullRequest.number,
|
|
51
|
+
cause,
|
|
52
|
+
});
|
|
53
|
+
return 'failed' as const;
|
|
54
|
+
}),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
{ concurrency: REFRESH_CONCURRENCY },
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
checked: pullRequests.length,
|
|
62
|
+
updated: results.filter((result) => result === 'updated').length,
|
|
63
|
+
failed: results.filter((result) => result === 'failed').length,
|
|
64
|
+
};
|
|
65
|
+
}, Effect.provide(FetchHttpClient.layer)),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export default handler;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import { afterEach, beforeEach, describe, test } from 'vitest';
|
|
7
|
+
|
|
8
|
+
import * as Trigger from '@dxos/compute/Trigger';
|
|
9
|
+
import { Database, Filter, Obj, Ref } from '@dxos/echo';
|
|
10
|
+
import { EchoTestBuilder } from '@dxos/echo-client/testing';
|
|
11
|
+
import * as EffectEx from '@dxos/effect/EffectEx';
|
|
12
|
+
import { PullRequest } from '@dxos/types';
|
|
13
|
+
|
|
14
|
+
import { GitHubOperation } from '#types';
|
|
15
|
+
|
|
16
|
+
import { REFRESH_CRON, ensureRefreshTrigger, queryInFlightPullRequests, selectRefreshBatch } from './refresh.ts';
|
|
17
|
+
|
|
18
|
+
describe('pull request refresh', () => {
|
|
19
|
+
let builder: EchoTestBuilder;
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
builder = await new EchoTestBuilder().open();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
await builder.close();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const setup = async () => {
|
|
30
|
+
const { db, graph } = await builder.createDatabase();
|
|
31
|
+
graph.registry.add([Trigger.Trigger, PullRequest.PullRequest]);
|
|
32
|
+
return db;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const run = <T>(db: Database.Database, effect: Effect.Effect<T, never, Database.Service>) =>
|
|
36
|
+
effect.pipe(Effect.provide(Database.layer(db)), EffectEx.runAndForwardErrors);
|
|
37
|
+
|
|
38
|
+
test('a space gets one remote timer trigger, however often it is ensured', async ({ expect }) => {
|
|
39
|
+
const db = await setup();
|
|
40
|
+
const first = await run(db, ensureRefreshTrigger());
|
|
41
|
+
const second = await run(db, ensureRefreshTrigger());
|
|
42
|
+
|
|
43
|
+
expect(second.id).toBe(first.id);
|
|
44
|
+
const triggers = await db.query(Filter.type(Trigger.Trigger)).run();
|
|
45
|
+
expect(triggers).toHaveLength(1);
|
|
46
|
+
expect(first.remote).toBe(true);
|
|
47
|
+
expect(first.enabled).toBe(true);
|
|
48
|
+
expect(first.spec).toEqual({ kind: 'timer', cron: REFRESH_CRON });
|
|
49
|
+
expect(first.runnable?.uri).toBe(GitHubOperation.RefreshPullRequests.meta.key.toString());
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('a disabled refresh trigger is left disabled', async ({ expect }) => {
|
|
53
|
+
const db = await setup();
|
|
54
|
+
const trigger = await run(db, ensureRefreshTrigger());
|
|
55
|
+
Obj.update(trigger, (trigger) => {
|
|
56
|
+
trigger.enabled = false;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const ensured = await run(db, ensureRefreshTrigger());
|
|
60
|
+
expect(ensured.id).toBe(trigger.id);
|
|
61
|
+
expect(ensured.enabled).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('only pull requests GitHub can still change are refreshed', async ({ expect }) => {
|
|
65
|
+
const db = await setup();
|
|
66
|
+
const make = (number: number, state: PullRequest.State) =>
|
|
67
|
+
db.add(PullRequest.make({ owner: 'dxos', repo: 'dxos', number, title: `#${number}`, state }));
|
|
68
|
+
make(1, 'open');
|
|
69
|
+
make(2, 'draft');
|
|
70
|
+
make(3, 'closed');
|
|
71
|
+
make(4, 'merged');
|
|
72
|
+
|
|
73
|
+
const inFlight = await run(db, queryInFlightPullRequests());
|
|
74
|
+
expect(inFlight.map((pullRequest) => pullRequest.number).sort()).toEqual([1, 2]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('duplicates a racing peer created collapse to the lowest-id trigger', async ({ expect }) => {
|
|
78
|
+
const db = await setup();
|
|
79
|
+
const make = () =>
|
|
80
|
+
db.add(
|
|
81
|
+
Trigger.make({
|
|
82
|
+
enabled: true,
|
|
83
|
+
remote: true,
|
|
84
|
+
spec: Trigger.specTimer(REFRESH_CRON),
|
|
85
|
+
runnable: Ref.fromURI(GitHubOperation.RefreshPullRequests.meta.key),
|
|
86
|
+
input: {},
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
const ids = [make().id, make().id].sort();
|
|
90
|
+
|
|
91
|
+
const kept = await run(db, ensureRefreshTrigger());
|
|
92
|
+
expect(kept.id).toBe(ids[0]);
|
|
93
|
+
const triggers = await db.query(Filter.type(Trigger.Trigger)).run();
|
|
94
|
+
expect(triggers.map((trigger) => trigger.id)).toEqual([ids[0]]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('successive runs walk every open pull request in bounded batches', async ({ expect }) => {
|
|
98
|
+
const db = await setup();
|
|
99
|
+
const pullRequests = Array.from({ length: 5 }, (_, index) =>
|
|
100
|
+
db.add(PullRequest.make({ owner: 'dxos', repo: 'dxos', number: index, title: `#${index}`, state: 'open' })),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(selectRefreshBatch(pullRequests, 0, 10)).toHaveLength(5);
|
|
104
|
+
const seen = new Set<string>();
|
|
105
|
+
for (let window = 0; window < 3; window++) {
|
|
106
|
+
const batch = selectRefreshBatch(pullRequests, window, 2);
|
|
107
|
+
expect(batch).toHaveLength(2);
|
|
108
|
+
batch.forEach((pullRequest) => seen.add(pullRequest.id));
|
|
109
|
+
}
|
|
110
|
+
expect(seen.size).toBe(5);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import * as Trigger from '@dxos/compute/Trigger';
|
|
8
|
+
import { Database, Filter, Obj, Ref } from '@dxos/echo';
|
|
9
|
+
import { PullRequest } from '@dxos/types';
|
|
10
|
+
|
|
11
|
+
import { GitHubOperation } from '#types';
|
|
12
|
+
|
|
13
|
+
import { pullRequestChanges } from '../pull-request.ts';
|
|
14
|
+
import { fetchPullRequestWithFallback } from './import-pull-request.ts';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* How often the space's refresh trigger polls its open pull requests: hourly, at an off-the-hour minute
|
|
18
|
+
* so the fleet of spaces does not land on EDGE's busiest tick, and because every open pull request
|
|
19
|
+
* costs a GitHub request against the connection's rate limit.
|
|
20
|
+
*/
|
|
21
|
+
export const REFRESH_CRON = '17 * * * *';
|
|
22
|
+
|
|
23
|
+
/** States GitHub can still move a pull request out of; a closed or merged one is settled. */
|
|
24
|
+
const IN_FLIGHT_STATES: readonly PullRequest.State[] = ['open', 'draft'];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Re-read one stored pull request from GitHub and write back the fields that changed.
|
|
28
|
+
*
|
|
29
|
+
* Uses the anonymous fallback, so a public pull request still refreshes behind a revoked token.
|
|
30
|
+
* Returns the names of the changed fields.
|
|
31
|
+
*/
|
|
32
|
+
export const refreshPullRequest = Effect.fn('refreshPullRequest')(function* (
|
|
33
|
+
pullRequest: PullRequest.PullRequest,
|
|
34
|
+
token: string,
|
|
35
|
+
) {
|
|
36
|
+
const pull = yield* fetchPullRequestWithFallback(pullRequest, token);
|
|
37
|
+
const changes = pullRequestChanges(pullRequest, pull);
|
|
38
|
+
const updated = Object.keys(changes);
|
|
39
|
+
if (updated.length > 0) {
|
|
40
|
+
Obj.update(pullRequest, (pullRequest) => {
|
|
41
|
+
Object.assign(pullRequest, changes);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return updated;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
/** Code-unit order, so every peer and EDGE agree on it regardless of locale. */
|
|
49
|
+
const byId = (left: { id: string }, right: { id: string }): number =>
|
|
50
|
+
left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
51
|
+
|
|
52
|
+
/** Most pull requests one run refreshes, so a run stays within GitHub's rate limit and EDGE's subrequest budget. */
|
|
53
|
+
export const REFRESH_BATCH_SIZE = 20;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The slice of `pullRequests` the run in window `window` refreshes: consecutive windows walk the list in
|
|
57
|
+
* id order and wrap, so every pull request is refreshed once every `ceil(count / size)` runs without
|
|
58
|
+
* storing a cursor.
|
|
59
|
+
*/
|
|
60
|
+
export const selectRefreshBatch = (
|
|
61
|
+
pullRequests: readonly PullRequest.PullRequest[],
|
|
62
|
+
window: number,
|
|
63
|
+
size = REFRESH_BATCH_SIZE,
|
|
64
|
+
): PullRequest.PullRequest[] => {
|
|
65
|
+
if (pullRequests.length <= size) {
|
|
66
|
+
return [...pullRequests];
|
|
67
|
+
}
|
|
68
|
+
const ordered = [...pullRequests].sort(byId);
|
|
69
|
+
const start = (window * size) % ordered.length;
|
|
70
|
+
return Array.from({ length: size }, (_, index) => ordered[(start + index) % ordered.length]);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** The space's pull requests GitHub may still change. */
|
|
74
|
+
export const queryInFlightPullRequests = () =>
|
|
75
|
+
Database.query(Filter.type(PullRequest.PullRequest)).run.pipe(
|
|
76
|
+
Effect.map((pullRequests) => pullRequests.filter((pullRequest) => IN_FLIGHT_STATES.includes(pullRequest.state))),
|
|
77
|
+
Effect.orDie,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const isRefreshTrigger = (trigger: Trigger.Trigger): boolean =>
|
|
81
|
+
trigger.runnable?.uri === GitHubOperation.RefreshPullRequests.meta.key.toString();
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Give the space its one pull-request refresh trigger, unless it has one already — including one the
|
|
85
|
+
* user disabled, which stays disabled.
|
|
86
|
+
*
|
|
87
|
+
* Peers that race to create it each add their own, so every caller converges on the same keeper (the
|
|
88
|
+
* lowest id) and removes the rest. The trigger runs on EDGE, so pull requests keep refreshing while no
|
|
89
|
+
* client has the space open.
|
|
90
|
+
*/
|
|
91
|
+
export const ensureRefreshTrigger = Effect.fn('ensureRefreshTrigger')(function* () {
|
|
92
|
+
const triggers = yield* Database.query(Filter.type(Trigger.Trigger)).run.pipe(Effect.orDie);
|
|
93
|
+
const [keeper, ...duplicates] = triggers.filter(isRefreshTrigger).sort(byId);
|
|
94
|
+
for (const duplicate of duplicates) {
|
|
95
|
+
yield* Database.remove(duplicate);
|
|
96
|
+
}
|
|
97
|
+
if (keeper) {
|
|
98
|
+
return keeper;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return yield* Database.add(
|
|
102
|
+
Trigger.make({
|
|
103
|
+
enabled: true,
|
|
104
|
+
remote: true,
|
|
105
|
+
spec: Trigger.specTimer(REFRESH_CRON),
|
|
106
|
+
// Statically defined in the registry, so referred to by key rather than copied into the space.
|
|
107
|
+
runnable: Ref.fromURI(GitHubOperation.RefreshPullRequests.meta.key),
|
|
108
|
+
input: {},
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as FetchHttpClient from 'effect/http/FetchHttpClient';
|
|
7
|
+
import * as Option from 'effect/Option';
|
|
8
|
+
|
|
9
|
+
import * as Operation from '@dxos/compute/Operation';
|
|
10
|
+
|
|
11
|
+
import { GitHubOperation } from '#types';
|
|
12
|
+
|
|
13
|
+
import { approvalCommentBody, isApprovalRefused } from '../approval.ts';
|
|
14
|
+
import { GitHubApi } from '../services/index.ts';
|
|
15
|
+
import { resolvePullRequest } from './pull-request.ts';
|
|
16
|
+
|
|
17
|
+
const handler: Operation.WithHandler<typeof GitHubOperation.SubmitPullRequestApproval> =
|
|
18
|
+
GitHubOperation.SubmitPullRequestApproval.pipe(
|
|
19
|
+
Operation.withHandler(
|
|
20
|
+
Effect.fn(function* ({ pullRequest: ref, body }) {
|
|
21
|
+
const { pullRequest, credentials } = yield* resolvePullRequest(ref);
|
|
22
|
+
const { owner, repo, number } = pullRequest;
|
|
23
|
+
const review = yield* GitHubApi.approvePullRequest(owner, repo, number, body).pipe(
|
|
24
|
+
Effect.provide(credentials),
|
|
25
|
+
Effect.asSome,
|
|
26
|
+
// Only a refusal to review becomes a comment; every other failure stays a failure.
|
|
27
|
+
Effect.catchIf(isApprovalRefused, () => Effect.succeedNone),
|
|
28
|
+
);
|
|
29
|
+
if (Option.isSome(review)) {
|
|
30
|
+
return { reviewId: review.value.id, commented: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const comment = yield* GitHubApi.createIssueComment(owner, repo, number, approvalCommentBody(body)).pipe(
|
|
34
|
+
Effect.provide(credentials),
|
|
35
|
+
);
|
|
36
|
+
return { commentId: comment.id, url: comment.html_url ?? undefined, commented: true };
|
|
37
|
+
}, Effect.provide(FetchHttpClient.layer)),
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
export default handler;
|