Merge pull request #7553 from paperclipai/codex/pap-10343-operator-qol-pr

[codex] Group operator QoL fixes
This commit is contained in:
Dotta
2026-06-05 05:29:56 -10:00
committed by GitHub
25 changed files with 896 additions and 68 deletions
@@ -162,6 +162,17 @@ function shouldSupersedeRequestConfirmationOnUserComment(interaction: RequestCon
return interaction.payload.supersedeOnUserComment === true;
}
function normalizeCreateInteractionInput(input: CreateIssueThreadInteraction): CreateIssueThreadInteraction {
if (input.kind !== "request_confirmation") return input;
return {
...input,
payload: {
...input.payload,
supersedeOnUserComment: input.payload.supersedeOnUserComment ?? true,
},
};
}
function isCommentAtOrAfterInteraction(args: {
commentCreatedAt: Date | string;
interactionCreatedAt: Date | string;
@@ -272,15 +283,20 @@ function normalizeQuestionAnswers(args: {
throw unprocessable(`Question ${answer.questionId} only allows one answer`);
}
const otherText = answer.otherText?.trim() ?? "";
answerByQuestionId.set(answer.questionId, {
questionId: answer.questionId,
optionIds: uniqueOptionIds,
...(otherText ? { otherText } : {}),
});
}
for (const question of args.questions) {
const answer = answerByQuestionId.get(question.id);
if (question.required && (!answer || answer.optionIds.length === 0)) {
if (
question.required
&& (!answer || (answer.optionIds.length === 0 && !answer.otherText))
) {
throw unprocessable(`Question ${question.id} requires an answer`);
}
}
@@ -668,7 +684,7 @@ export function issueThreadInteractionService(db: Db) {
input: CreateIssueThreadInteraction,
actor: InteractionActor,
) => {
const data = createIssueThreadInteractionSchema.parse(input);
const data = normalizeCreateInteractionInput(createIssueThreadInteractionSchema.parse(input));
if (data.idempotencyKey) {
const existing = await getIdempotentInteraction({
+23
View File
@@ -241,6 +241,7 @@ export interface IssueFilters {
includePluginOperations?: boolean;
includeBlockedBy?: boolean;
includeBlockedInboxAttention?: boolean;
hasPlanDocument?: boolean;
q?: string;
limit?: number;
offset?: number;
@@ -2169,6 +2170,19 @@ function issueRef(row: Pick<IssueRow, "id" | "identifier" | "title" | "status" |
};
}
function hasPlanDocumentCondition(companyId: string, hasPlanDocument: boolean): SQL {
const existsPlanDocument = sql<boolean>`
EXISTS (
SELECT 1
FROM ${issueDocuments}
WHERE ${issueDocuments.companyId} = ${companyId}
AND ${issueDocuments.issueId} = ${issues.id}
AND ${issueDocuments.key} = 'plan'
)
`;
return hasPlanDocument ? existsPlanDocument : sql<boolean>`NOT ${existsPlanDocument}`;
}
function isoDate(value: Date | string | null | undefined): string | null {
if (!value) return null;
const date = value instanceof Date ? value : new Date(value);
@@ -2881,6 +2895,9 @@ async function blockedInboxIssueConditions(
if (filters?.originKind) conditions.push(eq(issues.originKind, filters.originKind));
if (filters?.originKindPrefix) conditions.push(like(issues.originKind, `${filters.originKindPrefix}%`));
if (filters?.originId) conditions.push(eq(issues.originId, filters.originId));
if (filters?.hasPlanDocument !== undefined) {
conditions.push(hasPlanDocumentCondition(companyId, filters.hasPlanDocument));
}
if (!shouldIncludePluginOperationIssues(filters)) conditions.push(nonPluginOperationIssueCondition());
if (filters?.labelId) {
const labeledIssueIds = await dbOrTx
@@ -3826,6 +3843,9 @@ export function issueService(db: Db) {
if (filters?.originKind) conditions.push(eq(issues.originKind, filters.originKind));
if (filters?.originKindPrefix) conditions.push(like(issues.originKind, `${filters.originKindPrefix}%`));
if (filters?.originId) conditions.push(eq(issues.originId, filters.originId));
if (filters?.hasPlanDocument !== undefined) {
conditions.push(hasPlanDocumentCondition(companyId, filters.hasPlanDocument));
}
if (!shouldIncludePluginOperationIssues(filters)) {
conditions.push(nonPluginOperationIssueCondition());
}
@@ -3989,6 +4009,9 @@ export function issueService(db: Db) {
if (filters?.originKind) conditions.push(eq(issues.originKind, filters.originKind));
if (filters?.originKindPrefix) conditions.push(like(issues.originKind, `${filters.originKindPrefix}%`));
if (filters?.originId) conditions.push(eq(issues.originId, filters.originId));
if (filters?.hasPlanDocument !== undefined) {
conditions.push(hasPlanDocumentCondition(companyId, filters.hasPlanDocument));
}
if (!shouldIncludePluginOperationIssues(filters)) conditions.push(nonPluginOperationIssueCondition());
const [row] = await db
.select({ count: sql<number>`count(*)` })