Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a20280a
Add provider-aware pull-request viewed files
rynfar Sep 24, 2026
e53f289
Bind viewed-file marks to displayed diff sections and current account
rynfar Sep 24, 2026
c910905
Fence viewed-file actions by displayed account and mark digest
rynfar Sep 24, 2026
2b0a7b2
fix: pin GitHub viewed-file actions to one credential
rynfar Sep 24, 2026
6dbc353
fix: verify pinned viewer on explicit host and surface read failures
rynfar Sep 24, 2026
8a58429
docs: clarify viewed-file read failure state
rynfar Sep 24, 2026
00c7676
style(server): format viewed-files provider paths
rynfar Sep 24, 2026
844ac40
fix(server): encode viewed-file lane key through Schema
rynfar Sep 24, 2026
e7e1c0f
fix(web): bind viewed-file writes to committed PR scope
rynfar Sep 24, 2026
466267e
Start provider event worker before service exposure
rynfar Sep 24, 2026
5cc7cb3
Merge commit '466267ea1e12d1825adedccdbe57ffd0a055ecfa' into reconcil…
rynfar Sep 24, 2026
f214e30
fix(server): protect generated thread titles with persisted intent
rynfar Sep 24, 2026
b3e78f1
Merge commit '5cc7cb3ae209eb8911483e634ee69102ca7e9d83' into feat/thr…
rynfar Sep 24, 2026
a46c4b4
test(server): preserve imported and legacy title behavior
rynfar Sep 24, 2026
7887c92
fix(server): apply title intent to provider metadata
rynfar Sep 24, 2026
ce7c6f6
test(server): use reactor harness for response dispatches
rynfar Sep 24, 2026
07f289d
fix(server): redact title generation failure logs
rynfar Sep 24, 2026
ad4bc67
test(server): include title state in thread projection fixture
rynfar Sep 24, 2026
2918183
Merge pylon into viewed-files stack and preserve migration lineage
rynfar Sep 25, 2026
7882762
Merge viewed-files prerequisite and advance title migration
rynfar Sep 25, 2026
cea0843
Merge remote-tracking branch 'origin/upstream/2026-09-24-forgejo-gite…
rynfar Sep 25, 2026
93300a8
Merge remote-tracking branch 'origin/upstream/2026-09-24-pr-viewed-fi…
rynfar Sep 25, 2026
360f814
Merge remote-tracking branch 'origin/pylon' into upstream/2026-09-24-…
rynfar Sep 26, 2026
82795d3
Merge branch 'upstream/2026-09-24-pr-viewed-files' of https://github.…
rynfar Sep 26, 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
5 changes: 3 additions & 2 deletions apps/mobile/src/features/review/reviewModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { parsePatchFiles } from "@pierre/diffs/utils/parsePatchFiles";
import type { ChangeTypes, FileDiffMetadata } from "@pierre/diffs/types";
import type { OrchestrationCheckpointSummary, ReviewDiffPreviewSource } from "@t3tools/contracts";
import { unquoteGitPatchPath } from "@t3tools/shared/gitPatchPath";
import * as Arr from "effect/Array";
import { pipe } from "effect/Function";
import * as Order from "effect/Order";
Expand Down Expand Up @@ -372,8 +373,8 @@ function buildRenderableRows(file: FileDiffMetadata): ReadonlyArray<ReviewRender
}

function mapRenderableFile(file: FileDiffMetadata): ReviewRenderableFile {
const path = file.name || file.prevName || "";
const previousPath = file.prevName || null;
const path = unquoteGitPatchPath(file.name || file.prevName || "");
const previousPath = file.prevName ? unquoteGitPatchPath(file.prevName) : null;
const additions = file.hunks.reduce((total, hunk) => total + hunk.additionLines, 0);
const deletions = file.hunks.reduce((total, hunk) => total + hunk.deletionLines, 0);
const cacheKey = file.cacheKey ?? `${previousPath ?? "none"}:${path}:${file.type}`;
Expand Down
1 change: 1 addition & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@sigstore/core": "3.2.1",
"@sigstore/tuf": "4.0.0",
"@sigstore/verify": "3.0.0",
"diff": "8.0.3",
"effect": "catalog:",
"msgpackr-extract": "3.0.4",
"node-pty": "^1.1.0",
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/auth/RpcAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const RPC_REQUIRED_SCOPES = {
[WS_METHODS.pullRequestsActivity]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsThreadComments]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsDiffFileContents]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsFilesViewed]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRunAction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsUpdate]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsComment]: AuthOrchestrationOperateScope,
Expand All @@ -111,6 +112,7 @@ export const RPC_REQUIRED_SCOPES = {
[WS_METHODS.pullRequestsReplyToThread]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetThreadResolution]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetReaction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetFilesViewed]: AuthOrchestrationOperateScope,
// Read scope like the reads it un-caches: refreshing is part of reading, and a read-only
// client pressing refresh must not be told it may not look again.
[WS_METHODS.pullRequestsInvalidate]: AuthOrchestrationReadScope,
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/git/GitManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): {

return {
service: {
snapshotCredential: () => Effect.die("Unexpected credential snapshot in GitManager test"),
execute,
listOpenPullRequests: (input) =>
execute({
Expand Down
7 changes: 7 additions & 0 deletions apps/server/src/orchestration/Layers/ProjectionPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
threadId: event.payload.threadId,
projectId: event.payload.projectId,
title: event.payload.title,
titleState: event.payload.titleState ?? null,
modelSelection: event.payload.modelSelection,
runtimeMode: event.payload.runtimeMode,
interactionMode: event.payload.interactionMode,
Expand Down Expand Up @@ -649,6 +650,9 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
yield* projectionThreadRepository.upsert({
...existingRow.value,
archivedAt: event.payload.archivedAt,
...(event.payload.titleState !== undefined
? { titleState: event.payload.titleState }
: {}),
titleRegenerationRequestId: null,
titleRegenerationStartedAt: null,
updatedAt: event.payload.updatedAt,
Expand Down Expand Up @@ -803,6 +807,9 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
yield* projectionThreadRepository.upsert({
...existingRow.value,
...(event.payload.title !== undefined ? { title: event.payload.title } : {}),
...(event.payload.titleState !== undefined
? { titleState: event.payload.titleState }
: {}),
...(event.payload.activeOrderKey !== undefined
? { activeOrderKey: event.payload.activeOrderKey }
: {}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
type AgentSessionImportSource,
ChatAttachment,
CommandId,
ComposerContextId,
CheckpointRef,
EventId,
Expand Down Expand Up @@ -510,6 +511,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => {
pinOrderKey: "gm",
activeOrderKey: "hq",
titleRegeneration: null,
titleState: null,
continuedFromThreadId: null,
deletedAt: null,
messages: [
Expand Down Expand Up @@ -646,6 +648,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => {
pinOrderKey: "gm",
activeOrderKey: "hq",
titleRegeneration: null,
titleState: null,
continuedFromThreadId: null,
session: {
threadId: ThreadId.make("thread-1"),
Expand Down Expand Up @@ -781,7 +784,22 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => {
id: ThreadId.make("thread-1"),
projectId: asProjectId("project-1"),
title: "Thread 1",
session: snapshot.threads[0]?.session,
titleState: null,
session: snapshot.threads[0]?.session ?? null,
});
}

yield* sql`
UPDATE projection_threads
SET title_state_json = '{"source":"manual","version":"cmd-manual-title"}'
WHERE thread_id = 'thread-1'
`;
const ownedContext = yield* snapshotQuery.getThreadRuntimeContext(ThreadId.make("thread-1"));
assert.equal(ownedContext._tag, "Some");
if (ownedContext._tag === "Some") {
assert.deepEqual(ownedContext.value.titleState, {
source: "manual",
version: CommandId.make("cmd-manual-title"),
});
}

Expand Down
16 changes: 16 additions & 0 deletions apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
ModelSelection,
ProjectId,
ThreadLinkedPullRequest,
ThreadTitleState,
ThreadId,
ThreadPullRequestSnapshot,
ThreadPullRequestStack,
Expand Down Expand Up @@ -139,6 +140,7 @@ const ProjectionThreadPullRequestDbRowSchema = ProjectionThreadPullRequest.mapFi
const ProjectionThreadDbRowSchema = ProjectionThread.mapFields(
Struct.assign({
modelSelection: Schema.fromJsonString(ModelSelection),
titleState: Schema.NullOr(Schema.fromJsonString(ThreadTitleState)),
linkedPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)),
branchPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)),
}),
Expand Down Expand Up @@ -171,6 +173,7 @@ const ProjectionThreadRuntimeContextDbRowSchema = Schema.Struct({
id: ThreadId,
projectId: ProjectId,
title: Schema.String,
titleState: Schema.NullOr(Schema.fromJsonString(ThreadTitleState)),
session: Schema.NullOr(ProjectionThreadSessionDbRowSchema),
});
const ProjectionCheckpointDbRowSchema = ProjectionCheckpoint.mapFields(
Expand Down Expand Up @@ -700,6 +703,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
thread_id AS "threadId",
project_id AS "projectId",
title,
title_state_json AS "titleState",
model_selection_json AS "modelSelection",
runtime_mode AS "runtimeMode",
interaction_mode AS "interactionMode",
Expand Down Expand Up @@ -744,6 +748,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
thread_id AS "threadId",
project_id AS "projectId",
title,
title_state_json AS "titleState",
model_selection_json AS "modelSelection",
runtime_mode AS "runtimeMode",
interaction_mode AS "interactionMode",
Expand Down Expand Up @@ -790,6 +795,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
thread_id AS "threadId",
project_id AS "projectId",
title,
title_state_json AS "titleState",
model_selection_json AS "modelSelection",
runtime_mode AS "runtimeMode",
interaction_mode AS "interactionMode",
Expand Down Expand Up @@ -1442,6 +1448,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
thread_id AS "threadId",
project_id AS "projectId",
title,
title_state_json AS "titleState",
model_selection_json AS "modelSelection",
runtime_mode AS "runtimeMode",
interaction_mode AS "interactionMode",
Expand Down Expand Up @@ -1510,6 +1517,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
threads.thread_id AS id,
threads.project_id AS "projectId",
threads.title,
threads.title_state_json AS "titleState",
sessions.thread_id AS "threadId",
sessions.status,
sessions.provider_name AS "providerName",
Expand Down Expand Up @@ -1551,6 +1559,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
id: row.id,
projectId: row.projectId,
title: row.title,
titleState: row.titleState,
session: row.threadId === null ? null : row,
})),
),
Expand Down Expand Up @@ -2766,6 +2775,7 @@ pending_approval_requests AS (
pinOrderKey: row.pinOrderKey ?? null,
activeOrderKey: row.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(row),
titleState: row.titleState,
deletedAt: row.deletedAt,
messages: messagesByThread.get(row.threadId) ?? [],
proposedPlans: proposedPlansByThread.get(row.threadId) ?? [],
Expand Down Expand Up @@ -3016,6 +3026,7 @@ pending_approval_requests AS (
pinOrderKey: row.pinOrderKey ?? null,
activeOrderKey: row.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(row),
titleState: row.titleState,
deletedAt: row.deletedAt,
messages: [],
proposedPlans: proposedPlansByThread.get(row.threadId) ?? [],
Expand Down Expand Up @@ -3177,6 +3188,7 @@ pending_approval_requests AS (
pinOrderKey: row.pinOrderKey ?? null,
activeOrderKey: row.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(row),
titleState: row.titleState,
session: sessionByThread.get(row.threadId) ?? null,
latestUserMessageAt: row.latestUserMessageAt,
hasPendingApprovals: row.pendingApprovalCount > 0,
Expand Down Expand Up @@ -3348,6 +3360,7 @@ pending_approval_requests AS (
pinOrderKey: row.pinOrderKey ?? null,
activeOrderKey: row.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(row),
titleState: row.titleState,
session: sessionByThread.get(row.threadId) ?? null,
latestUserMessageAt: row.latestUserMessageAt,
hasPendingApprovals: row.pendingApprovalCount > 0,
Expand Down Expand Up @@ -3728,6 +3741,7 @@ pending_approval_requests AS (
pinOrderKey: threadRow.value.pinOrderKey ?? null,
activeOrderKey: threadRow.value.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(threadRow.value),
titleState: threadRow.value.titleState,
session: Option.isSome(sessionRow) ? mapSessionRow(sessionRow.value) : null,
latestUserMessageAt: threadRow.value.latestUserMessageAt,
hasPendingApprovals: threadRow.value.pendingApprovalCount > 0,
Expand Down Expand Up @@ -3757,6 +3771,7 @@ pending_approval_requests AS (
id: row.id,
projectId: row.projectId,
title: row.title,
titleState: row.titleState,
session: row.session === null ? null : mapSessionRow(row.session),
}));
});
Expand Down Expand Up @@ -4046,6 +4061,7 @@ pending_approval_requests AS (
pinOrderKey: threadRow.value.pinOrderKey ?? null,
activeOrderKey: threadRow.value.activeOrderKey ?? null,
titleRegeneration: mapTitleRegeneration(threadRow.value),
titleState: threadRow.value.titleState,
deletedAt: null,
messages: messageRows.map((row) => {
const message = {
Expand Down
Loading
Loading