@dxos/plugin-github 0.14.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 (86) 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 -384
  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 +33 -10
  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.map +1 -1
  43. package/dist/lib/chunk-link-resolver.mjs.map +1 -1
  44. package/dist/lib/chunk-pull-request2.mjs +1 -0
  45. package/dist/lib/chunk-pull-request2.mjs.map +1 -1
  46. package/dist/lib/chunk-react-surface.mjs +4 -4
  47. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  48. package/dist/lib/chunk-submit-pull-request-approval.mjs.map +1 -1
  49. package/dist/lib/chunk-sync.mjs.map +1 -1
  50. package/dist/lib/index.mjs +2 -2
  51. package/dist/lib/meta.mjs.map +1 -1
  52. package/dist/lib/ns/Extensions.mjs +2 -16
  53. package/dist/lib/types.mjs +4 -4
  54. package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -1
  55. package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -1
  56. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  57. package/dist/types/src/cards/GitHubCard.d.ts.map +1 -1
  58. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts +1 -1
  59. package/dist/types/src/components/PullRequestOverview/CheckRunList.d.ts.map +1 -1
  60. package/dist/types/src/components/PullRequestOverview/PullRequestOverview.d.ts.map +1 -1
  61. package/dist/types/src/operations/pull-request.d.ts.map +1 -1
  62. package/dist/types/src/services/github-api.d.ts +1 -0
  63. package/dist/types/src/services/github-api.d.ts.map +1 -1
  64. package/dist/types/src/stories/PullRequestOverview.stories.d.ts +2 -0
  65. package/dist/types/src/stories/PullRequestOverview.stories.d.ts.map +1 -1
  66. package/dist/types/src/types/GitHubOperation.d.ts +3 -0
  67. package/dist/types/src/types/GitHubOperation.d.ts.map +1 -1
  68. package/dist/types/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +47 -47
  70. package/src/capabilities/gen/browser.ts +1 -3
  71. package/src/capabilities/gen/tauri.ts +1 -3
  72. package/src/capabilities/index.ts +1 -4
  73. package/src/cards/GitHubCard.tsx +7 -3
  74. package/src/components/PullRequestOverview/CheckRunList.tsx +34 -6
  75. package/src/components/PullRequestOverview/PullRequestOverview.tsx +5 -1
  76. package/src/containers/PullRequestsArticle/PullRequestsArticle.tsx +12 -10
  77. package/src/operations/pull-request.ts +1 -0
  78. package/src/services/github-api.ts +1 -0
  79. package/src/stories/PullRequestOverview.stories.tsx +20 -0
  80. package/src/types/GitHubOperation.ts +2 -0
  81. package/dist/lib/GitHubCapabilities.mjs.map +0 -1
  82. package/dist/lib/GitHubEvents.mjs.map +0 -1
  83. package/dist/lib/GitHubOperation.mjs.map +0 -1
  84. package/dist/lib/GitHubPlugin.mjs.map +0 -1
  85. package/dist/lib/Walkthrough.mjs.map +0 -1
  86. package/dist/lib/ns/Extensions.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-PullRequestsArticle.mjs","names":[],"sources":["../../src/hooks/usePullRequestChecks.ts","../../src/types/PullRequestsView.ts","../../src/containers/PullRequestsArticle/arrange.ts","../../src/containers/PullRequestsArticle/format.ts","../../src/containers/PullRequestsArticle/PullRequestsArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect, useState } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Ref } from '@dxos/echo';\nimport { type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { type PullRequestChecks } from '../containers/PullRequestsArticle/arrange.ts';\n\n/** How long a pull request's checks stand before they are read from GitHub again. */\nconst CHECKS_INTERVAL = 5 * 60_000;\n\n/** Status reads in flight at once: each costs three GitHub requests, and a list can hold hundreds. */\nconst CONCURRENCY = 4;\n\n// Keyed by object id and shared across mounts, so reopening the list within the interval costs nothing.\nconst cache = new Map<string, { at: number; checks: PullRequestChecks }>();\n\n/** Whether a pull request's checks still change; a merged or closed one's head is settled. */\nconst isLive = (pullRequest: PullRequest.PullRequest) => pullRequest.state === 'open' || pullRequest.state === 'draft';\n\n/**\n * The CI and review standing of every live pull request in `pullRequests`, keyed by object id and\n * filled in as each read lands. Finished pull requests are not read: their checks no longer ask\n * anything of the reader.\n */\nexport const usePullRequestChecks = (\n pullRequests: readonly PullRequest.PullRequest[],\n spaceId: SpaceId | undefined,\n): ReadonlyMap<string, PullRequestChecks> => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const [checks, setChecks] = useState<ReadonlyMap<string, PullRequestChecks>>(\n () => new Map([...cache].map(([id, { checks }]) => [id, checks])),\n );\n\n useEffect(() => {\n if (!spaceId) {\n return;\n }\n\n let cancelled = false;\n const now = Date.now();\n const queue = pullRequests.filter(\n (pullRequest) => isLive(pullRequest) && now - (cache.get(pullRequest.id)?.at ?? 0) >= CHECKS_INTERVAL,\n );\n\n const worker = async () => {\n for (let pullRequest = queue.shift(); pullRequest && !cancelled; pullRequest = queue.shift()) {\n const { data, error } = await invokePromise(\n GitHubOperation.GetPullRequestStatus,\n { pullRequest: Ref.make(pullRequest) },\n { spaceId },\n );\n if (error || !data) {\n log.warn('pull request checks failed', { pullRequest: pullRequest.id, error });\n continue;\n }\n const next = { ci: data.ci, checks: data.checks, review: data.review, approvals: data.approvals };\n cache.set(pullRequest.id, { at: Date.now(), checks: next });\n // Set even once cancelled: the next run skips this pull request as freshly cached, so a read\n // that lands across a re-run would otherwise never reach the list.\n const id = pullRequest.id;\n setChecks((previous) => new Map(previous).set(id, next));\n }\n };\n\n void Promise.all(Array.from({ length: Math.min(CONCURRENCY, queue.length) }, worker));\n return () => {\n cancelled = true;\n };\n }, [invokePromise, pullRequests, spaceId]);\n\n return checks;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { ViewState } from '@dxos/react-ui-attention/types';\n\n/**\n * The fields the pull request list can be ordered by. `relevance` ranks what needs the reader first\n * (see `relevance`); `updated` and `created` are GitHub's times.\n */\nexport const SortField = Schema.Literals(['relevance', 'updated', 'created', 'number', 'title']);\nexport type SortField = Schema.Schema.Type<typeof SortField>;\n\nexport const SortDirection = Schema.Literals(['asc', 'desc']);\nexport type SortDirection = Schema.Schema.Type<typeof SortDirection>;\n\nexport const Sort = Schema.Struct({ field: SortField, direction: SortDirection });\nexport type Sort = Schema.Schema.Type<typeof Sort>;\n\n/** The fields the list can be grouped by; `none` is one ungrouped list. */\nexport const GroupField = Schema.Literals(['none', 'repo', 'state', 'checks', 'author']);\nexport type GroupField = Schema.Schema.Type<typeof GroupField>;\n\nexport const DEFAULT_SORT: Sort = { field: 'relevance', direction: 'desc' };\n\nexport const View = Schema.Struct({\n query: Schema.String,\n sort: Schema.optional(Sort),\n group: Schema.optional(GroupField),\n});\nexport type View = Schema.Schema.Type<typeof View>;\n\n/**\n * How a reader has the space's pull requests arranged, keyed by the space and held per device\n * (`local`), as a task set's list is: the filter, order and grouping are how this reader looks at the\n * list here, not a property of the space every member would see.\n */\nexport const aspect: ViewState.Aspect<View> = ViewState.define<View>({\n key: 'github-pull-requests-view',\n backend: 'local',\n schema: View,\n defaultValue: (): View => ({ query: '' }),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Filter } from '@dxos/echo';\nimport { matchesFilter } from '@dxos/echo-query';\nimport { PullRequest, type Task } from '@dxos/types';\n\nimport { type GitHubOperation } from '#types';\n\nimport type * as PullRequestsView from '../../types/PullRequestsView.ts';\n\n/** The live part of a pull request's standing, read from GitHub rather than stored. */\nexport type PullRequestChecks = {\n ci: GitHubOperation.CiState;\n checks: GitHubOperation.CheckCounts;\n review: GitHubOperation.ReviewState;\n approvals: number;\n};\n\n/** One row of the list: the stored pull request, its live checks once they arrive, and the tasks that list it. */\nexport type PullRequestRow = {\n pullRequest: PullRequest.PullRequest;\n checks?: PullRequestChecks;\n tasks: readonly Task.Task[];\n};\n\nexport type PullRequestRowGroup = {\n id: string;\n /** A literal (a repository, an author) or a translation key in the plugin's namespace. */\n label: string;\n translate?: boolean;\n icon: string;\n hue?: string;\n rows: readonly PullRequestRow[];\n};\n\n/** What a free-text term searches: what a reader sees in the row. */\nconst rowText = (pullRequest: PullRequest.PullRequest) => [\n pullRequest.title,\n PullRequest.reference(pullRequest),\n pullRequest.author,\n pullRequest.headBranch,\n];\n\n/** The rows the toolbar's query keeps, in input order; an absent filter keeps every row. */\nexport const filterRows = (rows: readonly PullRequestRow[], filter?: Filter.Any): readonly PullRequestRow[] =>\n filter ? rows.filter(({ pullRequest }) => matchesFilter(filter, pullRequest, { text: rowText })) : rows;\n\nconst STATE_WEIGHT: Record<PullRequest.State, number> = { open: 1_000, draft: 600, merged: 100, closed: 0 };\n\n/**\n * How much a row asks of the reader now: an open pull request outranks a draft, which outranks a\n * finished one; within those, red CI or requested changes (something to fix) outrank one ready to\n * merge, which outranks one still waiting; and a pull request some task tracks is nudged up.\n */\nexport const relevance = ({ pullRequest, checks, tasks }: PullRequestRow): number => {\n let score = STATE_WEIGHT[pullRequest.state];\n if (pullRequest.state === 'open' || pullRequest.state === 'draft') {\n if (checks?.ci === 'failure') {\n score += 300;\n }\n if (checks?.review === 'changes_requested') {\n score += 250;\n }\n if (checks?.review === 'approved' && checks.ci !== 'failure' && checks.ci !== 'pending') {\n score += 200;\n }\n if (checks?.ci === 'pending') {\n score += 50;\n }\n }\n if (tasks.length > 0) {\n score += 25;\n }\n return score;\n};\n\nconst time = (value: string | undefined): number => {\n const parsed = value ? Date.parse(value) : Number.NaN;\n return Number.isNaN(parsed) ? 0 : parsed;\n};\n\n/** Newest activity GitHub reported, falling back to when it was opened. */\nconst activity = (pullRequest: PullRequest.PullRequest): number =>\n time(pullRequest.updatedAt) || time(pullRequest.createdAt);\n\nconst byRecency = (left: PullRequestRow, right: PullRequestRow): number =>\n activity(left.pullRequest) - activity(right.pullRequest) || left.pullRequest.number - right.pullRequest.number;\n\nconst compareBy: Record<PullRequestsView.SortField, (left: PullRequestRow, right: PullRequestRow) => number> = {\n // Ties broken by recency, so equally urgent rows read newest first under the default (descending) order.\n relevance: (left, right) => relevance(left) - relevance(right) || byRecency(left, right),\n updated: byRecency,\n created: (left, right) =>\n time(left.pullRequest.createdAt) - time(right.pullRequest.createdAt) ||\n left.pullRequest.number - right.pullRequest.number,\n number: (left, right) => left.pullRequest.number - right.pullRequest.number,\n title: (left, right) =>\n (left.pullRequest.title ?? '').localeCompare(right.pullRequest.title ?? '', undefined, { sensitivity: 'base' }),\n};\n\n/** The rows reordered by `sort`, ties kept in input order. */\nexport const sortRows = (rows: readonly PullRequestRow[], sort: PullRequestsView.Sort): readonly PullRequestRow[] => {\n const compare = compareBy[sort.field];\n const sign = sort.direction === 'desc' ? -1 : 1;\n const index = new Map(rows.map((row, position) => [row.pullRequest.id, position]));\n return [...rows].sort(\n (left, right) =>\n sign * compare(left, right) || (index.get(left.pullRequest.id) ?? 0) - (index.get(right.pullRequest.id) ?? 0),\n );\n};\n\nconst STATE_ORDER: readonly PullRequest.State[] = ['open', 'draft', 'merged', 'closed'];\nconst STATE_ICON: Record<PullRequest.State, string> = {\n open: 'ph--git-pull-request--regular',\n draft: 'ph--git-pull-request--regular',\n merged: 'ph--git-merge--regular',\n closed: 'ph--x-circle--regular',\n};\nexport const STATE_HUE: Record<PullRequest.State, string> = {\n open: 'green',\n closed: 'red',\n merged: 'purple',\n draft: 'neutral',\n};\n\nconst CI_ORDER: readonly GitHubOperation.CiState[] = ['failure', 'pending', 'success', 'none'];\nconst CI_ICON: Record<GitHubOperation.CiState, string> = {\n failure: 'ph--x-circle--regular',\n pending: 'ph--circle-notch--regular',\n success: 'ph--check-circle--regular',\n none: 'ph--minus-circle--regular',\n};\nexport const CI_HUE: Record<GitHubOperation.CiState, string> = {\n success: 'green',\n failure: 'red',\n pending: 'amber',\n none: 'neutral',\n};\n\n/** Rows partitioned by a string key, groups in first-seen order unless `order` ranks them; empty groups dropped. */\nconst partition = <K extends string>(\n rows: readonly PullRequestRow[],\n key: (row: PullRequestRow) => K,\n make: (key: K, rows: readonly PullRequestRow[]) => PullRequestRowGroup,\n order?: (left: K, right: K) => number,\n): PullRequestRowGroup[] => {\n const byKey = new Map<K, PullRequestRow[]>();\n for (const row of rows) {\n const value = key(row);\n byKey.set(value, [...(byKey.get(value) ?? []), row]);\n }\n const keys = [...byKey.keys()];\n if (order) {\n keys.sort(order);\n }\n return keys.map((value) => make(value, byKey.get(value) ?? []));\n};\n\nconst rankOf =\n <T extends string>(values: readonly T[]) =>\n (left: T, right: T) =>\n values.indexOf(left) - values.indexOf(right);\n\n/**\n * The rows partitioned by `field`, each group's rows in input order (so a sort applies within every\n * group). Absent for `none`: an ungrouped list has no headers.\n */\nexport const groupRows = (\n rows: readonly PullRequestRow[],\n field: PullRequestsView.GroupField,\n): PullRequestRowGroup[] | undefined => {\n switch (field) {\n case 'none':\n return undefined;\n\n case 'repo':\n return partition(\n rows,\n ({ pullRequest }) => `${pullRequest.owner}/${pullRequest.repo}`,\n (repo, rows) => ({ id: `repo-${repo}`, label: repo, icon: 'ph--git-branch--regular', rows }),\n (left, right) => left.localeCompare(right),\n );\n\n case 'state':\n return partition(\n rows,\n ({ pullRequest }) => pullRequest.state,\n (state, rows) => ({\n id: `state-${state}`,\n label: `pull-request-state.${state}.label`,\n translate: true,\n icon: STATE_ICON[state],\n hue: STATE_HUE[state],\n rows,\n }),\n rankOf(STATE_ORDER),\n );\n\n case 'checks':\n return [\n ...partition(\n rows.filter((row) => row.checks),\n ({ checks }): GitHubOperation.CiState => checks?.ci ?? 'none',\n (ci, rows) => ({\n id: `checks-${ci}`,\n label: `ci-status.${ci}.label`,\n translate: true,\n icon: CI_ICON[ci],\n hue: CI_HUE[ci],\n rows,\n }),\n rankOf(CI_ORDER),\n ),\n // Rows whose checks have not arrived (or are not fetched, e.g. a merged pull request) last.\n ...partition(\n rows.filter((row) => !row.checks),\n () => 'unknown' as const,\n (_, rows) => ({\n id: 'checks-unknown',\n label: 'ci-status.unknown.label',\n translate: true,\n icon: 'ph--question--regular',\n rows,\n }),\n ),\n ];\n\n case 'author':\n return partition(\n rows,\n ({ pullRequest }) => pullRequest.author ?? '',\n (author, rows) => ({\n id: `author-${author}`,\n label: author || 'group-no-author.label',\n translate: !author,\n icon: author ? 'ph--user--regular' : 'ph--user-circle-dashed--regular',\n rows,\n }),\n // Unknown authors last; the rest by name.\n (left, right) => (left === '' ? 1 : right === '' ? -1 : left.localeCompare(right)),\n );\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nconst UNITS: readonly [Intl.RelativeTimeFormatUnit, number][] = [\n ['year', 365 * 24 * 60 * 60_000],\n ['month', 30 * 24 * 60 * 60_000],\n ['week', 7 * 24 * 60 * 60_000],\n ['day', 24 * 60 * 60_000],\n ['hour', 60 * 60_000],\n ['minute', 60_000],\n];\n\n// Built once: constructing an `Intl` formatter resolves the locale each time, and every row formats.\nlet formatter: Intl.RelativeTimeFormat | undefined;\n\n/** `5 minutes ago`, `yesterday`, `3 weeks ago` — in the largest unit that fits; empty for an invalid date. */\nexport const formatRelative = (value: string, now = Date.now()): string => {\n const date = Date.parse(value);\n if (Number.isNaN(date)) {\n return '';\n }\n formatter ??= new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });\n const elapsed = date - now;\n for (const [unit, size] of UNITS) {\n if (Math.abs(elapsed) >= size) {\n return formatter.format(Math.round(elapsed / size), unit);\n }\n }\n return formatter.format(0, 'minute');\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { useCallback, useMemo, useRef } from 'react';\n\nimport { type Database, Filter, Obj, Tag, Type } from '@dxos/echo';\nimport { QueryBuilder } from '@dxos/echo-query';\nimport { useQuery } from '@dxos/echo-react';\nimport { useAttention, useViewState, useViewStateActions } from '@dxos/react-ui-attention';\nimport { type EditorController } from '@dxos/react-ui-editor';\nimport { Listbox } from '@dxos/react-ui-list';\nimport { GroupMenu, SortMenu } from '@dxos/react-ui-menu';\nimport { QueryEditor, usePersistentQuery } from '@dxos/react-ui-query';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Status from '@dxos/react-ui/Status';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport { PullRequest, Task } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport { useOpenObject, usePullRequestChecks } from '../../hooks/index.ts';\nimport * as PullRequestsView from '../../types/PullRequestsView.ts';\nimport {\n CI_HUE,\n type PullRequestChecks,\n type PullRequestRow,\n type PullRequestRowGroup,\n STATE_HUE,\n filterRows,\n groupRows,\n sortRows,\n} from './arrange.ts';\nimport { formatRelative } from './format.ts';\n\nconst PULL_REQUEST_TYPENAME = Type.getTypename(PullRequest.PullRequest);\n\nconst SORT_ICONS: Record<PullRequestsView.SortField, string> = {\n relevance: 'ph--lightning--regular',\n updated: 'ph--clock-clockwise--regular',\n created: 'ph--calendar-plus--regular',\n number: 'ph--hash--regular',\n title: 'ph--text-aa--regular',\n};\n\nconst GROUP_ICONS: Record<PullRequestsView.GroupField, string> = {\n none: 'ph--list--regular',\n repo: 'ph--git-branch--regular',\n state: 'ph--git-pull-request--regular',\n checks: 'ph--check-circle--regular',\n author: 'ph--user--regular',\n};\n\nexport type PullRequestsArticleProps = {\n role?: string;\n attendableId: string;\n /** The space's database; absent when the type node carries no space, which renders nothing. */\n db?: Database.Database;\n};\n\n/**\n * Every pull request in a space as one list a reader triages from: repository, title, CI checks,\n * the tasks that track it and its state, ordered by relevance (what needs the reader first) or time.\n * The filter, order and grouping persist per device and per space, through the same view-state\n * aspect, query editor and sort/group menus a task set's list uses.\n */\nexport const PullRequestsArticle = ({ db, ...props }: PullRequestsArticleProps) =>\n db ? <PullRequestList db={db} {...props} /> : null;\n\nPullRequestsArticle.displayName = 'PullRequestsArticle';\n\nconst PullRequestList = ({ role, attendableId, db }: PullRequestsArticleProps & { db: Database.Database }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const { hasAttention } = useAttention(attendableId);\n const editorRef = useRef<EditorController>(null);\n const contextId = db.spaceId;\n\n const [query, setQuery] = usePersistentQuery(PullRequestsView.aspect, contextId, editorRef);\n const { sort = PullRequestsView.DEFAULT_SORT, group = 'none' } = useViewState(PullRequestsView.aspect, contextId);\n const { update } = useViewStateActions(PullRequestsView.aspect, contextId);\n const handleSortChange = useCallback(\n (sort: PullRequestsView.Sort) => update((view) => ({ ...view, sort })),\n [update],\n );\n const handleGroupChange = useCallback(\n (group: PullRequestsView.GroupField) => update((view) => ({ ...view, group })),\n [update],\n );\n const handleClear = useCallback(() => setQuery(''), [setQuery]);\n\n const tags = useTagMap(db);\n // A query that does not parse matches nothing rather than everything.\n const filter = useMemo(() => {\n const text = query.trim();\n return text.length === 0 ? undefined : (new QueryBuilder(tags).build(text).filter ?? Filter.nothing());\n }, [query, tags]);\n\n const pullRequests = useQuery(db, Filter.type(PullRequest.PullRequest));\n const tasks = useQuery(db, Filter.type(Task.Task));\n const checks = usePullRequestChecks(pullRequests, db.spaceId);\n const { rows, groups } = useArrangedRows(pullRequests, tasks, checks, { filter, sort, group });\n // In display order, so keyboard order follows the groups the reader sees.\n const options = useMemo(\n () =>\n (groups ? groups.flatMap((group) => group.rows) : rows).map(({ pullRequest }) => ({\n value: pullRequest.id,\n label: pullRequest.title,\n })),\n [groups, rows],\n );\n\n const sortFields = useMemo(\n () =>\n PullRequestsView.SortField.literals.map((id) => ({\n id,\n label: t(`pull-requests-sort-${id}.label`),\n icon: SORT_ICONS[id],\n })),\n [t],\n );\n const directionLabels = useMemo(\n () => ({ asc: t('pull-requests-sort-asc.label'), desc: t('pull-requests-sort-desc.label') }),\n [t],\n );\n const groupFields = useMemo(\n () =>\n PullRequestsView.GroupField.literals.map((id) => ({\n id,\n label: t(`pull-requests-group-${id}.label`),\n icon: GROUP_ICONS[id],\n })),\n [t],\n );\n\n const openObject = useOpenObject();\n\n return (\n <Panel.Root role={role} data-testid='pull-requests'>\n <Panel.Header>\n <Toolbar.Root inactive={!hasAttention}>\n <QueryEditor\n classNames='grow min-w-0 ps-1'\n db={db}\n tags={tags}\n value={query}\n onChange={setQuery}\n ref={editorRef}\n />\n <SortMenu\n fields={sortFields}\n value={sort}\n onChange={handleSortChange}\n label={t('pull-requests-sort.label')}\n directionLabels={directionLabels}\n testId='pull-requests.sort'\n />\n <GroupMenu\n fields={groupFields}\n value={group}\n onChange={handleGroupChange}\n label={t('pull-requests-group.label')}\n none='none'\n testId='pull-requests.group'\n />\n <Button.Root\n icon='ph--x--regular'\n iconOnly\n disabled={query.trim().length === 0}\n label={t('pull-requests-filter-clear.label')}\n data-testid='pull-requests.filter.clear'\n onClick={handleClear}\n />\n </Toolbar.Root>\n </Panel.Header>\n <Panel.Body>\n {rows.length === 0 ? (\n <Status.Empty classNames='dx-expand'>\n {t(pullRequests.length === 0 ? 'pull-requests-empty.message' : 'pull-requests-no-match.message')}\n </Status.Empty>\n ) : (\n <Listbox.Root items={options}>\n <Listbox.Content\n classNames='dx-expand'\n aria-label={t('typename.label_other', { ns: PULL_REQUEST_TYPENAME })}\n >\n {groups\n ? groups\n .filter((group) => group.rows.length > 0)\n .map((group) => <GroupSection key={group.id} group={group} onOpen={openObject} />)\n : rows.map((row) => <PullRequestListRow key={row.pullRequest.id} row={row} onOpen={openObject} />)}\n </Listbox.Content>\n </Listbox.Root>\n )}\n </Panel.Body>\n </Panel.Root>\n );\n};\n\ntype OpenHandler = (object: Obj.Any) => Promise<void>;\n\nconst GroupSection = ({ group, onOpen }: { group: PullRequestRowGroup; onOpen: OpenHandler }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n return (\n <Listbox.ItemGroup>\n <Listbox.ItemGroupLabel>\n <Layout.Flex align='center' gap='sm'>\n <Icon.Icon icon={group.icon} classNames='dx-text' data-hue={group.hue} />\n <span className='truncate'>{group.translate ? t(group.label) : group.label}</span>\n <span className='text-description'>{group.rows.length}</span>\n </Layout.Flex>\n </Listbox.ItemGroupLabel>\n {group.rows.map((row) => (\n <PullRequestListRow key={row.pullRequest.id} row={row} onOpen={onOpen} />\n ))}\n </Listbox.ItemGroup>\n );\n};\n\n/** One pull request: its repository and number, title, author and time, then checks, tasks and state. */\nconst PullRequestListRow = ({\n row: { pullRequest, checks, tasks },\n onOpen,\n}: {\n row: PullRequestRow;\n onOpen: OpenHandler;\n}) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const time = pullRequest.updatedAt ?? pullRequest.createdAt;\n return (\n <Listbox.Item\n id={pullRequest.id}\n classNames='cursor-pointer py-2'\n data-testid='pull-requests.row'\n onClick={() => void onOpen(pullRequest)}\n >\n <Layout.Flex column gap='xs' grow>\n <Layout.Flex align='center' gap='sm' classNames='min-w-0'>\n <span className='dx-tag dx-tag-inline shrink-0' data-hue='neutral'>\n {PullRequest.reference(pullRequest)}\n </span>\n <span className='truncate grow'>{pullRequest.title}</span>\n <ChecksTag pullRequest={pullRequest} checks={checks} />\n <span\n className='dx-tag dx-tag-inline shrink-0'\n data-hue={STATE_HUE[pullRequest.state]}\n data-testid='pull-requests.row.state'\n >\n {t(`pull-request-state.${pullRequest.state}.label`)}\n </span>\n </Layout.Flex>\n <Layout.Flex align='center' gap='sm' classNames='min-w-0 text-xs text-description'>\n {pullRequest.author && <span className='shrink-0'>{pullRequest.author}</span>}\n {time && (\n <time className='shrink-0' dateTime={time} title={new Date(time).toLocaleString()}>\n {formatRelative(time)}\n </time>\n )}\n {tasks.length > 0 && (\n <Layout.Flex align='center' gap='xs' classNames='min-w-0' data-testid='pull-requests.row.tasks'>\n <Icon.Icon icon='ph--check-square-offset--regular' size='xs' classNames='shrink-0' />\n <span className='truncate'>{tasks.map((task) => task.title || t('untitled-task.label')).join(', ')}</span>\n </Layout.Flex>\n )}\n </Layout.Flex>\n </Layout.Flex>\n </Listbox.Item>\n );\n};\n\nconst ChecksTag = ({ pullRequest, checks }: { pullRequest: PullRequest.PullRequest; checks?: PullRequestChecks }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n // A finished pull request's checks are not read (see `usePullRequestChecks`), so it shows none.\n if (!checks) {\n return pullRequest.state === 'open' || pullRequest.state === 'draft' ? (\n <span className='dx-tag dx-tag-inline' data-hue='neutral' data-testid='pull-requests.row.checks'>\n {t('ci-status.unknown.label')}\n </span>\n ) : null;\n }\n\n return (\n <>\n {checks.review !== 'none' && (\n <span\n className='dx-tag dx-tag-inline'\n data-hue={checks.review === 'approved' ? 'green' : 'red'}\n data-testid='pull-requests.row.review'\n >\n {t(`review-status.${checks.review}.label`, { count: checks.approvals })}\n </span>\n )}\n <span className='dx-tag dx-tag-inline' data-hue={CI_HUE[checks.ci]} data-testid='pull-requests.row.checks'>\n {t(`ci-status.${checks.ci}.label`)}\n {checks.checks.total > 0 && ` ${checks.checks.passed}/${checks.checks.total}`}\n </span>\n </>\n );\n};\n\ntype ArrangeOptions = {\n filter: Filter.Any | undefined;\n sort: PullRequestsView.Sort;\n group: PullRequestsView.GroupField;\n};\n\n/**\n * The rows the toolbar keeps, in the order it asks for, partitioned into its groups. Read through\n * atoms so a re-sync (a new state, a new title) or a task gaining the pull request as an artifact\n * re-arranges the list without the queries re-emitting.\n */\nconst useArrangedRows = (\n pullRequests: readonly PullRequest.PullRequest[],\n tasks: readonly Task.Task[],\n checks: ReadonlyMap<string, PullRequestChecks>,\n { filter, sort, group }: ArrangeOptions,\n): { rows: readonly PullRequestRow[]; groups?: PullRequestRowGroup[] } => {\n const atom = useMemo(\n () =>\n Atom.make((get) => {\n pullRequests.forEach((pullRequest) => get(Obj.atom(pullRequest)));\n const tasksByPullRequest = new Map<string, Task.Task[]>();\n for (const task of tasks) {\n for (const ref of get(Obj.atomProperty(task, 'artifacts')) ?? []) {\n const id = Task.refEntityId(ref);\n if (id) {\n tasksByPullRequest.set(id, [...(tasksByPullRequest.get(id) ?? []), task]);\n }\n }\n }\n const all = pullRequests.map((pullRequest) => ({\n pullRequest,\n checks: checks.get(pullRequest.id),\n tasks: tasksByPullRequest.get(pullRequest.id) ?? [],\n }));\n const rows = sortRows(filterRows(all, filter), sort);\n return { rows, groups: groupRows(rows, group) };\n }),\n [pullRequests, tasks, checks, filter, sort, group],\n );\n\n return useAtomValue(atom);\n};\n\n/** Tag registry keyed by the `Tag` object's uri — the id space `#tag` terms and `meta.tags` share. */\nconst useTagMap = (db: Database.Database): Tag.Map => {\n const tags = useQuery(db, Filter.type(Tag.Tag));\n return useMemo(\n () =>\n tags.reduce<Tag.Map>((acc, tag) => {\n acc[Obj.getURI(tag).toString()] = tag;\n return acc;\n }, {}),\n [tags],\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"chunk-PullRequestsArticle.mjs","names":["PullRequestsView.aspect","PullRequestsView.DEFAULT_SORT","_Fragment"],"sources":["../../src/hooks/usePullRequestChecks.ts","../../src/types/PullRequestsView.ts","../../src/containers/PullRequestsArticle/arrange.ts","../../src/containers/PullRequestsArticle/format.ts","../../src/containers/PullRequestsArticle/PullRequestsArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect, useState } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Ref } from '@dxos/echo';\nimport { type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { type PullRequestChecks } from '../containers/PullRequestsArticle/arrange.ts';\n\n/** How long a pull request's checks stand before they are read from GitHub again. */\nconst CHECKS_INTERVAL = 5 * 60_000;\n\n/** Status reads in flight at once: each costs three GitHub requests, and a list can hold hundreds. */\nconst CONCURRENCY = 4;\n\n// Keyed by object id and shared across mounts, so reopening the list within the interval costs nothing.\nconst cache = new Map<string, { at: number; checks: PullRequestChecks }>();\n\n/** Whether a pull request's checks still change; a merged or closed one's head is settled. */\nconst isLive = (pullRequest: PullRequest.PullRequest) => pullRequest.state === 'open' || pullRequest.state === 'draft';\n\n/**\n * The CI and review standing of every live pull request in `pullRequests`, keyed by object id and\n * filled in as each read lands. Finished pull requests are not read: their checks no longer ask\n * anything of the reader.\n */\nexport const usePullRequestChecks = (\n pullRequests: readonly PullRequest.PullRequest[],\n spaceId: SpaceId | undefined,\n): ReadonlyMap<string, PullRequestChecks> => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const [checks, setChecks] = useState<ReadonlyMap<string, PullRequestChecks>>(\n () => new Map([...cache].map(([id, { checks }]) => [id, checks])),\n );\n\n useEffect(() => {\n if (!spaceId) {\n return;\n }\n\n let cancelled = false;\n const now = Date.now();\n const queue = pullRequests.filter(\n (pullRequest) => isLive(pullRequest) && now - (cache.get(pullRequest.id)?.at ?? 0) >= CHECKS_INTERVAL,\n );\n\n const worker = async () => {\n for (let pullRequest = queue.shift(); pullRequest && !cancelled; pullRequest = queue.shift()) {\n const { data, error } = await invokePromise(\n GitHubOperation.GetPullRequestStatus,\n { pullRequest: Ref.make(pullRequest) },\n { spaceId },\n );\n if (error || !data) {\n log.warn('pull request checks failed', { pullRequest: pullRequest.id, error });\n continue;\n }\n const next = { ci: data.ci, checks: data.checks, review: data.review, approvals: data.approvals };\n cache.set(pullRequest.id, { at: Date.now(), checks: next });\n // Set even once cancelled: the next run skips this pull request as freshly cached, so a read\n // that lands across a re-run would otherwise never reach the list.\n const id = pullRequest.id;\n setChecks((previous) => new Map(previous).set(id, next));\n }\n };\n\n void Promise.all(Array.from({ length: Math.min(CONCURRENCY, queue.length) }, worker));\n return () => {\n cancelled = true;\n };\n }, [invokePromise, pullRequests, spaceId]);\n\n return checks;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { ViewState } from '@dxos/react-ui-attention/types';\n\n/**\n * The fields the pull request list can be ordered by. `relevance` ranks what needs the reader first\n * (see `relevance`); `updated` and `created` are GitHub's times.\n */\nexport const SortField = Schema.Literals(['relevance', 'updated', 'created', 'number', 'title']);\nexport type SortField = Schema.Schema.Type<typeof SortField>;\n\nexport const SortDirection = Schema.Literals(['asc', 'desc']);\nexport type SortDirection = Schema.Schema.Type<typeof SortDirection>;\n\nexport const Sort = Schema.Struct({ field: SortField, direction: SortDirection });\nexport type Sort = Schema.Schema.Type<typeof Sort>;\n\n/** The fields the list can be grouped by; `none` is one ungrouped list. */\nexport const GroupField = Schema.Literals(['none', 'repo', 'state', 'checks', 'author']);\nexport type GroupField = Schema.Schema.Type<typeof GroupField>;\n\nexport const DEFAULT_SORT: Sort = { field: 'relevance', direction: 'desc' };\n\nexport const View = Schema.Struct({\n query: Schema.String,\n sort: Schema.optional(Sort),\n group: Schema.optional(GroupField),\n});\nexport type View = Schema.Schema.Type<typeof View>;\n\n/**\n * How a reader has the space's pull requests arranged, keyed by the space and held per device\n * (`local`), as a task set's list is: the filter, order and grouping are how this reader looks at the\n * list here, not a property of the space every member would see.\n */\nexport const aspect: ViewState.Aspect<View> = ViewState.define<View>({\n key: 'github-pull-requests-view',\n backend: 'local',\n schema: View,\n defaultValue: (): View => ({ query: '' }),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Filter } from '@dxos/echo';\nimport { matchesFilter } from '@dxos/echo-query';\nimport { PullRequest, type Task } from '@dxos/types';\n\nimport { type GitHubOperation } from '#types';\n\nimport type * as PullRequestsView from '../../types/PullRequestsView.ts';\n\n/** The live part of a pull request's standing, read from GitHub rather than stored. */\nexport type PullRequestChecks = {\n ci: GitHubOperation.CiState;\n checks: GitHubOperation.CheckCounts;\n review: GitHubOperation.ReviewState;\n approvals: number;\n};\n\n/** One row of the list: the stored pull request, its live checks once they arrive, and the tasks that list it. */\nexport type PullRequestRow = {\n pullRequest: PullRequest.PullRequest;\n checks?: PullRequestChecks;\n tasks: readonly Task.Task[];\n};\n\nexport type PullRequestRowGroup = {\n id: string;\n /** A literal (a repository, an author) or a translation key in the plugin's namespace. */\n label: string;\n translate?: boolean;\n icon: string;\n hue?: string;\n rows: readonly PullRequestRow[];\n};\n\n/** What a free-text term searches: what a reader sees in the row. */\nconst rowText = (pullRequest: PullRequest.PullRequest) => [\n pullRequest.title,\n PullRequest.reference(pullRequest),\n pullRequest.author,\n pullRequest.headBranch,\n];\n\n/** The rows the toolbar's query keeps, in input order; an absent filter keeps every row. */\nexport const filterRows = (rows: readonly PullRequestRow[], filter?: Filter.Any): readonly PullRequestRow[] =>\n filter ? rows.filter(({ pullRequest }) => matchesFilter(filter, pullRequest, { text: rowText })) : rows;\n\nconst STATE_WEIGHT: Record<PullRequest.State, number> = { open: 1_000, draft: 600, merged: 100, closed: 0 };\n\n/**\n * How much a row asks of the reader now: an open pull request outranks a draft, which outranks a\n * finished one; within those, red CI or requested changes (something to fix) outrank one ready to\n * merge, which outranks one still waiting; and a pull request some task tracks is nudged up.\n */\nexport const relevance = ({ pullRequest, checks, tasks }: PullRequestRow): number => {\n let score = STATE_WEIGHT[pullRequest.state];\n if (pullRequest.state === 'open' || pullRequest.state === 'draft') {\n if (checks?.ci === 'failure') {\n score += 300;\n }\n if (checks?.review === 'changes_requested') {\n score += 250;\n }\n if (checks?.review === 'approved' && checks.ci !== 'failure' && checks.ci !== 'pending') {\n score += 200;\n }\n if (checks?.ci === 'pending') {\n score += 50;\n }\n }\n if (tasks.length > 0) {\n score += 25;\n }\n return score;\n};\n\nconst time = (value: string | undefined): number => {\n const parsed = value ? Date.parse(value) : Number.NaN;\n return Number.isNaN(parsed) ? 0 : parsed;\n};\n\n/** Newest activity GitHub reported, falling back to when it was opened. */\nconst activity = (pullRequest: PullRequest.PullRequest): number =>\n time(pullRequest.updatedAt) || time(pullRequest.createdAt);\n\nconst byRecency = (left: PullRequestRow, right: PullRequestRow): number =>\n activity(left.pullRequest) - activity(right.pullRequest) || left.pullRequest.number - right.pullRequest.number;\n\nconst compareBy: Record<PullRequestsView.SortField, (left: PullRequestRow, right: PullRequestRow) => number> = {\n // Ties broken by recency, so equally urgent rows read newest first under the default (descending) order.\n relevance: (left, right) => relevance(left) - relevance(right) || byRecency(left, right),\n updated: byRecency,\n created: (left, right) =>\n time(left.pullRequest.createdAt) - time(right.pullRequest.createdAt) ||\n left.pullRequest.number - right.pullRequest.number,\n number: (left, right) => left.pullRequest.number - right.pullRequest.number,\n title: (left, right) =>\n (left.pullRequest.title ?? '').localeCompare(right.pullRequest.title ?? '', undefined, { sensitivity: 'base' }),\n};\n\n/** The rows reordered by `sort`, ties kept in input order. */\nexport const sortRows = (rows: readonly PullRequestRow[], sort: PullRequestsView.Sort): readonly PullRequestRow[] => {\n const compare = compareBy[sort.field];\n const sign = sort.direction === 'desc' ? -1 : 1;\n const index = new Map(rows.map((row, position) => [row.pullRequest.id, position]));\n return [...rows].sort(\n (left, right) =>\n sign * compare(left, right) || (index.get(left.pullRequest.id) ?? 0) - (index.get(right.pullRequest.id) ?? 0),\n );\n};\n\nconst STATE_ORDER: readonly PullRequest.State[] = ['open', 'draft', 'merged', 'closed'];\nconst STATE_ICON: Record<PullRequest.State, string> = {\n open: 'ph--git-pull-request--regular',\n draft: 'ph--git-pull-request--regular',\n merged: 'ph--git-merge--regular',\n closed: 'ph--x-circle--regular',\n};\nexport const STATE_HUE: Record<PullRequest.State, string> = {\n open: 'green',\n closed: 'red',\n merged: 'purple',\n draft: 'neutral',\n};\n\nconst CI_ORDER: readonly GitHubOperation.CiState[] = ['failure', 'pending', 'success', 'none'];\nconst CI_ICON: Record<GitHubOperation.CiState, string> = {\n failure: 'ph--x-circle--regular',\n pending: 'ph--circle-notch--regular',\n success: 'ph--check-circle--regular',\n none: 'ph--minus-circle--regular',\n};\nexport const CI_HUE: Record<GitHubOperation.CiState, string> = {\n success: 'green',\n failure: 'red',\n pending: 'amber',\n none: 'neutral',\n};\n\n/** Rows partitioned by a string key, groups in first-seen order unless `order` ranks them; empty groups dropped. */\nconst partition = <K extends string>(\n rows: readonly PullRequestRow[],\n key: (row: PullRequestRow) => K,\n make: (key: K, rows: readonly PullRequestRow[]) => PullRequestRowGroup,\n order?: (left: K, right: K) => number,\n): PullRequestRowGroup[] => {\n const byKey = new Map<K, PullRequestRow[]>();\n for (const row of rows) {\n const value = key(row);\n byKey.set(value, [...(byKey.get(value) ?? []), row]);\n }\n const keys = [...byKey.keys()];\n if (order) {\n keys.sort(order);\n }\n return keys.map((value) => make(value, byKey.get(value) ?? []));\n};\n\nconst rankOf =\n <T extends string>(values: readonly T[]) =>\n (left: T, right: T) =>\n values.indexOf(left) - values.indexOf(right);\n\n/**\n * The rows partitioned by `field`, each group's rows in input order (so a sort applies within every\n * group). Absent for `none`: an ungrouped list has no headers.\n */\nexport const groupRows = (\n rows: readonly PullRequestRow[],\n field: PullRequestsView.GroupField,\n): PullRequestRowGroup[] | undefined => {\n switch (field) {\n case 'none':\n return undefined;\n\n case 'repo':\n return partition(\n rows,\n ({ pullRequest }) => `${pullRequest.owner}/${pullRequest.repo}`,\n (repo, rows) => ({ id: `repo-${repo}`, label: repo, icon: 'ph--git-branch--regular', rows }),\n (left, right) => left.localeCompare(right),\n );\n\n case 'state':\n return partition(\n rows,\n ({ pullRequest }) => pullRequest.state,\n (state, rows) => ({\n id: `state-${state}`,\n label: `pull-request-state.${state}.label`,\n translate: true,\n icon: STATE_ICON[state],\n hue: STATE_HUE[state],\n rows,\n }),\n rankOf(STATE_ORDER),\n );\n\n case 'checks':\n return [\n ...partition(\n rows.filter((row) => row.checks),\n ({ checks }): GitHubOperation.CiState => checks?.ci ?? 'none',\n (ci, rows) => ({\n id: `checks-${ci}`,\n label: `ci-status.${ci}.label`,\n translate: true,\n icon: CI_ICON[ci],\n hue: CI_HUE[ci],\n rows,\n }),\n rankOf(CI_ORDER),\n ),\n // Rows whose checks have not arrived (or are not fetched, e.g. a merged pull request) last.\n ...partition(\n rows.filter((row) => !row.checks),\n () => 'unknown' as const,\n (_, rows) => ({\n id: 'checks-unknown',\n label: 'ci-status.unknown.label',\n translate: true,\n icon: 'ph--question--regular',\n rows,\n }),\n ),\n ];\n\n case 'author':\n return partition(\n rows,\n ({ pullRequest }) => pullRequest.author ?? '',\n (author, rows) => ({\n id: `author-${author}`,\n label: author || 'group-no-author.label',\n translate: !author,\n icon: author ? 'ph--user--regular' : 'ph--user-circle-dashed--regular',\n rows,\n }),\n // Unknown authors last; the rest by name.\n (left, right) => (left === '' ? 1 : right === '' ? -1 : left.localeCompare(right)),\n );\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nconst UNITS: readonly [Intl.RelativeTimeFormatUnit, number][] = [\n ['year', 365 * 24 * 60 * 60_000],\n ['month', 30 * 24 * 60 * 60_000],\n ['week', 7 * 24 * 60 * 60_000],\n ['day', 24 * 60 * 60_000],\n ['hour', 60 * 60_000],\n ['minute', 60_000],\n];\n\n// Built once: constructing an `Intl` formatter resolves the locale each time, and every row formats.\nlet formatter: Intl.RelativeTimeFormat | undefined;\n\n/** `5 minutes ago`, `yesterday`, `3 weeks ago` — in the largest unit that fits; empty for an invalid date. */\nexport const formatRelative = (value: string, now = Date.now()): string => {\n const date = Date.parse(value);\n if (Number.isNaN(date)) {\n return '';\n }\n formatter ??= new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });\n const elapsed = date - now;\n for (const [unit, size] of UNITS) {\n if (Math.abs(elapsed) >= size) {\n return formatter.format(Math.round(elapsed / size), unit);\n }\n }\n return formatter.format(0, 'minute');\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { useCallback, useMemo, useRef } from 'react';\n\nimport { type Database, Filter, Obj, Tag, Type } from '@dxos/echo';\nimport { QueryBuilder } from '@dxos/echo-query';\nimport { useQuery } from '@dxos/echo-react';\nimport { useAttention, useViewState, useViewStateActions } from '@dxos/react-ui-attention';\nimport { type EditorController } from '@dxos/react-ui-editor';\nimport { Listbox } from '@dxos/react-ui-list';\nimport { GroupMenu, SortMenu } from '@dxos/react-ui-menu';\nimport { QueryEditor, usePersistentQuery } from '@dxos/react-ui-query';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Status from '@dxos/react-ui/Status';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport { PullRequest, Task } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport { useOpenObject, usePullRequestChecks } from '../../hooks/index.ts';\nimport * as PullRequestsView from '../../types/PullRequestsView.ts';\nimport {\n CI_HUE,\n type PullRequestChecks,\n type PullRequestRow,\n type PullRequestRowGroup,\n STATE_HUE,\n filterRows,\n groupRows,\n sortRows,\n} from './arrange.ts';\nimport { formatRelative } from './format.ts';\n\nconst PULL_REQUEST_TYPENAME = Type.getTypename(PullRequest.PullRequest);\n\nconst SORT_ICONS: Record<PullRequestsView.SortField, string> = {\n relevance: 'ph--lightning--regular',\n updated: 'ph--clock-clockwise--regular',\n created: 'ph--calendar-plus--regular',\n number: 'ph--hash--regular',\n title: 'ph--text-aa--regular',\n};\n\nconst GROUP_ICONS: Record<PullRequestsView.GroupField, string> = {\n none: 'ph--list--regular',\n repo: 'ph--git-branch--regular',\n state: 'ph--git-pull-request--regular',\n checks: 'ph--check-circle--regular',\n author: 'ph--user--regular',\n};\n\nexport type PullRequestsArticleProps = {\n role?: string;\n attendableId: string;\n /** The space's database; absent when the type node carries no space, which renders nothing. */\n db?: Database.Database;\n};\n\n/**\n * Every pull request in a space as one list a reader triages from: repository, title, CI checks,\n * the tasks that track it and its state, ordered by relevance (what needs the reader first) or time.\n * The filter, order and grouping persist per device and per space, through the same view-state\n * aspect, query editor and sort/group menus a task set's list uses.\n */\nexport const PullRequestsArticle = ({ db, ...props }: PullRequestsArticleProps) =>\n db ? <PullRequestList db={db} {...props} /> : null;\n\nPullRequestsArticle.displayName = 'PullRequestsArticle';\n\nconst PullRequestList = ({ role, attendableId, db }: PullRequestsArticleProps & { db: Database.Database }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const { hasAttention } = useAttention(attendableId);\n const editorRef = useRef<EditorController>(null);\n const contextId = db.spaceId;\n\n const [query, setQuery] = usePersistentQuery(PullRequestsView.aspect, contextId, editorRef);\n const { sort = PullRequestsView.DEFAULT_SORT, group = 'none' } = useViewState(PullRequestsView.aspect, contextId);\n const { update } = useViewStateActions(PullRequestsView.aspect, contextId);\n const handleSortChange = useCallback(\n (sort: PullRequestsView.Sort) => update((view) => ({ ...view, sort })),\n [update],\n );\n const handleGroupChange = useCallback(\n (group: PullRequestsView.GroupField) => update((view) => ({ ...view, group })),\n [update],\n );\n const handleClear = useCallback(() => setQuery(''), [setQuery]);\n\n const tags = useTagMap(db);\n // A query that does not parse matches nothing rather than everything.\n const filter = useMemo(() => {\n const text = query.trim();\n return text.length === 0 ? undefined : (new QueryBuilder(tags).build(text).filter ?? Filter.nothing());\n }, [query, tags]);\n\n const pullRequests = useQuery(db, Filter.type(PullRequest.PullRequest));\n const tasks = useQuery(db, Filter.type(Task.Task));\n const checks = usePullRequestChecks(pullRequests, db.spaceId);\n const { rows, groups } = useArrangedRows(pullRequests, tasks, checks, { filter, sort, group });\n // In display order, so keyboard order follows the groups the reader sees.\n const options = useMemo(\n () =>\n (groups ? groups.flatMap((group) => group.rows) : rows).map(({ pullRequest }) => ({\n value: pullRequest.id,\n label: pullRequest.title,\n })),\n [groups, rows],\n );\n\n const sortFields = useMemo(\n () =>\n PullRequestsView.SortField.literals.map((id) => ({\n id,\n label: t(`pull-requests-sort-${id}.label`),\n icon: SORT_ICONS[id],\n })),\n [t],\n );\n const directionLabels = useMemo(\n () => ({ asc: t('pull-requests-sort-asc.label'), desc: t('pull-requests-sort-desc.label') }),\n [t],\n );\n const groupFields = useMemo(\n () =>\n PullRequestsView.GroupField.literals.map((id) => ({\n id,\n label: t(`pull-requests-group-${id}.label`),\n icon: GROUP_ICONS[id],\n })),\n [t],\n );\n\n const openObject = useOpenObject();\n\n return (\n <Panel.Root role={role} data-testid='pull-requests'>\n <Panel.Header>\n <Toolbar.Root inactive={!hasAttention}>\n <QueryEditor\n classNames='grow min-w-0 ps-1'\n db={db}\n tags={tags}\n value={query}\n onChange={setQuery}\n ref={editorRef}\n />\n <SortMenu\n fields={sortFields}\n value={sort}\n onChange={handleSortChange}\n label={t('pull-requests-sort.label')}\n directionLabels={directionLabels}\n testId='pull-requests.sort'\n />\n <GroupMenu\n fields={groupFields}\n value={group}\n onChange={handleGroupChange}\n label={t('pull-requests-group.label')}\n none='none'\n testId='pull-requests.group'\n />\n <Button.Root\n icon='ph--x--regular'\n iconOnly\n disabled={query.trim().length === 0}\n label={t('pull-requests-filter-clear.label')}\n data-testid='pull-requests.filter.clear'\n onClick={handleClear}\n />\n </Toolbar.Root>\n </Panel.Header>\n <Panel.Body>\n {rows.length === 0 ? (\n <Status.Empty classNames='dx-expand'>\n {t(pullRequests.length === 0 ? 'pull-requests-empty.message' : 'pull-requests-no-match.message')}\n </Status.Empty>\n ) : (\n <Listbox.Root items={options}>\n <Listbox.Viewport>\n <Listbox.Content\n classNames='dx-expand'\n aria-label={t('typename.label_other', { ns: PULL_REQUEST_TYPENAME })}\n >\n {groups\n ? groups\n .filter((group) => group.rows.length > 0)\n .map((group) => <GroupSection key={group.id} group={group} onOpen={openObject} />)\n : rows.map((row) => <PullRequestListRow key={row.pullRequest.id} row={row} onOpen={openObject} />)}\n </Listbox.Content>\n </Listbox.Viewport>\n </Listbox.Root>\n )}\n </Panel.Body>\n </Panel.Root>\n );\n};\n\ntype OpenHandler = (object: Obj.Any) => Promise<void>;\n\nconst GroupSection = ({ group, onOpen }: { group: PullRequestRowGroup; onOpen: OpenHandler }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n return (\n <Listbox.ItemGroup>\n <Listbox.ItemGroupLabel>\n <Layout.Flex align='center' gap='sm'>\n <Icon.Icon icon={group.icon} classNames='dx-text' data-hue={group.hue} />\n <span className='truncate'>{group.translate ? t(group.label) : group.label}</span>\n <span className='text-description'>{group.rows.length}</span>\n </Layout.Flex>\n </Listbox.ItemGroupLabel>\n {group.rows.map((row) => (\n <PullRequestListRow key={row.pullRequest.id} row={row} onOpen={onOpen} />\n ))}\n </Listbox.ItemGroup>\n );\n};\n\n/** One pull request: its repository and number, title, author and time, then checks, tasks and state. */\nconst PullRequestListRow = ({\n row: { pullRequest, checks, tasks },\n onOpen,\n}: {\n row: PullRequestRow;\n onOpen: OpenHandler;\n}) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const time = pullRequest.updatedAt ?? pullRequest.createdAt;\n return (\n <Listbox.Item\n id={pullRequest.id}\n classNames='cursor-pointer py-2'\n data-testid='pull-requests.row'\n onClick={() => void onOpen(pullRequest)}\n >\n <Layout.Flex column gap='xs' grow>\n <Layout.Flex align='center' gap='sm' classNames='min-w-0'>\n <span className='dx-tag dx-tag-inline shrink-0' data-hue='neutral'>\n {PullRequest.reference(pullRequest)}\n </span>\n <span className='truncate grow'>{pullRequest.title}</span>\n <ChecksTag pullRequest={pullRequest} checks={checks} />\n <span\n className='dx-tag dx-tag-inline shrink-0'\n data-hue={STATE_HUE[pullRequest.state]}\n data-testid='pull-requests.row.state'\n >\n {t(`pull-request-state.${pullRequest.state}.label`)}\n </span>\n </Layout.Flex>\n <Layout.Flex align='center' gap='sm' classNames='min-w-0 text-xs text-description'>\n {pullRequest.author && <span className='shrink-0'>{pullRequest.author}</span>}\n {time && (\n <time className='shrink-0' dateTime={time} title={new Date(time).toLocaleString()}>\n {formatRelative(time)}\n </time>\n )}\n {tasks.length > 0 && (\n <Layout.Flex align='center' gap='xs' classNames='min-w-0' data-testid='pull-requests.row.tasks'>\n <Icon.Icon icon='ph--check-square-offset--regular' size='xs' classNames='shrink-0' />\n <span className='truncate'>{tasks.map((task) => task.title || t('untitled-task.label')).join(', ')}</span>\n </Layout.Flex>\n )}\n </Layout.Flex>\n </Layout.Flex>\n </Listbox.Item>\n );\n};\n\nconst ChecksTag = ({ pullRequest, checks }: { pullRequest: PullRequest.PullRequest; checks?: PullRequestChecks }) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n // A finished pull request's checks are not read (see `usePullRequestChecks`), so it shows none.\n if (!checks) {\n return pullRequest.state === 'open' || pullRequest.state === 'draft' ? (\n <span className='dx-tag dx-tag-inline' data-hue='neutral' data-testid='pull-requests.row.checks'>\n {t('ci-status.unknown.label')}\n </span>\n ) : null;\n }\n\n return (\n <>\n {checks.review !== 'none' && (\n <span\n className='dx-tag dx-tag-inline'\n data-hue={checks.review === 'approved' ? 'green' : 'red'}\n data-testid='pull-requests.row.review'\n >\n {t(`review-status.${checks.review}.label`, { count: checks.approvals })}\n </span>\n )}\n <span className='dx-tag dx-tag-inline' data-hue={CI_HUE[checks.ci]} data-testid='pull-requests.row.checks'>\n {t(`ci-status.${checks.ci}.label`)}\n {checks.checks.total > 0 && ` ${checks.checks.passed}/${checks.checks.total}`}\n </span>\n </>\n );\n};\n\ntype ArrangeOptions = {\n filter: Filter.Any | undefined;\n sort: PullRequestsView.Sort;\n group: PullRequestsView.GroupField;\n};\n\n/**\n * The rows the toolbar keeps, in the order it asks for, partitioned into its groups. Read through\n * atoms so a re-sync (a new state, a new title) or a task gaining the pull request as an artifact\n * re-arranges the list without the queries re-emitting.\n */\nconst useArrangedRows = (\n pullRequests: readonly PullRequest.PullRequest[],\n tasks: readonly Task.Task[],\n checks: ReadonlyMap<string, PullRequestChecks>,\n { filter, sort, group }: ArrangeOptions,\n): { rows: readonly PullRequestRow[]; groups?: PullRequestRowGroup[] } => {\n const atom = useMemo(\n () =>\n Atom.make((get) => {\n pullRequests.forEach((pullRequest) => get(Obj.atom(pullRequest)));\n const tasksByPullRequest = new Map<string, Task.Task[]>();\n for (const task of tasks) {\n for (const ref of get(Obj.atomProperty(task, 'artifacts')) ?? []) {\n const id = Task.refEntityId(ref);\n if (id) {\n tasksByPullRequest.set(id, [...(tasksByPullRequest.get(id) ?? []), task]);\n }\n }\n }\n const all = pullRequests.map((pullRequest) => ({\n pullRequest,\n checks: checks.get(pullRequest.id),\n tasks: tasksByPullRequest.get(pullRequest.id) ?? [],\n }));\n const rows = sortRows(filterRows(all, filter), sort);\n return { rows, groups: groupRows(rows, group) };\n }),\n [pullRequests, tasks, checks, filter, sort, group],\n );\n\n return useAtomValue(atom);\n};\n\n/** Tag registry keyed by the `Tag` object's uri — the id space `#tag` terms and `meta.tags` share. */\nconst useTagMap = (db: Database.Database): Tag.Map => {\n const tags = useQuery(db, Filter.type(Tag.Tag));\n return useMemo(\n () =>\n tags.reduce<Tag.Map>((acc, tag) => {\n acc[Obj.getURI(tag).toString()] = tag;\n return acc;\n }, {}),\n [tags],\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { PullRequest } from "@dxos/types";
3
+ import { Annotation, DXN, Format, Obj, Ref, Type } from "@dxos/echo";
4
+ import * as Schema from "effect/Schema";
5
+ //#region src/types/Walkthrough.ts
6
+ var Walkthrough_exports = /* @__PURE__ */ __exportAll({
7
+ Walkthrough: () => Walkthrough,
8
+ instanceOf: () => instanceOf,
9
+ isStale: () => isStale,
10
+ make: () => make,
11
+ makeTitle: () => makeTitle
12
+ });
13
+ /**
14
+ * A narrated reading of a pull request: one markdown document whose prose, headings and ```diff
15
+ * fences describe the change in the order a reviewer should meet it.
16
+ *
17
+ * Generated against ONE commit and stale the moment the branch moves, which is why `commit` is part
18
+ * of the record rather than something to infer — see {@link isStale}.
19
+ */
20
+ var Walkthrough = class extends Type.makeObject(DXN.make("org.dxos.type.walkthrough", "0.1.0"))(Schema.Struct({
21
+ /** The pull request this narrates. */
22
+ pullRequest: Ref.Ref(PullRequest.PullRequest),
23
+ /** `owner/repo#123: title`, copied at generation so the label needs no ref load. */
24
+ title: Schema.String.pipe(Schema.annotate({ title: "Title" }), Schema.optional),
25
+ /**
26
+ * The whole document, as a plain string rather than a text object.
27
+ *
28
+ * A walkthrough is replaced wholesale on every regeneration and is never co-edited character by
29
+ * character, so the CRDT a text object would impose is pure cost: it would keep per-character
30
+ * history for a document nobody edits.
31
+ */
32
+ body: Schema.String.pipe(Schema.annotate({ title: "Body" })),
33
+ /** Head SHA the walkthrough was generated from; anything else means it describes another change. */
34
+ commit: Schema.String.pipe(Schema.annotate({ title: "Commit" })),
35
+ generatedAt: Format.DateTime.pipe(Schema.annotate({ title: "Generated" }), Schema.optional),
36
+ /** Model that produced the prose, so a regression can be attributed after the default moves. */
37
+ model: Schema.String.pipe(Schema.annotate({ title: "Model" }), Schema.optional),
38
+ /** Hunks the prose accounts for, over the patch's total — how much of the change it narrates. */
39
+ covered: Schema.Number.pipe(Schema.annotate({ title: "Hunks covered" }), Schema.optional),
40
+ total: Schema.Number.pipe(Schema.annotate({ title: "Hunks total" }), Schema.optional)
41
+ }).pipe(Schema.annotate({
42
+ title: "Walkthrough",
43
+ description: "A narrated reading of a pull request."
44
+ }), Annotation.LabelAnnotation.set(["title", "commit"]), Annotation.IconAnnotation.set({
45
+ icon: "ph--path--regular",
46
+ hue: "indigo"
47
+ }), Annotation.UserType.set())) {};
48
+ /** Factory wrapper around `Obj.make` for {@link Walkthrough}. */
49
+ var make = (props) => Obj.make(Walkthrough, props);
50
+ /** Returns true when value is a Walkthrough object. */
51
+ var instanceOf = (value) => Obj.instanceOf(Walkthrough, value);
52
+ /** The label a walkthrough of this pull request carries. */
53
+ var makeTitle = (pullRequest, title = pullRequest.title) => `${PullRequest.reference(pullRequest)}: ${title}`;
54
+ /** Whether the walkthrough describes a commit other than the one given. */
55
+ var isStale = (walkthrough, head) => walkthrough.commit !== head;
56
+ //#endregion
57
+ export { make as a, isStale as i, Walkthrough_exports as n, makeTitle as o, instanceOf as r, Walkthrough as t };
58
+
59
+ //# sourceMappingURL=chunk-Walkthrough.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-Walkthrough.mjs","names":[],"sources":["../../src/types/Walkthrough.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation, DXN, Format, Obj, Ref, Type } from '@dxos/echo';\nimport { PullRequest } from '@dxos/types';\n\n/**\n * A narrated reading of a pull request: one markdown document whose prose, headings and ```diff\n * fences describe the change in the order a reviewer should meet it.\n *\n * Generated against ONE commit and stale the moment the branch moves, which is why `commit` is part\n * of the record rather than something to infer — see {@link isStale}.\n */\nexport class Walkthrough extends Type.makeObject<Walkthrough>(DXN.make('org.dxos.type.walkthrough', '0.1.0'))(\n Schema.Struct({\n /** The pull request this narrates. */\n pullRequest: Ref.Ref(PullRequest.PullRequest),\n\n /** `owner/repo#123: title`, copied at generation so the label needs no ref load. */\n title: Schema.String.pipe(Schema.annotate({ title: 'Title' }), Schema.optional),\n\n /**\n * The whole document, as a plain string rather than a text object.\n *\n * A walkthrough is replaced wholesale on every regeneration and is never co-edited character by\n * character, so the CRDT a text object would impose is pure cost: it would keep per-character\n * history for a document nobody edits.\n */\n body: Schema.String.pipe(Schema.annotate({ title: 'Body' })),\n\n /** Head SHA the walkthrough was generated from; anything else means it describes another change. */\n commit: Schema.String.pipe(Schema.annotate({ title: 'Commit' })),\n\n generatedAt: Format.DateTime.pipe(Schema.annotate({ title: 'Generated' }), Schema.optional),\n\n /** Model that produced the prose, so a regression can be attributed after the default moves. */\n model: Schema.String.pipe(Schema.annotate({ title: 'Model' }), Schema.optional),\n\n /** Hunks the prose accounts for, over the patch's total — how much of the change it narrates. */\n covered: Schema.Number.pipe(Schema.annotate({ title: 'Hunks covered' }), Schema.optional),\n total: Schema.Number.pipe(Schema.annotate({ title: 'Hunks total' }), Schema.optional),\n }).pipe(\n Schema.annotate({ title: 'Walkthrough', description: 'A narrated reading of a pull request.' }),\n Annotation.LabelAnnotation.set(['title', 'commit']),\n Annotation.IconAnnotation.set({ icon: 'ph--path--regular', hue: 'indigo' }),\n Annotation.UserType.set(),\n ),\n) {}\n\n/** Factory wrapper around `Obj.make` for {@link Walkthrough}. */\nexport const make = (props: Obj.MakeProps<typeof Walkthrough>): Walkthrough => Obj.make(Walkthrough, props);\n\n/** Returns true when value is a Walkthrough object. */\nexport const instanceOf = (value: unknown): value is Walkthrough => Obj.instanceOf(Walkthrough, value);\n\n/** The label a walkthrough of this pull request carries. */\nexport const makeTitle = (pullRequest: PullRequest.PullRequest, title = pullRequest.title): string =>\n `${PullRequest.reference(pullRequest)}: ${title}`;\n\n/** Whether the walkthrough describes a commit other than the one given. */\nexport const isStale = (walkthrough: Walkthrough, head: string): boolean => walkthrough.commit !== head;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,IAAa,cAAb,cAAiC,KAAK,WAAwB,IAAI,KAAK,6BAA6B,OAAO,CAAC,CAAC,CAC3G,OAAO,OAAO;;CAEZ,aAAa,IAAI,IAAI,YAAY,WAAW;;CAG5C,OAAO,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,QAAQ,CAAC,GAAG,OAAO,QAAQ;;;;;;;;CAS9E,MAAM,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,OAAO,CAAC,CAAC;;CAG3D,QAAQ,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,SAAS,CAAC,CAAC;CAE/D,aAAa,OAAO,SAAS,KAAK,OAAO,SAAS,EAAE,OAAO,YAAY,CAAC,GAAG,OAAO,QAAQ;;CAG1F,OAAO,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,QAAQ,CAAC,GAAG,OAAO,QAAQ;;CAG9E,SAAS,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,gBAAgB,CAAC,GAAG,OAAO,QAAQ;CACxF,OAAO,OAAO,OAAO,KAAK,OAAO,SAAS,EAAE,OAAO,cAAc,CAAC,GAAG,OAAO,QAAQ;AACtF,CAAC,CAAC,CAAC,KACD,OAAO,SAAS;CAAE,OAAO;CAAe,aAAa;AAAwC,CAAC,GAC9F,WAAW,gBAAgB,IAAI,CAAC,SAAS,QAAQ,CAAC,GAClD,WAAW,eAAe,IAAI;CAAE,MAAM;CAAqB,KAAK;AAAS,CAAC,GAC1E,WAAW,SAAS,IAAI,CAC1B,CACF,CAAC,CAAC,CAAC;;AAGH,IAAa,QAAQ,UAA0D,IAAI,KAAK,aAAa,KAAK;;AAG1G,IAAa,cAAc,UAAyC,IAAI,WAAW,aAAa,KAAK;;AAGrG,IAAa,aAAa,aAAsC,QAAQ,YAAY,UAClF,GAAG,YAAY,UAAU,WAAW,EAAE,IAAI;;AAG5C,IAAa,WAAW,aAA0B,SAA0B,YAAY,WAAW"}
@@ -2,8 +2,8 @@ import { t as PullRequestArticle } from "./chunk-PullRequestArticle.mjs";
2
2
  import "react";
3
3
  import { PullRequest } from "@dxos/types";
4
4
  import { Filter, Obj } from "@dxos/echo";
5
- import { jsx } from "react/jsx-runtime";
6
5
  import { useObject, useQuery } from "@dxos/echo-react";
6
+ import { jsx } from "react/jsx-runtime";
7
7
  //#region src/containers/WalkthroughArticle/WalkthroughArticle.tsx
8
8
  /**
9
9
  * A walkthrough opened directly — from a search result, or a link written before the pull request
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-add-pull-request-comment.mjs","names":[],"sources":["../../src/operations/add-pull-request-comment.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.AddPullRequestComment> =\n GitHubOperation.AddPullRequestComment.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const comment = yield* GitHubApi.createIssueComment(\n pullRequest.owner,\n pullRequest.repo,\n pullRequest.number,\n body,\n ).pipe(Effect.provide(credentials));\n return { commentId: comment.id, url: comment.html_url ?? undefined };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,sBAAsB,KACpC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,QAAQ;CAC/C,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,UAAU,OAAO,mBACrB,YAAY,OACZ,YAAY,MACZ,YAAY,QACZ,IACF,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CAClC,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;CAAU;AACrE,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-add-pull-request-comment.mjs","names":["GitHubApi.createIssueComment"],"sources":["../../src/operations/add-pull-request-comment.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.AddPullRequestComment> =\n GitHubOperation.AddPullRequestComment.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const comment = yield* GitHubApi.createIssueComment(\n pullRequest.owner,\n pullRequest.repo,\n pullRequest.number,\n body,\n ).pipe(Effect.provide(credentials));\n return { commentId: comment.id, url: comment.html_url ?? undefined };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,sBAAsB,KACpC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,QAAQ;CAC/C,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,UAAU,OAAOA,mBACrB,YAAY,OACZ,YAAY,MACZ,YAAY,QACZ,IACF,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CAClC,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;CAAU;AACrE,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-add-pull-request-review-comment.mjs","names":[],"sources":["../../src/operations/add-pull-request-review-comment.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.AddPullRequestReviewComment> =\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body, commit, path, line, side }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const comment = yield* GitHubApi.createReviewComment(pullRequest.owner, pullRequest.repo, pullRequest.number, {\n body,\n commit_id: commit,\n path,\n line,\n side,\n }).pipe(Effect.provide(credentials));\n return { commentId: comment.id, url: comment.html_url ?? undefined };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,4BAA4B,KAC1C,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,MAAM,QAAQ,MAAM,MAAM,QAAQ;CACzE,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,UAAU,OAAO,oBAA8B,YAAY,OAAO,YAAY,MAAM,YAAY,QAAQ;EAC5G;EACA,WAAW;EACX;EACA;EACA;CACF,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACnC,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;CAAU;AACrE,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-add-pull-request-review-comment.mjs","names":["GitHubApi.createReviewComment"],"sources":["../../src/operations/add-pull-request-review-comment.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.AddPullRequestReviewComment> =\n GitHubOperation.AddPullRequestReviewComment.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref, body, commit, path, line, side }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const comment = yield* GitHubApi.createReviewComment(pullRequest.owner, pullRequest.repo, pullRequest.number, {\n body,\n commit_id: commit,\n path,\n line,\n side,\n }).pipe(Effect.provide(credentials));\n return { commentId: comment.id, url: comment.html_url ?? undefined };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,4BAA4B,KAC1C,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,KAAK,MAAM,QAAQ,MAAM,MAAM,QAAQ;CACzE,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,UAAU,OAAOA,oBAA8B,YAAY,OAAO,YAAY,MAAM,YAAY,QAAQ;EAC5G;EACA,WAAW;EACX;EACA;EACA;CACF,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACnC,OAAO;EAAE,WAAW,QAAQ;EAAI,KAAK,QAAQ,YAAY,KAAA;CAAU;AACrE,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-connector.mjs","names":[],"sources":["../../src/capabilities/connector.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Credential from '@dxos/compute/Credential';\nimport { Obj } from '@dxos/echo';\nimport * as ConnectorError from '@dxos/plugin-connector/ConnectorError';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport { OAuthProvider } from '@dxos/protocols';\n\nimport { GitHubOperation } from '#types';\n\nimport { GITHUB_PROVIDER_ID, GITHUB_SOURCE } from '../constants.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Service-specific token-created hook for GitHub.\n *\n * Calls GitHub's `/user` to populate `accessToken.account` with the\n * authenticated user's login (falling back to email). Failures are elevated\n * with {@link Effect.orDie}; plugin-connector logs defects from the runner\n * and continues so a failed `/user` cannot block the Connection already\n * created.\n */\nconst onTokenCreated: ConnectorSpec.OnTokenCreated = ({ accessToken }) =>\n Effect.gen(function* () {\n if (accessToken.account) {\n return;\n }\n const token = yield* Credential.getApiKeyValue({ accessTokenId: accessToken.id });\n const user = yield* GitHubApi.fetchUser().pipe(\n Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })),\n );\n Obj.update(accessToken, (accessToken) => {\n accessToken.account = user.login ?? user.email;\n });\n }).pipe(Effect.orDie);\n\n/**\n * GitHub `testConnection`: `GET /user` with the stored token. A rejected token\n * (401/403 on a revoked grant) or transport failure surfaces as a user-facing\n * error so the connection UI can offer to reauthenticate.\n */\nconst testConnection: ConnectorSpec.TestConnection = ({ accessToken }) =>\n Effect.flatMap(Credential.getApiKeyValue({ accessTokenId: accessToken.id }), (token) =>\n GitHubApi.fetchUser().pipe(Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token }))),\n ).pipe(\n Effect.asVoid,\n Effect.mapError(\n () =>\n new ConnectorError.ConnectionTestError({\n message: 'GitHub rejected the credential. Reauthenticate to continue syncing.',\n }),\n ),\n );\n\n/**\n * Contributes a single `ConnectorSpec.Connector` entry that wires GitHub's two operations,\n * its target materializer, and the token-created hook to the `'github.com'`\n * source. plugin-connector routes by `connectorId`.\n *\n * Sync targets are repositories, not organizations — orgs and their members\n * are auto-pulled as a side effect of syncing any repo they own.\n *\n * `scopes` is intentionally empty: this is a GitHub *App* (not a classic\n * OAuth App), so permissions are declared in the App's settings on github.com\n * and OAuth scope strings are ignored on the user-authorization flow.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(ConnectorSpec.Connector, [\n {\n id: GITHUB_PROVIDER_ID,\n source: GITHUB_SOURCE,\n label: 'GitHub',\n oauth: {\n provider: OAuthProvider.GITHUB,\n scopes: [],\n },\n sync: {\n operation: GitHubOperation.SyncGitHubRepositories,\n getTargets: GitHubOperation.GetGitHubRepositories,\n materializeTarget: GitHubOperation.MaterializeGitHubTarget,\n optionsSchema: GitHubOperation.SyncOptions,\n },\n onTokenCreated,\n testConnection,\n },\n ]);\n }),\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,IAAM,kBAAgD,EAAE,kBACtD,OAAO,IAAI,aAAa;CACtB,IAAI,YAAY,SACd;CAEF,MAAM,QAAQ,OAAO,WAAW,eAAe,EAAE,eAAe,YAAY,GAAG,CAAC;CAChF,MAAM,OAAO,OAAO,UAAoB,CAAC,CAAC,KACxC,OAAO,QAAQ,MAAM,QAAQ,mBAA6B,EAAE,MAAM,CAAC,CAAC,CACtE;CACA,IAAI,OAAO,cAAc,gBAAgB;EACvC,YAAY,UAAU,KAAK,SAAS,KAAK;CAC3C,CAAC;AACH,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK;;;;;;AAOtB,IAAM,kBAAgD,EAAE,kBACtD,OAAO,QAAQ,WAAW,eAAe,EAAE,eAAe,YAAY,GAAG,CAAC,IAAI,UAC5E,UAAoB,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,QAAQ,mBAA6B,EAAE,MAAM,CAAC,CAAC,CAAC,CAClG,CAAC,CAAC,KACA,OAAO,QACP,OAAO,eAEH,IAAI,eAAe,oBAAoB,EACrC,SAAS,sEACX,CAAC,CACL,CACF;;;;;;;;;;;;;AAcF,IAAA,oBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,cAAc,WAAW,CACpD;EACE,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,OAAO;GACL,UAAU,cAAc;GACxB,QAAQ,CAAC;EACX;EACA,MAAM;GACJ,WAAW,gBAAgB;GAC3B,YAAY,gBAAgB;GAC5B,mBAAmB,gBAAgB;GACnC,eAAe,gBAAgB;EACjC;EACA;EACA;CACF,CACF,CAAC;AACH,CAAC,CACH"}
1
+ {"version":3,"file":"chunk-connector.mjs","names":["GitHubApi.fetchUser","GitHubApi.GitHubCredentials"],"sources":["../../src/capabilities/connector.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Credential from '@dxos/compute/Credential';\nimport { Obj } from '@dxos/echo';\nimport * as ConnectorError from '@dxos/plugin-connector/ConnectorError';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport { OAuthProvider } from '@dxos/protocols';\n\nimport { GitHubOperation } from '#types';\n\nimport { GITHUB_PROVIDER_ID, GITHUB_SOURCE } from '../constants.ts';\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Service-specific token-created hook for GitHub.\n *\n * Calls GitHub's `/user` to populate `accessToken.account` with the\n * authenticated user's login (falling back to email). Failures are elevated\n * with {@link Effect.orDie}; plugin-connector logs defects from the runner\n * and continues so a failed `/user` cannot block the Connection already\n * created.\n */\nconst onTokenCreated: ConnectorSpec.OnTokenCreated = ({ accessToken }) =>\n Effect.gen(function* () {\n if (accessToken.account) {\n return;\n }\n const token = yield* Credential.getApiKeyValue({ accessTokenId: accessToken.id });\n const user = yield* GitHubApi.fetchUser().pipe(\n Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token })),\n );\n Obj.update(accessToken, (accessToken) => {\n accessToken.account = user.login ?? user.email;\n });\n }).pipe(Effect.orDie);\n\n/**\n * GitHub `testConnection`: `GET /user` with the stored token. A rejected token\n * (401/403 on a revoked grant) or transport failure surfaces as a user-facing\n * error so the connection UI can offer to reauthenticate.\n */\nconst testConnection: ConnectorSpec.TestConnection = ({ accessToken }) =>\n Effect.flatMap(Credential.getApiKeyValue({ accessTokenId: accessToken.id }), (token) =>\n GitHubApi.fetchUser().pipe(Effect.provide(Layer.succeed(GitHubApi.GitHubCredentials, { token }))),\n ).pipe(\n Effect.asVoid,\n Effect.mapError(\n () =>\n new ConnectorError.ConnectionTestError({\n message: 'GitHub rejected the credential. Reauthenticate to continue syncing.',\n }),\n ),\n );\n\n/**\n * Contributes a single `ConnectorSpec.Connector` entry that wires GitHub's two operations,\n * its target materializer, and the token-created hook to the `'github.com'`\n * source. plugin-connector routes by `connectorId`.\n *\n * Sync targets are repositories, not organizations — orgs and their members\n * are auto-pulled as a side effect of syncing any repo they own.\n *\n * `scopes` is intentionally empty: this is a GitHub *App* (not a classic\n * OAuth App), so permissions are declared in the App's settings on github.com\n * and OAuth scope strings are ignored on the user-authorization flow.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(ConnectorSpec.Connector, [\n {\n id: GITHUB_PROVIDER_ID,\n source: GITHUB_SOURCE,\n label: 'GitHub',\n oauth: {\n provider: OAuthProvider.GITHUB,\n scopes: [],\n },\n sync: {\n operation: GitHubOperation.SyncGitHubRepositories,\n getTargets: GitHubOperation.GetGitHubRepositories,\n materializeTarget: GitHubOperation.MaterializeGitHubTarget,\n optionsSchema: GitHubOperation.SyncOptions,\n },\n onTokenCreated,\n testConnection,\n },\n ]);\n }),\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,IAAM,kBAAgD,EAAE,kBACtD,OAAO,IAAI,aAAa;CACtB,IAAI,YAAY,SACd;CAEF,MAAM,QAAQ,OAAO,WAAW,eAAe,EAAE,eAAe,YAAY,GAAG,CAAC;CAChF,MAAM,OAAO,OAAOA,UAAoB,CAAC,CAAC,KACxC,OAAO,QAAQ,MAAM,QAAQC,mBAA6B,EAAE,MAAM,CAAC,CAAC,CACtE;CACA,IAAI,OAAO,cAAc,gBAAgB;EACvC,YAAY,UAAU,KAAK,SAAS,KAAK;CAC3C,CAAC;AACH,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK;;;;;;AAOtB,IAAM,kBAAgD,EAAE,kBACtD,OAAO,QAAQ,WAAW,eAAe,EAAE,eAAe,YAAY,GAAG,CAAC,IAAI,UAC5ED,UAAoB,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,QAAQC,mBAA6B,EAAE,MAAM,CAAC,CAAC,CAAC,CAClG,CAAC,CAAC,KACA,OAAO,QACP,OAAO,eAEH,IAAI,eAAe,oBAAoB,EACrC,SAAS,sEACX,CAAC,CACL,CACF;;;;;;;;;;;;;AAcF,IAAA,oBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,cAAc,WAAW,CACpD;EACE,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,OAAO;GACL,UAAU,cAAc;GACxB,QAAQ,CAAC;EACX;EACA,MAAM;GACJ,WAAW,gBAAgB;GAC3B,YAAY,gBAAgB;GAC5B,mBAAmB,gBAAgB;GACnC,eAAe,gBAAgB;EACjC;EACA;EACA;CACF,CACF,CAAC;AACH,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-generate-walkthrough.mjs","names":[],"sources":["../../src/operations/generate-walkthrough.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Cause from 'effect/Cause';\nimport * as Effect from 'effect/Effect';\nimport * as Exit from 'effect/Exit';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\n\nimport { AiService } from '@dxos/ai';\nimport * as Progress from '@dxos/app-toolkit/Progress';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Obj, Ref } from '@dxos/echo';\nimport { PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubPullRequestUnstoredError } from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { GENERATE_PHASES, generateWalkthrough } from '../walkthrough/index.ts';\nimport { githubToken } from './pull-request.ts';\n\n/**\n * One-shot for now; a multi-turn agent that reads the repository is the obvious next step.\n *\n * The prompt's diff budget matters more than it looks: this model's output allowance covers its\n * reasoning as well as its answer, so an unbounded diff yields a response that is all reasoning and\n * no walkthrough. See `DEFAULT_MAX_DIFF_CHARS`.\n */\nconst MODEL = 'com.anthropic.model.claude-sonnet-5.default';\n\n/**\n * Generate a walkthrough of a pull request.\n *\n * Only the I/O is here — fetch the pull request, fetch its diff, run the model — because that is the\n * part a test cannot reach. The decisions live in {@link generateWalkthrough}.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.GenerateWalkthrough> =\n GitHubOperation.GenerateWalkthrough.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: pullRequestRef, force }) {\n // The invoker carries no database resolver, so the handler derives one from its input, as\n // every other operation in this plugin does.\n const pullRequest = pullRequestRef.target;\n const db = pullRequest ? Obj.getDatabase(pullRequest) : undefined;\n if (!pullRequest || !db) {\n // A preview card mints a pull request in memory rather than storing it, and there is\n // nowhere to put a walkthrough of one.\n return yield* Effect.die(new GitHubPullRequestUnstoredError());\n }\n\n const traceWriter = yield* Trace.TraceService;\n const progressKey = GitHubOperation.createWalkthroughProgressKey(pullRequest);\n const label = `Walkthrough of ${PullRequest.reference(pullRequest)}`;\n // Phase-first, since several meters on one object otherwise truncate to the same text.\n const report = (message: string, current: number) =>\n traceWriter.write(Trace.StatusUpdate, {\n message,\n progress: { key: progressKey, current, total: GENERATE_PHASES },\n });\n\n return yield* Effect.gen(function* () {\n report(label, 0);\n const { owner, repo, number } = pullRequest;\n const credentials = Layer.succeed(GitHubApi.GitHubCredentials, { token: yield* githubToken() });\n\n report(`${label}: reading the pull request`, 1);\n const remote = yield* GitHubApi.fetchPullRequest(owner, repo, number).pipe(Effect.provide(credentials));\n\n report(`${label}: fetching the diff`, 2);\n const diff = yield* GitHubApi.fetchPullRequestDiff(owner, repo, number).pipe(Effect.provide(credentials));\n\n const result = yield* generateWalkthrough({\n pullRequest,\n remote: {\n title: remote.title,\n description: remote.body ?? undefined,\n baseBranch: remote.base?.ref,\n headBranch: remote.head?.ref,\n commit: remote.head?.sha,\n },\n diff,\n force,\n model: MODEL,\n report,\n narrate: (prompt) =>\n LanguageModel.generateText({ prompt }).pipe(\n Effect.map((response) => response.text),\n Effect.provide(AiService.languageModel(MODEL).pipe(Layer.orDie)),\n Effect.orDie,\n ),\n });\n\n return {\n walkthrough: Ref.make(result.walkthrough),\n generated: result.generated,\n covered: result.covered,\n total: result.total,\n };\n }).pipe(\n // The meter stays open forever without a terminal, and the sentinel is all the UI shows —\n // the failure itself goes to the log.\n // `onExit`, not `tapError`: the model call and the database both surface as DEFECTS rather\n // than typed errors, and interruption raises neither. A meter with no terminal stays open\n // and leaves the action disabled.\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (Exit.isSuccess(exit)) {\n return;\n }\n const terminal = Cause.hasInterrupts(exit.cause) ? Progress.STATUS_CANCELLED : Progress.STATUS_FAILED;\n report(terminal, GENERATE_PHASES);\n }),\n ),\n Effect.provide(Database.layer(db)),\n );\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAM,QAAQ;;;;;;;AAQd,IAAM,UACJ,gBAAgB,oBAAoB,KAClC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,gBAAgB,SAAS;CAG3D,MAAM,cAAc,eAAe;CACnC,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW,IAAI,KAAA;CACxD,IAAI,CAAC,eAAe,CAAC,IAGnB,OAAO,OAAO,OAAO,IAAI,IAAI,+BAA+B,CAAC;CAG/D,MAAM,cAAc,OAAO,MAAM;CACjC,MAAM,cAAc,gBAAgB,6BAA6B,WAAW;CAC5E,MAAM,QAAQ,kBAAkB,YAAY,UAAU,WAAW;CAEjE,MAAM,UAAU,SAAiB,YAC/B,YAAY,MAAM,MAAM,cAAc;EACpC;EACA,UAAU;GAAE,KAAK;GAAa;GAAS,OAAA;EAAuB;CAChE,CAAC;CAEH,OAAO,OAAO,OAAO,IAAI,aAAa;EACpC,OAAO,OAAO,CAAC;EACf,MAAM,EAAE,OAAO,MAAM,WAAW;EAChC,MAAM,cAAc,MAAM,QAAQ,mBAA6B,EAAE,OAAO,OAAO,YAAY,EAAE,CAAC;EAE9F,OAAO,GAAG,MAAM,6BAA6B,CAAC;EAC9C,MAAM,SAAS,OAAO,iBAA2B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;EAEtG,OAAO,GAAG,MAAM,sBAAsB,CAAC;EACvC,MAAM,OAAO,OAAO,qBAA+B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;EAExG,MAAM,SAAS,OAAO,oBAAoB;GACxC;GACA,QAAQ;IACN,OAAO,OAAO;IACd,aAAa,OAAO,QAAQ,KAAA;IAC5B,YAAY,OAAO,MAAM;IACzB,YAAY,OAAO,MAAM;IACzB,QAAQ,OAAO,MAAM;GACvB;GACA;GACA;GACA,OAAO;GACP;GACA,UAAU,WACR,cAAc,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,KACrC,OAAO,KAAK,aAAa,SAAS,IAAI,GACtC,OAAO,QAAQ,UAAU,cAAc,KAAK,CAAC,CAAC,KAAK,MAAM,KAAK,CAAC,GAC/D,OAAO,KACT;EACJ,CAAC;EAED,OAAO;GACL,aAAa,IAAI,KAAK,OAAO,WAAW;GACxC,WAAW,OAAO;GAClB,SAAS,OAAO;GAChB,OAAO,OAAO;EAChB;CACF,CAAC,CAAC,CAAC,KAMD,OAAO,QAAQ,SACb,OAAO,WAAW;EAChB,IAAI,KAAK,UAAU,IAAI,GACrB;EAEF,MAAM,WAAW,MAAM,cAAc,KAAK,KAAK,IAAI,SAAS,mBAAmB,SAAS;EACxF,OAAO,UAAA,CAAyB;CAClC,CAAC,CACH,GACA,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CACnC;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-generate-walkthrough.mjs","names":["GitHubApi.GitHubCredentials","GitHubApi.fetchPullRequest","GitHubApi.fetchPullRequestDiff"],"sources":["../../src/operations/generate-walkthrough.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Cause from 'effect/Cause';\nimport * as Effect from 'effect/Effect';\nimport * as Exit from 'effect/Exit';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\n\nimport { AiService } from '@dxos/ai';\nimport * as Progress from '@dxos/app-toolkit/Progress';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Obj, Ref } from '@dxos/echo';\nimport { PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubPullRequestUnstoredError } from '../errors.ts';\nimport { GitHubApi } from '../services/index.ts';\nimport { GENERATE_PHASES, generateWalkthrough } from '../walkthrough/index.ts';\nimport { githubToken } from './pull-request.ts';\n\n/**\n * One-shot for now; a multi-turn agent that reads the repository is the obvious next step.\n *\n * The prompt's diff budget matters more than it looks: this model's output allowance covers its\n * reasoning as well as its answer, so an unbounded diff yields a response that is all reasoning and\n * no walkthrough. See `DEFAULT_MAX_DIFF_CHARS`.\n */\nconst MODEL = 'com.anthropic.model.claude-sonnet-5.default';\n\n/**\n * Generate a walkthrough of a pull request.\n *\n * Only the I/O is here — fetch the pull request, fetch its diff, run the model — because that is the\n * part a test cannot reach. The decisions live in {@link generateWalkthrough}.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.GenerateWalkthrough> =\n GitHubOperation.GenerateWalkthrough.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: pullRequestRef, force }) {\n // The invoker carries no database resolver, so the handler derives one from its input, as\n // every other operation in this plugin does.\n const pullRequest = pullRequestRef.target;\n const db = pullRequest ? Obj.getDatabase(pullRequest) : undefined;\n if (!pullRequest || !db) {\n // A preview card mints a pull request in memory rather than storing it, and there is\n // nowhere to put a walkthrough of one.\n return yield* Effect.die(new GitHubPullRequestUnstoredError());\n }\n\n const traceWriter = yield* Trace.TraceService;\n const progressKey = GitHubOperation.createWalkthroughProgressKey(pullRequest);\n const label = `Walkthrough of ${PullRequest.reference(pullRequest)}`;\n // Phase-first, since several meters on one object otherwise truncate to the same text.\n const report = (message: string, current: number) =>\n traceWriter.write(Trace.StatusUpdate, {\n message,\n progress: { key: progressKey, current, total: GENERATE_PHASES },\n });\n\n return yield* Effect.gen(function* () {\n report(label, 0);\n const { owner, repo, number } = pullRequest;\n const credentials = Layer.succeed(GitHubApi.GitHubCredentials, { token: yield* githubToken() });\n\n report(`${label}: reading the pull request`, 1);\n const remote = yield* GitHubApi.fetchPullRequest(owner, repo, number).pipe(Effect.provide(credentials));\n\n report(`${label}: fetching the diff`, 2);\n const diff = yield* GitHubApi.fetchPullRequestDiff(owner, repo, number).pipe(Effect.provide(credentials));\n\n const result = yield* generateWalkthrough({\n pullRequest,\n remote: {\n title: remote.title,\n description: remote.body ?? undefined,\n baseBranch: remote.base?.ref,\n headBranch: remote.head?.ref,\n commit: remote.head?.sha,\n },\n diff,\n force,\n model: MODEL,\n report,\n narrate: (prompt) =>\n LanguageModel.generateText({ prompt }).pipe(\n Effect.map((response) => response.text),\n Effect.provide(AiService.languageModel(MODEL).pipe(Layer.orDie)),\n Effect.orDie,\n ),\n });\n\n return {\n walkthrough: Ref.make(result.walkthrough),\n generated: result.generated,\n covered: result.covered,\n total: result.total,\n };\n }).pipe(\n // The meter stays open forever without a terminal, and the sentinel is all the UI shows —\n // the failure itself goes to the log.\n // `onExit`, not `tapError`: the model call and the database both surface as DEFECTS rather\n // than typed errors, and interruption raises neither. A meter with no terminal stays open\n // and leaves the action disabled.\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (Exit.isSuccess(exit)) {\n return;\n }\n const terminal = Cause.hasInterrupts(exit.cause) ? Progress.STATUS_CANCELLED : Progress.STATUS_FAILED;\n report(terminal, GENERATE_PHASES);\n }),\n ),\n Effect.provide(Database.layer(db)),\n );\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAM,QAAQ;;;;;;;AAQd,IAAM,UACJ,gBAAgB,oBAAoB,KAClC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,gBAAgB,SAAS;CAG3D,MAAM,cAAc,eAAe;CACnC,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW,IAAI,KAAA;CACxD,IAAI,CAAC,eAAe,CAAC,IAGnB,OAAO,OAAO,OAAO,IAAI,IAAI,+BAA+B,CAAC;CAG/D,MAAM,cAAc,OAAO,MAAM;CACjC,MAAM,cAAc,gBAAgB,6BAA6B,WAAW;CAC5E,MAAM,QAAQ,kBAAkB,YAAY,UAAU,WAAW;CAEjE,MAAM,UAAU,SAAiB,YAC/B,YAAY,MAAM,MAAM,cAAc;EACpC;EACA,UAAU;GAAE,KAAK;GAAa;GAAS,OAAA;EAAuB;CAChE,CAAC;CAEH,OAAO,OAAO,OAAO,IAAI,aAAa;EACpC,OAAO,OAAO,CAAC;EACf,MAAM,EAAE,OAAO,MAAM,WAAW;EAChC,MAAM,cAAc,MAAM,QAAQA,mBAA6B,EAAE,OAAO,OAAO,YAAY,EAAE,CAAC;EAE9F,OAAO,GAAG,MAAM,6BAA6B,CAAC;EAC9C,MAAM,SAAS,OAAOC,iBAA2B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;EAEtG,OAAO,GAAG,MAAM,sBAAsB,CAAC;EACvC,MAAM,OAAO,OAAOC,qBAA+B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;EAExG,MAAM,SAAS,OAAO,oBAAoB;GACxC;GACA,QAAQ;IACN,OAAO,OAAO;IACd,aAAa,OAAO,QAAQ,KAAA;IAC5B,YAAY,OAAO,MAAM;IACzB,YAAY,OAAO,MAAM;IACzB,QAAQ,OAAO,MAAM;GACvB;GACA;GACA;GACA,OAAO;GACP;GACA,UAAU,WACR,cAAc,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,KACrC,OAAO,KAAK,aAAa,SAAS,IAAI,GACtC,OAAO,QAAQ,UAAU,cAAc,KAAK,CAAC,CAAC,KAAK,MAAM,KAAK,CAAC,GAC/D,OAAO,KACT;EACJ,CAAC;EAED,OAAO;GACL,aAAa,IAAI,KAAK,OAAO,WAAW;GACxC,WAAW,OAAO;GAClB,SAAS,OAAO;GAChB,OAAO,OAAO;EAChB;CACF,CAAC,CAAC,CAAC,KAMD,OAAO,QAAQ,SACb,OAAO,WAAW;EAChB,IAAI,KAAK,UAAU,IAAI,GACrB;EAEF,MAAM,WAAW,MAAM,cAAc,KAAK,KAAK,IAAI,SAAS,mBAAmB,SAAS;EACxF,OAAO,UAAA,CAAyB;CAClC,CAAC,CACH,GACA,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CACnC;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-get-pull-request-diff.mjs","names":[],"sources":["../../src/operations/get-pull-request-diff.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetPullRequestDiff> =\n GitHubOperation.GetPullRequestDiff.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const [before, diff, after] = yield* Effect.all(\n [\n GitHubApi.fetchPullRequest(owner, repo, number),\n GitHubApi.fetchPullRequestDiff(owner, repo, number),\n GitHubApi.fetchPullRequest(owner, repo, number),\n ],\n { concurrency: 1 },\n ).pipe(Effect.provide(credentials));\n // A push between the reads would pair the diff with another commit's line numbers, so the\n // commit is only reported when the head held still across the diff.\n const commit = before.head?.sha;\n return { diff, ...(commit && commit === after.head?.sha ? { commit } : {}) };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,mBAAmB,KACjC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,CAAC,QAAQ,MAAM,SAAS,OAAO,OAAO,IAC1C;EACE,iBAA2B,OAAO,MAAM,MAAM;EAC9C,qBAA+B,OAAO,MAAM,MAAM;EAClD,iBAA2B,OAAO,MAAM,MAAM;CAChD,GACA,EAAE,aAAa,EAAE,CACnB,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CAGlC,MAAM,SAAS,OAAO,MAAM;CAC5B,OAAO;EAAE;EAAM,GAAI,UAAU,WAAW,MAAM,MAAM,MAAM,EAAE,OAAO,IAAI,CAAC;CAAG;AAC7E,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-get-pull-request-diff.mjs","names":["GitHubApi.fetchPullRequest","GitHubApi.fetchPullRequestDiff"],"sources":["../../src/operations/get-pull-request-diff.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';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest } from './pull-request.ts';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetPullRequestDiff> =\n GitHubOperation.GetPullRequestDiff.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const [before, diff, after] = yield* Effect.all(\n [\n GitHubApi.fetchPullRequest(owner, repo, number),\n GitHubApi.fetchPullRequestDiff(owner, repo, number),\n GitHubApi.fetchPullRequest(owner, repo, number),\n ],\n { concurrency: 1 },\n ).pipe(Effect.provide(credentials));\n // A push between the reads would pair the diff with another commit's line numbers, so the\n // commit is only reported when the head held still across the diff.\n const commit = before.head?.sha;\n return { diff, ...(commit && commit === after.head?.sha ? { commit } : {}) };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAcA,IAAM,UACJ,gBAAgB,mBAAmB,KACjC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,CAAC,QAAQ,MAAM,SAAS,OAAO,OAAO,IAC1C;EACEA,iBAA2B,OAAO,MAAM,MAAM;EAC9CC,qBAA+B,OAAO,MAAM,MAAM;EAClDD,iBAA2B,OAAO,MAAM,MAAM;CAChD,GACA,EAAE,aAAa,EAAE,CACnB,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CAGlC,MAAM,SAAS,OAAO,MAAM;CAC5B,OAAO;EAAE;EAAM,GAAI,UAAU,WAAW,MAAM,MAAM,MAAM,EAAE,OAAO,IAAI,CAAC;CAAG;AAC7E,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-get-pull-request-status.mjs","names":[],"sources":["../../src/operations/get-pull-request-status.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 { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest, summarizeCheckRuns, summarizeReviews, toCheckRun } from './pull-request.ts';\n\nconst toState = (pull: GitHubApi.GitHubPull): PullRequest.State =>\n pull.merged || pull.merged_at ? 'merged' : pull.draft ? 'draft' : pull.state === 'closed' ? 'closed' : 'open';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetPullRequestStatus> =\n GitHubOperation.GetPullRequestStatus.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const pull = yield* GitHubApi.fetchPullRequest(owner, repo, number).pipe(Effect.provide(credentials));\n const commit = pull.head?.sha;\n const runs = commit\n ? yield* GitHubApi.fetchCheckRuns(owner, repo, commit).pipe(Effect.provide(credentials))\n : [];\n const reviews = yield* GitHubApi.fetchReviews(owner, repo, number).pipe(Effect.provide(credentials));\n return {\n state: toState(pull),\n title: pull.title,\n commit,\n ...(pull.body ? { body: pull.body } : {}),\n ...summarizeCheckRuns(runs),\n runs: runs.map(toCheckRun),\n ...summarizeReviews(reviews),\n };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAeA,IAAM,WAAW,SACf,KAAK,UAAU,KAAK,YAAY,WAAW,KAAK,QAAQ,UAAU,KAAK,UAAU,WAAW,WAAW;AAEzG,IAAM,UACJ,gBAAgB,qBAAqB,KACnC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,OAAO,iBAA2B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACpG,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,OAAO,SACT,OAAO,eAAyB,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC,IACrF,CAAC;CACL,MAAM,UAAU,OAAO,aAAuB,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACnG,OAAO;EACL,OAAO,QAAQ,IAAI;EACnB,OAAO,KAAK;EACZ;EACA,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACvC,GAAG,mBAAmB,IAAI;EAC1B,MAAM,KAAK,IAAI,UAAU;EACzB,GAAG,iBAAiB,OAAO;CAC7B;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-get-pull-request-status.mjs","names":["GitHubApi.fetchPullRequest","GitHubApi.fetchCheckRuns","GitHubApi.fetchReviews"],"sources":["../../src/operations/get-pull-request-status.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 { type PullRequest } from '@dxos/types';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\nimport { resolvePullRequest, summarizeCheckRuns, summarizeReviews, toCheckRun } from './pull-request.ts';\n\nconst toState = (pull: GitHubApi.GitHubPull): PullRequest.State =>\n pull.merged || pull.merged_at ? 'merged' : pull.draft ? 'draft' : pull.state === 'closed' ? 'closed' : 'open';\n\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetPullRequestStatus> =\n GitHubOperation.GetPullRequestStatus.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ pullRequest: ref }) {\n const { pullRequest, credentials } = yield* resolvePullRequest(ref);\n const { owner, repo, number } = pullRequest;\n const pull = yield* GitHubApi.fetchPullRequest(owner, repo, number).pipe(Effect.provide(credentials));\n const commit = pull.head?.sha;\n const runs = commit\n ? yield* GitHubApi.fetchCheckRuns(owner, repo, commit).pipe(Effect.provide(credentials))\n : [];\n const reviews = yield* GitHubApi.fetchReviews(owner, repo, number).pipe(Effect.provide(credentials));\n return {\n state: toState(pull),\n title: pull.title,\n commit,\n ...(pull.body ? { body: pull.body } : {}),\n ...summarizeCheckRuns(runs),\n runs: runs.map(toCheckRun),\n ...summarizeReviews(reviews),\n };\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;AAeA,IAAM,WAAW,SACf,KAAK,UAAU,KAAK,YAAY,WAAW,KAAK,QAAQ,UAAU,KAAK,UAAU,WAAW,WAAW;AAEzG,IAAM,UACJ,gBAAgB,qBAAqB,KACnC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,aAAa,OAAO;CACzC,MAAM,EAAE,aAAa,gBAAgB,OAAO,mBAAmB,GAAG;CAClE,MAAM,EAAE,OAAO,MAAM,WAAW;CAChC,MAAM,OAAO,OAAOA,iBAA2B,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACpG,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,OAAO,SACT,OAAOC,eAAyB,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC,IACrF,CAAC;CACL,MAAM,UAAU,OAAOC,aAAuB,OAAO,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CACnG,OAAO;EACL,OAAO,QAAQ,IAAI;EACnB,OAAO,KAAK;EACZ;EACA,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACvC,GAAG,mBAAmB,IAAI;EAC1B,MAAM,KAAK,IAAI,UAAU;EACzB,GAAG,iBAAiB,OAAO;CAC7B;AACF,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-get-repositories.mjs","names":[],"sources":["../../src/operations/get-repositories.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';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Obj } from '@dxos/echo';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Discovery only — list GitHub repositories reachable from the connection's\n * token. Read-only: NO local Projects are created here. Materialization is\n * handled by the connector's `materializeTarget` when a binding is created.\n *\n * Output is sorted by `full_name` (case-insensitive) so the picker is stable\n * regardless of GitHub's response order.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetGitHubRepositories> =\n GitHubOperation.GetGitHubRepositories.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ connection }) {\n // TODO(wittjosiah): Mirror the Trello pattern — derive the db from the input ref's\n // target until the OperationInvoker has a `databaseResolver` and the operation\n // can declare `services: [Database.Service]` directly.\n const target = connection.target;\n const db = target ? Obj.getDatabase(target) : undefined;\n if (!db) {\n return yield* Effect.die(new Error('No database for connection ref.'));\n }\n\n return yield* Effect.gen(function* () {\n const remoteRepos = yield* GitHubApi.fetchUserRepos();\n const sorted = [...remoteRepos].sort((left, right) =>\n left.full_name.toLowerCase().localeCompare(right.full_name.toLowerCase()),\n );\n const targets = sorted.map((repo) => ({\n id: String(repo.id),\n name: repo.full_name,\n description: repo.description ?? undefined,\n }));\n return { targets };\n }).pipe(Effect.provide(Layer.provideMerge(Database.layer(db), GitHubApi.fromConnection(connection))));\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,IAAM,UACJ,gBAAgB,sBAAsB,KACpC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,cAAc;CAInC,MAAM,SAAS,WAAW;CAC1B,MAAM,KAAK,SAAS,IAAI,YAAY,MAAM,IAAI,KAAA;CAC9C,IAAI,CAAC,IACH,OAAO,OAAO,OAAO,oBAAI,IAAI,MAAM,iCAAiC,CAAC;CAGvE,OAAO,OAAO,OAAO,IAAI,aAAa;EAUpC,OAAO,EAAE,SARM,CAAC,GAAG,OADQ,eAAyB,CACtB,CAAC,CAAC,MAAM,MAAM,UAC1C,KAAK,UAAU,YAAY,CAAC,CAAC,cAAc,MAAM,UAAU,YAAY,CAAC,CAE1D,CAAA,CAAO,KAAK,UAAU;GACpC,IAAI,OAAO,KAAK,EAAE;GAClB,MAAM,KAAK;GACX,aAAa,KAAK,eAAe,KAAA;EACnC,EACS,EAAQ;CACnB,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,aAAa,SAAS,MAAM,EAAE,GAAG,eAAyB,UAAU,CAAC,CAAC,CAAC;AACtG,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
1
+ {"version":3,"file":"chunk-get-repositories.mjs","names":["GitHubApi.fetchUserRepos","GitHubApi.fromConnection"],"sources":["../../src/operations/get-repositories.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';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Obj } from '@dxos/echo';\n\nimport { GitHubOperation } from '#types';\n\nimport { GitHubApi } from '../services/index.ts';\n\n/**\n * Discovery only — list GitHub repositories reachable from the connection's\n * token. Read-only: NO local Projects are created here. Materialization is\n * handled by the connector's `materializeTarget` when a binding is created.\n *\n * Output is sorted by `full_name` (case-insensitive) so the picker is stable\n * regardless of GitHub's response order.\n */\nconst handler: Operation.WithHandler<typeof GitHubOperation.GetGitHubRepositories> =\n GitHubOperation.GetGitHubRepositories.pipe(\n Operation.withHandler(\n Effect.fn(function* ({ connection }) {\n // TODO(wittjosiah): Mirror the Trello pattern — derive the db from the input ref's\n // target until the OperationInvoker has a `databaseResolver` and the operation\n // can declare `services: [Database.Service]` directly.\n const target = connection.target;\n const db = target ? Obj.getDatabase(target) : undefined;\n if (!db) {\n return yield* Effect.die(new Error('No database for connection ref.'));\n }\n\n return yield* Effect.gen(function* () {\n const remoteRepos = yield* GitHubApi.fetchUserRepos();\n const sorted = [...remoteRepos].sort((left, right) =>\n left.full_name.toLowerCase().localeCompare(right.full_name.toLowerCase()),\n );\n const targets = sorted.map((repo) => ({\n id: String(repo.id),\n name: repo.full_name,\n description: repo.description ?? undefined,\n }));\n return { targets };\n }).pipe(Effect.provide(Layer.provideMerge(Database.layer(db), GitHubApi.fromConnection(connection))));\n }, Effect.provide(FetchHttpClient.layer)),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,IAAM,UACJ,gBAAgB,sBAAsB,KACpC,UAAU,YACR,OAAO,GAAG,WAAW,EAAE,cAAc;CAInC,MAAM,SAAS,WAAW;CAC1B,MAAM,KAAK,SAAS,IAAI,YAAY,MAAM,IAAI,KAAA;CAC9C,IAAI,CAAC,IACH,OAAO,OAAO,OAAO,oBAAI,IAAI,MAAM,iCAAiC,CAAC;CAGvE,OAAO,OAAO,OAAO,IAAI,aAAa;EAUpC,OAAO,EAAE,SARM,CAAC,GAAG,OADQA,eAAyB,CACtB,CAAC,CAAC,MAAM,MAAM,UAC1C,KAAK,UAAU,YAAY,CAAC,CAAC,cAAc,MAAM,UAAU,YAAY,CAAC,CAE1D,CAAA,CAAO,KAAK,UAAU;GACpC,IAAI,OAAO,KAAK,EAAE;GAClB,MAAM,KAAK;GACX,aAAa,KAAK,eAAe,KAAA;EACnC,EACS,EAAQ;CACnB,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,MAAM,aAAa,SAAS,MAAM,EAAE,GAAGC,eAAyB,UAAU,CAAC,CAAC,CAAC;AACtG,GAAG,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAC1C,CACF"}
@@ -347,6 +347,7 @@ var fetchReviews = (owner, repo, number) => githubPages(() => HttpClientRequest.
347
347
  /** POST /repos/{owner}/{repo}/issues/{number}/comments — a conversation comment, which a pull request shares with issues. */
348
348
  var createIssueComment = (owner, repo, issueNumber, body) => githubWrite(() => HttpClientRequest.post(`${GITHUB_API_BASE}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}/comments`), { body }, GitHubCommentSchema);
349
349
  var GitHubCheckRunSchema = Schema.Struct({
350
+ id: Schema.Number.pipe(Schema.optional),
350
351
  name: Schema.String,
351
352
  /** `queued`, `in_progress` or `completed`. */
352
353
  status: Schema.String,