ework-daemon 0.4.38 → 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 +31 -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);
|
|
@@ -1555,6 +1574,11 @@ export class Engine {
|
|
|
1555
1574
|
|
|
1556
1575
|
for (const issue of ownedIssues) {
|
|
1557
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
|
+
}
|
|
1558
1582
|
await this.observeIssue(issue);
|
|
1559
1583
|
} catch (err) {
|
|
1560
1584
|
log.error(`engine: observer error for ${issue.trackerScopeKey}#${issue.trackerIssueId}:`, (err as Error).message);
|
|
@@ -1787,6 +1811,13 @@ export class Engine {
|
|
|
1787
1811
|
const issue = await this.store.getIssue(session.issueId);
|
|
1788
1812
|
if (!issue || issue.state === "closed") continue;
|
|
1789
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
|
+
|
|
1790
1821
|
const k = this.sessionKey(session, issue);
|
|
1791
1822
|
if (this.running.has(k)) continue;
|
|
1792
1823
|
|