ework-web 0.10.45 → 0.10.47
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/config.ts +0 -2
- package/src/index.ts +5 -3
- package/src/render/layout.ts +1 -2
- package/src/views/issueThread.ts +0 -1
- package/src/webhooks.ts +18 -2
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -82,7 +82,6 @@ export const configSchema = z.object({
|
|
|
82
82
|
internalAuthHook: z.string().default(""),
|
|
83
83
|
userAuthHook: z.string().default(""),
|
|
84
84
|
loginPage: z.string().default(""),
|
|
85
|
-
statusHook: z.string().default(""),
|
|
86
85
|
// Default "provider/model" string passed to `opencode run --model <X>`.
|
|
87
86
|
// Empty = let opencode pick per its own opencode.json + env. ework-daemon
|
|
88
87
|
// pushes this (or the per-project override) on every spawn to defend
|
|
@@ -193,7 +192,6 @@ export async function loadConfig(): Promise<Config> {
|
|
|
193
192
|
internalAuthHook: process.env.WORK_INTERNAL_AUTH_HOOK ?? "",
|
|
194
193
|
userAuthHook: process.env.WORK_USER_AUTH_HOOK ?? "",
|
|
195
194
|
loginPage: process.env.WORK_LOGIN_PAGE ?? "",
|
|
196
|
-
statusHook: process.env.WORK_STATUS_HOOK ?? "",
|
|
197
195
|
defaultModel: db.defaultModel ?? process.env.WORK_DEFAULT_MODEL,
|
|
198
196
|
autowireActive: process.env.WORK_AUTOWIRE_ACTIVE !== "false",
|
|
199
197
|
webhookMaxConcurrent: Number(process.env.WORK_WEBHOOK_MAX_CONCURRENT ?? "6"),
|
package/src/index.ts
CHANGED
|
@@ -89,6 +89,7 @@ import {
|
|
|
89
89
|
emitCommentEvent,
|
|
90
90
|
emitStatusChanged,
|
|
91
91
|
emitPingEvent,
|
|
92
|
+
migrateWebhookEvents,
|
|
92
93
|
listWebhooks,
|
|
93
94
|
createWebhook,
|
|
94
95
|
deleteWebhook,
|
|
@@ -156,7 +157,7 @@ async function autoWireDaemon(projectId: number, origin: string): Promise<void>
|
|
|
156
157
|
project_id: projectId,
|
|
157
158
|
url: target,
|
|
158
159
|
secret: cfg.daemonWebhookSecret,
|
|
159
|
-
events: ["issues", "issue_comment"],
|
|
160
|
+
events: ["issues", "issue_comment", "status_changed"],
|
|
160
161
|
});
|
|
161
162
|
void emitPingEvent(projectId, origin);
|
|
162
163
|
}
|
|
@@ -185,6 +186,7 @@ async function autoWireAllProjects(origin: string): Promise<void> {
|
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
void autoWireAllProjects(`http://${cfg.host}:${cfg.port}`);
|
|
189
|
+
void migrateWebhookEvents().catch((e) => log.warn("migrateWebhookEvents failed", { err: e as Error }));
|
|
188
190
|
|
|
189
191
|
const SEC_HEADERS: Record<string, string> = {
|
|
190
192
|
"content-security-policy": buildCsp(cfg),
|
|
@@ -1729,8 +1731,8 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
|
|
|
1729
1731
|
const url_ = String(form.get("url") ?? "").trim();
|
|
1730
1732
|
const secret = String(form.get("secret") ?? "");
|
|
1731
1733
|
const events = form.getAll("events") as string[];
|
|
1732
|
-
const validEvents = (events.length > 0 ? events : ["issues", "issue_comment"])
|
|
1733
|
-
.filter((e): e is WebhookEventName => e === "issues" || e === "issue_comment");
|
|
1734
|
+
const validEvents = (events.length > 0 ? events : ["issues", "issue_comment", "status_changed"])
|
|
1735
|
+
.filter((e): e is WebhookEventName => e === "issues" || e === "issue_comment" || e === "status_changed");
|
|
1734
1736
|
const wh = await createWebhook({
|
|
1735
1737
|
project_id: project.id,
|
|
1736
1738
|
url: url_,
|
package/src/render/layout.ts
CHANGED
|
@@ -17,7 +17,6 @@ export interface LayoutProps {
|
|
|
17
17
|
labels?: { id: number; name: string; color: string }[];
|
|
18
18
|
canEditLabels?: boolean;
|
|
19
19
|
aiStatus?: string;
|
|
20
|
-
statusHook?: string;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
export const THEME_CSS = `
|
|
@@ -169,7 +168,7 @@ export function renderLayout(props: LayoutProps, inner: string, initialItems: st
|
|
|
169
168
|
if (!m) return "";
|
|
170
169
|
return `<span class="ai-badge ${m.cls}">${m.label}</span>`;
|
|
171
170
|
})();
|
|
172
|
-
const haltBtnHtml = props.writesEnabled !== false && props.aiStatus
|
|
171
|
+
const haltBtnHtml = props.writesEnabled !== false && props.aiStatus !== "halted"
|
|
173
172
|
? `<button type="button" id="haltBtn" class="halt-btn" title="停止 AI 处理">⏹ 停止</button>`
|
|
174
173
|
: "";
|
|
175
174
|
return `<!doctype html>
|
package/src/views/issueThread.ts
CHANGED
|
@@ -131,7 +131,6 @@ export async function buildIssueThread(
|
|
|
131
131
|
labels: labels.map((l) => ({ id: l.id, name: l.name, color: l.color })),
|
|
132
132
|
canEditLabels: cfg.writesEnabled !== false,
|
|
133
133
|
aiStatus: issue.ai_status ?? "",
|
|
134
|
-
statusHook: cfg.statusHook ?? "",
|
|
135
134
|
},
|
|
136
135
|
safeJsonEmbed(payload),
|
|
137
136
|
displayViews.map((v) => renderCommentCard(v, cfg)).join("")
|
package/src/webhooks.ts
CHANGED
|
@@ -60,7 +60,7 @@ export interface WebhookDeliveryRow {
|
|
|
60
60
|
created_at: string;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const DEFAULT_EVENTS: WebhookEventName[] = ["issues", "issue_comment"];
|
|
63
|
+
const DEFAULT_EVENTS: WebhookEventName[] = ["issues", "issue_comment", "status_changed"];
|
|
64
64
|
const MAX_RESPONSE_LOG_BYTES = 8192;
|
|
65
65
|
const HTTP_TIMEOUT_MS = 10_000;
|
|
66
66
|
const RETRY_DELAYS_MS = [0, 2_000, 8_000];
|
|
@@ -112,7 +112,7 @@ function parseEvents(events: unknown): WebhookEventName[] {
|
|
|
112
112
|
try {
|
|
113
113
|
const arr = JSON.parse(events) as unknown[];
|
|
114
114
|
const valid = arr.filter(
|
|
115
|
-
(v): v is WebhookEventName => v === "issues" || v === "issue_comment"
|
|
115
|
+
(v): v is WebhookEventName => v === "issues" || v === "issue_comment" || v === "status_changed"
|
|
116
116
|
);
|
|
117
117
|
return valid.length > 0 ? valid : DEFAULT_EVENTS;
|
|
118
118
|
} catch {
|
|
@@ -122,6 +122,20 @@ function parseEvents(events: unknown): WebhookEventName[] {
|
|
|
122
122
|
|
|
123
123
|
// ─── CRUD ────────────────────────────────────────────────────
|
|
124
124
|
|
|
125
|
+
export async function migrateWebhookEvents(): Promise<void> {
|
|
126
|
+
const rows = await getDB().all<WebhookRow>("SELECT * FROM {{webhooks}}");
|
|
127
|
+
for (const wh of rows) {
|
|
128
|
+
const current = parseEvents(wh.events);
|
|
129
|
+
if (!current.includes("status_changed")) {
|
|
130
|
+
const updated = [...current, "status_changed"];
|
|
131
|
+
await getDB().run("UPDATE {{webhooks}} SET events = ? WHERE id = ?", [
|
|
132
|
+
JSON.stringify(updated),
|
|
133
|
+
wh.id,
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
125
139
|
export async function listWebhooks(projectId: number): Promise<WebhookRow[]> {
|
|
126
140
|
return await getDB().all<WebhookRow>("SELECT * FROM {{webhooks}} WHERE project_id = ? ORDER BY id", [projectId]);
|
|
127
141
|
}
|
|
@@ -273,6 +287,7 @@ interface PayloadIssue {
|
|
|
273
287
|
pull_request: null;
|
|
274
288
|
repository: PayloadRepository;
|
|
275
289
|
user: PayloadUser;
|
|
290
|
+
ai_status?: string;
|
|
276
291
|
}
|
|
277
292
|
|
|
278
293
|
interface PayloadComment {
|
|
@@ -404,6 +419,7 @@ function buildIssue(
|
|
|
404
419
|
pull_request: null,
|
|
405
420
|
repository: buildRepository(project, origin, model),
|
|
406
421
|
user: buildUser(issue.author, origin),
|
|
422
|
+
ai_status: issue.ai_status ?? "",
|
|
407
423
|
};
|
|
408
424
|
}
|
|
409
425
|
|