ework-web 0.10.67 → 0.10.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/webhooks.ts +30 -12
package/package.json
CHANGED
package/src/webhooks.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
resolveModel,
|
|
29
29
|
listLabelsForIssue,
|
|
30
30
|
getUserByLogin,
|
|
31
|
+
type UserRow,
|
|
31
32
|
type IssueRow,
|
|
32
33
|
type ProjectRow,
|
|
33
34
|
type CommentRow,
|
|
@@ -229,6 +230,9 @@ interface PayloadUser {
|
|
|
229
230
|
html_url: string;
|
|
230
231
|
is_admin: boolean;
|
|
231
232
|
language: string;
|
|
233
|
+
kind?: string;
|
|
234
|
+
display_name?: string | null;
|
|
235
|
+
is_active?: boolean;
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
interface PayloadLabel {
|
|
@@ -348,6 +352,18 @@ function buildUser(login: string, origin: string): PayloadUser {
|
|
|
348
352
|
};
|
|
349
353
|
}
|
|
350
354
|
|
|
355
|
+
function buildUserFromRow(user: UserRow, origin: string): PayloadUser {
|
|
356
|
+
return {
|
|
357
|
+
...buildUser(user.login, origin),
|
|
358
|
+
full_name: user.display_name ?? user.login,
|
|
359
|
+
email: user.email ?? `${user.login}@${new URL(origin).host ?? "localhost"}.noreply.ework`,
|
|
360
|
+
is_admin: user.is_admin === 1,
|
|
361
|
+
kind: user.kind,
|
|
362
|
+
display_name: user.display_name,
|
|
363
|
+
is_active: user.is_active === 1,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
351
367
|
function buildRepository(project: ProjectRow, origin: string, model?: string): PayloadRepository {
|
|
352
368
|
const fullName = `${project.owner}/${project.name}`;
|
|
353
369
|
const htmlUrl = `${origin}/${encodeURIComponent(project.owner)}/${encodeURIComponent(project.name)}`;
|
|
@@ -639,11 +655,6 @@ export async function emitIssueEvent(
|
|
|
639
655
|
const issue = await getIssueById(issueId);
|
|
640
656
|
if (!issue) { log.warn(`emitIssueEvent: issue ${issueId} not found — silent skip prevented`); return; }
|
|
641
657
|
|
|
642
|
-
// Web is a dumb message bus for comments — always fan out.
|
|
643
|
-
// BUT for issue_opened, dispatch state is a subscription-level switch:
|
|
644
|
-
// if dispatch is off (global/project/issue), don't emit at all.
|
|
645
|
-
// This is the "webhook switch" — downstream never sees the event.
|
|
646
|
-
// We still include dispatch_off in payload for defense-in-depth.
|
|
647
658
|
const cfg = await getConfigAll();
|
|
648
659
|
const scopeKey = `${project.owner}/${project.name}`;
|
|
649
660
|
const globalOff = cfg["dispatchEnabled"] === "false";
|
|
@@ -651,11 +662,6 @@ export async function emitIssueEvent(
|
|
|
651
662
|
const issueOff = issue.ai_status === "dispatch_off" || issue.ai_status === "halted";
|
|
652
663
|
const dispatchOff = globalOff || projectOff || issueOff;
|
|
653
664
|
|
|
654
|
-
if (action === "opened" && dispatchOff) {
|
|
655
|
-
log.info(`webhook: issue_opened suppressed (dispatch off: global=${globalOff} project=${projectOff} issue=${issueOff}) for ${scopeKey}#${issue.number}`);
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
665
|
const commentCount = await countCommentsSafe(issueId);
|
|
660
666
|
// Resolve model: project override > global default. Empty string = no
|
|
661
667
|
// override (daemon omits --model, lets opencode pick). globalDefault
|
|
@@ -666,6 +672,11 @@ export async function emitIssueEvent(
|
|
|
666
672
|
const payload = buildIssuePayload(issue, project, commentCount, action, origin, model, labels);
|
|
667
673
|
(payload as IssueEventPayload).event_id = randomUUID();
|
|
668
674
|
(payload as IssueEventPayload).dispatch_off = dispatchOff;
|
|
675
|
+
const authorUser = await getUserByLogin(issue.author);
|
|
676
|
+
if (authorUser) {
|
|
677
|
+
payload.sender = buildUserFromRow(authorUser, origin);
|
|
678
|
+
payload.issue.user = buildUserFromRow(authorUser, origin);
|
|
679
|
+
}
|
|
669
680
|
const rawBody = JSON.stringify(payload);
|
|
670
681
|
await fanOut(projectId, "issues", rawBody);
|
|
671
682
|
} catch (e) {
|
|
@@ -700,7 +711,13 @@ export async function emitCommentEvent(
|
|
|
700
711
|
const labels = await toPayloadLabels(issueId);
|
|
701
712
|
const payload = buildCommentPayload(issue, comment, project, commentCount, origin, model, labels);
|
|
702
713
|
(payload as CommentEventPayload).event_id = randomUUID();
|
|
703
|
-
(
|
|
714
|
+
if (authorUser) {
|
|
715
|
+
payload.sender = buildUserFromRow(authorUser, origin);
|
|
716
|
+
payload.comment.user = buildUserFromRow(authorUser, origin);
|
|
717
|
+
(payload as CommentEventPayload).comment.author_kind = authorUser.kind;
|
|
718
|
+
} else {
|
|
719
|
+
(payload as CommentEventPayload).comment.author_kind = "human";
|
|
720
|
+
}
|
|
704
721
|
const rawBody = JSON.stringify(payload);
|
|
705
722
|
await fanOut(projectId, "issue_comment", rawBody);
|
|
706
723
|
} catch (e) {
|
|
@@ -728,8 +745,9 @@ export async function emitStatusChanged(
|
|
|
728
745
|
const issue = await getIssueById(issueId);
|
|
729
746
|
if (!issue) { log.warn(`emitStatusChanged: issue ${issueId} not found (project=${projectId}) — silent skip prevented`); return; }
|
|
730
747
|
const commentCount = await countCommentsSafe(issueId);
|
|
748
|
+
const actorUser = await getUserByLogin(actor);
|
|
749
|
+
const sender = actorUser ? buildUserFromRow(actorUser, origin) : buildUser(actor, origin);
|
|
731
750
|
const repo = buildRepository(project, origin);
|
|
732
|
-
const sender = buildUser(actor, origin);
|
|
733
751
|
const issuePayload = buildIssue(issue, project, commentCount, origin);
|
|
734
752
|
const payload: StatusChangedPayload = {
|
|
735
753
|
event_id: randomUUID(),
|