poly-weaver 0.15.2 → 1.0.0
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/dist/agents/implementors/handler.d.ts.map +1 -1
- package/dist/agents/implementors/handler.js +7 -2
- package/dist/agents/implementors/handler.js.map +1 -1
- package/dist/agents/interviewers/handler.d.ts.map +1 -1
- package/dist/agents/interviewers/handler.js +3 -1
- package/dist/agents/interviewers/handler.js.map +1 -1
- package/dist/agents/planners/adapter.d.ts.map +1 -1
- package/dist/agents/planners/adapter.js +30 -11
- package/dist/agents/planners/adapter.js.map +1 -1
- package/dist/agents/planners/handler.d.ts.map +1 -1
- package/dist/agents/planners/handler.js +7 -2
- package/dist/agents/planners/handler.js.map +1 -1
- package/dist/agents/reviewers/adapter.d.ts.map +1 -1
- package/dist/agents/reviewers/adapter.js +1 -0
- package/dist/agents/reviewers/adapter.js.map +1 -1
- package/dist/agents/reviewers/handler.d.ts.map +1 -1
- package/dist/agents/reviewers/handler.js +23 -4
- package/dist/agents/reviewers/handler.js.map +1 -1
- package/dist/agents/reviewers/types.d.ts +2 -0
- package/dist/agents/reviewers/types.d.ts.map +1 -1
- package/dist/agents/runner.d.ts +18 -1
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +136 -20
- package/dist/agents/runner.js.map +1 -1
- package/dist/agents/simplifiers/handler.d.ts.map +1 -1
- package/dist/agents/simplifiers/handler.js +7 -2
- package/dist/agents/simplifiers/handler.js.map +1 -1
- package/dist/auto-update/detect-agents.d.ts +1 -0
- package/dist/auto-update/detect-agents.d.ts.map +1 -1
- package/dist/auto-update/detect-agents.js +8 -7
- package/dist/auto-update/detect-agents.js.map +1 -1
- package/dist/cli.js +16 -4
- package/dist/cli.js.map +1 -1
- package/dist/crosscheck/coordinator.d.ts +5 -0
- package/dist/crosscheck/coordinator.d.ts.map +1 -1
- package/dist/crosscheck/coordinator.js +216 -96
- package/dist/crosscheck/coordinator.js.map +1 -1
- package/dist/crosscheck/live-agent-session.d.ts +10 -1
- package/dist/crosscheck/live-agent-session.d.ts.map +1 -1
- package/dist/crosscheck/live-agent-session.js +68 -7
- package/dist/crosscheck/live-agent-session.js.map +1 -1
- package/dist/crosscheck/state.d.ts +3 -0
- package/dist/crosscheck/state.d.ts.map +1 -1
- package/dist/crosscheck/state.js +17 -2
- package/dist/crosscheck/state.js.map +1 -1
- package/dist/dump/collector.d.ts.map +1 -1
- package/dist/dump/collector.js +3 -0
- package/dist/dump/collector.js.map +1 -1
- package/dist/dump/service.d.ts.map +1 -1
- package/dist/dump/service.js +3 -0
- package/dist/dump/service.js.map +1 -1
- package/dist/dump/types.d.ts +3 -0
- package/dist/dump/types.d.ts.map +1 -1
- package/dist/dump/types.js.map +1 -1
- package/dist/flow/executor.d.ts.map +1 -1
- package/dist/flow/executor.js +5 -0
- package/dist/flow/executor.js.map +1 -1
- package/dist/flow/types.d.ts +5 -0
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/flow/types.js.map +1 -1
- package/dist/offscreen/controller.d.ts +19 -5
- package/dist/offscreen/controller.d.ts.map +1 -1
- package/dist/offscreen/controller.js +336 -159
- package/dist/offscreen/controller.js.map +1 -1
- package/dist/offscreen/fork-launch.d.ts +2 -2
- package/dist/offscreen/fork-launch.d.ts.map +1 -1
- package/dist/offscreen/fork-launch.js +2 -2
- package/dist/offscreen/fork-launch.js.map +1 -1
- package/dist/offscreen/fork.d.ts +16 -2
- package/dist/offscreen/fork.d.ts.map +1 -1
- package/dist/offscreen/fork.js +79 -40
- package/dist/offscreen/fork.js.map +1 -1
- package/dist/offscreen/inquiry-pane.d.ts +2 -1
- package/dist/offscreen/inquiry-pane.d.ts.map +1 -1
- package/dist/offscreen/inquiry-pane.js +8 -2
- package/dist/offscreen/inquiry-pane.js.map +1 -1
- package/dist/offscreen/inquiry-sender.d.ts +1 -0
- package/dist/offscreen/inquiry-sender.d.ts.map +1 -1
- package/dist/offscreen/inquiry-sender.js +1 -0
- package/dist/offscreen/inquiry-sender.js.map +1 -1
- package/dist/offscreen/panes.d.ts +1 -0
- package/dist/offscreen/panes.d.ts.map +1 -1
- package/dist/offscreen/registry.d.ts +2 -2
- package/dist/offscreen/registry.d.ts.map +1 -1
- package/dist/offscreen/registry.js +5 -1
- package/dist/offscreen/registry.js.map +1 -1
- package/dist/offscreen/resolve.d.ts +2 -0
- package/dist/offscreen/resolve.d.ts.map +1 -1
- package/dist/offscreen/resolve.js +5 -1
- package/dist/offscreen/resolve.js.map +1 -1
- package/dist/offscreen/session-turn-monitor.d.ts +34 -33
- package/dist/offscreen/session-turn-monitor.d.ts.map +1 -1
- package/dist/offscreen/session-turn-monitor.js +327 -281
- package/dist/offscreen/session-turn-monitor.js.map +1 -1
- package/dist/offscreen/session-turn-receipt.d.ts +28 -0
- package/dist/offscreen/session-turn-receipt.d.ts.map +1 -0
- package/dist/offscreen/session-turn-receipt.js +53 -0
- package/dist/offscreen/session-turn-receipt.js.map +1 -0
- package/dist/offscreen/split-inquiry.d.ts.map +1 -1
- package/dist/offscreen/split-inquiry.js +5 -0
- package/dist/offscreen/split-inquiry.js.map +1 -1
- package/dist/offscreen/starting-pane.d.ts +13 -0
- package/dist/offscreen/starting-pane.d.ts.map +1 -0
- package/dist/offscreen/starting-pane.js +24 -0
- package/dist/offscreen/starting-pane.js.map +1 -0
- package/dist/offscreen/surface.d.ts +1 -0
- package/dist/offscreen/surface.d.ts.map +1 -1
- package/dist/offscreen/surface.js +5 -3
- package/dist/offscreen/surface.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +7 -1
- package/dist/orchestrator.js.map +1 -1
- package/dist/providers/base-completion.d.ts +1 -0
- package/dist/providers/base-completion.d.ts.map +1 -1
- package/dist/providers/base-completion.js +4 -2
- package/dist/providers/base-completion.js.map +1 -1
- package/dist/providers/codex/completion.d.ts +4 -2
- package/dist/providers/codex/completion.d.ts.map +1 -1
- package/dist/providers/codex/completion.js +99 -14
- package/dist/providers/codex/completion.js.map +1 -1
- package/dist/providers/codex/strategy.d.ts.map +1 -1
- package/dist/providers/codex/strategy.js +3 -2
- package/dist/providers/codex/strategy.js.map +1 -1
- package/dist/providers/copilot/completion.d.ts +32 -21
- package/dist/providers/copilot/completion.d.ts.map +1 -1
- package/dist/providers/copilot/completion.js +110 -166
- package/dist/providers/copilot/completion.js.map +1 -1
- package/dist/providers/copilot/environment.d.ts +2 -0
- package/dist/providers/copilot/environment.d.ts.map +1 -0
- package/dist/providers/copilot/environment.js +8 -0
- package/dist/providers/copilot/environment.js.map +1 -0
- package/dist/providers/copilot/fork-state.d.ts +7 -0
- package/dist/providers/copilot/fork-state.d.ts.map +1 -0
- package/dist/providers/copilot/fork-state.js +150 -0
- package/dist/providers/copilot/fork-state.js.map +1 -0
- package/dist/providers/copilot/observation.d.ts +275 -0
- package/dist/providers/copilot/observation.d.ts.map +1 -0
- package/dist/providers/copilot/observation.js +2072 -0
- package/dist/providers/copilot/observation.js.map +1 -0
- package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.d.mts +2 -0
- package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.d.mts.map +1 -0
- package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.mjs +426 -0
- package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.mjs.map +1 -0
- package/dist/providers/copilot/observer-extension/plugin.json +6 -0
- package/dist/providers/copilot/record-properties.d.ts +4 -0
- package/dist/providers/copilot/record-properties.d.ts.map +1 -0
- package/dist/providers/copilot/record-properties.js +14 -0
- package/dist/providers/copilot/record-properties.js.map +1 -0
- package/dist/providers/copilot/session.d.ts +8 -33
- package/dist/providers/copilot/session.d.ts.map +1 -1
- package/dist/providers/copilot/session.js +10 -176
- package/dist/providers/copilot/session.js.map +1 -1
- package/dist/providers/copilot/strategy.d.ts +4 -5
- package/dist/providers/copilot/strategy.d.ts.map +1 -1
- package/dist/providers/copilot/strategy.js +73 -67
- package/dist/providers/copilot/strategy.js.map +1 -1
- package/dist/providers/fork-cleanup.d.ts +4 -0
- package/dist/providers/fork-cleanup.d.ts.map +1 -0
- package/dist/providers/fork-cleanup.js +21 -0
- package/dist/providers/fork-cleanup.js.map +1 -0
- package/dist/providers/fork.d.ts +24 -3
- package/dist/providers/fork.d.ts.map +1 -1
- package/dist/providers/fork.js.map +1 -1
- package/dist/providers/invoke.d.ts.map +1 -1
- package/dist/providers/invoke.js +85 -34
- package/dist/providers/invoke.js.map +1 -1
- package/dist/providers/live.d.ts.map +1 -1
- package/dist/providers/live.js +62 -17
- package/dist/providers/live.js.map +1 -1
- package/dist/providers/observer-run.d.ts +4 -0
- package/dist/providers/observer-run.d.ts.map +1 -0
- package/dist/providers/observer-run.js +23 -0
- package/dist/providers/observer-run.js.map +1 -0
- package/dist/providers/session-launch.d.ts +5 -1
- package/dist/providers/session-launch.d.ts.map +1 -1
- package/dist/providers/session-launch.js +42 -16
- package/dist/providers/session-launch.js.map +1 -1
- package/dist/providers/types.d.ts +156 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/session/resume.d.ts.map +1 -1
- package/dist/session/resume.js +16 -2
- package/dist/session/resume.js.map +1 -1
- package/dist/terminal/paste-submit.d.ts +1 -0
- package/dist/terminal/paste-submit.d.ts.map +1 -1
- package/dist/terminal/paste-submit.js +45 -32
- package/dist/terminal/paste-submit.js.map +1 -1
- package/dist/user/host-curate-prompt.d.ts.map +1 -1
- package/dist/user/host-curate-prompt.js +9 -6
- package/dist/user/host-curate-prompt.js.map +1 -1
- package/dist/user/host-prompt.d.ts.map +1 -1
- package/dist/user/host-prompt.js +9 -6
- package/dist/user/host-prompt.js.map +1 -1
- package/package.json +4 -2
|
@@ -4,7 +4,7 @@ import { bold, dim, MUTED_YELLOW_BG, padOrClip, reset, TRUE_BLACK_FG, } from "..
|
|
|
4
4
|
import { APP_VERSION } from "../version.js";
|
|
5
5
|
import { buildExecutorInitialPrompt, buildExecutorCrosscheckPrompt, buildExecutorEffectiveTaskContext, buildExecutorFollowUpPrompt, buildExecutorReconcilePrompt, buildExecutorSteerFreshPrompt, buildExecutorSteerPrompt, } from "../agents/executors/prompts.js";
|
|
6
6
|
import { sendInquiryQuestion } from "../offscreen/inquiry-sender.js";
|
|
7
|
-
import { SessionTurnMonitor } from "../offscreen/session-turn-monitor.js";
|
|
7
|
+
import { SessionTurnMonitor, SessionTurnReceipt } from "../offscreen/session-turn-monitor.js";
|
|
8
8
|
import { resolveProvider } from "../providers/registry.js";
|
|
9
9
|
import { compactProviderConfigurationTokens, } from "../providers/configuration-presentation.js";
|
|
10
10
|
import { readSessionFileWithStatus } from "../session/reader.js";
|
|
@@ -87,6 +87,7 @@ export class CrosscheckCoordinator {
|
|
|
87
87
|
resultRefresh;
|
|
88
88
|
launchAbort;
|
|
89
89
|
sessionsReady = false;
|
|
90
|
+
launchReconciliationPending = false;
|
|
90
91
|
transientFlash;
|
|
91
92
|
crosscheckProgress;
|
|
92
93
|
selectionAgent;
|
|
@@ -110,7 +111,10 @@ export class CrosscheckCoordinator {
|
|
|
110
111
|
const layout = this.options.host.getLayout();
|
|
111
112
|
const dimensions = this.paneDimensions(layout.columns, layout.childRows);
|
|
112
113
|
await this.reconcilePersistedHistory();
|
|
114
|
+
if (this.finishing)
|
|
115
|
+
return { kind: "crosscheck", interrupted: true };
|
|
113
116
|
const persisted = this.store.snapshot();
|
|
117
|
+
this.launchReconciliationPending = true;
|
|
114
118
|
const launchAbort = new AbortController();
|
|
115
119
|
this.launchAbort = launchAbort;
|
|
116
120
|
const completion = new Promise((resolve, reject) => {
|
|
@@ -119,11 +123,12 @@ export class CrosscheckCoordinator {
|
|
|
119
123
|
if (this.pendingFailure !== undefined)
|
|
120
124
|
reject(this.pendingFailure);
|
|
121
125
|
});
|
|
126
|
+
completion.catch(() => { });
|
|
122
127
|
let hasLaunchFailure = false;
|
|
123
128
|
let firstLaunchFailure;
|
|
124
129
|
const launches = ["agent-1", "agent-2"].map(async (agent) => {
|
|
130
|
+
const config = this.options.configurations[agent];
|
|
125
131
|
try {
|
|
126
|
-
const config = this.options.configurations[agent];
|
|
127
132
|
const resultFile = persisted.generation.resultFiles[agent];
|
|
128
133
|
const resultState = persisted.generation.rewind?.[agent];
|
|
129
134
|
const resultReady = resultState ? false : await fileHasContent(resultFile);
|
|
@@ -160,7 +165,9 @@ export class CrosscheckCoordinator {
|
|
|
160
165
|
: activityState === "working"
|
|
161
166
|
? RESUME_CONTINUE_PROMPT
|
|
162
167
|
: resumePrompt;
|
|
168
|
+
const launchTurnReceipt = new SessionTurnReceipt();
|
|
163
169
|
const session = await (this.options.launchSession ?? LiveAgentSession.launch)({
|
|
170
|
+
launchTurnReceipt,
|
|
164
171
|
driver: config.driver,
|
|
165
172
|
workdir: this.options.workdir,
|
|
166
173
|
prompt,
|
|
@@ -176,6 +183,7 @@ export class CrosscheckCoordinator {
|
|
|
176
183
|
cols: dimensions[agent].cols,
|
|
177
184
|
rows: dimensions[agent].rows,
|
|
178
185
|
sessionFileWaitMs: this.options.sessionFileWaitMs,
|
|
186
|
+
observerRun: this.options.providerObserverRuns?.get(config.driver),
|
|
179
187
|
onRender: () => this.options.host.scheduleParentUiRender(),
|
|
180
188
|
onOscClipboard: (data) => this.options.host.forwardOscClipboard(data),
|
|
181
189
|
onSpawn: (session) => {
|
|
@@ -187,28 +195,11 @@ export class CrosscheckCoordinator {
|
|
|
187
195
|
this.fail(new Error(`${config.driver} ${agentLabel(agent)} exited unexpectedly (code ${event.exitCode})`));
|
|
188
196
|
}
|
|
189
197
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const monitor = new SessionTurnMonitor(config.driver, session.identity.sessionFilePath, session.baseline, {
|
|
193
|
-
initialHistorySnapshot: persisted.sessions[agent]?.historySnapshot,
|
|
194
|
-
onHistorySnapshot: (snapshot) => {
|
|
195
|
-
void this.store.updateSessionHistory(agent, snapshot);
|
|
196
|
-
},
|
|
197
|
-
onHistoryRegression: (_regression, snapshot) => {
|
|
198
|
-
this.runDispatchOperation(agent, this.invalidateGenerationForRewind(agent, snapshot), "invalidate rewound generation");
|
|
199
|
-
},
|
|
200
|
-
onChange: (idle) => {
|
|
201
|
-
this.refreshStatusHint();
|
|
202
|
-
this.options.host.scheduleParentUiRender();
|
|
203
|
-
if (idle) {
|
|
204
|
-
const progressIdentity = this.takeCrosscheckTurnIdentity(agent);
|
|
205
|
-
this.runDispatchOperation(agent, this.handleAgentIdle(agent, progressIdentity), "prepare resumed crosscheck");
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
onReadFailure: () => {
|
|
209
|
-
this.options.output.warn(`${config.driver} ${agentLabel(agent)} session log is unreadable; crosscheck remains disarmed`);
|
|
198
|
+
onObserverError: (error) => {
|
|
199
|
+
this.fail(observerFailureError(config.driver, agent, error));
|
|
210
200
|
},
|
|
211
201
|
});
|
|
202
|
+
this.launchingSessions.set(agent, session);
|
|
212
203
|
const persistedDispatch = persisted.generation.dispatch;
|
|
213
204
|
const freshForPendingDispatch = persistedDispatch !== undefined
|
|
214
205
|
&& (persistedDispatch.phase === "crosscheck"
|
|
@@ -216,23 +207,14 @@ export class CrosscheckCoordinator {
|
|
|
216
207
|
: true)
|
|
217
208
|
&& (prior?.pendingDispatchBaselineReset === true
|
|
218
209
|
|| session.resumed !== true);
|
|
219
|
-
|
|
220
|
-
config,
|
|
221
|
-
session,
|
|
222
|
-
monitor,
|
|
223
|
-
resultReady,
|
|
224
|
-
resultState,
|
|
225
|
-
freshForPendingDispatch,
|
|
226
|
-
launchTurnExpected: session.resumed !== true || prompt.length > 0,
|
|
227
|
-
});
|
|
228
|
-
monitor.startHistoryPolling();
|
|
210
|
+
// Initialize before observation can publish a new checkpoint or rewind.
|
|
229
211
|
await this.store.update((state) => {
|
|
230
212
|
const dispatch = state.generation.dispatch;
|
|
231
213
|
if (freshForPendingDispatch
|
|
232
214
|
&& state.generation.id === persisted.generation.id
|
|
233
215
|
&& dispatch !== undefined
|
|
234
|
-
&&
|
|
235
|
-
&& dispatch.token ===
|
|
216
|
+
&& persistedDispatch !== undefined
|
|
217
|
+
&& dispatch.token === persistedDispatch.token) {
|
|
236
218
|
if (dispatch.phase === "crosscheck") {
|
|
237
219
|
state.generation.consumed = false;
|
|
238
220
|
}
|
|
@@ -244,27 +226,73 @@ export class CrosscheckCoordinator {
|
|
|
244
226
|
...(freshForPendingDispatch && {
|
|
245
227
|
pendingDispatchBaselineReset: true,
|
|
246
228
|
}),
|
|
247
|
-
...(
|
|
248
|
-
historySnapshot:
|
|
229
|
+
...(prior?.historySnapshot && {
|
|
230
|
+
historySnapshot: prior.historySnapshot,
|
|
249
231
|
}),
|
|
250
232
|
};
|
|
251
233
|
});
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
234
|
+
let usingObserverMonitor = false;
|
|
235
|
+
const monitorOptions = {
|
|
236
|
+
pendingEvidencePolicy: "wait",
|
|
237
|
+
initialHistorySnapshot: persisted.sessions[agent]?.historySnapshot,
|
|
238
|
+
onHistorySnapshot: (snapshot) => {
|
|
239
|
+
if (this.finishing)
|
|
240
|
+
return;
|
|
241
|
+
this.runDispatchOperation(agent, this.store.updateSessionHistory(agent, snapshot), "persist session history");
|
|
242
|
+
},
|
|
243
|
+
onHistoryRegression: (_regression, snapshot) => {
|
|
244
|
+
if (this.finishing)
|
|
245
|
+
return;
|
|
246
|
+
this.runDispatchOperation(agent, this.invalidateGenerationForRewind(agent, snapshot), "invalidate rewound generation");
|
|
247
|
+
},
|
|
248
|
+
onChange: (idle) => {
|
|
249
|
+
if (this.finishing)
|
|
250
|
+
return;
|
|
251
|
+
this.refreshStatusHint();
|
|
252
|
+
this.options.host.scheduleParentUiRender();
|
|
253
|
+
if (idle && this.sessionsReady) {
|
|
254
|
+
const progressIdentity = this.takeCrosscheckTurnIdentity(agent);
|
|
255
|
+
this.runDispatchOperation(agent, this.handleAgentIdle(agent, progressIdentity), "prepare resumed crosscheck");
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
onReadFailure: () => {
|
|
259
|
+
this.options.output.warn(usingObserverMonitor
|
|
260
|
+
? `${config.driver} ${agentLabel(agent)} session observation is unavailable; crosscheck remains disarmed`
|
|
261
|
+
: `${config.driver} ${agentLabel(agent)} session log is unreadable; crosscheck remains disarmed`);
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
const observerMonitor = session.createTurnMonitor?.(monitorOptions);
|
|
265
|
+
usingObserverMonitor = observerMonitor !== undefined;
|
|
266
|
+
const monitor = observerMonitor ?? new SessionTurnMonitor(config.driver, session.identity.sessionFilePath, session.baseline, monitorOptions);
|
|
267
|
+
this.agents.set(agent, {
|
|
268
|
+
config,
|
|
269
|
+
session,
|
|
270
|
+
monitor,
|
|
271
|
+
resultReady,
|
|
272
|
+
resultState,
|
|
273
|
+
freshForPendingDispatch,
|
|
274
|
+
launchTurnExpected: session.resumed !== true || prompt.length > 0,
|
|
275
|
+
launchTurnReceipt,
|
|
276
|
+
});
|
|
277
|
+
this.launchingSessions.delete(agent);
|
|
278
|
+
if (this.agents.get(agent).launchTurnExpected) {
|
|
279
|
+
if (typeof monitor.attachTurn === "function")
|
|
280
|
+
monitor.attachTurn(launchTurnReceipt);
|
|
281
|
+
else
|
|
282
|
+
monitor.beginTurn();
|
|
257
283
|
}
|
|
284
|
+
monitor.startHistoryPolling();
|
|
258
285
|
}
|
|
259
286
|
catch (err) {
|
|
260
287
|
this.launchingSessions.get(agent)?.close();
|
|
261
288
|
this.launchingSessions.delete(agent);
|
|
289
|
+
const launchFailure = observerLaunchFailureError(config.driver, agent, err);
|
|
262
290
|
if (!hasLaunchFailure) {
|
|
263
291
|
hasLaunchFailure = true;
|
|
264
|
-
firstLaunchFailure =
|
|
265
|
-
launchAbort.abort(
|
|
292
|
+
firstLaunchFailure = launchFailure;
|
|
293
|
+
launchAbort.abort(launchFailure);
|
|
266
294
|
}
|
|
267
|
-
throw
|
|
295
|
+
throw launchFailure;
|
|
268
296
|
}
|
|
269
297
|
});
|
|
270
298
|
const launchResults = await Promise.allSettled(launches);
|
|
@@ -274,15 +302,14 @@ export class CrosscheckCoordinator {
|
|
|
274
302
|
throw firstLaunchFailure;
|
|
275
303
|
if (this.finishing)
|
|
276
304
|
return await completion;
|
|
277
|
-
this.sessionsReady = true;
|
|
278
|
-
this.refreshStatusHint();
|
|
279
|
-
this.options.host.scheduleParentUiRender();
|
|
280
305
|
for (const runtime of this.agents.values()) {
|
|
281
306
|
if (runtime.launchTurnExpected)
|
|
282
|
-
runtime.monitor.beginTurn();
|
|
307
|
+
runtime.monitor.beginTurn(runtime.launchTurnReceipt);
|
|
283
308
|
}
|
|
284
|
-
|
|
285
|
-
|
|
309
|
+
this.sessionsReady = true;
|
|
310
|
+
this.refreshStatusHint();
|
|
311
|
+
this.options.host.scheduleParentUiRender();
|
|
312
|
+
await this.reconcileLaunchDispatch();
|
|
286
313
|
this.broadcast.reconcileMode(this.currentReadiness(), this.currentGenerationPresentation());
|
|
287
314
|
this.refreshMouseModes();
|
|
288
315
|
this.resultTimer = setInterval(() => {
|
|
@@ -542,6 +569,8 @@ export class CrosscheckCoordinator {
|
|
|
542
569
|
continue;
|
|
543
570
|
}
|
|
544
571
|
if (isControlKey(event, 0x18)) {
|
|
572
|
+
if (this.finishing)
|
|
573
|
+
continue;
|
|
545
574
|
flush();
|
|
546
575
|
const canRetry = this.canRetryPendingDispatch();
|
|
547
576
|
const canCrosscheck = this.isCrosscheckArmed();
|
|
@@ -567,6 +596,8 @@ export class CrosscheckCoordinator {
|
|
|
567
596
|
if (this.routeMouse(event, mouseFrame))
|
|
568
597
|
continue;
|
|
569
598
|
}
|
|
599
|
+
if (this.finishing)
|
|
600
|
+
continue;
|
|
570
601
|
if (this.focus === "broadcast") {
|
|
571
602
|
flush();
|
|
572
603
|
const submissionState = this.currentSubmissionState();
|
|
@@ -604,6 +635,8 @@ export class CrosscheckCoordinator {
|
|
|
604
635
|
return true;
|
|
605
636
|
}
|
|
606
637
|
onClipboardPasteRequest() {
|
|
638
|
+
if (this.finishing)
|
|
639
|
+
return true;
|
|
607
640
|
if (this.focus !== "broadcast")
|
|
608
641
|
return false;
|
|
609
642
|
this.requestBroadcastPaste();
|
|
@@ -697,6 +730,8 @@ export class CrosscheckCoordinator {
|
|
|
697
730
|
const runtime = this.agents.get(target.agent);
|
|
698
731
|
if (!runtime || point.row <= HEADER_ROWS)
|
|
699
732
|
return true;
|
|
733
|
+
if (this.finishing && event.kind !== "wheel")
|
|
734
|
+
return true;
|
|
700
735
|
const localRow = point.row - HEADER_ROWS;
|
|
701
736
|
if (event.kind === "wheel"
|
|
702
737
|
&& !runtime.session.vt.isAlternate
|
|
@@ -738,6 +773,8 @@ export class CrosscheckCoordinator {
|
|
|
738
773
|
return true;
|
|
739
774
|
}
|
|
740
775
|
forwardMouseFrameToAgent(agent, frame) {
|
|
776
|
+
if (this.finishing)
|
|
777
|
+
return;
|
|
741
778
|
const runtime = this.agents.get(agent);
|
|
742
779
|
if (!runtime)
|
|
743
780
|
return;
|
|
@@ -893,9 +930,13 @@ export class CrosscheckCoordinator {
|
|
|
893
930
|
return "ready";
|
|
894
931
|
}
|
|
895
932
|
requestBroadcastPaste() {
|
|
933
|
+
if (this.finishing)
|
|
934
|
+
return;
|
|
896
935
|
void handleImagePasteIntent(this.broadcast.attachments, () => {
|
|
897
936
|
this.flashTransient(PASTING_IMAGE_HINT, 3000);
|
|
898
937
|
}).then((outcome) => {
|
|
938
|
+
if (this.finishing)
|
|
939
|
+
return;
|
|
899
940
|
if (outcome.inserted !== undefined) {
|
|
900
941
|
this.broadcast.applyInsertedText(outcome.inserted);
|
|
901
942
|
this.resizeSessions();
|
|
@@ -913,7 +954,7 @@ export class CrosscheckCoordinator {
|
|
|
913
954
|
return this.isCrosscheckArmed() || this.isReconcileArmed();
|
|
914
955
|
}
|
|
915
956
|
isCrosscheckArmed() {
|
|
916
|
-
if (!this.store || !this.sessionsReady)
|
|
957
|
+
if (this.finishing || !this.store || !this.sessionsReady)
|
|
917
958
|
return false;
|
|
918
959
|
if (this.store.generationInvalidated())
|
|
919
960
|
return false;
|
|
@@ -923,7 +964,7 @@ export class CrosscheckCoordinator {
|
|
|
923
964
|
return this.allResultsReady() && this.allAgentsIdle();
|
|
924
965
|
}
|
|
925
966
|
isReconcileArmed() {
|
|
926
|
-
if (!this.store || !this.sessionsReady)
|
|
967
|
+
if (this.finishing || !this.store || !this.sessionsReady)
|
|
927
968
|
return false;
|
|
928
969
|
if (this.store.generationInvalidated())
|
|
929
970
|
return false;
|
|
@@ -952,11 +993,12 @@ export class CrosscheckCoordinator {
|
|
|
952
993
|
return status !== undefined && status !== "delivered";
|
|
953
994
|
}
|
|
954
995
|
canRetryPendingDispatch() {
|
|
955
|
-
if (!this.store)
|
|
996
|
+
if (this.finishing || !this.store)
|
|
956
997
|
return false;
|
|
957
998
|
const dispatchPhase = this.store.dispatchPhase();
|
|
958
999
|
if (this.dispatching
|
|
959
1000
|
|| !this.sessionsReady
|
|
1001
|
+
|| this.launchReconciliationPending
|
|
960
1002
|
|| dispatchPhase === undefined
|
|
961
1003
|
|| (this.store.generationConsumed() && dispatchPhase === "crosscheck")
|
|
962
1004
|
|| !this.allResultsReady()
|
|
@@ -1120,28 +1162,50 @@ export class CrosscheckCoordinator {
|
|
|
1120
1162
|
let submitted = false;
|
|
1121
1163
|
const provider = resolveProvider(runtime.config.driver);
|
|
1122
1164
|
const releaseInputLock = this.lockAutomatedInput(agent);
|
|
1165
|
+
let receipt;
|
|
1166
|
+
const markSubmitted = () => {
|
|
1167
|
+
receipt?.markWritten();
|
|
1168
|
+
if (!receipt || submitted || !this.isCurrentGenerationOperation(generationId, operation))
|
|
1169
|
+
return;
|
|
1170
|
+
submitted = true;
|
|
1171
|
+
if (progressAttemptId) {
|
|
1172
|
+
this.markCrosscheckSlotSubmitted(agent, generationId, dispatch.token, progressAttemptId);
|
|
1173
|
+
const identity = { generationId, dispatchToken: dispatch.token, attemptId: progressAttemptId };
|
|
1174
|
+
receipt.onSettled((result) => {
|
|
1175
|
+
if ((result !== "completed" && result !== "cancelled")
|
|
1176
|
+
|| !this.isCurrentGenerationOperation(generationId, operation))
|
|
1177
|
+
return;
|
|
1178
|
+
this.settleCrosscheckSlot(agent, identity);
|
|
1179
|
+
this.runDispatchOperation(agent, this.handleAgentIdle(agent, identity), "settle crosscheck request");
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1123
1183
|
try {
|
|
1184
|
+
receipt = await runtime.monitor.reserveTurnFromSession();
|
|
1124
1185
|
await (this.options.sendInquiry ?? sendInquiryQuestion)(runtime.session, this.buildDispatchPrompt(agent, generationId, dispatch.phase, dispatch.round), {
|
|
1125
1186
|
signal: operation.signal,
|
|
1126
1187
|
composer: provider.composer,
|
|
1188
|
+
onSubmitWritten: markSubmitted,
|
|
1127
1189
|
onSubmitted: () => {
|
|
1128
1190
|
if (!this.isCurrentGenerationOperation(generationId, operation))
|
|
1129
1191
|
return;
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
this.markCrosscheckSlotSubmitted(agent, generationId, dispatch.token, progressAttemptId);
|
|
1133
|
-
}
|
|
1134
|
-
runtime.monitor.beginTurn();
|
|
1192
|
+
markSubmitted();
|
|
1193
|
+
runtime.monitor.beginTurn(receipt);
|
|
1135
1194
|
},
|
|
1136
1195
|
});
|
|
1137
1196
|
}
|
|
1138
1197
|
finally {
|
|
1139
1198
|
releaseInputLock();
|
|
1199
|
+
receipt?.release();
|
|
1200
|
+
if (submitted && this.isCurrentGenerationOperation(generationId, operation)) {
|
|
1201
|
+
await this.transitionDispatchStatus(agent, generationId, dispatch.token, "pending", "submitted");
|
|
1202
|
+
if (runtime.monitor.isIdle)
|
|
1203
|
+
await this.handleAgentIdle(agent);
|
|
1204
|
+
}
|
|
1140
1205
|
}
|
|
1141
1206
|
if (!submitted || !this.isCurrentGenerationOperation(generationId, operation))
|
|
1142
1207
|
return;
|
|
1143
|
-
await this.
|
|
1144
|
-
const classification = await provider.live.classifyDispatchDelivery(runtime.session.identity.sessionFilePath, dispatch.agents[agent].baseline);
|
|
1208
|
+
const classification = await this.classifyRuntimeDispatchDelivery(runtime, dispatch.agents[agent].baseline);
|
|
1145
1209
|
if (!this.isCurrentGenerationOperation(generationId, operation))
|
|
1146
1210
|
return;
|
|
1147
1211
|
if (classification === "present") {
|
|
@@ -1150,6 +1214,8 @@ export class CrosscheckCoordinator {
|
|
|
1150
1214
|
if (!this.isCurrentGenerationOperation(generationId, operation))
|
|
1151
1215
|
return;
|
|
1152
1216
|
await this.finalizeDispatchIfComplete(generationId);
|
|
1217
|
+
// The matching turns may have settled before delivery confirmation finished.
|
|
1218
|
+
await this.maybeSettleReconcileGate();
|
|
1153
1219
|
}
|
|
1154
1220
|
buildDispatchPrompt(agent, generationId, phase, round) {
|
|
1155
1221
|
const other = otherAgent(agent);
|
|
@@ -1165,7 +1231,23 @@ export class CrosscheckCoordinator {
|
|
|
1165
1231
|
const ownJsonFile = reconcileJsonFilePath(this.options.persistentDir, agent, generationId, round);
|
|
1166
1232
|
return buildExecutorReconcilePrompt(otherJsonFile, ownJsonFile);
|
|
1167
1233
|
}
|
|
1234
|
+
async reconcileLaunchDispatch() {
|
|
1235
|
+
if (!this.launchReconciliationPending
|
|
1236
|
+
|| !this.sessionsReady
|
|
1237
|
+
|| !this.allAgentsIdle())
|
|
1238
|
+
return;
|
|
1239
|
+
// Release once: later dispatches still reconcile each side independently.
|
|
1240
|
+
this.launchReconciliationPending = false;
|
|
1241
|
+
for (const agent of this.agents.keys())
|
|
1242
|
+
await this.handleAgentIdle(agent);
|
|
1243
|
+
await this.reconcilePersistedDispatch();
|
|
1244
|
+
await this.maybeSettleReconcileGate();
|
|
1245
|
+
}
|
|
1168
1246
|
async reconcilePersistedDispatch() {
|
|
1247
|
+
if (this.launchReconciliationPending) {
|
|
1248
|
+
await this.reconcileLaunchDispatch();
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1169
1251
|
const snapshot = this.store.snapshot();
|
|
1170
1252
|
const generationId = snapshot.generation.id;
|
|
1171
1253
|
const dispatch = snapshot.generation.dispatch;
|
|
@@ -1185,6 +1267,7 @@ export class CrosscheckCoordinator {
|
|
|
1185
1267
|
async retryPersistedDispatch() {
|
|
1186
1268
|
if (this.dispatching
|
|
1187
1269
|
|| !this.sessionsReady
|
|
1270
|
+
|| this.launchReconciliationPending
|
|
1188
1271
|
|| !this.allResultsReady()
|
|
1189
1272
|
|| !this.allAgentsIdle())
|
|
1190
1273
|
return;
|
|
@@ -1235,18 +1318,9 @@ export class CrosscheckCoordinator {
|
|
|
1235
1318
|
async reconcileDispatchSide(agent, generationId, dispatch, expectedStatus, onAbsent, operation = this.currentDispatchOperationContext()) {
|
|
1236
1319
|
if (!this.isCurrentGenerationOperation(generationId, operation))
|
|
1237
1320
|
return false;
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
return runtime
|
|
1242
|
-
? {
|
|
1243
|
-
driver: runtime.config.driver,
|
|
1244
|
-
sessionFilePath: runtime.session.identity.sessionFilePath,
|
|
1245
|
-
}
|
|
1246
|
-
: undefined;
|
|
1247
|
-
})()
|
|
1248
|
-
: this.store.snapshot().sessions[agent];
|
|
1249
|
-
if (!target) {
|
|
1321
|
+
const runtimeTarget = onAbsent ? this.agents.get(agent) : undefined;
|
|
1322
|
+
const persistedTarget = onAbsent ? undefined : this.store.snapshot().sessions[agent];
|
|
1323
|
+
if (!runtimeTarget && !persistedTarget) {
|
|
1250
1324
|
if (!onAbsent
|
|
1251
1325
|
&&
|
|
1252
1326
|
this.isCurrentDispatchSide(agent, generationId, dispatch.token, expectedStatus)) {
|
|
@@ -1254,11 +1328,13 @@ export class CrosscheckCoordinator {
|
|
|
1254
1328
|
}
|
|
1255
1329
|
return true;
|
|
1256
1330
|
}
|
|
1257
|
-
if (
|
|
1331
|
+
if (persistedTarget?.pendingDispatchBaselineReset) {
|
|
1258
1332
|
return true;
|
|
1259
1333
|
}
|
|
1260
|
-
const classification =
|
|
1261
|
-
.
|
|
1334
|
+
const classification = runtimeTarget
|
|
1335
|
+
? await this.classifyRuntimeDispatchDelivery(runtimeTarget, dispatch.agents[agent].baseline)
|
|
1336
|
+
: await resolveProvider(persistedTarget.driver)
|
|
1337
|
+
.live.classifyDispatchDelivery(persistedTarget.sessionFilePath, dispatch.agents[agent].baseline);
|
|
1262
1338
|
if (!this.isCurrentGenerationOperation(generationId, operation))
|
|
1263
1339
|
return false;
|
|
1264
1340
|
if (!this.isCurrentDispatch(generationId, dispatch.token))
|
|
@@ -1334,6 +1410,8 @@ export class CrosscheckCoordinator {
|
|
|
1334
1410
|
this.refreshStatusHint();
|
|
1335
1411
|
}
|
|
1336
1412
|
async maybeSettleReconcileGate() {
|
|
1413
|
+
if (this.finishing)
|
|
1414
|
+
return;
|
|
1337
1415
|
const snapshot = this.store.snapshot();
|
|
1338
1416
|
if (snapshot.generation.reconcilePendingSettlement
|
|
1339
1417
|
&& !snapshot.generation.dispatch
|
|
@@ -1404,6 +1482,12 @@ export class CrosscheckCoordinator {
|
|
|
1404
1482
|
this.refreshStatusHint();
|
|
1405
1483
|
this.options.host.scheduleParentUiRender();
|
|
1406
1484
|
}
|
|
1485
|
+
async classifyRuntimeDispatchDelivery(runtime, baseline) {
|
|
1486
|
+
const liveClassification = runtime.monitor.classifyDeliverySince?.(baseline);
|
|
1487
|
+
if (liveClassification)
|
|
1488
|
+
return liveClassification;
|
|
1489
|
+
return await resolveProvider(runtime.config.driver).live.classifyDispatchDelivery(runtime.session.identity.sessionFilePath, baseline);
|
|
1490
|
+
}
|
|
1407
1491
|
markDispatchDelivered(agent, generationId, dispatchToken, expectedStatus) {
|
|
1408
1492
|
return this.transitionDispatchStatus(agent, generationId, dispatchToken, expectedStatus, "delivered");
|
|
1409
1493
|
}
|
|
@@ -1433,6 +1517,8 @@ export class CrosscheckCoordinator {
|
|
|
1433
1517
|
}
|
|
1434
1518
|
/** Sends the committed Broadcast text and, for Steer/Follow-up, starts the next generation first. */
|
|
1435
1519
|
async submitBroadcast() {
|
|
1520
|
+
if (this.finishing)
|
|
1521
|
+
return;
|
|
1436
1522
|
const text = this.broadcast.submissionText();
|
|
1437
1523
|
if (text === undefined)
|
|
1438
1524
|
return;
|
|
@@ -1538,6 +1624,7 @@ export class CrosscheckCoordinator {
|
|
|
1538
1624
|
: text;
|
|
1539
1625
|
const provider = resolveProvider(runtime.config.driver);
|
|
1540
1626
|
const releaseInputLock = this.lockAutomatedInput(agent);
|
|
1627
|
+
let receipt;
|
|
1541
1628
|
try {
|
|
1542
1629
|
if (generationKind && provider.cancelSequence) {
|
|
1543
1630
|
await sendCancelSequence(runtime.session.pty, provider.cancelSequence, operation.signal, runtime.monitor.isIdle);
|
|
@@ -1545,19 +1632,22 @@ export class CrosscheckCoordinator {
|
|
|
1545
1632
|
if (!this.isCurrentGenerationOperation(generationId, operation, { allowRewound: conversational })) {
|
|
1546
1633
|
return;
|
|
1547
1634
|
}
|
|
1635
|
+
receipt = await runtime.monitor.reserveTurnFromSession();
|
|
1548
1636
|
await (this.options.sendInquiry ?? sendInquiryQuestion)(runtime.session, prompt, {
|
|
1549
1637
|
signal: operation.signal,
|
|
1550
1638
|
composer: provider.composer,
|
|
1639
|
+
onSubmitWritten: () => receipt?.markWritten(),
|
|
1551
1640
|
onSubmitted: () => {
|
|
1552
1641
|
if (!this.isCurrentGenerationOperation(generationId, operation, { allowRewound: conversational }))
|
|
1553
1642
|
return;
|
|
1554
|
-
runtime.monitor.beginTurn();
|
|
1643
|
+
runtime.monitor.beginTurn(receipt);
|
|
1555
1644
|
},
|
|
1556
1645
|
...(generationKind ? { escapeBeforePaste: true } : {}),
|
|
1557
1646
|
});
|
|
1558
1647
|
}
|
|
1559
1648
|
finally {
|
|
1560
1649
|
releaseInputLock();
|
|
1650
|
+
receipt?.release();
|
|
1561
1651
|
}
|
|
1562
1652
|
}
|
|
1563
1653
|
refreshResults() {
|
|
@@ -1579,8 +1669,9 @@ export class CrosscheckCoordinator {
|
|
|
1579
1669
|
agent,
|
|
1580
1670
|
ready: await fileHasContent(generation.resultFiles[agent]),
|
|
1581
1671
|
})));
|
|
1582
|
-
//
|
|
1583
|
-
|
|
1672
|
+
// A same-generation rewind also invalidates an outstanding result read.
|
|
1673
|
+
const current = this.store.snapshot().generation;
|
|
1674
|
+
if (this.finishing || current.id !== generation.id || current.rewind)
|
|
1584
1675
|
return;
|
|
1585
1676
|
for (const { agent, ready } of readiness) {
|
|
1586
1677
|
const runtime = this.agents.get(agent);
|
|
@@ -1649,6 +1740,7 @@ export class CrosscheckCoordinator {
|
|
|
1649
1740
|
if (this.finishing
|
|
1650
1741
|
|| this.dispatching
|
|
1651
1742
|
|| !this.sessionsReady
|
|
1743
|
+
|| this.launchReconciliationPending
|
|
1652
1744
|
|| this.resendAfterLaunch.size === 0
|
|
1653
1745
|
|| !this.allResultsReady()
|
|
1654
1746
|
|| [...this.agents.values()].some((runtime) => runtime.freshForPendingDispatch)
|
|
@@ -1658,6 +1750,12 @@ export class CrosscheckCoordinator {
|
|
|
1658
1750
|
this.runDispatchOperation(undefined, this.retryPersistedDispatch(), "resume crosscheck");
|
|
1659
1751
|
}
|
|
1660
1752
|
async handleAgentIdle(agent, progressIdentity = this.takeCrosscheckTurnIdentity(agent)) {
|
|
1753
|
+
if (this.finishing)
|
|
1754
|
+
return;
|
|
1755
|
+
if (this.launchReconciliationPending) {
|
|
1756
|
+
await this.reconcileLaunchDispatch();
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1661
1759
|
this.settleCrosscheckSlot(agent, progressIdentity);
|
|
1662
1760
|
const runtime = this.agents.get(agent);
|
|
1663
1761
|
if (runtime?.freshForPendingDispatch
|
|
@@ -1694,8 +1792,7 @@ export class CrosscheckCoordinator {
|
|
|
1694
1792
|
if (runtime
|
|
1695
1793
|
&& dispatch?.agents[agent].status === "submitted"
|
|
1696
1794
|
&& !runtime.freshForPendingDispatch) {
|
|
1697
|
-
const classification = await
|
|
1698
|
-
.live.classifyDispatchDelivery(runtime.session.identity.sessionFilePath, dispatch.agents[agent].baseline);
|
|
1795
|
+
const classification = await this.classifyRuntimeDispatchDelivery(runtime, dispatch.agents[agent].baseline);
|
|
1699
1796
|
if (!this.isCurrentDispatch(snapshot.generation.id, dispatch.token)) {
|
|
1700
1797
|
this.maybeRetryPersistedDispatch();
|
|
1701
1798
|
return;
|
|
@@ -1773,6 +1870,7 @@ export class CrosscheckCoordinator {
|
|
|
1773
1870
|
this.launchAbort?.abort(new Error("Crosscheck launch cancelled"));
|
|
1774
1871
|
this.dispatchAbort.abort(new Error("Crosscheck coordinator stopped"));
|
|
1775
1872
|
this.abortActiveDispatchOperations(new Error("Crosscheck coordinator stopped"));
|
|
1873
|
+
this.options.host.scheduleParentUiRender();
|
|
1776
1874
|
this.finishResolve?.({ kind: "crosscheck", interrupted: true });
|
|
1777
1875
|
}
|
|
1778
1876
|
fail(error) {
|
|
@@ -1799,24 +1897,32 @@ export class CrosscheckCoordinator {
|
|
|
1799
1897
|
if (this.activityTimer)
|
|
1800
1898
|
clearInterval(this.activityTimer);
|
|
1801
1899
|
this.activityTimer = undefined;
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
this.
|
|
1900
|
+
try {
|
|
1901
|
+
const monitors = await Promise.allSettled([...this.agents.values()].map((runtime) => runtime.monitor.shutdown()));
|
|
1902
|
+
await Promise.allSettled([...this.dispatchOperations]);
|
|
1903
|
+
await this.resultRefresh;
|
|
1904
|
+
this.trackActivity();
|
|
1905
|
+
await Promise.allSettled([...this.activityOperations]);
|
|
1906
|
+
await this.store?.drain();
|
|
1907
|
+
const failedMonitor = monitors.find((result) => result.status === "rejected");
|
|
1908
|
+
if (failedMonitor?.status === "rejected")
|
|
1909
|
+
throw failedMonitor.reason;
|
|
1805
1910
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1911
|
+
finally {
|
|
1912
|
+
for (const runtime of this.agents.values())
|
|
1913
|
+
runtime.session.close();
|
|
1914
|
+
for (const session of this.launchingSessions.values())
|
|
1915
|
+
session.close();
|
|
1916
|
+
if (this.transientFlash) {
|
|
1917
|
+
clearTimeout(this.transientFlash.timer);
|
|
1918
|
+
this.transientFlash = undefined;
|
|
1919
|
+
}
|
|
1920
|
+
this.detachUi?.();
|
|
1921
|
+
this.detachUi = undefined;
|
|
1922
|
+
this.options.host.clearMouseModeSource(MOUSE_SOURCE);
|
|
1923
|
+
this.agents.clear();
|
|
1924
|
+
this.launchingSessions.clear();
|
|
1815
1925
|
}
|
|
1816
|
-
for (const session of this.launchingSessions.values())
|
|
1817
|
-
session.close();
|
|
1818
|
-
this.agents.clear();
|
|
1819
|
-
this.launchingSessions.clear();
|
|
1820
1926
|
}
|
|
1821
1927
|
runDispatchOperation(agent, operation, action) {
|
|
1822
1928
|
const tracked = operation
|
|
@@ -1921,6 +2027,7 @@ export class CrosscheckCoordinator {
|
|
|
1921
2027
|
catch {
|
|
1922
2028
|
// Result may not exist while the executor is still working.
|
|
1923
2029
|
}
|
|
2030
|
+
const observerDiagnostics = runtime?.session.observerDiagnostics?.() ?? [];
|
|
1924
2031
|
return {
|
|
1925
2032
|
seq: index,
|
|
1926
2033
|
stepId: agent,
|
|
@@ -1934,6 +2041,9 @@ export class CrosscheckCoordinator {
|
|
|
1934
2041
|
sessionFilePaths: runtime ? [runtime.session.identity.sessionFilePath] : [],
|
|
1935
2042
|
inFlight: true,
|
|
1936
2043
|
...(runtime && { ptyTailSnapshot: runtime.session.ptyTail.snapshot() }),
|
|
2044
|
+
...(observerDiagnostics && observerDiagnostics.length > 0 && {
|
|
2045
|
+
observerDiagnostics,
|
|
2046
|
+
}),
|
|
1937
2047
|
};
|
|
1938
2048
|
}));
|
|
1939
2049
|
}
|
|
@@ -1983,6 +2093,16 @@ export function buildCrosscheckConfigurations(values) {
|
|
|
1983
2093
|
function otherAgent(agent) {
|
|
1984
2094
|
return agent === "agent-1" ? "agent-2" : "agent-1";
|
|
1985
2095
|
}
|
|
2096
|
+
function observerLaunchFailureError(driver, agent, cause) {
|
|
2097
|
+
if (!(cause instanceof Error))
|
|
2098
|
+
return cause;
|
|
2099
|
+
return /\bobserver\b/i.test(cause.message)
|
|
2100
|
+
? observerFailureError(driver, agent, cause)
|
|
2101
|
+
: cause;
|
|
2102
|
+
}
|
|
2103
|
+
function observerFailureError(driver, agent, cause) {
|
|
2104
|
+
return new Error(`${driver} ${agentLabel(agent)} observer failed: ${cause.message}`, { cause });
|
|
2105
|
+
}
|
|
1986
2106
|
function agentLabel(agent) {
|
|
1987
2107
|
return agent === "agent-1" ? "Agent 1" : "Agent 2";
|
|
1988
2108
|
}
|