@floless/app 0.31.1 → 0.31.2
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/dist/floless-server.cjs +2 -2
- package/dist/web/app.css +5 -0
- package/dist/web/app.js +1 -1
- package/dist/web/aware.js +43 -6
- package/package.json +1 -1
package/dist/floless-server.cjs
CHANGED
|
@@ -52835,7 +52835,7 @@ function appVersion() {
|
|
|
52835
52835
|
return resolveVersion({
|
|
52836
52836
|
isSea: isSea2(),
|
|
52837
52837
|
sqVersionXml: readSqVersionXml(),
|
|
52838
|
-
define: true ? "0.31.
|
|
52838
|
+
define: true ? "0.31.2" : void 0,
|
|
52839
52839
|
pkgVersion: readPkgVersion()
|
|
52840
52840
|
});
|
|
52841
52841
|
}
|
|
@@ -52845,7 +52845,7 @@ function resolveChannel(s) {
|
|
|
52845
52845
|
return "dev";
|
|
52846
52846
|
}
|
|
52847
52847
|
function appChannel() {
|
|
52848
|
-
return resolveChannel({ isSea: isSea2(), define: true ? "0.31.
|
|
52848
|
+
return resolveChannel({ isSea: isSea2(), define: true ? "0.31.2" : void 0 });
|
|
52849
52849
|
}
|
|
52850
52850
|
|
|
52851
52851
|
// oauth-presets.ts
|
package/dist/web/app.css
CHANGED
|
@@ -566,6 +566,7 @@
|
|
|
566
566
|
font-size: 12px;
|
|
567
567
|
background: var(--accent-soft);
|
|
568
568
|
flex-shrink: 0;
|
|
569
|
+
cursor: help;
|
|
569
570
|
}
|
|
570
571
|
.agent-card .fav-btn {
|
|
571
572
|
position: absolute;
|
|
@@ -1124,6 +1125,10 @@
|
|
|
1124
1125
|
never deletes — matching the app's other destructive affordances. */
|
|
1125
1126
|
.modal-actions button.danger { border-color: var(--border-strong); color: var(--text); font-weight: 600; }
|
|
1126
1127
|
.modal-actions button.danger:hover { color: var(--err); border-color: var(--err); background: rgba(248, 113, 113, 0.1); box-shadow: none; }
|
|
1128
|
+
/* #125: form modal with many fields must not overflow the viewport — cap + scroll
|
|
1129
|
+
the body between the pinned title and actions, mirroring .modal.routines. */
|
|
1130
|
+
#form-modal .modal { max-height: 86vh; display: flex; flex-direction: column; }
|
|
1131
|
+
#form-modal-body { overflow-y: auto; flex: 1 1 auto; min-height: 0; }
|
|
1127
1132
|
.modal.library {
|
|
1128
1133
|
width: 720px;
|
|
1129
1134
|
max-height: 82vh;
|
package/dist/web/app.js
CHANGED
|
@@ -352,7 +352,7 @@ function cardEl(id, ports) {
|
|
|
352
352
|
<div class="kind">${a.kind}</div>
|
|
353
353
|
<div class="ver">${a.version}</div>
|
|
354
354
|
</div>
|
|
355
|
-
<div class="icon">${a.icon}</div>
|
|
355
|
+
<div class="icon"${a.iconTip ? ` data-tip="${escapeAttr(a.iconTip)}"` : ''}>${a.icon}</div>
|
|
356
356
|
</div>
|
|
357
357
|
<div class="title">${a.title}</div>
|
|
358
358
|
<div class="subtitle">${a.subtitle}</div>
|
package/dist/web/aware.js
CHANGED
|
@@ -94,10 +94,28 @@
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const AGENT_ICONS = {
|
|
97
|
+
tekla: '<line x1="4" y1="5" x2="20" y2="5"/><line x1="12" y1="5" x2="12" y2="20"/>',
|
|
98
|
+
file: '<path d="M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z"/><polyline points="13 2 13 9 20 9"/>',
|
|
99
|
+
excel: '<rect x="2" y="3" width="20" height="18" rx="2"/><line x1="12" y1="3" x2="12" y2="21"/><line x1="2" y1="12" x2="22" y2="12"/>',
|
|
100
|
+
revit: '<rect x="3" y="4" width="18" height="17" rx="1"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="12" y1="21" x2="12" y2="12"/>',
|
|
101
|
+
slack: '<line x1="4" y1="10" x2="20" y2="10"/><line x1="4" y1="14" x2="20" y2="14"/><line x1="10" y1="4" x2="8" y2="20"/><line x1="16" y1="4" x2="14" y2="20"/>',
|
|
102
|
+
'trimble-connect': '<path d="M17.5 10a4.5 4.5 0 00-9 0A4 4 0 009 18h6a4 4 0 002.5-7z"/><line x1="12" y1="18" x2="12" y2="12"/><polyline points="9 15 12 12 15 15"/>',
|
|
103
|
+
'microsoft-365': '<rect x="2" y="2" width="8" height="8" rx="1"/><rect x="14" y="2" width="8" height="8" rx="1"/><rect x="2" y="14" width="8" height="8" rx="1"/><rect x="14" y="14" width="8" height="8" rx="1"/>',
|
|
104
|
+
email: '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="M2 7l10 7 10-7"/>',
|
|
105
|
+
http: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
|
|
106
|
+
};
|
|
107
|
+
const AGENT_NAMES = {
|
|
108
|
+
tekla: 'Tekla', file: 'File', excel: 'Excel', revit: 'Revit', slack: 'Slack',
|
|
109
|
+
'trimble-connect': 'Trimble Connect', 'microsoft-365': 'Microsoft 365', email: 'Email', http: 'HTTP',
|
|
110
|
+
};
|
|
111
|
+
const _svgWrap = (inner) => `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${inner}</svg>`;
|
|
112
|
+
const iconFor = (agent) => _svgWrap(AGENT_ICONS[agent] || '<path d="M12 2l8 10-8 10L4 12z"/>');
|
|
113
|
+
const iconTipFor = (agent) => AGENT_NAMES[agent] || (agent ? agent.replace(/-/g, ' ') : '');
|
|
114
|
+
const AGENT_ICONS_TEXT = {
|
|
97
115
|
tekla: '⊞', file: '🗀', excel: '◵', revit: '◰', slack: '✦',
|
|
98
116
|
'trimble-connect': '☁', 'microsoft-365': '✉', email: '✉', http: '⇄',
|
|
99
117
|
};
|
|
100
|
-
const
|
|
118
|
+
const iconTextFor = (agent) => AGENT_ICONS_TEXT[agent] || '◈';
|
|
101
119
|
|
|
102
120
|
// The demo's renderChat staggers narration via setTimeout; its bootstrap call
|
|
103
121
|
// (fired before this script runs) would otherwise drip stale demo lines into
|
|
@@ -289,6 +307,7 @@
|
|
|
289
307
|
// Description tab: a plain-English explanation + a small input table that
|
|
290
308
|
// EXCLUDES the code (code belongs to the Code tab, never dumped here).
|
|
291
309
|
const plainDesc = execSource ? leadingComment(execSource) : '';
|
|
310
|
+
const blurbText = plainDesc && (s => s.length > 80 ? s.slice(0, 79) + '…' : s)(plainDesc.replace(/\.\s+.*/, '.').trim());
|
|
292
311
|
const inputsNoCode = {};
|
|
293
312
|
for (const [k, v] of Object.entries(inputs || {})) if (k !== 'code') inputsNoCode[k] = v;
|
|
294
313
|
return {
|
|
@@ -296,11 +315,12 @@
|
|
|
296
315
|
_runtimeModel: !!n.runtimeModel, // B2: lock stamped runtime-model → card badge
|
|
297
316
|
_frozen: !!n.frozen, // source node carries a `frozen:` block → card badge + Unfreeze menu
|
|
298
317
|
icon: iconFor(n.agent),
|
|
318
|
+
iconTip: iconTipFor(n.agent),
|
|
299
319
|
kind: n.kind === 'agent' && n.agent ? `${agentLabel} agent` : escapeHtml(n.kind),
|
|
300
320
|
version: pin ? `v${escapeHtml(String(pin))}` : '—',
|
|
301
321
|
title: escapeHtml(n.id),
|
|
302
322
|
subtitle: `${agentLabel}${cmd ? '/' + cmd : ''} · ${mode}`,
|
|
303
|
-
blurb: n.notes[0] ? escapeHtml(humanizeNote(n.notes[0].text)) : `${mode}-mode ${cmd ? '<code>' + cmd + '</code>' : escapeHtml(n.kind)} node`,
|
|
323
|
+
blurb: blurbText ? escapeHtml(blurbText) : n.notes[0] ? escapeHtml(humanizeNote(n.notes[0].text)) : `${mode}-mode ${cmd ? '<code>' + cmd + '</code>' : escapeHtml(n.kind)} node`,
|
|
304
324
|
description: `${plainDesc ? `<p>${escapeHtml(plainDesc)}</p>` : ''}<p>Resolves to ${modeBadge} via <code>${escapeHtml(n.agent || n.kind)}${n.command ? '.' + escapeHtml(n.command) : ''}</code>.</p>${Object.keys(inputsNoCode).length ? `<p><strong>Inputs</strong></p>${kvTable(inputsNoCode)}` : ''}${execSource ? `<p class="dim-note">Full source in the <strong>Code</strong> tab.</p>` : ''}${notesHtml}`,
|
|
305
325
|
// Rich agent/command detail when the manifest is installed (n.skill); else
|
|
306
326
|
// the lock-pointer fallback below (exec/agent-less nodes, uninstalled agents).
|
|
@@ -1624,7 +1644,7 @@
|
|
|
1624
1644
|
card.setAttribute('role', 'status');
|
|
1625
1645
|
|
|
1626
1646
|
const status = mkEl('div', 'cred-fail-status');
|
|
1627
|
-
const icon = mkEl('span', 'cred-fail-icon',
|
|
1647
|
+
const icon = mkEl('span', 'cred-fail-icon', iconTextFor(cred.id));
|
|
1628
1648
|
icon.setAttribute('aria-hidden', 'true');
|
|
1629
1649
|
status.append(icon, document.createTextNode('SESSION EXPIRED'));
|
|
1630
1650
|
|
|
@@ -1774,6 +1794,7 @@
|
|
|
1774
1794
|
const first = $body.querySelector('input:not(.fm-file-input),textarea');
|
|
1775
1795
|
if (first) { first.focus(); if (first.select) first.select(); }
|
|
1776
1796
|
else if (danger) $cancel.focus();
|
|
1797
|
+
else $ok.focus();
|
|
1777
1798
|
// ── images-field setup ──────────────────────────────────────────────────────
|
|
1778
1799
|
const imageStates = new Map();
|
|
1779
1800
|
$body.querySelectorAll('.fm-images').forEach((box) => {
|
|
@@ -2563,6 +2584,7 @@
|
|
|
2563
2584
|
// popover → Update now → POST /api/update/apply, which downloads + relaunches into
|
|
2564
2585
|
// the new version. Hidden in dev/npm (supported:false).
|
|
2565
2586
|
const $appUpdate = document.getElementById('app-update');
|
|
2587
|
+
let _appUpdateRecoveryTimer = null; // cleared before each new apply attempt
|
|
2566
2588
|
// The apply body, extracted so the popover's "Update now" can drive it with the
|
|
2567
2589
|
// polled target version (no textContent scrape). Preserves the npm-vs-desktop
|
|
2568
2590
|
// branch verbatim: npm copies the command; desktop confirms → relaunch.
|
|
@@ -2578,18 +2600,32 @@
|
|
|
2578
2600
|
}
|
|
2579
2601
|
// desktop (Velopack): one-click download + relaunch
|
|
2580
2602
|
const v = version || '';
|
|
2581
|
-
|
|
2603
|
+
const go = await formModal({ title: 'Update and relaunch', sub: 'FloLess will download v' + v + ', close, and relaunch into the new version.', fields: [], okLabel: 'Update now' });
|
|
2604
|
+
if (!go) return;
|
|
2582
2605
|
// Record the pending version so the new build's first paint can reveal the
|
|
2583
2606
|
// what's-new panel (survives the relaunch via localStorage; cleared once shown).
|
|
2584
2607
|
try { localStorage.setItem('floless.whatsNew.pending', v); } catch { /* private mode */ }
|
|
2608
|
+
if (_appUpdateRecoveryTimer) { clearTimeout(_appUpdateRecoveryTimer); _appUpdateRecoveryTimer = null; }
|
|
2585
2609
|
$appUpdate.disabled = true;
|
|
2586
2610
|
$appUpdate.textContent = '↑ Updating…';
|
|
2587
2611
|
try {
|
|
2588
|
-
const r = await fetch('/api/update/apply', { method: 'POST', headers: { 'content-type': 'application/json' } });
|
|
2612
|
+
const r = await fetch('/api/update/apply', { method: 'POST', headers: { 'content-type': 'application/json' }, signal: AbortSignal.timeout(5 * 60 * 1000) });
|
|
2589
2613
|
const d = await r.json().catch(() => ({}));
|
|
2590
2614
|
if (!r.ok || !d.ok) throw new Error(d.error || 'update failed');
|
|
2591
2615
|
// Success: the server is exiting + Update.exe relaunches the new build. The health
|
|
2592
2616
|
// poll flips to offline (R1 overlay), then the new version reconnects on its own.
|
|
2617
|
+
// Recovery guard: if the relaunch never happens and this page stays alive (e.g. a UAC
|
|
2618
|
+
// prompt was declined after the server already responded), re-enable the pill after 90 s
|
|
2619
|
+
// so the user can retry — the page won't go offline in that case.
|
|
2620
|
+
_appUpdateRecoveryTimer = setTimeout(() => {
|
|
2621
|
+
_appUpdateRecoveryTimer = null;
|
|
2622
|
+
if ($appUpdate && $appUpdate.disabled) {
|
|
2623
|
+
$appUpdate.disabled = false;
|
|
2624
|
+
$appUpdate.textContent = '↑ Relaunch failed — retry';
|
|
2625
|
+
try { localStorage.removeItem('floless.whatsNew.pending'); } catch { /* private mode */ }
|
|
2626
|
+
refreshUpdate(); // re-poll so the pill state reflects reality, same as catch path
|
|
2627
|
+
}
|
|
2628
|
+
}, 90_000);
|
|
2593
2629
|
} catch (e) {
|
|
2594
2630
|
$appUpdate.disabled = false;
|
|
2595
2631
|
try { localStorage.removeItem('floless.whatsNew.pending'); } catch { /* private mode */ }
|
|
@@ -2667,7 +2703,8 @@
|
|
|
2667
2703
|
async function applyAwareUpdate(version) {
|
|
2668
2704
|
if (!$awareUpdate) return;
|
|
2669
2705
|
const v = version || '';
|
|
2670
|
-
|
|
2706
|
+
const go = await formModal({ title: 'Upgrade AWARE runtime', sub: 'Reinstalls @aware-aeco/cli to v' + v + ' in place. The app stays open — the version updates automatically when the install finishes.', fields: [], okLabel: 'Upgrade now' });
|
|
2707
|
+
if (!go) return;
|
|
2671
2708
|
$awareUpdate.disabled = true;
|
|
2672
2709
|
$awareUpdate.textContent = '↑ Upgrading…';
|
|
2673
2710
|
try {
|