@farmslot/adapter-web 0.6.9 → 0.7.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/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to `@farmslot/adapter-web` are tracked here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.7.0 - 2026-10-12
8
+
9
+ - Collect opt-in rendered HUD observations around screenshot capture for live conformance.
10
+ - Keep recipe HUD intent on two bounded lines through the shared display policy, with authoring warnings above 80 characters and errors above 120.
11
+
12
+ ## 0.6.10 - 2026-10-11
13
+
14
+ - Align published runtime dependencies with recipe-runner 0.29.0 for shared cancellation and execution.
15
+
7
16
  ## 0.6.9 - 2026-10-11
8
17
 
9
18
  - Align the adapter-sdk and recipe-runner dependencies with 0.8.5 and 0.28.5 so consumers resolve one copy.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/adapter-web",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "Web platform adapter for Farmslot recipes: resolve and launch an isolated Chromium, own its CDP port, load unpacked extensions, and keep macOS focus.",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -83,8 +83,9 @@
83
83
  "prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/adapter-web"
84
84
  },
85
85
  "dependencies": {
86
- "@farmslot/adapter-sdk": "0.8.5",
87
- "@farmslot/recipe-runner": "0.28.5",
86
+ "@farmslot/adapter-sdk": "0.9.0",
87
+ "@farmslot/protocol": "0.39.0",
88
+ "@farmslot/recipe-runner": "0.30.0",
88
89
  "ws": "^8.18.0"
89
90
  },
90
91
  "devDependencies": {
@@ -13,15 +13,10 @@
13
13
  import { readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
14
14
  import path from 'node:path';
15
15
 
16
+ import { HUD_PANEL_BOUNDS, hudIntentDisplay, hudSecondaryText } from '@farmslot/protocol/recipe';
17
+
16
18
  export const HUD_ELEMENT = 'mm-harness-hud';
17
19
  export const HUD_FILE = 'hud.json';
18
- const MAX_TEXT = 180;
19
-
20
- function text(value, max = MAX_TEXT) {
21
- if (typeof value !== 'string' && typeof value !== 'number') return '';
22
- const flat = String(value).replace(/\s+/gu, ' ').trim();
23
- return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
24
- }
25
20
 
26
21
  function progressOf(raw) {
27
22
  if (!raw || typeof raw !== 'object') return null;
@@ -39,11 +34,12 @@ export function nextHudState(prior, node = {}, nodeId = '') {
39
34
  const previous = prior?.finished ? { seq: prior.seq } : prior;
40
35
  const status = ['running', 'pass', 'fail'].includes(node.status) ? node.status : 'running';
41
36
  const progress = progressOf(node.progress);
42
- const intent = text(node.intent ?? node.text ?? node.detail) || text(nodeId);
43
- const id = text(node.node_id ?? node.nodeId ?? nodeId, 80);
37
+ const intent =
38
+ hudIntentDisplay(node.intent ?? node.text ?? node.detail).text || hudIntentDisplay(nodeId).text;
39
+ const id = hudSecondaryText(node.node_id ?? node.nodeId ?? nodeId, 80);
44
40
  const state = {
45
41
  seq: (previous?.seq ?? 0) + 1,
46
- title: text(node.title, 80) || previous?.title || 'Recipe run',
42
+ title: hudSecondaryText(node.title, 80) || previous?.title || 'Recipe run',
47
43
  current: previous?.current ?? null,
48
44
  last: previous?.last ?? null,
49
45
  finished: null,
@@ -56,7 +52,7 @@ export function nextHudState(prior, node = {}, nodeId = '') {
56
52
  };
57
53
  return state;
58
54
  }
59
- const error = status === 'fail' ? text(node.error) : '';
55
+ const error = status === 'fail' ? hudSecondaryText(node.error) : '';
60
56
  state.last = { nodeId: id, intent, status, ...(error ? { error } : {}) };
61
57
  if (progress?.complete || id === 'recipe-complete') {
62
58
  state.finished = status;
@@ -96,7 +92,7 @@ export function clearHudState(runtimeDir) {
96
92
 
97
93
  const STYLE = `
98
94
  :host { all: initial; }
99
- .hud { position: fixed; top: 220px; left: 12px; z-index: 2147483647; width: 360px; max-width: calc(50vw - 24px);
95
+ .hud { position: fixed; top: 220px; left: 12px; z-index: 2147483647; width: ${HUD_PANEL_BOUNDS.card.maxWidth}px; max-width: calc(100vw - 24px); max-height: ${HUD_PANEL_BOUNDS.card.maxHeight}px; overflow: hidden;
100
96
  box-sizing: border-box; padding: 8px 10px; border-radius: 8px; border: 1px solid rgba(255,255,255,.18);
101
97
  background: rgba(16,18,24,.82); color: #f2f4f7; font: 12px/1.35 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
102
98
  pointer-events: none; user-select: none; box-shadow: 0 4px 16px rgba(0,0,0,.35); }
@@ -125,6 +121,7 @@ export function hudRenderExpression(state, appOrigin) {
125
121
  existing?.remove();
126
122
  const host = document.createElement('${HUD_ELEMENT}');
127
123
  host.dataset.seq = String(state.seq);
124
+ host.setAttribute('data-farmslot-hud-node', state.current?.nodeId || '');
128
125
  host.setAttribute('aria-hidden', 'true');
129
126
  host.inert = true;
130
127
  host.style.cssText = 'all: initial; position: fixed; inset: 0 auto auto 0; width: 0; height: 0; pointer-events: none; z-index: 2147483647;';
@@ -132,6 +129,7 @@ export function hudRenderExpression(state, appOrigin) {
132
129
  const el = (tag, cls, value) => { const node = document.createElement(tag); if (cls) node.className = cls; if (value != null) node.textContent = value; return node; };
133
130
  const style = el('style', null, ${JSON.stringify(STYLE)});
134
131
  const box = el('div', 'hud');
132
+ const intentStyle = ${JSON.stringify(hudIntentDisplay('').webStyle)};
135
133
  const head = el('div', 'row');
136
134
  head.append(el('span', 'title', state.title));
137
135
  const progress = state.current && state.current.progress;
@@ -139,12 +137,16 @@ export function hudRenderExpression(state, appOrigin) {
139
137
  box.append(head);
140
138
  if (state.current) {
141
139
  const line = el('div', 'intent');
140
+ Object.assign(line.style, intentStyle);
142
141
  const status = state.finished || 'running';
143
- line.append(el('span', 'badge ' + status, status === 'running' ? 'RUN' : status.toUpperCase()), ' ', state.current.intent);
142
+ const intent = el('span', null, state.current.intent);
143
+ intent.setAttribute('data-farmslot-hud-intent', '');
144
+ line.append(el('span', 'badge ' + status, status === 'running' ? 'RUN' : status.toUpperCase()), ' ', intent);
144
145
  box.append(line);
145
146
  }
146
147
  if (state.last && !state.finished) {
147
148
  const line = el('div', 'last');
149
+ Object.assign(line.style, intentStyle);
148
150
  line.append(el('span', 'badge ' + state.last.status, state.last.status.toUpperCase()), ' ', state.last.intent);
149
151
  box.append(line);
150
152
  }