baxian 1.2.61 → 2.0.1
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/README.md +7 -4
- package/README.zh-CN.md +7 -4
- package/dist/agent/bootstrap-poller.d.ts +1 -1
- package/dist/agent/bootstrap-poller.d.ts.map +1 -1
- package/dist/agent/bootstrap-poller.js.map +1 -1
- package/dist/agent/bootstrap.d.ts +1 -1
- package/dist/agent/bootstrap.d.ts.map +1 -1
- package/dist/agent/bootstrap.js +6 -2
- package/dist/agent/bootstrap.js.map +1 -1
- package/dist/agent/branch.d.ts +1 -3
- package/dist/agent/branch.d.ts.map +1 -1
- package/dist/agent/branch.js +2 -2
- package/dist/agent/branch.js.map +1 -1
- package/dist/agent/dispatch-reconciler.d.ts +0 -1
- package/dist/agent/dispatch-reconciler.d.ts.map +1 -1
- package/dist/agent/dispatch-reconciler.js +15 -49
- package/dist/agent/dispatch-reconciler.js.map +1 -1
- package/dist/agent/manager.d.ts +212 -90
- package/dist/agent/manager.d.ts.map +1 -1
- package/dist/agent/manager.js +2983 -1574
- package/dist/agent/manager.js.map +1 -1
- package/dist/agent/net-exec.d.ts +3 -0
- package/dist/agent/net-exec.d.ts.map +1 -1
- package/dist/agent/net-exec.js +6 -0
- package/dist/agent/net-exec.js.map +1 -1
- package/dist/agent/pane-streamer-manager.d.ts +6 -6
- package/dist/agent/pane-streamer-manager.d.ts.map +1 -1
- package/dist/agent/pane-streamer-manager.js.map +1 -1
- package/dist/agent/pane-streamer.d.ts +2 -2
- package/dist/agent/pane-streamer.d.ts.map +1 -1
- package/dist/agent/pane-streamer.js +46 -36
- package/dist/agent/pane-streamer.js.map +1 -1
- package/dist/agent/phase-signal-watcher.d.ts +20 -2
- package/dist/agent/phase-signal-watcher.d.ts.map +1 -1
- package/dist/agent/phase-signal-watcher.js +135 -17
- package/dist/agent/phase-signal-watcher.js.map +1 -1
- package/dist/agent/phase-signal.d.ts +9 -7
- package/dist/agent/phase-signal.d.ts.map +1 -1
- package/dist/agent/phase-signal.js +18 -9
- package/dist/agent/phase-signal.js.map +1 -1
- package/dist/agent/preflight.d.ts +4 -1
- package/dist/agent/preflight.d.ts.map +1 -1
- package/dist/agent/preflight.js +46 -45
- package/dist/agent/preflight.js.map +1 -1
- package/dist/agent/prompt.d.ts +8 -5
- package/dist/agent/prompt.d.ts.map +1 -1
- package/dist/agent/prompt.js +34 -30
- package/dist/agent/prompt.js.map +1 -1
- package/dist/agent/repo-store.d.ts +8 -1
- package/dist/agent/repo-store.d.ts.map +1 -1
- package/dist/agent/repo-store.js +70 -15
- package/dist/agent/repo-store.js.map +1 -1
- package/dist/agent/review-transport.d.ts +20 -1
- package/dist/agent/review-transport.d.ts.map +1 -1
- package/dist/agent/review-transport.js +68 -20
- package/dist/agent/review-transport.js.map +1 -1
- package/dist/agent/root-agent-runtime.d.ts +80 -0
- package/dist/agent/root-agent-runtime.d.ts.map +1 -0
- package/dist/agent/root-agent-runtime.js +635 -0
- package/dist/agent/root-agent-runtime.js.map +1 -0
- package/dist/agent/root-recovery-coordinator.d.ts +125 -0
- package/dist/agent/root-recovery-coordinator.d.ts.map +1 -0
- package/dist/agent/root-recovery-coordinator.js +1579 -0
- package/dist/agent/root-recovery-coordinator.js.map +1 -0
- package/dist/agent/runner.d.ts +1 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +103 -7
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/tmux-probe-poller.d.ts +1 -0
- package/dist/agent/tmux-probe-poller.d.ts.map +1 -1
- package/dist/agent/tmux-probe-poller.js +16 -10
- package/dist/agent/tmux-probe-poller.js.map +1 -1
- package/dist/agent/tmux.d.ts +3 -0
- package/dist/agent/tmux.d.ts.map +1 -1
- package/dist/agent/tmux.js +11 -5
- package/dist/agent/tmux.js.map +1 -1
- package/dist/api/agents.d.ts.map +1 -1
- package/dist/api/agents.js +42 -1
- package/dist/api/agents.js.map +1 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +88 -17
- package/dist/api/config.js.map +1 -1
- package/dist/api/hosts.d.ts.map +1 -1
- package/dist/api/hosts.js +71 -15
- package/dist/api/hosts.js.map +1 -1
- package/dist/api/platform-guard.d.ts +10 -2
- package/dist/api/platform-guard.d.ts.map +1 -1
- package/dist/api/platform-guard.js +112 -10
- package/dist/api/platform-guard.js.map +1 -1
- package/dist/api/projects.d.ts.map +1 -1
- package/dist/api/projects.js +57 -16
- package/dist/api/projects.js.map +1 -1
- package/dist/api/tasks.d.ts.map +1 -1
- package/dist/api/tasks.js +21 -36
- package/dist/api/tasks.js.map +1 -1
- package/dist/app.d.ts +6 -4
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +6 -0
- package/dist/app.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +49 -7
- package/dist/cli.js.map +1 -1
- package/dist/config/hot-reload.d.ts +11 -2
- package/dist/config/hot-reload.d.ts.map +1 -1
- package/dist/config/hot-reload.js +43 -8
- package/dist/config/hot-reload.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +23 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/normalizer.d.ts.map +1 -1
- package/dist/config/normalizer.js +18 -0
- package/dist/config/normalizer.js.map +1 -1
- package/dist/config/validator.d.ts +3 -1
- package/dist/config/validator.d.ts.map +1 -1
- package/dist/config/validator.js +247 -54
- package/dist/config/validator.js.map +1 -1
- package/dist/event/handlers.d.ts.map +1 -1
- package/dist/event/handlers.js +615 -1069
- package/dist/event/handlers.js.map +1 -1
- package/dist/event/server-handlers.d.ts.map +1 -1
- package/dist/event/server-handlers.js +787 -487
- package/dist/event/server-handlers.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +99 -79
- package/dist/index.js.map +1 -1
- package/dist/platform/command-renderer.d.ts +1 -0
- package/dist/platform/command-renderer.d.ts.map +1 -1
- package/dist/platform/command-renderer.js +16 -2
- package/dist/platform/command-renderer.js.map +1 -1
- package/dist/platform/comment-cursor.d.ts +9 -0
- package/dist/platform/comment-cursor.d.ts.map +1 -1
- package/dist/platform/comment-cursor.js +63 -5
- package/dist/platform/comment-cursor.js.map +1 -1
- package/dist/platform/driver-host.d.ts.map +1 -1
- package/dist/platform/driver-host.js +0 -2
- package/dist/platform/driver-host.js.map +1 -1
- package/dist/platform/driver-spec.d.ts.map +1 -1
- package/dist/platform/driver-spec.js +17 -6
- package/dist/platform/driver-spec.js.map +1 -1
- package/dist/platform/feedback.d.ts.map +1 -1
- package/dist/platform/feedback.js +0 -9
- package/dist/platform/feedback.js.map +1 -1
- package/dist/platform/git-driver.d.ts +3 -0
- package/dist/platform/git-driver.d.ts.map +1 -1
- package/dist/platform/git-driver.js +45 -3
- package/dist/platform/git-driver.js.map +1 -1
- package/dist/platform/platform-poller.d.ts +18 -5
- package/dist/platform/platform-poller.d.ts.map +1 -1
- package/dist/platform/platform-poller.js +283 -38
- package/dist/platform/platform-poller.js.map +1 -1
- package/dist/platform/plugins/github/baxian-plugin.json +1 -1
- package/dist/platform/plugins/github/driver.json +14 -3
- package/dist/platform/plugins/github/skills/baxian-cli-gh/SKILL.md +7 -6
- package/dist/platform/plugins/github/skills/baxian-cli-gh/agents/openai.yaml +2 -0
- package/dist/platform/pr-binding.d.ts.map +1 -1
- package/dist/platform/pr-binding.js +0 -2
- package/dist/platform/pr-binding.js.map +1 -1
- package/dist/platform/pr-conversation-cache.d.ts.map +1 -0
- package/dist/platform/pr-conversation-cache.js.map +1 -0
- package/dist/platform/row-schema.d.ts.map +1 -1
- package/dist/platform/row-schema.js +1 -0
- package/dist/platform/row-schema.js.map +1 -1
- package/dist/platform/startup.d.ts +29 -1
- package/dist/platform/startup.d.ts.map +1 -1
- package/dist/platform/startup.js +82 -4
- package/dist/platform/startup.js.map +1 -1
- package/dist/platform/types.d.ts +2 -0
- package/dist/platform/types.d.ts.map +1 -1
- package/dist/platform/types.js +6 -4
- package/dist/platform/types.js.map +1 -1
- package/dist/platform/verdict-engine.d.ts.map +1 -1
- package/dist/platform/verdict-engine.js +0 -2
- package/dist/platform/verdict-engine.js.map +1 -1
- package/dist/shared/constants.d.ts +7 -1
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +5 -0
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/types.d.ts +98 -7
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +18 -0
- package/dist/shared/types.js.map +1 -1
- package/dist/skills/baxian-pr-feedback/SKILL.md +5 -15
- package/dist/skills/baxian-pr-recheck/SKILL.md +5 -44
- package/dist/skills/baxian-pr-review/SKILL.md +6 -43
- package/dist/skills/baxian-research/SKILL.md +1 -1
- package/dist/skills/baxian-server-feedback/SKILL.md +7 -5
- package/dist/skills/baxian-server-review/SKILL.md +2 -2
- package/dist/skills/baxian-signals/SKILL.md +11 -7
- package/dist/skills/baxian-task-check/SKILL.md +3 -5
- package/dist/state/agent-store.js +0 -2
- package/dist/state/agent-store.js.map +1 -1
- package/dist/state/init.d.ts.map +1 -1
- package/dist/state/init.js +1 -0
- package/dist/state/init.js.map +1 -1
- package/dist/state/lock.d.ts +6 -0
- package/dist/state/lock.d.ts.map +1 -1
- package/dist/state/lock.js +8 -0
- package/dist/state/lock.js.map +1 -1
- package/dist/state/review-store.d.ts +21 -1
- package/dist/state/review-store.d.ts.map +1 -1
- package/dist/state/review-store.js +132 -0
- package/dist/state/review-store.js.map +1 -1
- package/dist/state/root-recovery-store.d.ts +107 -0
- package/dist/state/root-recovery-store.d.ts.map +1 -0
- package/dist/state/root-recovery-store.js +400 -0
- package/dist/state/root-recovery-store.js.map +1 -0
- package/dist/state/task-store.d.ts +6 -0
- package/dist/state/task-store.d.ts.map +1 -1
- package/dist/state/task-store.js +266 -21
- package/dist/state/task-store.js.map +1 -1
- package/dist/terminal/attach.d.ts +3 -3
- package/dist/terminal/attach.d.ts.map +1 -1
- package/dist/terminal/attach.js.map +1 -1
- package/dist/terminal/stream-ws.d.ts.map +1 -1
- package/dist/terminal/stream-ws.js.map +1 -1
- package/dist/web/assets/index-BXfgaFNm.js +18 -0
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/github/mapper.d.ts +0 -9
- package/dist/github/mapper.d.ts.map +0 -1
- package/dist/github/mapper.js +0 -25
- package/dist/github/mapper.js.map +0 -1
- package/dist/github/poller.d.ts +0 -73
- package/dist/github/poller.d.ts.map +0 -1
- package/dist/github/poller.js +0 -556
- package/dist/github/poller.js.map +0 -1
- package/dist/github/pr-conversation-cache.d.ts.map +0 -1
- package/dist/github/pr-conversation-cache.js.map +0 -1
- package/dist/github/pr-conversation.d.ts +0 -7
- package/dist/github/pr-conversation.d.ts.map +0 -1
- package/dist/github/pr-conversation.js +0 -175
- package/dist/github/pr-conversation.js.map +0 -1
- package/dist/github/resolver.d.ts +0 -8
- package/dist/github/resolver.d.ts.map +0 -1
- package/dist/github/resolver.js +0 -28
- package/dist/github/resolver.js.map +0 -1
- package/dist/state/post-approve-store.d.ts +0 -23
- package/dist/state/post-approve-store.d.ts.map +0 -1
- package/dist/state/post-approve-store.js +0 -82
- package/dist/state/post-approve-store.js.map +0 -1
- package/dist/web/assets/index-CUJtd0bC.js +0 -16
- /package/dist/{github → platform}/pr-conversation-cache.d.ts +0 -0
- /package/dist/{github → platform}/pr-conversation-cache.js +0 -0
|
@@ -3,6 +3,7 @@ import { computeBackoffMs } from '../timing/backoff.js';
|
|
|
3
3
|
import { computePollerHealth } from './poller-health.js';
|
|
4
4
|
import { BRANCH_PREFIX } from '../shared/constants.js';
|
|
5
5
|
import { repoIdentityKey } from '../shared/git-url.js';
|
|
6
|
+
import { TASK_TERMINAL_STATUS_SET } from '../shared/constants.js';
|
|
6
7
|
import { DriverOpError } from './git-driver.js';
|
|
7
8
|
import { versionTimeOf } from './row-schema.js';
|
|
8
9
|
import { CommentCursorStore } from './comment-cursor.js';
|
|
@@ -11,6 +12,28 @@ import { collectValidAcks, rowBodyDigest } from './markers.js';
|
|
|
11
12
|
import { createHash } from 'node:crypto';
|
|
12
13
|
import { buildAckCarrierRows, feedbackEventTarget, scanCommentSourcesOnce } from './feedback.js';
|
|
13
14
|
import { checkPrBinding } from './pr-binding.js';
|
|
15
|
+
// TaskState 到轮询视图的唯一投影:poller 只看这些字段,其余任务状态一律不进轮询面。
|
|
16
|
+
export function platformTaskView(task) {
|
|
17
|
+
return {
|
|
18
|
+
taskId: task.id,
|
|
19
|
+
terminal: TASK_TERMINAL_STATUS_SET.has(task.status),
|
|
20
|
+
reviewMode: task.reviewMode,
|
|
21
|
+
status: task.status,
|
|
22
|
+
inReview: task.status === 'review',
|
|
23
|
+
closedUnmergedAnchor: task.closedUnmergedAnchor !== undefined && task.closedUnmergedAnchor.cleared !== true,
|
|
24
|
+
...(task.branch !== undefined ? { branch: task.branch } : {}),
|
|
25
|
+
...(task.phase !== undefined ? { phase: task.phase } : {}),
|
|
26
|
+
...(task.prNumber !== undefined ? { prNumber: task.prNumber } : {}),
|
|
27
|
+
...(task.reviewHeadAnchorSha !== undefined ? { anchorSha: task.reviewHeadAnchorSha } : {}),
|
|
28
|
+
...(task.passToken !== undefined ? { passToken: task.passToken } : {}),
|
|
29
|
+
...(task.failToken !== undefined ? { failToken: task.failToken } : {}),
|
|
30
|
+
...(task.signalToken !== undefined ? { signalToken: task.signalToken } : {}),
|
|
31
|
+
...(task.baseBranch !== undefined ? { expectedBase: task.baseBranch } : {}),
|
|
32
|
+
...(task.latestHeadSha !== undefined ? { latestHeadSha: task.latestHeadSha } : {}),
|
|
33
|
+
...(task.replyActorId !== undefined ? { replyActorId: task.replyActorId } : {}),
|
|
34
|
+
...(task.replyActorStatus !== undefined ? { replyActorStatus: task.replyActorStatus } : {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
14
37
|
// 限流后必须停止请求并退避(GitHub 平台要求,持续触发 secondary limit 会招致封禁):
|
|
15
38
|
// 命中即短路该 entry 本周期剩余工作,退避窗口内整周期跳过,成功周期重置。
|
|
16
39
|
// abort 携带此前已入列的全部失败:混合周期(如 ACCESS_DENIED → RATE_LIMIT)的真实
|
|
@@ -32,10 +55,17 @@ class CycleFailuresError extends Error {
|
|
|
32
55
|
this.name = 'CycleFailuresError';
|
|
33
56
|
}
|
|
34
57
|
}
|
|
58
|
+
class EntryRetiredError extends Error {
|
|
59
|
+
constructor() {
|
|
60
|
+
super('platform poller entry retired during reconciliation');
|
|
61
|
+
this.name = 'EntryRetiredError';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
35
64
|
const RATE_LIMIT_BACKOFF_MIN_MS = 60_000;
|
|
36
65
|
const RATE_LIMIT_BACKOFF_MAX_MS = 900_000;
|
|
37
66
|
// 与 spec §8 base 快照同一时效纪律:projectView 连续失败 ≥3 周期后缓存默认分支视为缺失。
|
|
38
67
|
const DEFAULT_BRANCH_STALE_CYCLES = 3;
|
|
68
|
+
const ADOPTION_DEFERRAL_INTERVENTION_CYCLES = 3;
|
|
39
69
|
export class PlatformPoller {
|
|
40
70
|
opts;
|
|
41
71
|
entries = [];
|
|
@@ -43,6 +73,7 @@ export class PlatformPoller {
|
|
|
43
73
|
periodicRunner;
|
|
44
74
|
isPolling = false;
|
|
45
75
|
intervalMs;
|
|
76
|
+
lifecycleHook;
|
|
46
77
|
now;
|
|
47
78
|
constructor(opts) {
|
|
48
79
|
this.opts = opts;
|
|
@@ -52,6 +83,7 @@ export class PlatformPoller {
|
|
|
52
83
|
this.entries.push({
|
|
53
84
|
...init,
|
|
54
85
|
repoKey: repoIdentityKey(init.repoUrl),
|
|
86
|
+
retired: false,
|
|
55
87
|
status: { isPolling: false, consecutiveFailures: 0 },
|
|
56
88
|
defaultBranchStale: 0,
|
|
57
89
|
observedPr: new Map(),
|
|
@@ -59,14 +91,74 @@ export class PlatformPoller {
|
|
|
59
91
|
deliveredVerdicts: new Map(),
|
|
60
92
|
loggedUndated: new Set(),
|
|
61
93
|
baseMismatch: new Map(),
|
|
94
|
+
adoptionDeferrals: new Map(),
|
|
62
95
|
});
|
|
63
96
|
}
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.
|
|
69
|
-
|
|
97
|
+
reconcile(wanted) {
|
|
98
|
+
const wantedByKey = this.indexWantedEntries(wanted);
|
|
99
|
+
this.retireUnwantedEntries(wantedByKey);
|
|
100
|
+
this.upsertWantedEntries(wantedByKey);
|
|
101
|
+
this.fireLifecycle();
|
|
102
|
+
}
|
|
103
|
+
indexWantedEntries(wanted) {
|
|
104
|
+
const wantedByKey = new Map();
|
|
105
|
+
for (const init of wanted) {
|
|
106
|
+
const key = repoIdentityKey(init.repoUrl);
|
|
107
|
+
if (!wantedByKey.has(key))
|
|
108
|
+
wantedByKey.set(key, init);
|
|
109
|
+
}
|
|
110
|
+
return wantedByKey;
|
|
111
|
+
}
|
|
112
|
+
retireUnwantedEntries(wantedByKey) {
|
|
113
|
+
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
114
|
+
if (!wantedByKey.has(this.entries[i].repoKey)) {
|
|
115
|
+
this.entries[i].retired = true;
|
|
116
|
+
this.entries.splice(i, 1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
upsertWantedEntries(wantedByKey) {
|
|
121
|
+
// Reusing repo-keyed entries keeps durable cursors and in-memory observations aligned across reloads.
|
|
122
|
+
const existingByKey = new Map(this.entries.map(e => [e.repoKey, e]));
|
|
123
|
+
for (const [key, init] of wantedByKey) {
|
|
124
|
+
const existing = existingByKey.get(key);
|
|
125
|
+
if (existing) {
|
|
126
|
+
if (existing.status.isPolling) {
|
|
127
|
+
existing.pendingInit = { projectId: init.projectId, driver: init.driver };
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.applyEntryInit(existing, init);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this.add(init);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
applyEntryInit(entry, init) {
|
|
139
|
+
if (entry.retired)
|
|
140
|
+
return;
|
|
141
|
+
entry.projectId = init.projectId;
|
|
142
|
+
const samePreflight = entry.driver.preflightIdentity !== undefined
|
|
143
|
+
&& init.driver.preflightIdentity !== undefined
|
|
144
|
+
? entry.driver.preflightIdentity === init.driver.preflightIdentity
|
|
145
|
+
: entry.driver === init.driver;
|
|
146
|
+
if (!samePreflight)
|
|
147
|
+
entry.preflightPassed = undefined;
|
|
148
|
+
entry.driver = init.driver;
|
|
149
|
+
}
|
|
150
|
+
setLifecycleHook(fn) {
|
|
151
|
+
this.lifecycleHook = fn;
|
|
152
|
+
}
|
|
153
|
+
fireLifecycle() {
|
|
154
|
+
if (!this.lifecycleHook)
|
|
155
|
+
return;
|
|
156
|
+
try {
|
|
157
|
+
this.lifecycleHook();
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error('[PlatformPoller] lifecycle hook threw:', err);
|
|
161
|
+
}
|
|
70
162
|
}
|
|
71
163
|
// 超龄即视为缺失;纯缓存读,派发路径零网络调用。
|
|
72
164
|
defaultBranchSnapshot(repoKey) {
|
|
@@ -107,6 +199,12 @@ export class PlatformPoller {
|
|
|
107
199
|
}
|
|
108
200
|
this.periodicRunner.start();
|
|
109
201
|
}
|
|
202
|
+
// 热重载改 pollIntervalMs:只调整已在运行的 runner,不替一个从未 start 的 poller 启动
|
|
203
|
+
// (启动是 index 装配的职责)。未运行时仅记下新间隔,下次 start 生效。
|
|
204
|
+
reschedule(intervalMs) {
|
|
205
|
+
this.intervalMs = intervalMs;
|
|
206
|
+
this.periodicRunner?.reschedule(intervalMs);
|
|
207
|
+
}
|
|
110
208
|
stop() {
|
|
111
209
|
this.periodicRunner?.stop();
|
|
112
210
|
}
|
|
@@ -119,11 +217,15 @@ export class PlatformPoller {
|
|
|
119
217
|
}
|
|
120
218
|
this.isPolling = true;
|
|
121
219
|
try {
|
|
122
|
-
for (const entry of this.entries) {
|
|
220
|
+
for (const entry of [...this.entries]) {
|
|
221
|
+
if (entry.retired || !this.entries.includes(entry))
|
|
222
|
+
continue;
|
|
123
223
|
try {
|
|
124
224
|
await this.pollOne(entry);
|
|
125
225
|
}
|
|
126
226
|
catch (e) {
|
|
227
|
+
if (e instanceof EntryRetiredError)
|
|
228
|
+
continue;
|
|
127
229
|
console.warn(`[PlatformPoller] entry ${entry.repoKey} failed:`, e instanceof Error ? e.message : e);
|
|
128
230
|
}
|
|
129
231
|
}
|
|
@@ -133,11 +235,15 @@ export class PlatformPoller {
|
|
|
133
235
|
}
|
|
134
236
|
}
|
|
135
237
|
async pollOne(entry) {
|
|
136
|
-
|
|
238
|
+
this.assertEntryActive(entry);
|
|
239
|
+
if (entry.rateLimit !== undefined && this.now() < entry.rateLimit.until) {
|
|
240
|
+
entry.defaultBranchStale += 1;
|
|
137
241
|
return;
|
|
242
|
+
}
|
|
138
243
|
const startedAt = this.now();
|
|
139
244
|
entry.status.isPolling = true;
|
|
140
245
|
entry.status.lastPollStartedAt = new Date(startedAt).toISOString();
|
|
246
|
+
this.fireLifecycle();
|
|
141
247
|
try {
|
|
142
248
|
if (entry.cursor === undefined) {
|
|
143
249
|
const cursor = new CommentCursorStore(entry.statePath, entry.repoUrl);
|
|
@@ -154,6 +260,8 @@ export class PlatformPoller {
|
|
|
154
260
|
entry.status.lastErrorClass = undefined;
|
|
155
261
|
}
|
|
156
262
|
catch (e) {
|
|
263
|
+
if (e instanceof EntryRetiredError)
|
|
264
|
+
return;
|
|
157
265
|
if (e instanceof RateLimitAbort) {
|
|
158
266
|
// 不计凭据健康度(spec §5.3 要点):退避顺延重试并在状态里如实标注 rate-limited。
|
|
159
267
|
const attempt = (entry.rateLimit?.attempt ?? 0) + 1;
|
|
@@ -178,9 +286,14 @@ export class PlatformPoller {
|
|
|
178
286
|
}
|
|
179
287
|
finally {
|
|
180
288
|
entry.status.isPolling = false;
|
|
289
|
+
if (!entry.retired && entry.pendingInit !== undefined) {
|
|
290
|
+
this.applyEntryInit(entry, entry.pendingInit);
|
|
291
|
+
entry.pendingInit = undefined;
|
|
292
|
+
}
|
|
181
293
|
const endedAt = this.now();
|
|
182
294
|
entry.status.lastPollEndedAt = new Date(endedAt).toISOString();
|
|
183
295
|
entry.status.lastPollDurationMs = endedAt - startedAt;
|
|
296
|
+
this.fireLifecycle();
|
|
184
297
|
}
|
|
185
298
|
}
|
|
186
299
|
recordFailure(entry, message, errorClass) {
|
|
@@ -192,6 +305,8 @@ export class PlatformPoller {
|
|
|
192
305
|
async pollCycle(entry) {
|
|
193
306
|
const failures = [];
|
|
194
307
|
const fail = (context, e) => {
|
|
308
|
+
if (e instanceof EntryRetiredError)
|
|
309
|
+
throw e;
|
|
195
310
|
const failure = {
|
|
196
311
|
message: `${context}: ${e instanceof Error ? e.message : String(e)}`,
|
|
197
312
|
errorClass: e instanceof DriverOpError ? e.info.errorClass : undefined,
|
|
@@ -202,17 +317,29 @@ export class PlatformPoller {
|
|
|
202
317
|
};
|
|
203
318
|
try {
|
|
204
319
|
await entry.cursor.flushIfDirty();
|
|
320
|
+
this.assertEntryActive(entry);
|
|
205
321
|
}
|
|
206
322
|
catch (e) {
|
|
207
323
|
fail('cursor flush', e);
|
|
208
324
|
}
|
|
209
325
|
const tasks = await this.opts.tasks(entry.projectId);
|
|
326
|
+
this.assertEntryActive(entry);
|
|
210
327
|
const byId = new Map(tasks.map(t => [t.taskId, t]));
|
|
211
328
|
for (const gen of entry.cursor.generations()) {
|
|
212
|
-
|
|
213
|
-
|
|
329
|
+
let authoritative;
|
|
330
|
+
try {
|
|
331
|
+
authoritative = await this.opts.task(gen);
|
|
332
|
+
this.assertEntryActive(entry);
|
|
333
|
+
}
|
|
334
|
+
catch (e) {
|
|
335
|
+
fail(`read task ${gen}`, e);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (authoritative === null || authoritative.terminal) {
|
|
214
339
|
try {
|
|
340
|
+
this.assertEntryActive(entry);
|
|
215
341
|
await entry.cursor.dropGeneration(gen);
|
|
342
|
+
this.assertEntryActive(entry);
|
|
216
343
|
}
|
|
217
344
|
catch (e) {
|
|
218
345
|
fail(`dropGeneration ${gen}`, e);
|
|
@@ -258,6 +385,7 @@ export class PlatformPoller {
|
|
|
258
385
|
let steps;
|
|
259
386
|
try {
|
|
260
387
|
steps = await entry.driver.runPreflightSteps();
|
|
388
|
+
this.assertEntryActive(entry);
|
|
261
389
|
}
|
|
262
390
|
catch (e) {
|
|
263
391
|
entry.defaultBranchStale += 1;
|
|
@@ -274,6 +402,7 @@ export class PlatformPoller {
|
|
|
274
402
|
let defaultBranch;
|
|
275
403
|
try {
|
|
276
404
|
const [row] = await entry.driver.runOp('projectView');
|
|
405
|
+
this.assertEntryActive(entry);
|
|
277
406
|
if (row !== undefined && typeof row.defaultBranch === 'string') {
|
|
278
407
|
entry.defaultBranch = row.defaultBranch;
|
|
279
408
|
entry.defaultBranchStale = 0;
|
|
@@ -282,6 +411,7 @@ export class PlatformPoller {
|
|
|
282
411
|
if (row !== undefined && entry.preflightPassed !== true && entry.driver.runPreflightSteps !== undefined) {
|
|
283
412
|
if (row.pushPermitted === false) {
|
|
284
413
|
fail('preflight-push', new Error(`push permission missing for ${entry.repoUrl} — server merge/close requires write access`));
|
|
414
|
+
return failures;
|
|
285
415
|
}
|
|
286
416
|
else {
|
|
287
417
|
if (row.pushPermitted === undefined) {
|
|
@@ -302,6 +432,7 @@ export class PlatformPoller {
|
|
|
302
432
|
? entry.defaultBranch
|
|
303
433
|
: undefined);
|
|
304
434
|
await this.pollListPrs(entry, tasks, byId, defaultBranch, fail, failures);
|
|
435
|
+
this.assertEntryActive(entry);
|
|
305
436
|
for (const task of tasks) {
|
|
306
437
|
if (task.terminal || task.prNumber === undefined)
|
|
307
438
|
continue;
|
|
@@ -310,14 +441,11 @@ export class PlatformPoller {
|
|
|
310
441
|
if (task.closedUnmergedAnchor === true)
|
|
311
442
|
continue;
|
|
312
443
|
await this.subPoll(entry, task, usableDefault, fail);
|
|
444
|
+
this.assertEntryActive(entry);
|
|
313
445
|
}
|
|
314
446
|
return failures;
|
|
315
447
|
}
|
|
316
|
-
// PR 收编后仍可被 retarget
|
|
317
|
-
// (branch/fork/target,spec §7 fresh prView 完整谓词核验),失配转 intervention 并停子轮询。
|
|
318
|
-
// 期望值缺失即无法核验:预设「无法核验 = 匹配」会给 retarget 后的 PR 继续发 push/merged/裁决
|
|
319
|
-
// ——task.branch 缺失按失配交人工(任务视图结构异常),base 期望双缺失按不可核验静默停
|
|
320
|
-
// (projectView 故障已在健康度,恢复即自愈)。
|
|
448
|
+
// PR 收编后仍可被 retarget/改写:产出生命周期/裁决事件前按 fresh prView 复核绑定,「无法核验」不得视同「匹配」。
|
|
321
449
|
bindingCheck(task, prRow, defaultBranch) {
|
|
322
450
|
return checkPrBinding(prRow, {
|
|
323
451
|
branch: task.branch,
|
|
@@ -341,19 +469,56 @@ export class PlatformPoller {
|
|
|
341
469
|
return vt !== undefined && vt < prsCursor.watermarkTime;
|
|
342
470
|
});
|
|
343
471
|
});
|
|
472
|
+
this.assertEntryActive(entry);
|
|
344
473
|
}
|
|
345
474
|
catch (e) {
|
|
346
475
|
fail('listPrs', e);
|
|
347
476
|
return;
|
|
348
477
|
}
|
|
478
|
+
const listedPrRows = [...prRows];
|
|
479
|
+
const pendingByPr = new Map();
|
|
480
|
+
const activeDeferrals = new Set();
|
|
481
|
+
for (const pending of entry.cursor.pendingAdoptions()) {
|
|
482
|
+
let task;
|
|
483
|
+
try {
|
|
484
|
+
task = await this.opts.task(pending.taskId);
|
|
485
|
+
this.assertEntryActive(entry);
|
|
486
|
+
if (task === null || task.terminal || (task.prNumber !== undefined && task.prNumber !== pending.prNumber)) {
|
|
487
|
+
await entry.cursor.clearAdoptionPending(pending.taskId, pending.prNumber);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (task.prNumber === pending.prNumber) {
|
|
491
|
+
await entry.cursor.markAdoptionDelivered(pending.taskId, pending.prNumber);
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
byId.set(task.taskId, task);
|
|
495
|
+
pendingByPr.set(pending.prNumber, pending.taskId);
|
|
496
|
+
if (prRows.some(row => row.prNumber === pending.prNumber))
|
|
497
|
+
continue;
|
|
498
|
+
const [row] = await entry.driver.runOp('prView', { prNumber: pending.prNumber });
|
|
499
|
+
this.assertEntryActive(entry);
|
|
500
|
+
if (row !== undefined)
|
|
501
|
+
prRows.push({ ...row, prNumber: pending.prNumber });
|
|
502
|
+
}
|
|
503
|
+
catch (e) {
|
|
504
|
+
activeDeferrals.add(pending.prNumber);
|
|
505
|
+
fail(`retry adoption pr#${pending.prNumber}`, e);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
349
508
|
const boundByPr = new Map();
|
|
350
509
|
for (const t of tasks) {
|
|
351
510
|
if (!t.terminal && t.prNumber !== undefined)
|
|
352
511
|
boundByPr.set(t.prNumber, t);
|
|
353
512
|
}
|
|
354
513
|
const failuresBefore = failures.length;
|
|
355
|
-
let deferredAdoptions = 0;
|
|
356
514
|
const seenPrs = new Set();
|
|
515
|
+
const clearPending = async (prNumber) => {
|
|
516
|
+
const taskId = pendingByPr.get(prNumber);
|
|
517
|
+
if (taskId === undefined)
|
|
518
|
+
return;
|
|
519
|
+
await entry.cursor.clearAdoptionPending(taskId, prNumber);
|
|
520
|
+
pendingByPr.delete(prNumber);
|
|
521
|
+
};
|
|
357
522
|
for (const row of prRows) {
|
|
358
523
|
const prNumber = row.prNumber;
|
|
359
524
|
seenPrs.add(prNumber);
|
|
@@ -364,10 +529,11 @@ export class PlatformPoller {
|
|
|
364
529
|
};
|
|
365
530
|
const boundTask = boundByPr.get(prNumber);
|
|
366
531
|
if (boundTask !== undefined) {
|
|
532
|
+
await clearPending(prNumber);
|
|
367
533
|
// reopen 是显式 durable 观察:closed-unmerged 锚在 TaskState,主轮询见重开即合成(spec §6)。
|
|
368
534
|
if (boundTask.closedUnmergedAnchor === true && row.state === 'open') {
|
|
369
535
|
try {
|
|
370
|
-
await this.emit(entry, 'pr.updated', { ...base, kind: 'reopened' });
|
|
536
|
+
await this.emit(entry, 'pr.updated', { ...base, kind: 'reopened' }, boundTask.taskId);
|
|
371
537
|
entry.observedPr.delete(`${boundTask.taskId}:${prNumber}`);
|
|
372
538
|
}
|
|
373
539
|
catch (e) {
|
|
@@ -376,31 +542,48 @@ export class PlatformPoller {
|
|
|
376
542
|
}
|
|
377
543
|
continue;
|
|
378
544
|
}
|
|
379
|
-
if (row.state !== 'open' || row.draft === true)
|
|
545
|
+
if (row.state !== 'open' || row.draft === true) {
|
|
546
|
+
await clearPending(prNumber);
|
|
380
547
|
continue;
|
|
381
|
-
|
|
548
|
+
}
|
|
549
|
+
if (!base.branch.startsWith(BRANCH_PREFIX)) {
|
|
550
|
+
await clearPending(prNumber);
|
|
382
551
|
continue;
|
|
552
|
+
}
|
|
383
553
|
const task = byId.get(base.branch.slice(BRANCH_PREFIX.length));
|
|
384
|
-
if (task === undefined || task.terminal || task.prNumber !== undefined)
|
|
554
|
+
if (task === undefined || task.terminal || task.prNumber !== undefined) {
|
|
555
|
+
await clearPending(prNumber);
|
|
385
556
|
continue;
|
|
557
|
+
}
|
|
558
|
+
const pendingTaskId = pendingByPr.get(prNumber);
|
|
559
|
+
if (pendingTaskId !== undefined && pendingTaskId !== task.taskId)
|
|
560
|
+
await clearPending(prNumber);
|
|
386
561
|
// 统一谓词 branch === task.branch:branch 缺失的任务视图无从核验绑定,收编一并 fail closed
|
|
387
562
|
// (与子轮询 bindingCheck 对称——「无法核验」不是「匹配」)。
|
|
388
|
-
if (task.branch !== base.branch)
|
|
563
|
+
if (task.branch !== base.branch) {
|
|
564
|
+
await clearPending(prNumber);
|
|
389
565
|
continue;
|
|
566
|
+
}
|
|
390
567
|
if (row.sourceProjectId === null || row.sourceProjectId === undefined
|
|
391
|
-
|| row.sourceProjectId !== row.targetProjectId)
|
|
568
|
+
|| row.sourceProjectId !== row.targetProjectId) {
|
|
569
|
+
await clearPending(prNumber);
|
|
392
570
|
continue;
|
|
571
|
+
}
|
|
393
572
|
const target = String(row.targetBranch);
|
|
573
|
+
if (entry.cursor.isAdoptionDelivered(task.taskId, prNumber))
|
|
574
|
+
continue;
|
|
394
575
|
try {
|
|
395
576
|
if (task.expectedBase !== undefined) {
|
|
396
|
-
if (target !== task.expectedBase)
|
|
577
|
+
if (target !== task.expectedBase) {
|
|
578
|
+
await clearPending(prNumber);
|
|
397
579
|
continue;
|
|
580
|
+
}
|
|
398
581
|
}
|
|
399
582
|
else {
|
|
400
583
|
if (defaultBranch === undefined) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
584
|
+
await entry.cursor.markAdoptionPending(task.taskId, prNumber);
|
|
585
|
+
pendingByPr.set(prNumber, task.taskId);
|
|
586
|
+
activeDeferrals.add(prNumber);
|
|
404
587
|
continue;
|
|
405
588
|
}
|
|
406
589
|
if (target !== defaultBranch) {
|
|
@@ -410,17 +593,61 @@ export class PlatformPoller {
|
|
|
410
593
|
if (entry.baseMismatch.get(prNumber) !== fp) {
|
|
411
594
|
await this.emit(entry, 'human.intervention', {
|
|
412
595
|
...base, reason: 'base-mismatch', targetBranch: target, expectedBase: defaultBranch, taskId: task.taskId,
|
|
413
|
-
});
|
|
596
|
+
}, task.taskId);
|
|
414
597
|
entry.baseMismatch.set(prNumber, fp);
|
|
415
598
|
}
|
|
599
|
+
await clearPending(prNumber);
|
|
416
600
|
continue;
|
|
417
601
|
}
|
|
418
602
|
}
|
|
603
|
+
const adoptionFingerprint = [
|
|
604
|
+
task.taskId,
|
|
605
|
+
task.status ?? '',
|
|
606
|
+
task.phase ?? '',
|
|
607
|
+
task.signalToken ?? '',
|
|
608
|
+
task.reviewMode,
|
|
609
|
+
base.branch,
|
|
610
|
+
target,
|
|
611
|
+
String(row.headSha),
|
|
612
|
+
].join('\0');
|
|
613
|
+
const deferred = entry.adoptionDeferrals.get(prNumber);
|
|
614
|
+
if (deferred?.fingerprint === adoptionFingerprint) {
|
|
615
|
+
deferred.cycles += 1;
|
|
616
|
+
activeDeferrals.add(prNumber);
|
|
617
|
+
if (!deferred.interventionDelivered
|
|
618
|
+
&& deferred.cycles >= ADOPTION_DEFERRAL_INTERVENTION_CYCLES) {
|
|
619
|
+
await this.emit(entry, 'human.intervention', {
|
|
620
|
+
...base,
|
|
621
|
+
reason: 'pr-adoption-deferred',
|
|
622
|
+
taskId: task.taskId,
|
|
623
|
+
status: task.status,
|
|
624
|
+
phase: task.phase,
|
|
625
|
+
cycles: deferred.cycles,
|
|
626
|
+
}, task.taskId);
|
|
627
|
+
deferred.interventionDelivered = true;
|
|
628
|
+
}
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
entry.adoptionDeferrals.delete(prNumber);
|
|
419
632
|
await this.emit(entry, 'pr.created', {
|
|
420
633
|
...base, headSha: String(row.headSha), targetBranch: target,
|
|
421
634
|
...(typeof row.prAuthorId === 'string' ? { prAuthorId: row.prAuthorId } : {}),
|
|
422
|
-
});
|
|
635
|
+
}, task.taskId);
|
|
636
|
+
const adoptedTask = await this.opts.task(task.taskId);
|
|
637
|
+
if (adoptedTask?.prNumber !== prNumber) {
|
|
638
|
+
await entry.cursor.markAdoptionPending(task.taskId, prNumber);
|
|
639
|
+
pendingByPr.set(prNumber, task.taskId);
|
|
640
|
+
entry.adoptionDeferrals.set(prNumber, {
|
|
641
|
+
fingerprint: adoptionFingerprint,
|
|
642
|
+
cycles: 1,
|
|
643
|
+
interventionDelivered: false,
|
|
644
|
+
});
|
|
645
|
+
activeDeferrals.add(prNumber);
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
await entry.cursor.markAdoptionDelivered(task.taskId, prNumber);
|
|
423
649
|
entry.baseMismatch.delete(prNumber);
|
|
650
|
+
entry.adoptionDeferrals.delete(prNumber);
|
|
424
651
|
}
|
|
425
652
|
catch (e) {
|
|
426
653
|
fail(`adopt pr#${prNumber}`, e);
|
|
@@ -430,10 +657,15 @@ export class PlatformPoller {
|
|
|
430
657
|
if (!seenPrs.has(pr))
|
|
431
658
|
entry.baseMismatch.delete(pr);
|
|
432
659
|
}
|
|
433
|
-
|
|
660
|
+
for (const pr of entry.adoptionDeferrals.keys()) {
|
|
661
|
+
if (!activeDeferrals.has(pr))
|
|
662
|
+
entry.adoptionDeferrals.delete(pr);
|
|
663
|
+
}
|
|
664
|
+
if (failures.length > failuresBefore)
|
|
434
665
|
return;
|
|
435
666
|
try {
|
|
436
|
-
|
|
667
|
+
this.assertEntryActive(entry);
|
|
668
|
+
await entry.cursor.commitListPrs(listedPrRows, scanStartedAt - entry.driver.visibilityLagMs);
|
|
437
669
|
}
|
|
438
670
|
catch (e) {
|
|
439
671
|
fail('listPrs cursor commit', e);
|
|
@@ -445,6 +677,7 @@ export class PlatformPoller {
|
|
|
445
677
|
let prRow;
|
|
446
678
|
try {
|
|
447
679
|
[prRow] = await entry.driver.runOp('prView', { prNumber });
|
|
680
|
+
this.assertEntryActive(entry);
|
|
448
681
|
}
|
|
449
682
|
catch (e) {
|
|
450
683
|
fail(`prView pr#${prNumber}`, e);
|
|
@@ -467,7 +700,7 @@ export class PlatformPoller {
|
|
|
467
700
|
taskId: task.taskId,
|
|
468
701
|
targetBranch: String(prRow.targetBranch),
|
|
469
702
|
...(task.expectedBase !== undefined ? { expectedBase: task.expectedBase } : {}),
|
|
470
|
-
});
|
|
703
|
+
}, task.taskId);
|
|
471
704
|
observed.bindingMismatch = binding.mismatch;
|
|
472
705
|
}
|
|
473
706
|
catch (e) {
|
|
@@ -482,7 +715,7 @@ export class PlatformPoller {
|
|
|
482
715
|
if (typeof prRow.mergedAt === 'string') {
|
|
483
716
|
if (observed.merged !== true) {
|
|
484
717
|
try {
|
|
485
|
-
await this.emit(entry, 'pr.merged', base);
|
|
718
|
+
await this.emit(entry, 'pr.merged', base, task.taskId);
|
|
486
719
|
observed.merged = true;
|
|
487
720
|
}
|
|
488
721
|
catch (e) {
|
|
@@ -492,7 +725,7 @@ export class PlatformPoller {
|
|
|
492
725
|
}
|
|
493
726
|
else if (observed.closedUnmerged !== true) {
|
|
494
727
|
try {
|
|
495
|
-
await this.emit(entry, 'pr.updated', { ...base, kind: 'closed-unmerged' });
|
|
728
|
+
await this.emit(entry, 'pr.updated', { ...base, kind: 'closed-unmerged' }, task.taskId);
|
|
496
729
|
observed.closedUnmerged = true;
|
|
497
730
|
}
|
|
498
731
|
catch (e) {
|
|
@@ -503,10 +736,14 @@ export class PlatformPoller {
|
|
|
503
736
|
return;
|
|
504
737
|
}
|
|
505
738
|
observed.closedUnmerged = false;
|
|
739
|
+
if (task.reviewMode === 'server') {
|
|
740
|
+
this.engine.dropCandidate(task.taskId, prNumber);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
506
743
|
const headSha = String(prRow.headSha);
|
|
507
744
|
if (task.latestHeadSha !== undefined && headSha !== task.latestHeadSha.toLowerCase() && observed.pushSha !== headSha) {
|
|
508
745
|
try {
|
|
509
|
-
await this.emit(entry, 'pr.updated', { ...base, kind: 'push', headSha });
|
|
746
|
+
await this.emit(entry, 'pr.updated', { ...base, kind: 'push', headSha }, task.taskId);
|
|
510
747
|
observed.pushSha = headSha;
|
|
511
748
|
}
|
|
512
749
|
catch (e) {
|
|
@@ -548,6 +785,7 @@ export class PlatformPoller {
|
|
|
548
785
|
// 评论源扫描最长可达分钟级,扫描期间 head/状态可被平台改写(TOCTOU):emit 前以
|
|
549
786
|
// 权威 prView 复核 open/!draft/绑定/锚点,失配清候选走 push/recheck,查询失败按瞬态重试。
|
|
550
787
|
const [freshRow] = await entry.driver.runOp('prView', { prNumber });
|
|
788
|
+
this.assertEntryActive(entry);
|
|
551
789
|
const freshEligible = freshRow !== undefined
|
|
552
790
|
&& this.bindingCheck(task, freshRow, defaultBranch) === undefined
|
|
553
791
|
&& freshRow.state === 'open' && freshRow.draft === false
|
|
@@ -558,6 +796,7 @@ export class PlatformPoller {
|
|
|
558
796
|
}
|
|
559
797
|
await this.emit(entry, 'review.submitted', {
|
|
560
798
|
...base,
|
|
799
|
+
source: 'platform-poller',
|
|
561
800
|
action: decision.kind === 'pass' ? 'APPROVE' : 'REQUEST_CHANGES',
|
|
562
801
|
headSha: decision.anchorSha,
|
|
563
802
|
currentHeadSha: String(freshRow.headSha),
|
|
@@ -566,7 +805,7 @@ export class PlatformPoller {
|
|
|
566
805
|
verdictToken: decision.token,
|
|
567
806
|
verdictConflict: decision.conflict,
|
|
568
807
|
verdictCarrier: decision.carrier,
|
|
569
|
-
});
|
|
808
|
+
}, task.taskId);
|
|
570
809
|
entry.deliveredVerdicts.set(obsKey, fp);
|
|
571
810
|
}
|
|
572
811
|
catch (e) {
|
|
@@ -648,7 +887,7 @@ export class PlatformPoller {
|
|
|
648
887
|
...(scan.sourceClass === 'threaded' && row.discussionId !== null && row.discussionId !== undefined
|
|
649
888
|
? { reviewCommentReply: true }
|
|
650
889
|
: {}),
|
|
651
|
-
});
|
|
890
|
+
}, task.taskId);
|
|
652
891
|
await entry.cursor.markDelivered(task.taskId, base.prNumber, scan.key, id, digest);
|
|
653
892
|
}
|
|
654
893
|
catch (e) {
|
|
@@ -658,6 +897,7 @@ export class PlatformPoller {
|
|
|
658
897
|
}
|
|
659
898
|
if (delivered) {
|
|
660
899
|
try {
|
|
900
|
+
this.assertEntryActive(entry);
|
|
661
901
|
await entry.cursor.commitSource(task.taskId, base.prNumber, scan.key, scan.rows, cutoff);
|
|
662
902
|
}
|
|
663
903
|
catch (e) {
|
|
@@ -677,8 +917,13 @@ export class PlatformPoller {
|
|
|
677
917
|
}
|
|
678
918
|
return scans;
|
|
679
919
|
}
|
|
680
|
-
async emit(entry, type, data) {
|
|
681
|
-
|
|
920
|
+
async emit(entry, type, data, taskId) {
|
|
921
|
+
this.assertEntryActive(entry);
|
|
922
|
+
await this.opts.onEvent(entry.projectId, { type, repo: entry.repoKey, data, taskId });
|
|
923
|
+
}
|
|
924
|
+
assertEntryActive(entry) {
|
|
925
|
+
if (entry.retired || !this.entries.includes(entry))
|
|
926
|
+
throw new EntryRetiredError();
|
|
682
927
|
}
|
|
683
928
|
}
|
|
684
929
|
//# sourceMappingURL=platform-poller.js.map
|