Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
7014eda
feat(issues): add issue tracking core, contracts, and GitHub tracker
juliusmarminge Oct 14, 2026
d344e4b
chore(issues): refresh the lockfile for Effect 4.0.4
juliusmarminge Oct 14, 2026
cf13507
fix(server): give issue RPCs their own handler layer
juliusmarminge Oct 14, 2026
3e938b5
chore(issues): drop unused exports and register new packages in CI lists
juliusmarminge Oct 14, 2026
c306735
fix(issues): match GitHub search words apart, not as one phrase
juliusmarminge Oct 14, 2026
0e1f41c
style(issues): format the issue service
juliusmarminge Oct 14, 2026
b72ded8
fix(issues): select GitHub issue comments once in the detail query
juliusmarminge Oct 14, 2026
06b7b6c
feat(client-runtime): add issue tracking atoms and an issues capability
juliusmarminge Oct 14, 2026
7e98ff8
feat(issues): read and edit GitLab issues
juliusmarminge Oct 14, 2026
48753f6
feat(issues): read and edit Azure DevOps work items
juliusmarminge Oct 14, 2026
3996bbb
feat(web): add an Issues page with detail panel and composer
juliusmarminge Oct 14, 2026
cb3d0c5
feat(issues): read and edit Forgejo issues
juliusmarminge Oct 14, 2026
2f21e09
feat(issues): link issues to threads with a server-kept snapshot
juliusmarminge Oct 14, 2026
363a55e
chore(issues): drop unused exports and register new packages in CI lists
juliusmarminge Oct 14, 2026
d927a3b
chore(issues): drop unused exports and register new packages in CI lists
juliusmarminge Oct 14, 2026
07d751e
feat(mcp): issue tools for agents
juliusmarminge Oct 14, 2026
2176636
feat(web): show and open a thread's linked issues
juliusmarminge Oct 14, 2026
ed67534
chore(issues): drop unused exports and register new packages in CI lists
juliusmarminge Oct 14, 2026
a2de948
feat(issues): add Linear as a standalone issue tracker
juliusmarminge Oct 14, 2026
73008e5
feat(web): connect standalone issue trackers and bind projects in set…
juliusmarminge Oct 14, 2026
ffc2ba2
refactor(issues): keep Linear package internals private and drop trac…
juliusmarminge Oct 14, 2026
624e4bc
chore(issues): refresh the Linear lockfile entries for Effect 4.0.4
juliusmarminge Oct 14, 2026
322107b
chore(issues): drop unused exports and register new packages in CI lists
juliusmarminge Oct 14, 2026
1a4e4c1
test(issues): focus coverage on observable behavior
juliusmarminge Oct 19, 2026
b846a88
fix(issues): integrate tracker with current GitHub clients
juliusmarminge Oct 19, 2026
f0b32e9
fix(issues): support YAML forms and interactive writes
juliusmarminge Oct 19, 2026
2702072
fix(issues): keep valid templates when a form is malformed
juliusmarminge Oct 19, 2026
53554e6
fix(issues): preserve continuation cursors for retry
juliusmarminge Oct 19, 2026
d95de65
fix(issues): verify GitHub issue targets before writing
juliusmarminge Oct 19, 2026
b8fb68b
fix(server): deduplicate issue lists by canonical repository
juliusmarminge Oct 19, 2026
b4f989d
fix(issues): preserve duplicate reasons and skip blank form names
juliusmarminge Oct 19, 2026
d45d8dc
Merge remote-tracking branch 'github/main' into issues/1-core
juliusmarminge Oct 22, 2026
dd171e7
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 22, 2026
a559e3d
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
6906f4a
fix(issues): read Azure DevOps finished states from the project's pro…
juliusmarminge Oct 22, 2026
feea186
refactor(issues): name the issue list and GitHub reads as Effect func…
juliusmarminge Oct 22, 2026
4cb24ed
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 22, 2026
4f21bc6
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
76a2aea
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 22, 2026
d75bc47
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 22, 2026
9b346b5
refactor(web): let the React Compiler memoize the issues page
juliusmarminge Oct 22, 2026
724c6b0
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 22, 2026
61ea4fa
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
a78b4fc
refactor(issues): name thread issue writes as Effect functions
juliusmarminge Oct 22, 2026
3a4497b
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 22, 2026
6f99f93
refactor(issues): name Linear reads and writes as Effect functions
juliusmarminge Oct 22, 2026
8e601da
fix(issues): typecheck issue-tracker-core with tsc like main's packages
juliusmarminge Oct 22, 2026
30ad848
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 22, 2026
2d7ab9f
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
52b6d39
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 22, 2026
835c30b
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 22, 2026
628f6ee
fix(issues): typecheck issue-tracker-linear with tsc like main's pack…
juliusmarminge Oct 22, 2026
9ce624e
fix(web): let the React Compiler compile the issue tracker settings
juliusmarminge Oct 22, 2026
10bf7c8
chore(issues): retrigger CI after a stale conflict state
juliusmarminge Oct 22, 2026
35f2f6f
Merge remote-tracking branch 'github/main' into issues/1-core
juliusmarminge Oct 22, 2026
50eb753
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 22, 2026
6b0919c
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
8aac9ce
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 22, 2026
3b27665
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 22, 2026
361e85a
fix(issues): give blank tracker failures a detail and trace issue ope…
juliusmarminge Oct 22, 2026
4ae6d55
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 22, 2026
728a8ed
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 22, 2026
9abec72
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 22, 2026
44014a5
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 22, 2026
76d78f4
fix(web): say why loading more issues failed and keep its errors
juliusmarminge Oct 23, 2026
eb826fe
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 23, 2026
3f4a7b8
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 23, 2026
e7bf1ee
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 23, 2026
786a24e
fix(issues): give an unusable tracker's summary a detail too
juliusmarminge Oct 23, 2026
6562d68
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 23, 2026
9395d47
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 23, 2026
121cf9b
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 23, 2026
ddf3fac
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 23, 2026
25980d0
refactor(issues): share the tracker failure detail fallback
juliusmarminge Oct 23, 2026
ce38a9b
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 23, 2026
a378311
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 23, 2026
306a38b
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 23, 2026
02615e4
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 23, 2026
6c27158
fix(issues): give Linear connection failures a detail when Linear sen…
juliusmarminge Oct 23, 2026
fb10e05
refactor(issues): keep the tracker detail fallback private to the ser…
juliusmarminge Oct 23, 2026
f3ff1b3
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 23, 2026
972513d
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 23, 2026
e84e8a1
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 23, 2026
4053f99
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 23, 2026
119f15b
refactor(issues): share the tracker detail fallback with Linear conne…
juliusmarminge Oct 23, 2026
e9773e8
fix(issues): require a created GitHub issue to come back with a URL
juliusmarminge Oct 23, 2026
57d1d45
Merge branch 'issues/1-core' into issues/2-web
juliusmarminge Oct 23, 2026
c295457
Merge branch 'issues/2-web' into issues/4-git-hosts
juliusmarminge Oct 23, 2026
b192b8c
Merge branch 'issues/4-git-hosts' into issues/5-threads
juliusmarminge Oct 23, 2026
5a89e79
Merge branch 'issues/5-threads' into issues/5-linear
juliusmarminge Oct 23, 2026
20703ed
refactor(issues): generate the Linear client with graphqlgen
juliusmarminge Oct 23, 2026
c989a15
Merge remote-tracking branch 'upstream/main' into try/issue-trackers
xgooz3x Oct 24, 2026
b744b6f
fix(web): reuse open issue tabs and keep the tracker filter reachable
xgooz3x Oct 24, 2026
baaeca0
fix(issues): address CodeRabbit review on the issue trackers
xgooz3x Oct 25, 2026
24a86f8
fix(issues): address CodeRabbit's second review
xgooz3x Oct 25, 2026
36af969
fix(issues): Linear comment reactions check the comment is on the nam…
xgooz3x Oct 25, 2026
dde3de0
test(issues): cover removing a Linear reaction on a foreign comment
xgooz3x Oct 25, 2026
8431b68
chore(fork): run CI on GitHub-hosted runners
xgooz3x Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# Batch files need CRLF for cmd.exe to parse them reliably.
*.cmd text eol=crlf
*.bat text eol=crlf
# GitHub's and Expo's GraphQL schemas and the operations graphqlgen writes from them.
# GitHub's, Linear's and Expo's GraphQL schemas and the operations graphqlgen writes from them.
packages/source-control-github/schema/** linguist-generated
packages/issue-tracker-linear/schema/** linguist-generated
apps/server/schema/** linguist-generated
**/*.graphql.ts linguist-generated
23 changes: 13 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
# open: if the diff cannot be resolved, everything runs.
changes:
name: Changes
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
typecheck: ${{ steps.detect.outputs.typecheck }}
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
# when every other job passes or was skipped by `changes`.
lint:
name: Lint
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -104,14 +104,17 @@ jobs:
- name: Check generated Expo GraphQL operations
run: vp run --filter t3 generate --check

- name: Check generated Linear GraphQL operations
run: vp run --filter @t3tools/issue-tracker-linear generate --check

- name: Check
run: vp check

build:
name: Build and Typecheck
needs: changes
if: ${{ !cancelled() && (needs.changes.outputs.build != 'false' || needs.changes.outputs.typecheck != 'false') }}
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -200,7 +203,7 @@ jobs:
name: Test
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.test != 'false' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -281,7 +284,7 @@ jobs:
name: Test Web
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.test_web != 'false' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -334,7 +337,7 @@ jobs:
# ~15s for `changes`: a shard the change cannot affect stops after checkout.
test_server:
name: Test Server ${{ matrix.shard }}
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
strategy:
fail-fast: false
Expand Down Expand Up @@ -435,7 +438,7 @@ jobs:
name: Rust
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.rust != 'false' }}
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -468,7 +471,7 @@ jobs:
name: Mobile Native Static Analysis
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.mobile_native != 'false' }}
runs-on: blacksmith-6vcpu-macos-26
runs-on: macos-latest
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -498,7 +501,7 @@ jobs:
name: Release Smoke
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.release_smoke != 'false' }}
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
Expand Down Expand Up @@ -536,7 +539,7 @@ jobs:
mobile_native_static_analysis,
release_smoke,
]
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Require every job to pass
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/mobile-fingerprint-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ concurrency:
jobs:
fingerprint:
name: Native fingerprint diff
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
permissions:
contents: read
issues: write
Expand Down
2 changes: 2 additions & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"@muse-code/sdk": "1.4.6",
"@napi-rs/keyring": "^1.3.0",
"@opencode-ai/sdk": "^1.3.15",
"@t3tools/issue-tracker-core": "workspace:*",
"@t3tools/issue-tracker-linear": "workspace:*",
"@t3tools/provider-acp": "workspace:*",
"@t3tools/provider-acp-registry": "workspace:*",
"@t3tools/provider-core": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/auth/McpOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ export const layerMcpClientAuthenticator = Layer.effect(
"orchestration",
"worktree",
"pull-requests",
"issues",
]),
issuedAt,
})),
Expand Down
53 changes: 53 additions & 0 deletions apps/server/src/auth/RpcAuthorization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
AuthSettingsWriteScope,
DEFAULT_SERVER_SETTINGS,
ProviderInstanceId,
ProjectId,
IssueTrackerKind,
ThreadId,
AuthOrchestrationOperateScope,
AuthOrchestrationReadScope,
Expand Down Expand Up @@ -129,6 +131,57 @@ describe("RPC scope middleware", () => {
);
});

it.effect("allows issue reads but requires a source-control grant before commenting", () =>
Effect.gen(function* () {
const tested = [WS_METHODS.issuesList, WS_METHODS.issuesComment] as const;
const group = WsRpcGroup.omit(
...[...WsRpcGroup.requests.keys()].filter(
(tag): tag is Exclude<keyof typeof RPC_REQUIRED_SCOPES, (typeof tested)[number]> =>
!(tested as ReadonlyArray<string>).includes(tag),
),
);
const comments: string[] = [];
const handlers = Layer.mergeAll(
group.toLayerHandler(WS_METHODS.issuesList, () =>
Effect.succeed({ entries: [], trackers: [], errors: [], viewers: {}, nextCursors: {} }),
),
group.toLayerHandler(WS_METHODS.issuesComment, ({ body }) =>
Effect.sync(() => {
comments.push(body);
}),
),
);
const reader = yield* RpcTest.makeClient(group).pipe(
Effect.provide(Layer.merge(handlers, RpcAuthorization.layer([AuthOrchestrationReadScope]))),
);
const comment = {
projectId: ProjectId.make("web"),
tracker: IssueTrackerKind.make("github"),
scope: "acme/web",
key: "42",
body: "Repro attached.",
};

expect((yield* reader[WS_METHODS.issuesList]({ state: "open" })).entries).toEqual([]);
expect(yield* reader[WS_METHODS.issuesComment](comment).pipe(Effect.flip)).toMatchObject({
_tag: "EnvironmentAuthorizationError",
requiredPermission: AuthSourceControlWriteScope,
});
expect(comments).toEqual([]);

const writer = yield* RpcTest.makeClient(group).pipe(
Effect.provide(
Layer.merge(
handlers,
RpcAuthorization.layer([AuthOrchestrationReadScope, AuthSourceControlWriteScope]),
),
),
);
yield* writer[WS_METHODS.issuesComment](comment);
expect(comments).toEqual(["Repro attached."]);
}).pipe(Effect.scoped),
);

describe("settings mutation authorization", () => {
const group = WsRpcGroup.omit(
...[...WsRpcGroup.requests.keys()].filter(
Expand Down
8 changes: 8 additions & 0 deletions apps/server/src/auth/RpcAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ export const RPC_REQUIRED_SCOPES = {
[WS_METHODS.pullRequestsStack]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsLinkedThreads]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsDetail]: AuthOrchestrationReadScope,
[WS_METHODS.issuesList]: AuthOrchestrationReadScope,
[WS_METHODS.issuesDetail]: AuthOrchestrationReadScope,
[WS_METHODS.issuesComments]: AuthOrchestrationReadScope,
[WS_METHODS.issuesTemplates]: AuthOrchestrationReadScope,
[WS_METHODS.issuesCandidates]: AuthOrchestrationReadScope,
[WS_METHODS.issueTrackersList]: AuthOrchestrationReadScope,
[WS_METHODS.issueTrackersConnect]: AuthSettingsWriteScope,
[WS_METHODS.issueTrackersBindProject]: AuthSettingsWriteScope,
[WS_METHODS.pullRequestsPreview]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsChecks]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsActivity]: AuthOrchestrationReadScope,
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/environment/ServerEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ export const make = Effect.gen(function* () {
fileAttachments: { maxUploadBytes: PROVIDER_SEND_TURN_MAX_FILE_BYTES },
pullRequests: true,
pullRequestChecks: true,
issues: true,
inlineMessageContext: true,
requiredWorktreeBootstrap: true,
threadSettlement: true,
Expand Down
Loading
Loading