@floless/app 0.31.2 → 0.31.4
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
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.4" : 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.4" : void 0 });
|
|
52849
52849
|
}
|
|
52850
52850
|
|
|
52851
52851
|
// oauth-presets.ts
|
|
@@ -166,6 +166,31 @@ Two rules that bite immediately:
|
|
|
166
166
|
whatever the node returns.
|
|
167
167
|
- **No `System.Net`** (so no `WebUtility.HtmlEncode`) — escape with a manual lambda.
|
|
168
168
|
|
|
169
|
+
## Every node's Description must be plain English (HARD guardrail)
|
|
170
|
+
|
|
171
|
+
The Inspect → **Description** tab is written **for non-coders**: it must always say, in plain
|
|
172
|
+
English, *what the node does* — never raw code, markup, or jargon (CLAUDE.md standing rule).
|
|
173
|
+
When authoring a `.flo`, that is **your** job, node by node:
|
|
174
|
+
|
|
175
|
+
- **Each `exec` node's Description IS its leading `//` comment.** `web/aware.js` `leadingComment()`
|
|
176
|
+
derives both the Description paragraph and the card blurb from the comment block at the top of
|
|
177
|
+
`config.code`. So **start every exec `code:` with a 1–2 sentence plain-English comment** that
|
|
178
|
+
explains what the node does for someone who can't read C# — e.g.
|
|
179
|
+
`// Reads the chosen phase and builds the bill of materials as an HTML table.` A node with no
|
|
180
|
+
leading comment falls back to a generic "read-mode exec node" line — that's the rubbish this
|
|
181
|
+
rule forbids. (You may *mention* a `{{ upstream.result.x }}` knob in the prose, but never let a
|
|
182
|
+
description be *only* a bare `{{ … }}` ref — and remember braces inside `code` are a run-time
|
|
183
|
+
footgun, see the templating note above.)
|
|
184
|
+
- **The workflow itself needs a plain-English top-level `description:`** (a paragraph saying what
|
|
185
|
+
the app is for) — it's required, not decorative.
|
|
186
|
+
- **Don't rely on the display layer to save you.** The Inspect tab summarizes oversized/baked blob
|
|
187
|
+
*inputs* (e.g. a baked `args.html` → `baked HTML · 223 KB`) so they never dump raw markup — but
|
|
188
|
+
that's a safety net for input *values*, not a license to skip the node's own plain-English
|
|
189
|
+
description.
|
|
190
|
+
- **Enforced in CI:** `npm run verify:flo` (`server/build/verify-flo-descriptions.mjs`) fails the
|
|
191
|
+
build if any committed `demos/*/*.flo` ships a node with no plain-English Description. Run it
|
|
192
|
+
before you call a `.flo` done.
|
|
193
|
+
|
|
169
194
|
## The build loop (install → validate → compile → run)
|
|
170
195
|
|
|
171
196
|
Resolve the `aware` CLI the same way the adapter does: prefer the npm global
|
|
@@ -377,6 +402,9 @@ past a few hard facts, split it into a `references/` file and link it.
|
|
|
377
402
|
|
|
378
403
|
## Guardrails (do not drift)
|
|
379
404
|
|
|
405
|
+
- **Every node's Description is plain English** — each exec node opens with a 1–2 sentence
|
|
406
|
+
plain-English `//` comment (its Description), and the app has a plain-English `description:`.
|
|
407
|
+
Enforced by `npm run verify:flo` in CI. See "Every node's Description must be plain English".
|
|
380
408
|
- Determinism is AWARE's: `<app>.lock` is the approved artifact; Run is gated on a fresh
|
|
381
409
|
source-hash. Never let the UI run on drift.
|
|
382
410
|
- Any change under `web/` requires a Playwright pass (visual + interaction), not just a check of
|
package/dist/web/aware.js
CHANGED
|
@@ -171,6 +171,57 @@
|
|
|
171
171
|
.join('')}</table>`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
// The Description tab is for non-coders — it must read as plain English about what a
|
|
175
|
+
// node does, never a wall of code/markup. Short scalar inputs (phase: 1, version:
|
|
176
|
+
// '2025.0') are the real knobs and show verbatim; but a baked blob (HTML markup, a
|
|
177
|
+
// large JSON payload pre-built at compile time, e.g. a steel overlay's `args.html`)
|
|
178
|
+
// is NOT plain English — dumping it raw is the "rubbish" this view must never show.
|
|
179
|
+
// So anything oversized collapses to a dimmed one-line summary ("baked HTML · 210.0 KB").
|
|
180
|
+
const DESC_BLOB_CHARS = 500;
|
|
181
|
+
function summarizeInputValue(v) {
|
|
182
|
+
const isStr = typeof v === 'string';
|
|
183
|
+
const raw = isStr ? v : v == null ? '' : JSON.stringify(v);
|
|
184
|
+
// Summarize on size OR on any markup/code shape — a non-coder must never see raw
|
|
185
|
+
// markup, however short. (The slice bounds the scan to 500 chars; the regex is
|
|
186
|
+
// already linear — a single [^>]* with a disjoint `>` terminator — so no ReDoS.)
|
|
187
|
+
const markup = /<\/?[a-z!][^>]*>/i.test(raw.slice(0, 500));
|
|
188
|
+
if (raw.length <= DESC_BLOB_CHARS && !markup) return { text: raw, blob: false };
|
|
189
|
+
const size = raw.length >= 1024 ? (raw.length / 1024).toFixed(1) + ' KB' : raw.length + ' chars';
|
|
190
|
+
const kind = markup ? 'HTML' : isStr ? 'content' : 'JSON';
|
|
191
|
+
return { text: `baked ${kind} · ${size}`, blob: true };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Exec nodes receive their inputs wrapped in an `args` object (an AWARE implementation
|
|
195
|
+
// detail of how exec passes data in). Flatten that one level so a non-coder sees the
|
|
196
|
+
// real knobs (phase, html…) directly instead of an `args: {…}` row. `code` is the
|
|
197
|
+
// implementation, never an input, so it's dropped; a flattened member that collides
|
|
198
|
+
// with a real top-level input yields to the top-level value.
|
|
199
|
+
function flattenInputs(inputs) {
|
|
200
|
+
const out = Object.create(null); // null-proto: keys like `constructor`/`__proto__` stay plain data
|
|
201
|
+
for (const [k, v] of Object.entries(inputs || {})) {
|
|
202
|
+
if (k === 'code') continue;
|
|
203
|
+
if (k === 'args' && v && typeof v === 'object' && !Array.isArray(v)) {
|
|
204
|
+
for (const [ak, av] of Object.entries(v)) if (ak !== 'code' && !Object.hasOwn(out, ak)) out[ak] = av;
|
|
205
|
+
} else {
|
|
206
|
+
out[k] = v;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Description-tab Inputs block: flattened, plain-English, baked blobs summarized and
|
|
213
|
+
// dimmed (meta, not data). Empty inputs → no block at all.
|
|
214
|
+
function descInputs(inputs) {
|
|
215
|
+
const rows = Object.entries(flattenInputs(inputs));
|
|
216
|
+
if (!rows.length) return '';
|
|
217
|
+
const body = rows.map(([k, v]) => {
|
|
218
|
+
const s = summarizeInputValue(v);
|
|
219
|
+
const cell = s.blob ? `<span class="dim-note">${escapeHtml(s.text)}</span>` : escapeHtml(s.text);
|
|
220
|
+
return `<tr><th>${escapeHtml(k)}</th><td>${cell}</td></tr>`;
|
|
221
|
+
}).join('');
|
|
222
|
+
return `<p><strong>Inputs</strong></p><table class="kv">${body}</table>`;
|
|
223
|
+
}
|
|
224
|
+
|
|
174
225
|
// Plain-text summary of one declared command input (for the Skill tab's inputs
|
|
175
226
|
// table — kvTable escapes it, so this stays text, no markup): "type (enum vals)
|
|
176
227
|
// · default X — description".
|
|
@@ -308,8 +359,6 @@
|
|
|
308
359
|
// EXCLUDES the code (code belongs to the Code tab, never dumped here).
|
|
309
360
|
const plainDesc = execSource ? leadingComment(execSource) : '';
|
|
310
361
|
const blurbText = plainDesc && (s => s.length > 80 ? s.slice(0, 79) + '…' : s)(plainDesc.replace(/\.\s+.*/, '.').trim());
|
|
311
|
-
const inputsNoCode = {};
|
|
312
|
-
for (const [k, v] of Object.entries(inputs || {})) if (k !== 'code') inputsNoCode[k] = v;
|
|
313
362
|
return {
|
|
314
363
|
_mode: n.mode,
|
|
315
364
|
_runtimeModel: !!n.runtimeModel, // B2: lock stamped runtime-model → card badge
|
|
@@ -321,7 +370,7 @@
|
|
|
321
370
|
title: escapeHtml(n.id),
|
|
322
371
|
subtitle: `${agentLabel}${cmd ? '/' + cmd : ''} · ${mode}`,
|
|
323
372
|
blurb: blurbText ? escapeHtml(blurbText) : n.notes[0] ? escapeHtml(humanizeNote(n.notes[0].text)) : `${mode}-mode ${cmd ? '<code>' + cmd + '</code>' : escapeHtml(n.kind)} node`,
|
|
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>${
|
|
373
|
+
description: `${plainDesc ? `<p>${escapeHtml(plainDesc)}</p>` : ''}<p>Resolves to ${modeBadge} via <code>${escapeHtml(n.agent || n.kind)}${n.command ? '.' + escapeHtml(n.command) : ''}</code>.</p>${descInputs(inputs)}${execSource ? `<p class="dim-note">Full source in the <strong>Code</strong> tab.</p>` : ''}${notesHtml}`,
|
|
325
374
|
// Rich agent/command detail when the manifest is installed (n.skill); else
|
|
326
375
|
// the lock-pointer fallback below (exec/agent-less nodes, uninstalled agents).
|
|
327
376
|
skill: skillBody(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floless/app",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Thin localhost host for floless.app — serves web/ and shells the aware CLI. No engine, no LLM.",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"build": "node build/bundle.mjs",
|
|
25
25
|
"build:exe": "node build/bundle.mjs && node build/make-sea.mjs",
|
|
26
26
|
"verify:skills": "node build/verify-shipped-skills.mjs",
|
|
27
|
+
"verify:flo": "node build/verify-flo-descriptions.mjs",
|
|
27
28
|
"typecheck": "tsc --noEmit",
|
|
28
29
|
"prepack": "npm run build"
|
|
29
30
|
},
|