@farmslot/adapter-web 0.15.0 → 0.17.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
@@ -6,6 +6,14 @@ All notable changes to `@farmslot/adapter-web` are tracked here.
6
6
 
7
7
  - Active-development baseline; add user-facing changes here before release or package publication.
8
8
 
9
+ ## 0.17.0 - 2026-10-20
10
+
11
+ - The web-dapp HUD shows the current intent as a 16px main line with no RUN badge, whole in a 500px card that grows instead of clipping it, and the step that just finished as one muted `✓`/`✗` line. A finished run reads `Recipe passed` or `Recipe failed` in the outcome colour.
12
+
13
+ ## 0.16.0 - 2026-10-19
14
+
15
+ - Align with `@farmslot/protocol` 0.59.0, `@farmslot/adapter-sdk` 0.24.0 and `@farmslot/recipe-runner` 0.45.0.
16
+
9
17
  ## 0.15.0 - 2026-10-19
10
18
 
11
19
  - Align with `@farmslot/protocol` 0.58.0, `@farmslot/adapter-sdk` 0.23.0 and `@farmslot/recipe-runner` 0.44.0.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/adapter-web",
3
- "version": "0.15.0",
3
+ "version": "0.17.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,9 +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.23.0",
87
- "@farmslot/protocol": "0.58.0",
88
- "@farmslot/recipe-runner": "0.44.0",
86
+ "@farmslot/adapter-sdk": "0.25.0",
87
+ "@farmslot/protocol": "0.60.0",
88
+ "@farmslot/recipe-runner": "0.46.0",
89
89
  "ws": "^8.18.0"
90
90
  },
91
91
  "devDependencies": {
@@ -14,7 +14,11 @@ import { readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
14
14
  import path from 'node:path';
15
15
 
16
16
  import {
17
+ HUD_COLORS,
18
+ HUD_FINISHED_FONT_SIZE,
19
+ HUD_FINISHED_LINE_HEIGHT,
17
20
  HUD_PANEL_BOUNDS,
21
+ hudFinishedLine,
18
22
  hudIntentDisplay,
19
23
  hudPlacement,
20
24
  hudSecondaryText,
@@ -33,7 +37,7 @@ function progressOf(raw) {
33
37
  }
34
38
 
35
39
  // Fold one app.hud node into the previous state. A running node becomes the
36
- // current step; a pass/fail node also becomes the "last result" line, and the
40
+ // current step; a pass/fail node also becomes the "just finished" line, and the
37
41
  // recipe-complete node closes the run.
38
42
  export function nextHudState(prior, node = {}, nodeId = '') {
39
43
  // A finished run's HUD stays up until the next run's first update replaces it.
@@ -98,30 +102,34 @@ export function clearHudState(runtimeDir) {
98
102
  rmSync(hudFile(runtimeDir), { force: true });
99
103
  }
100
104
 
105
+ // The card grows with the intent: nothing clips, clamps or ellipsizes it.
101
106
  const STYLE = `
102
107
  :host { all: initial; }
103
- .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;
108
+ .hud { position: fixed; top: 220px; left: 12px; z-index: 2147483647; width: ${HUD_PANEL_BOUNDS.card.maxWidth}px; max-width: calc(100vw - 24px);
104
109
  box-sizing: border-box; padding: 8px 10px; border-radius: 8px; border: 1px solid rgba(255,255,255,.18);
105
110
  background: rgba(16,18,24,.82); color: #f2f4f7; font: 12px/1.35 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
106
111
  pointer-events: none; user-select: none; box-shadow: 0 4px 16px rgba(0,0,0,.35); }
107
- .row { display: flex; gap: 6px; align-items: baseline; }
112
+ .row { display: flex; gap: 6px; align-items: baseline; font-size: 11px; color: ${HUD_COLORS.muted}; }
108
113
  .title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
109
- .step { color: #a9b1bd; font-variant-numeric: tabular-nums; }
110
- .intent { margin-top: 4px; }
111
- .badge { display: inline-block; padding: 0 5px; border-radius: 4px; font-size: 10px; font-weight: 700; letter-spacing: .03em; }
112
- .running { background: #2f6fed; color: #fff; }
113
- .pass { background: #1f9d55; color: #fff; }
114
- .fail { background: #d64545; color: #fff; }
115
- .last { margin-top: 4px; color: #c7cdd6; }
116
- .error { color: #ffb4b4; }
114
+ .step { font-variant-numeric: tabular-nums; }
115
+ .intent { margin-top: 4px; color: #fff; }
116
+ .intent.pass { color: ${HUD_COLORS.pass}; }
117
+ .intent.fail { color: ${HUD_COLORS.fail}; }
118
+ .last { margin-top: 4px; font-size: ${HUD_FINISHED_FONT_SIZE}px; line-height: ${HUD_FINISHED_LINE_HEIGHT}px; color: ${HUD_COLORS.muted}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
119
+ .last.fail { color: ${HUD_COLORS.fail}; }
120
+ .error { margin-top: 2px; font-size: ${HUD_FINISHED_FONT_SIZE}px; line-height: ${HUD_FINISHED_LINE_HEIGHT}px; color: #ffb4b4;
121
+ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
117
122
  `;
118
123
 
119
124
  // A self-contained page expression: draws (or clears, for null) the HUD when
120
125
  // the document is on the selected origin, and skips an unchanged state/layout.
121
126
  // The wallet screenshot consumer uses bottom-dock to keep footer controls clear.
122
127
  export function hudRenderExpression(state, appOrigin, { layout = 'card' } = {}) {
128
+ const finished =
129
+ state && !state.finished ? hudFinishedLine(state.last, state.current?.nodeId) : null;
123
130
  return `(() => {
124
131
  const state = ${JSON.stringify(state ?? null)};
132
+ const finished = ${JSON.stringify(finished)};
125
133
  const layout = ${JSON.stringify(layout)};
126
134
  const docked = layout === 'bottom-dock';
127
135
  if (location.origin !== ${JSON.stringify(String(appOrigin).replace(/\/$/u, ''))}) return { hud: false, reason: 'not-app-origin' };
@@ -148,7 +156,7 @@ export function hudRenderExpression(state, appOrigin, { layout = 'card' } = {})
148
156
  const style = el('style', null, ${JSON.stringify(STYLE)});
149
157
  const box = el('div', 'hud');
150
158
  if (docked) {
151
- Object.assign(box.style, { top: 'auto', bottom: '0', left: '0', right: '0', width: '100vw', maxWidth: 'none', maxHeight: 'none', borderRadius: '0', padding: '5px 8px' });
159
+ Object.assign(box.style, { top: 'auto', bottom: '0', left: '0', right: '0', width: '100vw', maxWidth: 'none', borderRadius: '0', padding: '5px 8px' });
152
160
  } else if (state.position) {
153
161
  box.style.top = state.position === 'top' ? '12px' : 'auto';
154
162
  box.style.bottom = state.position === 'bottom' ? '12px' : 'auto';
@@ -160,21 +168,16 @@ export function hudRenderExpression(state, appOrigin, { layout = 'card' } = {})
160
168
  if (progress) head.append(el('span', 'step', 'step ' + progress.current + '/' + progress.total));
161
169
  box.append(head);
162
170
  if (state.current) {
163
- const line = el('div', 'intent');
164
- Object.assign(line.style, intentStyle);
165
- const status = state.finished || 'running';
166
- const intent = el('span', null, state.current.intent);
171
+ // A failing step stays the main line, in the fail colour, rather than repeating below.
172
+ const failing = state.last && state.last.status === 'fail' && state.last.nodeId === state.current.nodeId;
173
+ const tone = state.finished || (failing ? 'fail' : '');
174
+ const intent = el('div', tone ? 'intent ' + tone : 'intent', state.current.intent);
175
+ Object.assign(intent.style, intentStyle);
167
176
  intent.setAttribute('data-farmslot-hud-intent', '');
168
- line.append(el('span', 'badge ' + status, status === 'running' ? 'RUN' : status.toUpperCase()), ' ', intent);
169
- box.append(line);
177
+ box.append(intent);
170
178
  }
171
- if (state.last && !state.finished) {
172
- const line = el('div', 'last');
173
- Object.assign(line.style, intentStyle);
174
- line.append(el('span', 'badge ' + state.last.status, state.last.status.toUpperCase()), ' ', state.last.intent);
175
- box.append(line);
176
- }
177
- if (state.last && state.last.error) box.append(el('div', 'last error', state.last.error));
179
+ if (finished) box.append(el('div', 'last ' + finished.tone, finished.text));
180
+ if (state.last && state.last.error) box.append(el('div', 'error', state.last.error));
178
181
  root.append(style, box);
179
182
  document.documentElement.append(host);
180
183
  let height;