openvibers/openvibe.shared Commits

Shared 4.136.0: the Dock's step and Now read the one Computer (#324)

OP OpenVibers committed 6 days ago · b15cee446c · 6 files, +37 −3

A timeline step shows its Computer's machine and cost hint (the same object
the task record and Surf's card carry, never a copy). Now offers Take over,
and Give it back while the person drives, on a step that names its task and
its Computer: one call to Actor's /tasks/{id}/takeover or /giveback, the same
hand-off the agent's own hand_to_person uses. Existing meta line and Dock
button; no new layout or CSS.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 8d6073a..496fa93 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,14 @@
# Changelog
++## 4.136.0 — 2026-11-07
++
++- **One Computer in the Dock** (plan 2026-11-07: "Surf, Computer and Actor are one experience"): a timeline step
++ that works on a Computer shows its machine and cost hint (`computer.machine`, `computer.cost_hint`) — the same
++ object the task record and Surf's card carry, never a copy. The Now card offers **Take over** (and **Give it
++ back** while you drive) on a step that names its task (`ref`) and its Computer: one call to OpenVibe.Actor's
++ `POST /api/v1/tasks/{id}/takeover` or `…/giveback`, the same hand-off the agent's own `hand_to_person` uses.
++ No new layout and no new CSS: the line is an existing meta row and the button an existing Dock button.
++
## 4.135.0 — 2026-11-07
- **Ask your agent, from any page** (plan Z3; the owner, 11-07: "have your agent with you wherever you go"):
ddiff --git a/README.md b/README.md
iindex ecca8f6..cd4e2d9 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
--**Status:** alpha, v4.135.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
++**Status:** alpha, v4.136.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
ddiff --git a/STATUS.json b/STATUS.json
iindex ca8e726..41329dc 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -4,7 +4,7 @@
"code": true,
"wave": "W2",
"package": "openvibe-shared",
-- "version": "4.135.0",
++ "version": "4.136.0",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
ddiff --git a/dock-timeline.js b/dock-timeline.js
iindex e94c233..93cba7c 100644
---- a/dock-timeline.js
++++ b/dock-timeline.js
@@@ -174,7 +174,27 @@
if (now.placement && (now.placement.where || now.placement.why)) {
card.appendChild(el(doc, 'div', 'ovdt-meta', [now.placement.where, now.placement.why].filter(Boolean).join(': ')));
}
++ // The Computer this step works on (plan 2026-11-07): the same machine and cost the task record carries.
++ if (now.computer) card.appendChild(el(doc, 'div', 'ovdt-meta', [now.computer.machine, now.computer.cost_hint].filter(Boolean).join(' · ')));
const buttons = el(doc, 'div', 'ovdt-buttons');
++ // Take over / Give it back: one API on the task at Actor, the same hand-off the agent's own
++ // hand_to_person tool uses. Only a step that names its task (ref) and its Computer offers it.
++ if (now.computer && now.ref) {
++ const driving = now.computer.driving === true || /^You took over/.test(String(now.title || ''));
++ const take = el(doc, 'button', 'ovdt-btn is-primary', driving ? 'Give it back' : 'Take over');
++ take.type = 'button';
++ take.addEventListener('click', async () => {
++ take.disabled = true;
++ const auth = await bearer();
++ try {
++ await api('/api/v1/tasks/' + encodeURIComponent(now.ref) + (driving ? '/giveback' : '/takeover'), {
++ method: 'POST', headers: { 'Content-Type': 'application/json', ...(auth ? { Authorization: auth } : {}) }, body: '{}',
++ });
++ } catch (err) { /* the panel refreshes either way */ }
++ refresh();
++ });
++ buttons.appendChild(take);
++ }
const stop = el(doc, 'button', 'ovdt-btn is-stop', 'Stop');
stop.type = 'button';
stop.addEventListener('click', async () => {
@@@ -236,6 +256,7 @@
else if (entry.placement && (entry.placement.where || entry.placement.why)) {
card.appendChild(el(doc, 'div', 'ovdt-meta', [entry.placement.where, entry.placement.why].filter(Boolean).join(': ')));
}
++ if (entry.computer) card.appendChild(el(doc, 'div', 'ovdt-meta', [entry.computer.machine, entry.computer.cost_hint].filter(Boolean).join(' · ')));
if (entry.reason) card.appendChild(el(doc, 'div', 'ovdt-meta', entry.reason));
if (entry.cost_usd !== null && entry.cost_usd !== undefined) card.appendChild(el(doc, 'div', 'ovdt-meta', '$' + Number(entry.cost_usd).toFixed(2)));
if (entry.link) {
ddiff --git a/package.json b/package.json
iindex c0a5b1f..30265f0 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-shared",
-- "version": "4.135.0",
++ "version": "4.136.0",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"bin": {
ddiff --git a/test/dock-timeline.test.js b/test/dock-timeline.test.js
iindex a5fe9a0..87faa70 100644
---- a/test/dock-timeline.test.js
++++ b/test/dock-timeline.test.js
@@@ -26,6 +26,10 @@ assert.ok(panel.includes('placement'), 'the entry says where it ran and why');
assert.ok(panel.includes('transition'), 'a mode change is a line of its own');
assert.ok(panel.includes('cost_usd'), 'the cost is shown when there was one');
assert.ok(panel.includes('entry.link'), 'the entry links to the step\'s own page');
++// One Computer (plan 2026-11-07): the step reads the same fields the task record carries, and Now can hand over.
++assert.ok(panel.includes('entry.computer'), 'a step names its Computer');
++assert.ok(panel.includes('now.computer'), 'Now names the Computer');
++assert.ok(panel.includes('/takeover') && panel.includes('/giveback'), 'the Dock calls the one take-over API');
// The folds and the filters.
assert.ok(panel.includes('Yesterday ('), 'earlier days fold with a count');