ework-daemon 0.4.37 → 0.4.39
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/opencode.ts +36 -0
- package/src/trackers/gitea-tracker.ts +2 -0
- package/src/trackers/types.ts +1 -0
package/package.json
CHANGED
package/src/opencode.ts
CHANGED
|
@@ -388,6 +388,25 @@ export class Engine {
|
|
|
388
388
|
} catch { /* non-critical */ }
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
private async webGateAllows(issue: Issue): Promise<{ allowed: boolean; reason: string }> {
|
|
392
|
+
const parts = issue.trackerScopeKey.split("/");
|
|
393
|
+
const owner = parts[0] ?? "";
|
|
394
|
+
const repo = parts.slice(1).join("/");
|
|
395
|
+
if (!owner || !repo) return { allowed: true, reason: "unparseable scope" };
|
|
396
|
+
const url = `${this.cfg.gitea.url}/api/v1/dispatch-state?owner=${encodeURIComponent(owner)}&repo=${encodeURIComponent(repo)}&number=${encodeURIComponent(issue.trackerIssueId)}`;
|
|
397
|
+
try {
|
|
398
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(5000), headers: { Authorization: `token ${this.cfg.gitea.token}` } });
|
|
399
|
+
if (!resp.ok) return { allowed: false, reason: `web returned ${resp.status}` };
|
|
400
|
+
const data = await resp.json() as { dispatchOff?: boolean; aiStatus?: string };
|
|
401
|
+
if (data.dispatchOff) return { allowed: false, reason: "dispatch off" };
|
|
402
|
+
if (data.aiStatus === "halted" || data.aiStatus === "dispatch_off") return { allowed: false, reason: `ai_status=${data.aiStatus}` };
|
|
403
|
+
return { allowed: true, reason: "ok" };
|
|
404
|
+
} catch (err) {
|
|
405
|
+
log.warn(`engine: web gate query failed for ${issue.trackerScopeKey}#${issue.trackerIssueId}: ${(err as Error).message} — fail-closed (skipping)`);
|
|
406
|
+
return { allowed: false, reason: `web unreachable: ${(err as Error).message}` };
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
391
410
|
setMaxConcurrent(n: number): void {
|
|
392
411
|
if (!Number.isFinite(n) || n < 1) return;
|
|
393
412
|
this.maxConcurrent = Math.floor(n);
|
|
@@ -667,6 +686,11 @@ export class Engine {
|
|
|
667
686
|
return;
|
|
668
687
|
}
|
|
669
688
|
|
|
689
|
+
if (event.dispatch_off && event.type === "issue_opened") {
|
|
690
|
+
log.info(`engine: dispatch_off (global/project) — skipping issue_opened for ${ref.trackerType}:${scopeKey}#${ref.issueId}`);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
|
|
670
694
|
if (event.type === "comment_created" && event.comment?.author) {
|
|
671
695
|
const author = event.comment.author;
|
|
672
696
|
const authorKind = event.comment.author_kind ?? "human";
|
|
@@ -1550,6 +1574,11 @@ export class Engine {
|
|
|
1550
1574
|
|
|
1551
1575
|
for (const issue of ownedIssues) {
|
|
1552
1576
|
try {
|
|
1577
|
+
const gate = await this.webGateAllows(issue);
|
|
1578
|
+
if (!gate.allowed) {
|
|
1579
|
+
log.info(`engine: observer — web gate blocked ${issue.trackerScopeKey}#${issue.trackerIssueId} (${gate.reason})`);
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1553
1582
|
await this.observeIssue(issue);
|
|
1554
1583
|
} catch (err) {
|
|
1555
1584
|
log.error(`engine: observer error for ${issue.trackerScopeKey}#${issue.trackerIssueId}:`, (err as Error).message);
|
|
@@ -1782,6 +1811,13 @@ export class Engine {
|
|
|
1782
1811
|
const issue = await this.store.getIssue(session.issueId);
|
|
1783
1812
|
if (!issue || issue.state === "closed") continue;
|
|
1784
1813
|
|
|
1814
|
+
const gate = await this.webGateAllows(issue);
|
|
1815
|
+
if (!gate.allowed) {
|
|
1816
|
+
log.info(`engine: recover — web gate blocked ${issue.trackerScopeKey}#${issue.trackerIssueId} (${gate.reason}), marking pending messages as skipped`);
|
|
1817
|
+
for (const m of msgs) await this.store.updateMessageStatus(m.id, "failed", `web gate: ${gate.reason}`);
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1785
1821
|
const k = this.sessionKey(session, issue);
|
|
1786
1822
|
if (this.running.has(k)) continue;
|
|
1787
1823
|
|
|
@@ -141,11 +141,13 @@ export class GiteaTracker implements IssueTracker {
|
|
|
141
141
|
|
|
142
142
|
const issueUser = issue.user as Record<string, string>;
|
|
143
143
|
const aiStatus = typeof issue.ai_status === "string" ? issue.ai_status : "";
|
|
144
|
+
const dispatchOff = payload.dispatch_off === true;
|
|
144
145
|
|
|
145
146
|
if (action === "opened" || action === "reopened") {
|
|
146
147
|
return {
|
|
147
148
|
type: "issue_opened",
|
|
148
149
|
ref,
|
|
150
|
+
dispatch_off: dispatchOff,
|
|
149
151
|
issue: {
|
|
150
152
|
title: issue.title as string,
|
|
151
153
|
body: (issue.body as string) ?? "",
|
package/src/trackers/types.ts
CHANGED