@reticlehq/browser 3.6.0 → 3.8.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 (129) hide show
  1. package/dist/actions/action-report.d.ts +64 -0
  2. package/dist/actions/action-report.js +87 -0
  3. package/dist/actions/actions-dom.d.ts +5 -0
  4. package/dist/actions/actions-dom.js +32 -4
  5. package/dist/actions/actions-press.d.ts +1 -0
  6. package/dist/actions/actions-press.js +25 -1
  7. package/dist/actions/actions.d.ts +2 -37
  8. package/dist/actions/actions.js +56 -80
  9. package/dist/actions/appeared-text.js +5 -2
  10. package/dist/actions/click-target.d.ts +1 -0
  11. package/dist/actions/click-target.js +14 -0
  12. package/dist/actions/danger-context.d.ts +4 -1
  13. package/dist/actions/danger-context.js +45 -4
  14. package/dist/actions/value-input.d.ts +1 -0
  15. package/dist/actions/value-input.js +11 -0
  16. package/dist/activate.d.ts +14 -0
  17. package/dist/activate.js +43 -0
  18. package/dist/busy.d.ts +3 -0
  19. package/dist/busy.js +42 -0
  20. package/dist/commands/commands.js +49 -17
  21. package/dist/connect-options.d.ts +12 -1
  22. package/dist/connect-options.js +18 -1
  23. package/dist/dom/a11y.d.ts +2 -0
  24. package/dist/dom/a11y.js +353 -80
  25. package/dist/dom/addressing/coverage-markers.d.ts +6 -0
  26. package/dist/dom/addressing/coverage-markers.js +13 -0
  27. package/dist/dom/chart.d.ts +3 -2
  28. package/dist/dom/chart.js +3 -2
  29. package/dist/dom/dom-ignore.d.ts +8 -0
  30. package/dist/dom/dom-ignore.js +57 -2
  31. package/dist/dom/layout-audit.d.ts +15 -0
  32. package/dist/dom/layout-audit.js +208 -0
  33. package/dist/dom/paint-context.d.ts +15 -0
  34. package/dist/dom/paint-context.js +78 -0
  35. package/dist/dom/query.d.ts +2 -1
  36. package/dist/dom/query.js +163 -38
  37. package/dist/dom/render-page.d.ts +12 -0
  38. package/dist/dom/render-page.js +135 -0
  39. package/dist/dom/shadow-registry.d.ts +1 -0
  40. package/dist/dom/shadow-registry.js +27 -0
  41. package/dist/dom/snapshot.d.ts +5 -0
  42. package/dist/dom/snapshot.js +135 -36
  43. package/dist/dom/stable-selector.d.ts +1 -0
  44. package/dist/dom/stable-selector.js +19 -0
  45. package/dist/dom/text-match.d.ts +12 -0
  46. package/dist/dom/text-match.js +115 -0
  47. package/dist/dom/theme.d.ts +1 -0
  48. package/dist/dom/theme.js +21 -9
  49. package/dist/dom/virtualized.js +5 -1
  50. package/dist/index.d.ts +2 -1
  51. package/dist/index.js +5 -0
  52. package/dist/observers/blind-spots.js +3 -2
  53. package/dist/observers/canvas.d.ts +18 -0
  54. package/dist/observers/canvas.js +76 -0
  55. package/dist/observers/dom.js +96 -32
  56. package/dist/observers/field.d.ts +11 -0
  57. package/dist/observers/field.js +116 -30
  58. package/dist/observers/install-all.js +4 -0
  59. package/dist/observers/media.d.ts +2 -0
  60. package/dist/observers/media.js +32 -0
  61. package/dist/observers/net-detail/network-body.d.ts +2 -0
  62. package/dist/observers/net-detail/network-body.js +8 -1
  63. package/dist/observers/network.js +82 -13
  64. package/dist/observers/perf.js +53 -1
  65. package/dist/observers/route.d.ts +2 -0
  66. package/dist/observers/route.js +39 -9
  67. package/dist/presenter/carousel/carousel.js +2 -7
  68. package/dist/presenter/carousel/panel-slides.d.ts +2 -4
  69. package/dist/presenter/carousel/panel-slides.js +17 -15
  70. package/dist/presenter/chrome/log-memory.d.ts +1 -0
  71. package/dist/presenter/chrome/presenter-log.d.ts +7 -0
  72. package/dist/presenter/chrome/presenter-log.js +48 -8
  73. package/dist/presenter/chrome/presenter-morph.d.ts +1 -0
  74. package/dist/presenter/chrome/presenter-morph.js +34 -0
  75. package/dist/presenter/chrome/presenter-report-copy.d.ts +12 -4
  76. package/dist/presenter/chrome/presenter-report-copy.js +12 -4
  77. package/dist/presenter/hud-telemetry.js +55 -4
  78. package/dist/presenter/presenter-account-styles.js +3 -3
  79. package/dist/presenter/presenter-account.d.ts +27 -5
  80. package/dist/presenter/presenter-account.js +83 -6
  81. package/dist/presenter/presenter-agent-link.d.ts +9 -0
  82. package/dist/presenter/presenter-agent-link.js +62 -0
  83. package/dist/presenter/presenter-chat-views.d.ts +25 -4
  84. package/dist/presenter/presenter-chat-views.js +339 -72
  85. package/dist/presenter/presenter-config.d.ts +3 -0
  86. package/dist/presenter/presenter-config.js +2 -0
  87. package/dist/presenter/presenter-controls.d.ts +0 -1
  88. package/dist/presenter/presenter-controls.js +13 -91
  89. package/dist/presenter/presenter-design-tokens.js +1 -1
  90. package/dist/presenter/presenter-frame.d.ts +3 -2
  91. package/dist/presenter/presenter-frame.js +31 -24
  92. package/dist/presenter/presenter-harness-row.d.ts +56 -0
  93. package/dist/presenter/presenter-harness-row.js +170 -0
  94. package/dist/presenter/presenter-personas.d.ts +35 -0
  95. package/dist/presenter/presenter-personas.js +95 -0
  96. package/dist/presenter/presenter-plan.js +25 -24
  97. package/dist/presenter/presenter-report-styles.js +23 -22
  98. package/dist/presenter/presenter-report.js +29 -13
  99. package/dist/presenter/presenter-run-state.js +2 -1
  100. package/dist/presenter/presenter-settings-styles.js +8 -4
  101. package/dist/presenter/presenter-settings.d.ts +4 -4
  102. package/dist/presenter/presenter-settings.js +66 -28
  103. package/dist/presenter/presenter-shell-styles.js +12 -3
  104. package/dist/presenter/presenter-shell.d.ts +11 -3
  105. package/dist/presenter/presenter-shell.js +60 -22
  106. package/dist/presenter/presenter-styles.js +0 -2
  107. package/dist/presenter/presenter-workspace.js +10 -3
  108. package/dist/presenter/presenter.d.ts +3 -2
  109. package/dist/presenter/presenter.js +107 -25
  110. package/dist/registry/declared-platform.js +2 -0
  111. package/dist/registry/store-adapters.d.ts +5 -2
  112. package/dist/registry/store-adapters.js +40 -10
  113. package/dist/reticle-inject.js +771 -703
  114. package/dist/reticle.d.ts +4 -2
  115. package/dist/reticle.js +72 -8
  116. package/dist/security/page-location.d.ts +2 -0
  117. package/dist/security/page-location.js +7 -0
  118. package/dist/security/serialization.js +1 -1
  119. package/dist/storage-keys.d.ts +4 -2
  120. package/dist/storage-keys.js +8 -3
  121. package/dist/timers/native/native-timers.d.ts +1 -0
  122. package/dist/timers/native/native-timers.js +5 -0
  123. package/dist/transport/transport.d.ts +1 -0
  124. package/dist/transport/transport.js +23 -3
  125. package/dist/transport/unreachable-message.d.ts +1 -1
  126. package/dist/transport/unreachable-message.js +3 -5
  127. package/package.json +6 -2
  128. package/dist/presenter/carousel/offer-card.d.ts +0 -21
  129. package/dist/presenter/carousel/offer-card.js +0 -56
@@ -1,11 +1,13 @@
1
- import { ActionType, HudCorner, HudVisibility, HumanControlKind, ReticleCommand, PresenterMode, SessionState, isPresenterTone, isSessionState, } from '@reticlehq/core';
1
+ import { ActionType, HudCorner, HudVisibility, HUD_RELOAD_TO_RESTORE, HumanControlKind, ReticleCommand, PresenterMode, SessionState, isPresenterTone, isSessionState, } from '@reticlehq/core';
2
2
  import { refs } from '../dom/addressing/refs.js';
3
- import { unreachableStripText } from '../transport/unreachable-message.js';
3
+ import { UNREACHABLE_HEADLINE, unreachableMessage } from '../transport/unreachable-message.js';
4
4
  import { actionVerb } from './chrome/presenter-verbs.js';
5
5
  import { nativeSetTimeout, nativeClearTimeout, nativeNow } from '../timers/native/native-timers.js';
6
- import { LOG_KIND, CHIP_LABEL, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, clearLogRows, trimLogRows, } from './chrome/presenter-log.js';
6
+ import { LOG_KIND, CHIP_LABEL, LOG_ACTOR, DATA_RETICLE_LOG, clampLogMax, formatElapsed, humanDuration, appendLogRow, clearLogRows, trimLogRows, } from './chrome/presenter-log.js';
7
7
  import { PRESENTER_CSS } from './presenter-styles.js';
8
8
  import { HudShell } from './presenter-shell.js';
9
+ import { HARNESS_LOG_ATTR } from './presenter-harness-row.js';
10
+ import { platformDetails } from './presenter-account.js';
9
11
  import { parseImpactSnapshot } from './chrome/presenter-report-copy.js';
10
12
  import { scheduleSyncDockLayout } from './presenter-dock-layout.js';
11
13
  import { applyHudPosition, clampHudPosition, hudLayoutBox, resetHudDockPosition, } from './presenter-hud-position.js';
@@ -15,12 +17,12 @@ import { moveCursor, ringAround, spawnRipple, pace } from './chrome/presenter-ef
15
17
  import { GlowController } from './presenter-glow.js';
16
18
  import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon } from './icons/presenter-icons.js';
17
19
  import { renderTally } from './chrome/presenter-tally.js';
18
- import { CONTROLS_BANNER_HTML, CONTROLS_FLOWS_HTML, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML, CONTROLS_STATUS_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
19
- import { statusTheme, blockerHtml, getPresenterSettings, OutputDetail, syncPageBlocker, } from './presenter-settings.js';
20
+ import { CONTROLS_BANNER_HTML, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML, CONTROLS_STATUS_HTML, ENDED_FADE_MS, ControlPanel, } from './presenter-controls.js';
21
+ import { statusTheme, blockerHtml, getPresenterSettings, OutputDetail, syncPageBlocker, paintSdkVersion, } from './presenter-settings.js';
20
22
  import { Annotator } from '../review/annotator.js';
21
- import { shouldAutoOpenChat } from './presenter-shell.js';
23
+ import { shouldAutoOpenChat, shouldReopenPanel } from './presenter-shell.js';
22
24
  import { installHudTelemetry } from './hud-telemetry.js';
23
- import { PLAN_HTML, PlanBoard, parsePlanView } from './presenter-plan.js';
25
+ import { PlanBoard, parsePlanView } from './presenter-plan.js';
24
26
  import { claimLog, readRememberedLog, rememberLog, } from './chrome/log-memory.js';
25
27
  const COPIED_FLASH_MS = 1600;
26
28
  export { GlowPhase } from './presenter-config.js';
@@ -46,6 +48,7 @@ export class Presenter {
46
48
  #borderMode;
47
49
  #glowCtl;
48
50
  #lastActionText = '';
51
+ #lastActor;
49
52
  #heartbeatTimer;
50
53
  #idleEndMs;
51
54
  #sessionId;
@@ -53,8 +56,12 @@ export class Presenter {
53
56
  #endMs;
54
57
  #runLog = [];
55
58
  #sessionActive = false;
59
+ #agentOpened = false;
56
60
  #logMax;
57
61
  #log;
62
+ #harnessLog;
63
+ #harnessRunId;
64
+ #harnessSteps;
58
65
  #plan = new PlanBoard();
59
66
  #remembered = [];
60
67
  #logBaseMs;
@@ -64,6 +71,7 @@ export class Presenter {
64
71
  #panel;
65
72
  #shell;
66
73
  #annotator;
74
+ #removed = false;
67
75
  constructor(options = {}) {
68
76
  this.#paceMs = effectivePaceMs(options.paceMs);
69
77
  this.#now = options.now ?? nativeNow;
@@ -100,6 +108,12 @@ export class Presenter {
100
108
  onSyncNow: () => this.#onControl?.({ kind: HumanControlKind.SYNC }),
101
109
  onSignIn: () => this.#onControl?.({ kind: HumanControlKind.SIGNIN }),
102
110
  onHarness: (enabled) => this.#onControl?.({ kind: HumanControlKind.HARNESS, text: enabled ? 'on' : 'off' }),
111
+ onHarnessRun: (persona) => this.#onControl?.({
112
+ kind: HumanControlKind.HARNESS_RUN,
113
+ ...(persona === undefined ? {} : { text: persona }),
114
+ }),
115
+ onHarnessStop: () => this.#onControl?.({ kind: HumanControlKind.HARNESS_STOP }),
116
+ onHarnessLink: () => this.#onControl?.({ kind: HumanControlKind.HARNESS_LINK }),
103
117
  settings: {
104
118
  onBeforeOpen: () => {
105
119
  if (this.#shell.isCollapsed())
@@ -111,6 +125,7 @@ export class Presenter {
111
125
  onHarness: (enabled) => this.#onControl?.({ kind: HumanControlKind.HARNESS, text: enabled ? 'on' : 'off' }),
112
126
  },
113
127
  });
128
+ this.#shell.setProjectId(options.projectId);
114
129
  }
115
130
  setControlHandler(handler) {
116
131
  this.#onControl = handler;
@@ -127,6 +142,10 @@ export class Presenter {
127
142
  refilterFlows() {
128
143
  this.#panel.refilterFlows();
129
144
  }
145
+ showSdkVersion(version) {
146
+ if (this.#root !== undefined)
147
+ paintSdkVersion(this.#root, version);
148
+ }
130
149
  handlePush(command) {
131
150
  const a = command.args;
132
151
  if (command.name === ReticleCommand.FLOWS)
@@ -143,8 +162,11 @@ export class Presenter {
143
162
  const snapshot = parseImpactSnapshot(a['snapshot']);
144
163
  if (snapshot !== undefined) {
145
164
  this.#shell.report.setSnapshot(snapshot);
146
- this.#shell.paintOffer(snapshot.harnessOffer, snapshot.notices);
165
+ this.#shell.paintNotices(snapshot.notices);
147
166
  this.#shell.paintHarness(snapshot.harnessConfig);
167
+ this.#shell.paintHarnessDrive(snapshot.harnessDrive, snapshot.lastDrive);
168
+ this.#paintHarnessRun(snapshot.harnessDrive);
169
+ this.#shell.paintAgent(snapshot.agent);
148
170
  this.#shell.paintImpact(snapshot.project.counts.verdicts);
149
171
  const owner = true === snapshot.account?.signedIn ? snapshot.account.email : undefined;
150
172
  if (claimLog(owner))
@@ -154,6 +176,7 @@ export class Presenter {
154
176
  dashboardUrl: snapshot.dashboardUrl,
155
177
  verdicts: snapshot.project.counts.verdicts,
156
178
  defects: snapshot.project.counts.failed,
179
+ ...platformDetails(snapshot.harnessConfig, snapshot.sync),
157
180
  });
158
181
  }
159
182
  return;
@@ -180,13 +203,13 @@ export class Presenter {
180
203
  document.head.appendChild(style);
181
204
  const root = document.createElement('div');
182
205
  root.setAttribute('data-reticle-overlay', '');
183
- const actStrip = `<div class="reticle-act-strip" data-liveness="idle"><span class="reticle-act-dot" aria-hidden="true"></span><span class="reticle-act">${ACT_STRIP.READY}</span>${CONTROLS_BANNER_HTML}<span class="reticle-chip" data-reticle-chip></span><div class="reticle-act-actions">${CONTROLS_STATUS_HTML}</div></div>`;
206
+ const actStrip = `<div class="reticle-act-strip" data-liveness="idle"><span class="reticle-act-dot" aria-hidden="true"></span><span class="reticle-act" data-reticle-act-line>${ACT_STRIP.READY}</span>${CONTROLS_BANNER_HTML}<span class="reticle-chip" data-reticle-chip></span><div class="reticle-act-actions">${CONTROLS_STATUS_HTML}</div></div>`;
184
207
  root.innerHTML = `
185
208
  ${blockerHtml()}
186
209
  <div data-reticle-glow></div>
187
210
  <div data-reticle-cursor></div>
188
211
  <div data-reticle-ring></div>
189
- ${HudShell.dockHtml(actStrip, PLAN_HTML, DATA_RETICLE_LOG, CONTROLS_MARKS_HTML + CONTROLS_FLOWS_HTML, CONTROLS_FOOT_HTML)}`;
212
+ ${HudShell.dockHtml(actStrip, '', DATA_RETICLE_LOG, CONTROLS_MARKS_HTML, CONTROLS_FOOT_HTML)}`;
190
213
  document.body.appendChild(root);
191
214
  this.#root = root;
192
215
  this.#glow = root.querySelector('[data-reticle-glow]') ?? undefined;
@@ -200,6 +223,7 @@ export class Presenter {
200
223
  this.#chatPillTime =
201
224
  root.querySelector('[data-reticle-chat-pill-time]') ?? undefined;
202
225
  this.#log = root.querySelector(`[${DATA_RETICLE_LOG}]`) ?? undefined;
226
+ this.#harnessLog = root.querySelector(`[${HARNESS_LOG_ATTR}]`) ?? undefined;
203
227
  this.#chip = root.querySelector('[data-reticle-chip]') ?? undefined;
204
228
  this.#tally = root.querySelector('[data-reticle-tally]') ?? undefined;
205
229
  this.#shell.mount(root);
@@ -215,13 +239,14 @@ export class Presenter {
215
239
  this.#renderTally();
216
240
  }
217
241
  #restoreLog() {
218
- const log = this.#log;
219
- if (log === undefined || 0 < this.#remembered.length)
242
+ if (this.#log === undefined || 0 < this.#remembered.length)
220
243
  return;
221
244
  for (const row of readRememberedLog().slice(-this.#logMax)) {
222
- const handle = appendLogRow(log, row.kind, row.text, row.ts, this.#logMax, row.actor);
223
- if (row.result !== undefined)
224
- handle.result(row.result);
245
+ for (const log of this.#logsFor(row.actor, true === row.summary)) {
246
+ const handle = appendLogRow(log, row.kind, row.text, row.ts, this.#logMax, row.actor);
247
+ if (row.result !== undefined)
248
+ handle.result(row.result);
249
+ }
225
250
  this.#logBaseMs = this.#now() - row.at;
226
251
  this.#runLog.push({
227
252
  at: row.at,
@@ -295,6 +320,7 @@ export class Presenter {
295
320
  this.#sessionActive = false;
296
321
  this.#logBaseMs = undefined;
297
322
  this.#log = undefined;
323
+ this.#harnessLog = undefined;
298
324
  this.#remembered = [];
299
325
  rememberLog([]);
300
326
  this.#root?.remove();
@@ -316,7 +342,7 @@ export class Presenter {
316
342
  this.#showSession();
317
343
  this.#glowCtl.resetActivity(this.#now());
318
344
  this.#startHeartbeat();
319
- if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat)) {
345
+ if (shouldReopenPanel()) {
320
346
  this.#shell.openChat();
321
347
  }
322
348
  }
@@ -327,10 +353,12 @@ export class Presenter {
327
353
  const dock = this.#root?.querySelector('[data-reticle-dock]');
328
354
  dock?.setAttribute(DATA_ON, GLOW_ON);
329
355
  this.#hud?.setAttribute(DATA_ON, GLOW_ON);
330
- this.#lastActionText = unreachableStripText(url, attempts);
356
+ this.#lastActionText = UNREACHABLE_HEADLINE;
331
357
  this.#paintActStrip(this.#lastActionText, true);
332
- if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat))
358
+ this.#actLine?.setAttribute('title', unreachableMessage(url, attempts));
359
+ if (shouldReopenPanel()) {
333
360
  this.#shell.openChat();
361
+ }
334
362
  }
335
363
  #showSession() {
336
364
  const dock = this.#root?.querySelector('[data-reticle-dock]');
@@ -406,9 +434,29 @@ export class Presenter {
406
434
  this.#lastActionText = text;
407
435
  this.#paintActStrip(text, false);
408
436
  }
409
- #paintActStrip(text, idle) {
410
- if (this.#actLine !== undefined)
437
+ #paintHarnessRun(drive) {
438
+ const log = this.#harnessLog;
439
+ if (drive !== undefined && drive.runId !== this.#harnessRunId) {
440
+ this.#harnessRunId = drive.runId;
441
+ if (log !== undefined)
442
+ clearLogRows(log);
443
+ }
444
+ if (log !== undefined && 0 === log.childElementCount)
445
+ for (const line of drive?.lines ?? [])
446
+ appendLogRow(log, LOG_KIND.NARRATION, line, '', this.#logMax, LOG_ACTOR.HARNESS);
447
+ const was = this.#harnessSteps;
448
+ this.#harnessSteps = drive?.steps;
449
+ if (drive !== undefined)
450
+ this.#paintActStrip(this.#lastActionText, false);
451
+ else if (was !== undefined)
452
+ this.#paintActStrip(ACT_STRIP.READY, true);
453
+ }
454
+ #paintActStrip(raw, idle) {
455
+ const text = this.#harnessSteps === undefined ? raw : ACT_STRIP.harnessTesting(this.#harnessSteps);
456
+ if (this.#actLine !== undefined) {
411
457
  this.#actLine.textContent = text;
458
+ this.#actLine.removeAttribute('title');
459
+ }
412
460
  const liveness = idle ? 'idle' : 'active';
413
461
  if (this.#actStrip !== undefined)
414
462
  this.#actStrip.setAttribute('data-liveness', liveness);
@@ -444,6 +492,12 @@ export class Presenter {
444
492
  return;
445
493
  if ('' === this.#lastActionText)
446
494
  return;
495
+ if (this.#harnessSteps !== undefined)
496
+ return;
497
+ if (LOG_ACTOR.HARNESS === this.#lastActor) {
498
+ this.#paintActStrip(ACT_STRIP.READY, true);
499
+ return;
500
+ }
447
501
  const since = ACT_STRIP.SINCE_LAST;
448
502
  this.#paintActStrip(`${ACT_STRIP.PLANNING_PREFIX}${humanDuration(idleMs)}${since}`, true);
449
503
  if (this.#chatPillTime !== undefined)
@@ -460,10 +514,14 @@ export class Presenter {
460
514
  }
461
515
  placeHud(visibility, corner) {
462
516
  const root = this.#root;
463
- if (root === undefined)
517
+ if (root === undefined) {
518
+ if (this.#removed)
519
+ return [HUD_RELOAD_TO_RESTORE];
464
520
  return [];
521
+ }
465
522
  const applied = [];
466
523
  if (HudVisibility.REMOVED === visibility) {
524
+ this.#removed = true;
467
525
  this.destroy();
468
526
  return [visibility];
469
527
  }
@@ -526,6 +584,8 @@ export class Presenter {
526
584
  this.#tallied = { passes: 0, fails: 0 };
527
585
  if (this.#log !== undefined)
528
586
  clearLogRows(this.#log);
587
+ if (this.#harnessLog !== undefined)
588
+ clearLogRows(this.#harnessLog);
529
589
  this.#renderTally();
530
590
  }
531
591
  #applyHideUntilRestart() {
@@ -542,9 +602,17 @@ export class Presenter {
542
602
  }
543
603
  this.#syncAnnotator();
544
604
  }
545
- log(kind, text, result, actor) {
605
+ #logsFor(actor, summary) {
606
+ const agent = this.#log;
607
+ const harness = this.#harnessLog;
608
+ if (LOG_ACTOR.HARNESS !== actor || harness === undefined)
609
+ return agent === undefined ? [] : [agent];
610
+ return summary && agent !== undefined ? [agent, harness] : [harness];
611
+ }
612
+ log(kind, text, result, actor, summary = false) {
546
613
  const ms = this.#now();
547
614
  this.#glowCtl.markActivity(ms);
615
+ this.#lastActor = actor;
548
616
  if (this.#log === undefined)
549
617
  return undefined;
550
618
  const trimmed = text.trim();
@@ -558,7 +626,8 @@ export class Presenter {
558
626
  while (this.#runLog.length > this.#logMax)
559
627
  this.#runLog.shift();
560
628
  const ts = formatElapsed(ms - this.#logBaseMs);
561
- const handle = appendLogRow(this.#log, kind, trimmed, ts, this.#logMax, actor);
629
+ const handles = this.#logsFor(actor, summary).map((log) => appendLogRow(log, kind, trimmed, ts, this.#logMax, actor));
630
+ const handle = { result: (r) => handles.forEach((h) => h.result(r)) };
562
631
  if (result !== undefined)
563
632
  handle.result(result);
564
633
  const kept = {
@@ -567,12 +636,14 @@ export class Presenter {
567
636
  ts,
568
637
  at: ms - this.#logBaseMs,
569
638
  ...(actor === undefined ? {} : { actor }),
639
+ ...(summary ? { summary: true } : {}),
570
640
  ...(result === undefined ? {} : { result }),
571
641
  };
572
642
  this.#remembered.push(kept);
573
643
  while (this.#remembered.length > this.#logMax)
574
644
  this.#remembered.shift();
575
645
  rememberLog(this.#remembered);
646
+ this.#openForAgent(kind);
576
647
  if (this.#shell.isCollapsed())
577
648
  this.#shell.pulseFab(true);
578
649
  this.#renderTally();
@@ -586,6 +657,15 @@ export class Presenter {
586
657
  },
587
658
  };
588
659
  }
660
+ #openForAgent(kind) {
661
+ if (this.#agentOpened || LOG_KIND.HUMAN === kind) {
662
+ return;
663
+ }
664
+ this.#agentOpened = true;
665
+ if (shouldAutoOpenChat(getPresenterSettings().autoOpenChat)) {
666
+ this.#shell.openChat();
667
+ }
668
+ }
589
669
  #renderTally() {
590
670
  if (!getPresenterSettings().showTally) {
591
671
  this.#tally?.setAttribute('hidden', '');
@@ -593,14 +673,16 @@ export class Presenter {
593
673
  }
594
674
  this.#tallied = renderTally(this.#tally, this.#runLog, this.#tallied);
595
675
  }
596
- narrate(text, level = 'info') {
676
+ narrate(text, level = 'info', actor = LOG_ACTOR.AGENT, summary = false) {
597
677
  const line = 'info' === level ? text : `[${level}] ${text}`;
598
- return this.log(LOG_KIND.NARRATION, line);
678
+ return this.log(LOG_KIND.NARRATION, line, undefined, actor, summary);
599
679
  }
600
680
  #pruneLog() {
601
681
  if (this.#log === undefined)
602
682
  return;
603
683
  trimLogRows(this.#log, this.#logMax);
684
+ if (this.#harnessLog !== undefined)
685
+ trimLogRows(this.#harnessLog, this.#logMax);
604
686
  }
605
687
  setThrottled(throttled) {
606
688
  this.#root?.setAttribute(THROTTLED_ATTR, throttled ? '1' : '0');
@@ -25,11 +25,13 @@ export const SERVED_COMMANDS = [
25
25
  ReticleCommand.PRESENTER,
26
26
  ReticleCommand.IMPACT,
27
27
  ReticleCommand.CAPTURE,
28
+ ReticleCommand.RENDER,
28
29
  ReticleCommand.NAVIGATE,
29
30
  ReticleCommand.REFRESH,
30
31
  ReticleCommand.FLOWS,
31
32
  ReticleCommand.FLOW_PROGRESS,
32
33
  ReticleCommand.PLAN,
34
+ ReticleCommand.MARKERS,
33
35
  ];
34
36
  export function declaredCommands() {
35
37
  return [...SERVED_COMMANDS];
@@ -9,6 +9,7 @@ interface QueryLike {
9
9
  message?: string;
10
10
  } | null;
11
11
  data?: unknown;
12
+ isInvalidated?: boolean;
12
13
  };
13
14
  isStale?: () => boolean;
14
15
  }
@@ -23,16 +24,18 @@ export interface QuerySnapshot {
23
24
  status: string;
24
25
  fetchStatus: string | undefined;
25
26
  isStale: boolean | undefined;
27
+ isInvalidated: boolean | undefined;
26
28
  dataUpdatedAt: number | undefined;
27
29
  error: string | null;
28
30
  data: unknown;
29
31
  }
30
32
  export declare function tanstackQueryStore(client: QueryClientLike): StoreLike;
33
+ type Deferred<T> = [T][T extends unknown ? 0 : never];
31
34
  interface JotaiStoreLike<A> {
32
35
  get: (atom: A) => unknown;
33
36
  sub: (atom: A, listener: () => void) => () => void;
34
37
  }
35
- export declare function jotaiStore<A>(store: JotaiStoreLike<A>, atoms: Record<string, A>): StoreLike;
38
+ export declare function jotaiStore<A>(store: JotaiStoreLike<A>, atoms: Record<string, Deferred<A>>): StoreLike;
36
39
  interface ActorLike {
37
40
  getSnapshot: () => unknown;
38
41
  subscribe: (listener: () => void) => {
@@ -54,7 +57,7 @@ export interface RecoilAtomSnapshot {
54
57
  value: unknown;
55
58
  error: string | null;
56
59
  }
57
- export declare function recoilStore<A>(atoms: Record<string, A>, snapshot: () => RecoilSnapshotLike<A>, subscribe: StoreSubscribe): StoreLike;
60
+ export declare function recoilStore<A>(atoms: Record<string, Deferred<A>>, snapshot: () => RecoilSnapshotLike<A>, subscribe: StoreSubscribe): StoreLike;
58
61
  interface SvelteReadable {
59
62
  subscribe: (run: (value: unknown) => void) => (() => void) | {
60
63
  unsubscribe: () => void;
@@ -9,37 +9,63 @@ function snapshotLive(value) {
9
9
  }
10
10
  }
11
11
  function copyPlain(value, seen) {
12
- if ('object' !== typeof value || null === value)
12
+ if ('object' !== typeof value || null === value) {
13
13
  return value;
14
+ }
14
15
  const done = seen.get(value);
15
- if (done !== undefined)
16
+ if (done !== undefined) {
16
17
  return done;
18
+ }
17
19
  if (Array.isArray(value)) {
18
20
  const out = [];
19
21
  seen.set(value, out);
20
- for (const item of value)
22
+ for (const item of value) {
21
23
  out.push(copyPlain(item, seen));
24
+ }
22
25
  return out;
23
26
  }
24
27
  const proto = Object.getPrototypeOf(value);
25
- if (proto !== Object.prototype && proto !== null)
28
+ if (proto !== Object.prototype && proto !== null) {
26
29
  return value;
30
+ }
27
31
  const out = {};
28
32
  seen.set(value, out);
29
- for (const [key, item] of Object.entries(value))
33
+ for (const [key, item] of Object.entries(value)) {
30
34
  out[key] = copyPlain(item, seen);
35
+ }
31
36
  return out;
32
37
  }
38
+ function queryKeyPart(part) {
39
+ if ('object' !== typeof part || null === part) {
40
+ return String(part);
41
+ }
42
+ return JSON.stringify(part, (_key, value) => {
43
+ if ('object' !== typeof value || null === value || Array.isArray(value)) {
44
+ return value;
45
+ }
46
+ const proto = Object.getPrototypeOf(value);
47
+ if (proto !== Object.prototype && proto !== null) {
48
+ return value;
49
+ }
50
+ const plain = value;
51
+ const sorted = {};
52
+ for (const key of Object.keys(plain).sort()) {
53
+ sorted[key] = plain[key];
54
+ }
55
+ return sorted;
56
+ });
57
+ }
33
58
  export function tanstackQueryStore(client) {
34
59
  const store = {
35
60
  getState: () => {
36
61
  const out = {};
37
62
  for (const query of client.getQueryCache().getAll()) {
38
- const key = query.queryKey.map((part) => String(part)).join('/');
63
+ const key = query.queryKey.map(queryKeyPart).join('/');
39
64
  out[key] = {
40
65
  status: query.state.status,
41
66
  fetchStatus: query.state.fetchStatus,
42
67
  isStale: query.isStale?.(),
68
+ isInvalidated: query.state.isInvalidated,
43
69
  dataUpdatedAt: query.state.dataUpdatedAt,
44
70
  error: query.state.error?.message ?? null,
45
71
  data: query.state.data,
@@ -56,15 +82,17 @@ export function jotaiStore(store, atoms) {
56
82
  return {
57
83
  getState: () => {
58
84
  const out = {};
59
- for (const [name, atom] of Object.entries(atoms))
85
+ for (const [name, atom] of Object.entries(atoms)) {
60
86
  out[name] = store.get(atom);
87
+ }
61
88
  return out;
62
89
  },
63
90
  subscribe: (listener) => {
64
91
  const unsubs = Object.values(atoms).map((atom) => store.sub(atom, listener));
65
92
  return () => {
66
- for (const unsub of unsubs)
93
+ for (const unsub of unsubs) {
67
94
  unsub();
95
+ }
68
96
  };
69
97
  },
70
98
  };
@@ -151,8 +179,9 @@ export function svelteStore(readable, warn = nativeWarn) {
151
179
  subscribe: (listener) => {
152
180
  let inSubscribeCall = true;
153
181
  const handle = readable.subscribe(() => {
154
- if (!inSubscribeCall)
182
+ if (!inSubscribeCall) {
155
183
  listener();
184
+ }
156
185
  });
157
186
  inSubscribeCall = false;
158
187
  return () => stopSubscription(handle);
@@ -177,8 +206,9 @@ export function pushStore(initial) {
177
206
  store: { getState: () => current, subscribe },
178
207
  push: (value) => {
179
208
  current = value;
180
- for (const listener of listeners)
209
+ for (const listener of listeners) {
181
210
  listener();
211
+ }
182
212
  },
183
213
  };
184
214
  }