poly-weaver 0.15.3 → 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.
Files changed (174) hide show
  1. package/dist/agents/implementors/handler.d.ts.map +1 -1
  2. package/dist/agents/implementors/handler.js +7 -2
  3. package/dist/agents/implementors/handler.js.map +1 -1
  4. package/dist/agents/interviewers/handler.d.ts.map +1 -1
  5. package/dist/agents/interviewers/handler.js +3 -1
  6. package/dist/agents/interviewers/handler.js.map +1 -1
  7. package/dist/agents/planners/adapter.d.ts.map +1 -1
  8. package/dist/agents/planners/adapter.js +30 -11
  9. package/dist/agents/planners/adapter.js.map +1 -1
  10. package/dist/agents/planners/handler.d.ts.map +1 -1
  11. package/dist/agents/planners/handler.js +7 -2
  12. package/dist/agents/planners/handler.js.map +1 -1
  13. package/dist/agents/reviewers/adapter.d.ts.map +1 -1
  14. package/dist/agents/reviewers/adapter.js +1 -0
  15. package/dist/agents/reviewers/adapter.js.map +1 -1
  16. package/dist/agents/reviewers/handler.d.ts.map +1 -1
  17. package/dist/agents/reviewers/handler.js +23 -4
  18. package/dist/agents/reviewers/handler.js.map +1 -1
  19. package/dist/agents/reviewers/types.d.ts +2 -0
  20. package/dist/agents/reviewers/types.d.ts.map +1 -1
  21. package/dist/agents/runner.d.ts +18 -1
  22. package/dist/agents/runner.d.ts.map +1 -1
  23. package/dist/agents/runner.js +136 -20
  24. package/dist/agents/runner.js.map +1 -1
  25. package/dist/agents/simplifiers/handler.d.ts.map +1 -1
  26. package/dist/agents/simplifiers/handler.js +7 -2
  27. package/dist/agents/simplifiers/handler.js.map +1 -1
  28. package/dist/auto-update/detect-agents.d.ts +1 -0
  29. package/dist/auto-update/detect-agents.d.ts.map +1 -1
  30. package/dist/auto-update/detect-agents.js +8 -7
  31. package/dist/auto-update/detect-agents.js.map +1 -1
  32. package/dist/cli.js +16 -4
  33. package/dist/cli.js.map +1 -1
  34. package/dist/crosscheck/coordinator.d.ts +5 -0
  35. package/dist/crosscheck/coordinator.d.ts.map +1 -1
  36. package/dist/crosscheck/coordinator.js +177 -91
  37. package/dist/crosscheck/coordinator.js.map +1 -1
  38. package/dist/crosscheck/live-agent-session.d.ts +7 -1
  39. package/dist/crosscheck/live-agent-session.d.ts.map +1 -1
  40. package/dist/crosscheck/live-agent-session.js +61 -7
  41. package/dist/crosscheck/live-agent-session.js.map +1 -1
  42. package/dist/crosscheck/state.d.ts +3 -0
  43. package/dist/crosscheck/state.d.ts.map +1 -1
  44. package/dist/crosscheck/state.js +17 -2
  45. package/dist/crosscheck/state.js.map +1 -1
  46. package/dist/dump/collector.d.ts.map +1 -1
  47. package/dist/dump/collector.js +3 -0
  48. package/dist/dump/collector.js.map +1 -1
  49. package/dist/dump/service.d.ts.map +1 -1
  50. package/dist/dump/service.js +3 -0
  51. package/dist/dump/service.js.map +1 -1
  52. package/dist/dump/types.d.ts +3 -0
  53. package/dist/dump/types.d.ts.map +1 -1
  54. package/dist/dump/types.js.map +1 -1
  55. package/dist/flow/executor.d.ts.map +1 -1
  56. package/dist/flow/executor.js +5 -0
  57. package/dist/flow/executor.js.map +1 -1
  58. package/dist/flow/types.d.ts +5 -0
  59. package/dist/flow/types.d.ts.map +1 -1
  60. package/dist/flow/types.js.map +1 -1
  61. package/dist/offscreen/controller.d.ts +13 -2
  62. package/dist/offscreen/controller.d.ts.map +1 -1
  63. package/dist/offscreen/controller.js +212 -91
  64. package/dist/offscreen/controller.js.map +1 -1
  65. package/dist/offscreen/fork-launch.d.ts +2 -2
  66. package/dist/offscreen/fork-launch.d.ts.map +1 -1
  67. package/dist/offscreen/fork-launch.js +2 -2
  68. package/dist/offscreen/fork-launch.js.map +1 -1
  69. package/dist/offscreen/fork.d.ts +16 -2
  70. package/dist/offscreen/fork.d.ts.map +1 -1
  71. package/dist/offscreen/fork.js +79 -40
  72. package/dist/offscreen/fork.js.map +1 -1
  73. package/dist/offscreen/inquiry-pane.d.ts +2 -1
  74. package/dist/offscreen/inquiry-pane.d.ts.map +1 -1
  75. package/dist/offscreen/inquiry-pane.js +8 -2
  76. package/dist/offscreen/inquiry-pane.js.map +1 -1
  77. package/dist/offscreen/panes.d.ts +1 -0
  78. package/dist/offscreen/panes.d.ts.map +1 -1
  79. package/dist/offscreen/registry.d.ts +2 -2
  80. package/dist/offscreen/registry.d.ts.map +1 -1
  81. package/dist/offscreen/registry.js +5 -1
  82. package/dist/offscreen/registry.js.map +1 -1
  83. package/dist/offscreen/resolve.d.ts +2 -0
  84. package/dist/offscreen/resolve.d.ts.map +1 -1
  85. package/dist/offscreen/resolve.js +5 -1
  86. package/dist/offscreen/resolve.js.map +1 -1
  87. package/dist/offscreen/session-turn-monitor.d.ts +3 -1
  88. package/dist/offscreen/session-turn-monitor.d.ts.map +1 -1
  89. package/dist/offscreen/session-turn-monitor.js +10 -2
  90. package/dist/offscreen/session-turn-monitor.js.map +1 -1
  91. package/dist/offscreen/split-inquiry.d.ts.map +1 -1
  92. package/dist/offscreen/split-inquiry.js +5 -0
  93. package/dist/offscreen/split-inquiry.js.map +1 -1
  94. package/dist/offscreen/starting-pane.d.ts +13 -0
  95. package/dist/offscreen/starting-pane.d.ts.map +1 -0
  96. package/dist/offscreen/starting-pane.js +24 -0
  97. package/dist/offscreen/starting-pane.js.map +1 -0
  98. package/dist/offscreen/surface.d.ts +1 -0
  99. package/dist/offscreen/surface.d.ts.map +1 -1
  100. package/dist/offscreen/surface.js +5 -3
  101. package/dist/offscreen/surface.js.map +1 -1
  102. package/dist/orchestrator.d.ts.map +1 -1
  103. package/dist/orchestrator.js +7 -1
  104. package/dist/orchestrator.js.map +1 -1
  105. package/dist/providers/copilot/completion.d.ts +32 -21
  106. package/dist/providers/copilot/completion.d.ts.map +1 -1
  107. package/dist/providers/copilot/completion.js +100 -165
  108. package/dist/providers/copilot/completion.js.map +1 -1
  109. package/dist/providers/copilot/environment.d.ts +2 -0
  110. package/dist/providers/copilot/environment.d.ts.map +1 -0
  111. package/dist/providers/copilot/environment.js +8 -0
  112. package/dist/providers/copilot/environment.js.map +1 -0
  113. package/dist/providers/copilot/fork-state.d.ts +7 -0
  114. package/dist/providers/copilot/fork-state.d.ts.map +1 -0
  115. package/dist/providers/copilot/fork-state.js +150 -0
  116. package/dist/providers/copilot/fork-state.js.map +1 -0
  117. package/dist/providers/copilot/observation.d.ts +275 -0
  118. package/dist/providers/copilot/observation.d.ts.map +1 -0
  119. package/dist/providers/copilot/observation.js +2072 -0
  120. package/dist/providers/copilot/observation.js.map +1 -0
  121. package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.d.mts +2 -0
  122. package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.d.mts.map +1 -0
  123. package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.mjs +426 -0
  124. package/dist/providers/copilot/observer-extension/com.github.copilot/extensions/poly-weaver-observer/extension.mjs.map +1 -0
  125. package/dist/providers/copilot/observer-extension/plugin.json +6 -0
  126. package/dist/providers/copilot/record-properties.d.ts +4 -0
  127. package/dist/providers/copilot/record-properties.d.ts.map +1 -0
  128. package/dist/providers/copilot/record-properties.js +14 -0
  129. package/dist/providers/copilot/record-properties.js.map +1 -0
  130. package/dist/providers/copilot/session.d.ts +8 -33
  131. package/dist/providers/copilot/session.d.ts.map +1 -1
  132. package/dist/providers/copilot/session.js +10 -176
  133. package/dist/providers/copilot/session.js.map +1 -1
  134. package/dist/providers/copilot/strategy.d.ts +3 -5
  135. package/dist/providers/copilot/strategy.d.ts.map +1 -1
  136. package/dist/providers/copilot/strategy.js +59 -66
  137. package/dist/providers/copilot/strategy.js.map +1 -1
  138. package/dist/providers/fork-cleanup.d.ts +4 -0
  139. package/dist/providers/fork-cleanup.d.ts.map +1 -0
  140. package/dist/providers/fork-cleanup.js +21 -0
  141. package/dist/providers/fork-cleanup.js.map +1 -0
  142. package/dist/providers/fork.d.ts +8 -3
  143. package/dist/providers/fork.d.ts.map +1 -1
  144. package/dist/providers/fork.js.map +1 -1
  145. package/dist/providers/invoke.d.ts.map +1 -1
  146. package/dist/providers/invoke.js +85 -34
  147. package/dist/providers/invoke.js.map +1 -1
  148. package/dist/providers/live.d.ts.map +1 -1
  149. package/dist/providers/live.js +43 -17
  150. package/dist/providers/live.js.map +1 -1
  151. package/dist/providers/observer-run.d.ts +4 -0
  152. package/dist/providers/observer-run.d.ts.map +1 -0
  153. package/dist/providers/observer-run.js +23 -0
  154. package/dist/providers/observer-run.js.map +1 -0
  155. package/dist/providers/session-launch.d.ts +3 -1
  156. package/dist/providers/session-launch.d.ts.map +1 -1
  157. package/dist/providers/session-launch.js +38 -19
  158. package/dist/providers/session-launch.js.map +1 -1
  159. package/dist/providers/types.d.ts +156 -4
  160. package/dist/providers/types.d.ts.map +1 -1
  161. package/dist/providers/types.js.map +1 -1
  162. package/dist/session/resume.d.ts.map +1 -1
  163. package/dist/session/resume.js +16 -2
  164. package/dist/session/resume.js.map +1 -1
  165. package/dist/terminal/paste-submit.d.ts.map +1 -1
  166. package/dist/terminal/paste-submit.js +43 -37
  167. package/dist/terminal/paste-submit.js.map +1 -1
  168. package/dist/user/host-curate-prompt.d.ts.map +1 -1
  169. package/dist/user/host-curate-prompt.js +9 -6
  170. package/dist/user/host-curate-prompt.js.map +1 -1
  171. package/dist/user/host-prompt.d.ts.map +1 -1
  172. package/dist/user/host-prompt.js +9 -6
  173. package/dist/user/host-prompt.js.map +1 -1
  174. package/package.json +4 -2
@@ -3,6 +3,7 @@ import { builtinStrategies, resolveProvider } from "../providers/registry.js";
3
3
  import { Fork } from "./fork.js";
4
4
  import { foldAltMetaKeys, isPrimaryIssueKey, isPrimaryShowKey, isSecondaryIssueKey, isSecondaryShowKey, isSummarizeKey, } from "./keys.js";
5
5
  import { InquiryPaneController } from "./inquiry-pane.js";
6
+ import { StartingInquiryPane } from "./starting-pane.js";
6
7
  import { ArtifactPaneController } from "./artifact-pane.js";
7
8
  import { registerOffscreenDisposer } from "./registry.js";
8
9
  import { SplitInquiryCoordinator } from "./split-inquiry.js";
@@ -19,6 +20,7 @@ export class OffscreenController {
19
20
  host;
20
21
  workdir;
21
22
  inquiry;
23
+ observerRuns;
22
24
  slots = new Map();
23
25
  artifactConfigs;
24
26
  turnPollMs;
@@ -26,6 +28,9 @@ export class OffscreenController {
26
28
  tracksTurns;
27
29
  forks = new Map();
28
30
  pending = new Map();
31
+ pendingForks = new Map();
32
+ pendingQuestions = new Map();
33
+ launchAbort = new AbortController();
29
34
  sendPending = new Set();
30
35
  turnInProgress = new Set();
31
36
  turnMonitors = new Map();
@@ -41,14 +46,17 @@ export class OffscreenController {
41
46
  forkSubmitFloorReads = new Map();
42
47
  forkLocateWarned = new Set();
43
48
  activeArtifactIndexes = new Map();
49
+ artifactPanes = new Map();
44
50
  unregister;
45
51
  split;
46
52
  shown;
47
53
  disposed = false;
48
- constructor(host, workdir, slots, artifactConfigs = {}, inquiry) {
54
+ disposal;
55
+ constructor(host, workdir, slots, artifactConfigs = {}, inquiry, observerRuns) {
49
56
  this.host = host;
50
57
  this.workdir = workdir;
51
58
  this.inquiry = inquiry;
59
+ this.observerRuns = observerRuns;
52
60
  for (const slot of slots) {
53
61
  this.slots.set(slot.binding, slot);
54
62
  }
@@ -66,7 +74,7 @@ export class OffscreenController {
66
74
  }
67
75
  selectionDelegate() {
68
76
  return {
69
- fork: this.shown ? this.forks.get(this.shown) : undefined,
77
+ fork: this.shown ? this.presentedFork(this.shown) : undefined,
70
78
  layout: this.host.getLayout(),
71
79
  coordinator: this.activeCoordinator(),
72
80
  };
@@ -74,15 +82,16 @@ export class OffscreenController {
74
82
  wrap(base) {
75
83
  return {
76
84
  getSurface: () => {
77
- const fork = this.shown ? this.forks.get(this.shown) : undefined;
78
- if (!fork)
85
+ const fork = this.shown ? this.presentedFork(this.shown) : undefined;
86
+ if (!this.shown)
79
87
  return base.getSurface();
80
88
  const layout = this.host.getLayout();
81
89
  const coordinator = this.activeCoordinator();
82
90
  if (coordinator) {
83
91
  return coordinator.getSurface(layout.columns, layout.childRows);
84
92
  }
85
- return new InquiryPaneController(fork).render(layout.columns, layout.childRows);
93
+ return (fork ? new InquiryPaneController(fork, this.forks.has(this.shown)) : this.startingPane(this.shown))
94
+ .render(layout.columns, layout.childRows);
86
95
  },
87
96
  selectionRegionAt: (column, row) => {
88
97
  const { fork, layout, coordinator } = this.selectionDelegate();
@@ -90,7 +99,7 @@ export class OffscreenController {
90
99
  return coordinator.selectionRegionAt(column, row, layout.columns, layout.childRows);
91
100
  }
92
101
  if (!fork)
93
- return base.selectionRegionAt?.(column, row);
102
+ return this.shown ? null : base.selectionRegionAt?.(column, row);
94
103
  if (row < 2 || row > layout.childRows)
95
104
  return null;
96
105
  return fork.vt.isAlternate === true
@@ -103,7 +112,7 @@ export class OffscreenController {
103
112
  return coordinator.selectionTargetAt(column, row, layout.columns, layout.childRows);
104
113
  }
105
114
  if (!fork)
106
- return base.selectionTargetAt?.(column, row) ?? null;
115
+ return this.shown ? null : base.selectionTargetAt?.(column, row) ?? null;
107
116
  if (fork.vt.isAlternate === true)
108
117
  return null;
109
118
  if (column < 1 || column > layout.columns || row < 2 || row > layout.childRows)
@@ -116,7 +125,7 @@ export class OffscreenController {
116
125
  return coordinator.scrollSelectableSurfaceAt(column, row, direction, layout.columns, layout.childRows);
117
126
  }
118
127
  if (!fork || fork.vt.isAlternate === true) {
119
- return base.scrollSelectableSurfaceAt?.(column, row, direction) ?? 0;
128
+ return this.shown ? 0 : base.scrollSelectableSurfaceAt?.(column, row, direction) ?? 0;
120
129
  }
121
130
  if (column < 1 || column > layout.columns)
122
131
  return 0;
@@ -134,7 +143,7 @@ export class OffscreenController {
134
143
  return placement ? { region: placement.region, vt: fork.vt } : undefined;
135
144
  }
136
145
  if (!fork || fork.vt.isAlternate === true || layout.childRows < 2) {
137
- return base.forkSelectionPlacement?.();
146
+ return this.shown ? undefined : base.forkSelectionPlacement?.();
138
147
  }
139
148
  return {
140
149
  region: { rowStart: 2, rowEnd: layout.childRows, colStart: 1, colEnd: layout.columns },
@@ -146,7 +155,7 @@ export class OffscreenController {
146
155
  if (coordinator) {
147
156
  return coordinator.artifactPlacementAt(column, row, layout.columns, layout.childRows);
148
157
  }
149
- if (fork)
158
+ if (this.shown)
150
159
  return undefined;
151
160
  return base.docSurfaceSelectionPlacementAt?.(column, row);
152
161
  },
@@ -156,7 +165,7 @@ export class OffscreenController {
156
165
  const placement = coordinator.artifactPlacement(layout.columns, layout.childRows);
157
166
  return placement ? [placement] : [];
158
167
  }
159
- if (fork)
168
+ if (this.shown)
160
169
  return [];
161
170
  return base.docSurfaceSelectionPlacements?.() ?? [];
162
171
  },
@@ -165,11 +174,13 @@ export class OffscreenController {
165
174
  if (coordinator) {
166
175
  return coordinator.artifactPlacement(layout.columns, layout.childRows);
167
176
  }
168
- if (fork)
177
+ if (this.shown)
169
178
  return undefined;
170
179
  return base.artifactSelectionPlacement?.();
171
180
  },
172
181
  onEvents: (keys) => {
182
+ if (this.disposed)
183
+ return true;
173
184
  const events = this.inquiry ? foldAltMetaKeys(keys) : keys;
174
185
  if (keys.some(isSummarizeKey) && this.canSummarize("primary")) {
175
186
  return this.summarize("primary");
@@ -201,41 +212,60 @@ export class OffscreenController {
201
212
  onResize: (cols, rows) => {
202
213
  if (this.disposed)
203
214
  return;
204
- const fork = this.shown ? this.forks.get(this.shown) : undefined;
205
- if (fork && this.shown)
215
+ const fork = this.shown ? this.presentedFork(this.shown) : undefined;
216
+ if (this.shown)
206
217
  this.configurePresentation(this.shown, fork, cols, rows);
207
218
  this.updateForkState();
208
219
  },
209
220
  };
210
221
  }
211
222
  dispose() {
212
- if (this.disposed)
213
- return;
223
+ if (this.disposal)
224
+ return this.disposal;
214
225
  this.disposed = true;
226
+ this.launchAbort.abort();
215
227
  this.unregister();
216
228
  for (const binding of Array.from(this.sendControllers.keys())) {
217
229
  this.abortIssueSend(binding);
218
230
  }
219
231
  this.clearForkSessionWatchers();
220
- for (const fork of this.forks.values()) {
221
- fork.kill();
222
- }
232
+ const releases = [...this.forks.values(), ...this.pendingForks.values()].map((fork) => fork.kill());
233
+ const pending = Array.from(this.pending.values());
223
234
  this.forks.clear();
224
235
  this.pending.clear();
236
+ this.pendingForks.clear();
237
+ this.pendingQuestions.clear();
238
+ this.artifactPanes.clear();
225
239
  this.sendPending.clear();
226
240
  this.sendLocks.clear();
227
241
  this.shown = undefined;
228
242
  this.clearSplitCoordinator();
229
243
  this.host.clearMouseModeSource(OFFSCREEN_MOUSE_SOURCE);
230
244
  this.updateForkState();
245
+ return this.disposal = Promise.all([...releases, ...pending]).then(() => { });
231
246
  }
232
247
  handleForkEvents(keys) {
233
248
  const binding = this.shown;
234
249
  const fork = binding ? this.forks.get(binding) : undefined;
235
250
  if (!fork) {
236
- this.shown = undefined;
237
- this.clearSplitCoordinator();
238
- this.updateForkState();
251
+ if (!binding)
252
+ return true;
253
+ if (keys.some((key) => key.kind === "control" && key.byte === 0x03)) {
254
+ this.hideFork(this.pendingForks.get(binding));
255
+ return true;
256
+ }
257
+ for (const key of keys) {
258
+ if (isArtifactViewerKey(key) && this.cycleCompanionArtifact(binding))
259
+ continue;
260
+ const shortcut = this.inquiry ? inquiryShortcutForKey(key) : undefined;
261
+ if (shortcut?.kind === "issue" && shortcut.binding === binding) {
262
+ this.openInquiry(shortcut);
263
+ }
264
+ }
265
+ const layout = this.host.getLayout();
266
+ const result = this.activeCoordinator()?.handleArtifactScroll(keys, layout.columns, layout.childRows);
267
+ if (result)
268
+ this.applyPaneResult(undefined, result);
239
269
  return true;
240
270
  }
241
271
  if (binding && this.sendLocks.has(binding)) {
@@ -335,14 +365,17 @@ export class OffscreenController {
335
365
  this.hideFork(fork);
336
366
  }
337
367
  }
368
+ presentedFork(binding) {
369
+ return this.forks.get(binding) ?? this.pendingForks.get(binding);
370
+ }
338
371
  hideFork(fork) {
339
372
  if (this.shown)
340
373
  this.abortIssueSend(this.shown);
341
374
  if (this.activeCoordinator()) {
342
375
  const layout = this.host.getLayout();
343
- fork.resize(layout.columns, layout.childRows);
376
+ fork?.resize(layout.columns, layout.childRows);
344
377
  }
345
- fork.setVisible(false);
378
+ fork?.setVisible(false);
346
379
  this.shown = undefined;
347
380
  this.clearSplitCoordinator();
348
381
  this.host.clearMouseModeSource(OFFSCREEN_MOUSE_SOURCE);
@@ -375,7 +408,7 @@ export class OffscreenController {
375
408
  ];
376
409
  }
377
410
  nextCompanionArtifactHint(binding) {
378
- if (this.shown !== binding || !this.forks.has(binding))
411
+ if (this.shown !== binding)
379
412
  return undefined;
380
413
  const config = this.artifactConfigs[binding];
381
414
  if (!config)
@@ -388,8 +421,8 @@ export class OffscreenController {
388
421
  }
389
422
  cycleCompanionArtifact(binding) {
390
423
  const primary = this.artifactConfigs[binding];
391
- const fork = this.forks.get(binding);
392
- if (!primary || !fork)
424
+ const fork = this.presentedFork(binding);
425
+ if (!primary)
393
426
  return false;
394
427
  const count = this.companionArtifacts(primary).length;
395
428
  if (count <= 1)
@@ -405,21 +438,33 @@ export class OffscreenController {
405
438
  configurePresentation(binding, fork, cols, rows) {
406
439
  const artifact = this.activeArtifactConfig(binding);
407
440
  if (artifact && (cols >= SPLIT_COLLAPSE_AT_COLS || artifact.collapseWhenNarrow)) {
441
+ const index = this.activeArtifactIndexes.get(binding) ?? 0;
442
+ let panes = this.artifactPanes.get(binding);
443
+ if (!panes)
444
+ this.artifactPanes.set(binding, panes = new Map());
445
+ let artifactPane = panes.get(index);
446
+ if (!artifactPane) {
447
+ artifactPane = new ArtifactPaneController(artifact.renderArtifact, artifact.styleVersion);
448
+ panes.set(index, artifactPane);
449
+ }
408
450
  this.split = {
409
451
  binding,
410
452
  coordinator: new SplitInquiryCoordinator({
411
453
  inquirySide: artifact.inquirySide,
412
- inquiryPane: new InquiryPaneController(fork),
413
- artifactPane: new ArtifactPaneController(artifact.renderArtifact, artifact.styleVersion),
454
+ inquiryPane: fork ? new InquiryPaneController(fork, this.forks.has(binding)) : this.startingPane(binding),
455
+ artifactPane,
414
456
  collapseAt: SPLIT_COLLAPSE_AT_COLS,
415
457
  collapseArtifact: artifact.collapseWhenNarrow,
416
458
  }),
417
459
  };
418
- fork.resize(this.split.coordinator.inquiryWidth(cols), this.split.coordinator.inquiryHeight(cols, rows));
460
+ fork?.resize(this.split.coordinator.inquiryWidth(cols), this.split.coordinator.inquiryHeight(cols, rows));
419
461
  return;
420
462
  }
421
463
  this.clearSplitCoordinator();
422
- fork.resize(cols, rows);
464
+ fork?.resize(cols, rows);
465
+ }
466
+ startingPane(binding) {
467
+ return new StartingInquiryPane(this.slots.get(binding).roleLabel);
423
468
  }
424
469
  focusArtifactForCurrentIssue(binding) {
425
470
  if (this.shown !== binding)
@@ -445,60 +490,98 @@ export class OffscreenController {
445
490
  this.host.scheduleParentUiRender();
446
491
  return;
447
492
  }
448
- void this.ensureFork(binding, slot)
449
- .then((fork) => {
450
- if (this.disposed) {
451
- fork.kill();
452
- return;
453
- }
454
- for (const [key, other] of this.forks) {
455
- if (key !== binding)
456
- other.setVisible(false);
457
- }
458
- const layout = this.host.getLayout();
459
- this.shown = binding;
460
- this.configurePresentation(binding, fork, layout.columns, layout.childRows);
461
- if (focusIssueArtifact)
462
- this.focusArtifactForCurrentIssue(binding);
463
- fork.setVisible(true);
464
- this.updateForkState();
465
- this.host.scheduleRender();
493
+ if (this.shown && this.shown !== binding)
494
+ this.abortIssueSend(this.shown);
495
+ for (const [key, other] of [...this.forks, ...this.pendingForks]) {
496
+ if (key !== binding)
497
+ other.setVisible(false);
498
+ }
499
+ const fork = this.forks.get(binding);
500
+ const presented = this.presentedFork(binding);
501
+ const layout = this.host.getLayout();
502
+ this.shown = binding;
503
+ this.configurePresentation(binding, presented, layout.columns, layout.childRows);
504
+ if (focusIssueArtifact)
505
+ this.focusArtifactForCurrentIssue(binding);
506
+ presented?.setVisible(true);
507
+ this.updateForkState();
508
+ this.host.scheduleRender();
509
+ if (fork) {
466
510
  if (question)
467
511
  this.startInquirySend(binding, fork, question);
468
- })
469
- .catch((err) => {
470
- this.clearSendPending(binding);
471
- const reason = err instanceof Error ? err.message : String(err);
472
- this.host.output.warn(`offscreen ${slot.roleLabel} fork failed: ${reason}`);
473
- this.updateForkState();
474
- this.host.scheduleParentUiRender();
475
- });
512
+ }
513
+ else {
514
+ if (question)
515
+ this.pendingQuestions.set(binding, question);
516
+ this.ensureFork(binding, slot);
517
+ }
476
518
  }
477
519
  ensureFork(binding, slot) {
478
- const existing = this.forks.get(binding);
479
- if (existing)
480
- return Promise.resolve(existing);
481
- const pending = this.pending.get(binding);
482
- if (pending)
483
- return pending;
484
- const layout = this.host.getLayout();
485
- const created = Fork.spawn(slot, this.workdir, this.host, layout.columns, layout.childRows, () => this.updateForkState()).then((fork) => {
486
- this.pending.delete(binding);
487
- if (this.disposed) {
488
- fork.kill();
489
- return fork;
520
+ if (this.pending.has(binding))
521
+ return;
522
+ let constructed;
523
+ // The host's coalesced first frame must run before any provider preparation.
524
+ const created = new Promise((resolve) => setImmediate(resolve)).then(async () => {
525
+ this.launchAbort.signal.throwIfAborted();
526
+ const layout = this.host.getLayout();
527
+ return Fork.spawn(slot, this.workdir, this.host, layout.columns, layout.childRows, () => {
528
+ if (!this.disposed && constructed && this.presentedFork(binding) === constructed) {
529
+ this.updateForkState();
530
+ }
531
+ }, this.observerRuns, this.launchAbort.signal, (fork) => {
532
+ constructed = fork;
533
+ if (this.disposed || this.pending.get(binding) !== created) {
534
+ void fork.kill();
535
+ return;
536
+ }
537
+ this.pendingForks.set(binding, fork);
538
+ if (this.shown !== binding)
539
+ return;
540
+ const layout = this.host.getLayout();
541
+ this.configurePresentation(binding, fork, layout.columns, layout.childRows);
542
+ fork.setVisible(true);
543
+ this.updateForkState();
544
+ this.host.scheduleParentUiRender();
545
+ });
546
+ }).then(async (fork) => {
547
+ if (this.disposed || this.pending.get(binding) !== created) {
548
+ await fork.kill();
549
+ return;
490
550
  }
551
+ constructed = fork;
552
+ this.pendingForks.delete(binding);
491
553
  this.forks.set(binding, fork);
492
554
  if (this.tracksTurns) {
493
555
  void this.ensureForkSession(binding, fork);
494
556
  }
495
- return fork;
557
+ if (this.shown === binding) {
558
+ const layout = this.host.getLayout();
559
+ this.configurePresentation(binding, fork, layout.columns, layout.childRows);
560
+ fork.setVisible(true);
561
+ this.updateForkState();
562
+ this.host.scheduleRender();
563
+ }
564
+ const question = this.pendingQuestions.get(binding);
565
+ this.pendingQuestions.delete(binding);
566
+ if (question)
567
+ this.startInquirySend(binding, fork, question);
496
568
  }).catch((err) => {
497
- this.pending.delete(binding);
498
- throw err;
569
+ if (this.disposed && err === this.launchAbort.signal.reason)
570
+ return;
571
+ const reason = err instanceof Error ? err.message : String(err);
572
+ this.host.output.warn(`offscreen ${slot.roleLabel} fork failed: ${reason}`);
573
+ if (this.disposed || this.pending.get(binding) !== created)
574
+ return;
575
+ this.pendingQuestions.delete(binding);
576
+ this.clearSendPending(binding);
577
+ this.pendingForks.delete(binding);
578
+ if (this.shown === binding)
579
+ this.hideFork();
580
+ }).finally(() => {
581
+ if (this.pending.get(binding) === created)
582
+ this.pending.delete(binding);
499
583
  });
500
584
  this.pending.set(binding, created);
501
- return created;
502
585
  }
503
586
  startInquirySend(binding, fork, question) {
504
587
  if (this.disposed || this.sendControllers.has(binding))
@@ -515,13 +598,16 @@ export class OffscreenController {
515
598
  composer,
516
599
  beforeSubmit: async () => {
517
600
  await this.turnMonitors.get(binding)?.refreshExpiredAttempts();
601
+ controller.signal.throwIfAborted();
602
+ this.launchAbort.signal.throwIfAborted();
518
603
  receipt = this.reserveTurn(binding);
519
604
  },
520
605
  onSubmitWritten: () => receipt?.markWritten(),
521
606
  onSubmitted: () => {
522
607
  submitted = true;
523
608
  receipt?.confirm();
524
- this.clearSendPending(binding);
609
+ if (!this.disposed && this.sendControllers.get(binding) === controller)
610
+ this.clearSendPending(binding);
525
611
  },
526
612
  }).catch((err) => {
527
613
  if (!controller.signal.aborted) {
@@ -530,6 +616,8 @@ export class OffscreenController {
530
616
  }
531
617
  }).finally(() => {
532
618
  receipt?.release();
619
+ if (this.disposed)
620
+ return;
533
621
  if (receipt?.settlement === "released") {
534
622
  const remaining = (this.pendingTurns.get(binding) ?? []).filter((pending) => pending !== receipt);
535
623
  if (remaining.length > 0)
@@ -538,9 +626,9 @@ export class OffscreenController {
538
626
  this.pendingTurns.delete(binding);
539
627
  this.refreshStagedActivity(binding);
540
628
  }
541
- if (this.sendControllers.get(binding) === controller) {
542
- this.sendControllers.delete(binding);
543
- }
629
+ if (this.sendControllers.get(binding) !== controller)
630
+ return;
631
+ this.sendControllers.delete(binding);
544
632
  this.sendLocks.delete(binding);
545
633
  if (!submitted)
546
634
  this.clearSendPending(binding);
@@ -556,7 +644,8 @@ export class OffscreenController {
556
644
  clearSendPending(binding) {
557
645
  if (!this.sendPending.delete(binding))
558
646
  return;
559
- this.host.scheduleParentUiRender();
647
+ if (!this.disposed)
648
+ this.host.scheduleParentUiRender();
560
649
  }
561
650
  reserveTurn(binding, rawAttempt = false) {
562
651
  const pendingChanged = this.sendPending.delete(binding);
@@ -619,8 +708,9 @@ export class OffscreenController {
619
708
  const turnChanged = !this.turnInProgress.has(binding);
620
709
  this.turnInProgress.add(binding);
621
710
  const fork = this.forks.get(binding);
622
- if (!this.forkSessionFiles.has(binding)
623
- || (fork && this.needsSubmitFloor(binding, fork))) {
711
+ if (!this.turnMonitors.has(binding)
712
+ && (!this.forkSessionFiles.has(binding)
713
+ || (fork && this.needsSubmitFloor(binding, fork)))) {
624
714
  if (fork) {
625
715
  this.forkLocateAborts.get(binding)?.abort();
626
716
  this.forkSession.delete(binding);
@@ -649,6 +739,17 @@ export class OffscreenController {
649
739
  const abort = new AbortController();
650
740
  this.forkLocateAborts.set(binding, abort);
651
741
  const promise = (async () => {
742
+ const liveMonitor = fork.createTurnMonitor?.(this.forkMonitorOptions(binding));
743
+ if (liveMonitor) {
744
+ this.installForkTurnMonitor(binding, liveMonitor);
745
+ return;
746
+ }
747
+ const policy = resolveProvider(fork.driver).forkSubmitFloor;
748
+ if (!policy) {
749
+ if (this.turnInProgress.has(binding))
750
+ this.warnForkSessionUnavailable(binding);
751
+ return;
752
+ }
652
753
  await this.captureForkSubmitFloor(binding, fork, abort.signal);
653
754
  if (this.disposed || abort.signal.aborted)
654
755
  return;
@@ -673,7 +774,6 @@ export class OffscreenController {
673
774
  }
674
775
  }
675
776
  else {
676
- const policy = resolveProvider(fork.driver).forkSubmitFloor;
677
777
  while (!this.disposed && !abort.signal.aborted && this.needsTurnObservation(binding)) {
678
778
  let lines;
679
779
  try {
@@ -711,7 +811,8 @@ export class OffscreenController {
711
811
  return promise;
712
812
  }
713
813
  async captureForkSubmitFloor(binding, fork, signal) {
714
- if (resolveProvider(fork.driver).forkSubmitFloor.from !== "source")
814
+ const policy = resolveProvider(fork.driver).forkSubmitFloor;
815
+ if (!policy || policy.from !== "source")
715
816
  return;
716
817
  if (this.forkSubmitFloors.has(binding))
717
818
  return;
@@ -775,6 +876,8 @@ export class OffscreenController {
775
876
  void this.ensureForkSession(binding, fork);
776
877
  return;
777
878
  }
879
+ if (!resolveProvider(fork.driver).forkSubmitFloor)
880
+ return;
778
881
  const providerFork = resolveProvider(fork.driver).fork;
779
882
  const effectiveSubmitCount = providerFork.forkFileSubmitFloor
780
883
  ? (lines) => Math.max(0, submitCount(fork.driver, lines) -
@@ -786,6 +889,14 @@ export class OffscreenController {
786
889
  submitFloor: this.forkSubmitFloors.get(binding),
787
890
  submitCount: effectiveSubmitCount,
788
891
  readResult: readSessionFileWithStatus,
892
+ ...this.forkMonitorOptions(binding),
893
+ });
894
+ this.installForkTurnMonitor(binding, monitor);
895
+ }
896
+ forkMonitorOptions(binding) {
897
+ return {
898
+ pollMs: this.turnPollMs,
899
+ attemptTimeoutMs: this.turnAttemptTimeoutMs,
789
900
  onReadFailure: () => this.warnForkSessionUnavailable(binding),
790
901
  onHistorySnapshot: (snapshot) => {
791
902
  this.forkBaselines.set(binding, snapshot.lineCount);
@@ -802,27 +913,36 @@ export class OffscreenController {
802
913
  }
803
914
  return;
804
915
  }
805
- this.forkBaselines.set(binding, monitor.lineBaseline);
806
- const submitFloor = monitor.currentSubmitFloor;
807
- if (submitFloor !== undefined) {
808
- this.forkSubmitFloors.set(binding, submitFloor);
916
+ const monitor = this.turnMonitors.get(binding);
917
+ if (monitor) {
918
+ this.forkBaselines.set(binding, monitor.lineBaseline);
919
+ const submitFloor = monitor.currentSubmitFloor;
920
+ if (submitFloor !== undefined) {
921
+ this.forkSubmitFloors.set(binding, submitFloor);
922
+ }
809
923
  }
810
924
  this.releaseTurn(binding);
811
925
  },
812
- });
926
+ };
927
+ }
928
+ installForkTurnMonitor(binding, monitor, initialLines) {
813
929
  this.turnMonitors.set(binding, monitor);
814
930
  const pending = this.pendingTurns.get(binding) ?? [];
815
931
  this.clearStagedAttemptTimers(binding);
816
932
  this.pendingTurns.delete(binding);
817
933
  monitor.attachTurns(pending, initialLines);
818
934
  }
819
- needsSubmitFloor(binding, _fork) {
935
+ needsSubmitFloor(binding, fork) {
936
+ if (!resolveProvider(fork.driver).forkSubmitFloor)
937
+ return false;
820
938
  return !this.forkSubmitFloors.has(binding);
821
939
  }
822
940
  clearTurnPoll(binding) {
823
941
  const monitor = this.turnMonitors.get(binding);
824
942
  if (monitor) {
825
- if (monitor.supportsHistoryRegression || monitor.hasUnobservedExpiredAttempts)
943
+ if (monitor.supportsHistoryRegression
944
+ || monitor.hasUnobservedExpiredAttempts
945
+ || monitor.classifyDeliverySince)
826
946
  return;
827
947
  monitor.dispose();
828
948
  this.turnMonitors.delete(binding);
@@ -855,6 +975,7 @@ export class OffscreenController {
855
975
  this.host.output.warn(`offscreen inquiry fork session unavailable for ${binding}; inquiry remains busy`);
856
976
  }
857
977
  abortIssueSend(binding) {
978
+ this.pendingQuestions.delete(binding);
858
979
  const controller = this.sendControllers.get(binding);
859
980
  if (controller) {
860
981
  controller.abort(new Error("Inquiry send aborted"));
@@ -889,7 +1010,7 @@ export class OffscreenController {
889
1010
  }
890
1011
  updateVisibleMouseModes() {
891
1012
  const fork = this.shown ? this.forks.get(this.shown) : undefined;
892
- if (!fork) {
1013
+ if (!this.shown) {
893
1014
  this.host.clearMouseModeSource(OFFSCREEN_MOUSE_SOURCE);
894
1015
  return;
895
1016
  }
@@ -901,7 +1022,7 @@ export class OffscreenController {
901
1022
  this.updateVisibleMouseModes();
902
1023
  }
903
1024
  visibleMouseModes(fork) {
904
- const modes = fork.mouseModes();
1025
+ const modes = fork?.mouseModes() ?? [];
905
1026
  const coordinator = this.activeCoordinator();
906
1027
  if (!coordinator)
907
1028
  return modes;