@floless/app 0.22.0 → 0.23.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.
@@ -52729,7 +52729,7 @@ function appVersion() {
52729
52729
  return resolveVersion({
52730
52730
  isSea: isSea2(),
52731
52731
  sqVersionXml: readSqVersionXml(),
52732
- define: true ? "0.22.0" : void 0,
52732
+ define: true ? "0.23.0" : void 0,
52733
52733
  pkgVersion: readPkgVersion()
52734
52734
  });
52735
52735
  }
@@ -52739,7 +52739,7 @@ function resolveChannel(s) {
52739
52739
  return "dev";
52740
52740
  }
52741
52741
  function appChannel() {
52742
- return resolveChannel({ isSea: isSea2(), define: true ? "0.22.0" : void 0 });
52742
+ return resolveChannel({ isSea: isSea2(), define: true ? "0.23.0" : void 0 });
52743
52743
  }
52744
52744
 
52745
52745
  // oauth-presets.ts
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: floless-app-steel-from-drawings
3
- description: This skill should be used to turn a structural steel drawing into an interactive 3D model in floless.app — the "Steel from Drawings" reader. Triggers on a pending floless `rebake` request for the `steel-from-drawings` app (queued from its "Re-read & re-bake ▸" button), or asks like "read this framing plan into 3D", "turn this steel drawing into a model", "bake my drawing into steel-from-drawings". It teaches the host AI to READ a steel drawing (PDF/image) with its own vision, extract a schematic 3D scene (grids, members, sizes, takeoff) in the viewer-3d scene schema, bake it INLINE into the app's `view` node, recompile, and ask the user to approve — all at COMPOSE time (no model in the run path, no API key). Also bakes the same scene into the `steel-to-ifc` companion so the model exports to a universal IFC file (open in Tekla, SDS2, Revit, Navisworks). Triggers also on "export this to IFC", "bake to Tekla/SDS2/Revit".
3
+ description: This skill should be used to turn a structural steel drawing into an interactive 3D model in floless.app — the "Steel from Drawings" reader. Triggers on a pending floless `rebake` request for the `steel-from-drawings` app (queued from its "Re-read & re-bake ▸" button), or asks like "read this framing plan into 3D", "turn this steel drawing into a model", "bake my drawing into steel-from-drawings". It teaches the host AI to READ a steel drawing (PDF/image) with its own vision, extract a schematic 3D scene (grids, members, sizes, takeoff) in the viewer-3d scene schema, bake it INLINE into the app's `view` node, recompile, and ask the user to approve — all at COMPOSE time (no model in the run path, no API key). Also bakes the same scene into the `steel-to-ifc` companion (universal IFC file) and the `steel-to-tekla` companion (native Tekla parts via the Open API, needs Tekla open). Triggers also on "export this to IFC", "bake to Tekla/SDS2/Revit", "bake into Tekla".
4
4
  metadata:
5
5
  version: 0.1.0
6
6
  ---
@@ -17,11 +17,12 @@ and no AI API key**: the brain is you, in the terminal (the FloLess thin-UI cont
17
17
  and **for `steel-from-drawings` it supersedes the generic re-bake** — you bake the scene INLINE into
18
18
  the `.flo`'s `view` node, not into `config.yaml`).
19
19
 
20
- **Bake-out companion (`steel-to-ifc`).** A sibling app writes the SAME scene to a universal **IFC**
21
- file (IfcColumn/IfcBeam on the real grid) — open it in Tekla, SDS2, Revit or Navisworks; no Tekla
22
- needed to export. When you bake a scene, bake the *identical* scene into `steel-to-ifc` too (loop
23
- step 6) so the IFC matches the 3D the user confirmed. The whole loop: **read the drawing → see it in
24
- 3D (`steel-from-drawings`) bake it out to IFC (`steel-to-ifc`) finish in your detailing tool.**
20
+ **Bake-out companions.** Two sibling apps consume the SAME scene: **`steel-to-ifc`** writes a
21
+ universal **IFC** file (open in Tekla, SDS2, Revit, Navisworks; no Tekla needed), and
22
+ **`steel-to-tekla`** creates **native Tekla members** directly via the Open API (needs Tekla open).
23
+ When you bake a scene, bake the *identical* scene into whichever of these are installed (loop steps
24
+ 6–7) so every output matches the 3D the user confirmed. The whole loop: **read the drawing → see it
25
+ in 3D (`steel-from-drawings`) → bake it out (an IFC file and/or native Tekla parts) → finish in your tool.**
25
26
 
26
27
  > **Pasted a request?** If the user pastes a message beginning with a `[floless-request type=rebake
27
28
  > id=…]` marker, that's a request copied from the FloLess Dashboard — resolve it via
@@ -51,11 +52,19 @@ step 6) so the IFC matches the 3D the user confirmed. The whole loop: **read the
51
52
  present), then `aware app compile ~/.aware/apps/steel-to-ifc`. This keeps the exported IFC matching
52
53
  the 3D the user confirmed. (`steel-to-ifc` writes a real IFC file — IfcColumn/IfcBeam on the grid —
53
54
  openable in Tekla, SDS2, Revit or Navisworks; it never touches a Tekla model, so no Tekla needed.)
54
- 7. **Hand the approval to the user.** Tell them what you read (e.g. "read 6 columns + 8 beams on grids
55
+ 7. **Bake the SAME scene into `steel-to-tekla` (native Tekla parts), if it's installed.** Check
56
+ `~/.aware/apps/steel-to-tekla/`. If present, replace the `scene:` under that app's `bake-tekla` node
57
+ `config.args` with the IDENTICAL scene (installed + `demos/steel-to-tekla/`), set `config.version`
58
+ to the user's RUNNING Tekla version (e.g. "2026.0" — the Open API connects to a version-specific
59
+ channel, so a wrong version silently finds no model), then `aware app compile
60
+ ~/.aware/apps/steel-to-tekla`. It creates a real Tekla member per element via the Open API (mode:
61
+ write, snapshot — Undo reverts the whole bake); needs Tekla OPEN with a model. Profiles fall back
62
+ to a sized rectangular section when the environment lacks the drawing's catalogue profile.
63
+ 8. **Hand the approval to the user.** Tell them what you read (e.g. "read 6 columns + 8 beams on grids
55
64
  A–C / 1–2, heights assumed 4.5 m — review in Inspect → Code, then Compile/Approve, then ▶ Run to
56
- see the 3D; run **steel-to-ifc** to export the IFC"). The human eyeballing the read in 3D **is the
57
- safety gate**. Never auto-run.
58
- 8. **Clear the request.** `DELETE http://localhost:<port>/api/requests/<id>` once done (if from one).
65
+ see the 3D; run **steel-to-ifc** for an IFC file or **steel-to-tekla** for native Tekla parts").
66
+ The human eyeballing the read in 3D **is the safety gate**. Never auto-run.
67
+ 9. **Clear the request.** `DELETE http://localhost:<port>/api/requests/<id>` once done (if from one).
59
68
 
60
69
  ## Scene schema (the bake target — exactly what `viewer-3d` renders)
61
70
 
package/dist/web/app.css CHANGED
@@ -1125,9 +1125,17 @@
1125
1125
  overflow-y: auto;
1126
1126
  display: grid;
1127
1127
  grid-template-columns: 1fr 1fr;
1128
+ /* align-items:start so a collapsed card isn't stretched to match an
1129
+ expanded sibling in the same row (the accordion-in-grid pattern). */
1130
+ align-items: start;
1128
1131
  gap: 6px;
1129
1132
  padding-right: 4px;
1130
1133
  }
1134
+ /* One grid cell per agent: holds the card header + its command list, so the
1135
+ commands nest directly under the picked card (see renderLibrary). */
1136
+ .lib-card { min-width: 0; }
1137
+ .lib-card.expanded .lib-item { border-color: var(--accent-dim); }
1138
+ .lib-card.expanded .lib-fav { transform: rotate(180deg); }
1131
1139
  .lib-item {
1132
1140
  background: var(--surface-2);
1133
1141
  border: 1px solid var(--border-strong);
@@ -1162,6 +1170,7 @@
1162
1170
  border-radius: 3px;
1163
1171
  flex-shrink: 0;
1164
1172
  line-height: 1;
1173
+ transition: transform 0.15s ease, color 0.15s, border-color 0.15s;
1165
1174
  }
1166
1175
  .lib-item .lib-fav.faved { color: var(--star); border-color: var(--star); }
1167
1176
 
package/dist/web/aware.js CHANGED
@@ -3681,15 +3681,20 @@
3681
3681
  renderLibrary = function renderLibraryReal() {
3682
3682
  const q = ($libSearch.value || '').toLowerCase().trim();
3683
3683
  const items = agentCatalog.filter((a) => !q || a.id.toLowerCase().includes(q) || (a.kind || '').toLowerCase().includes(q));
3684
+ // Each agent is ONE grid cell: the card header + its (lazy) command list live
3685
+ // in the same `.lib-card`, so expanding nests the commands directly under the
3686
+ // picked card instead of scattering them into a neighbouring grid slot.
3684
3687
  $libList.innerHTML = items.map((a) => `
3685
- <div class="lib-item" data-agent="${escapeAttr(a.id)}">
3686
- <div class="info">
3687
- <div class="name">${escapeHtml(a.id)} <span style="color:var(--text-dim);font-weight:400">v${escapeHtml(String(a.version))}</span></div>
3688
- <div class="meta">${escapeHtml(a.kind || 'agent')} · ${a.commands} command${a.commands === 1 ? '' : 's'} · ${a.skills} skill${a.skills === 1 ? '' : 's'}</div>
3688
+ <div class="lib-card" data-agent="${escapeAttr(a.id)}">
3689
+ <div class="lib-item">
3690
+ <div class="info">
3691
+ <div class="name">${escapeHtml(a.id)} <span style="color:var(--text-dim);font-weight:400">v${escapeHtml(String(a.version))}</span></div>
3692
+ <div class="meta">${escapeHtml(a.kind || 'agent')} · ${a.commands} command${a.commands === 1 ? '' : 's'} · ${a.skills} skill${a.skills === 1 ? '' : 's'}</div>
3693
+ </div>
3694
+ <button class="lib-fav" data-expand="${escapeAttr(a.id)}" data-tip="Show commands">⌄</button>
3689
3695
  </div>
3690
- <button class="lib-fav" data-expand="${escapeAttr(a.id)}" data-tip="Show commands">⌄</button>
3696
+ <div class="lib-commands" id="cmds-${escapeAttr(a.id)}" hidden></div>
3691
3697
  </div>
3692
- <div class="lib-commands" id="cmds-${escapeAttr(a.id)}" hidden></div>
3693
3698
  `).join('') || '<div class="empty-state">No agents match.</div>';
3694
3699
  $libList.querySelectorAll('[data-expand]').forEach((btn) => {
3695
3700
  btn.onclick = () => expandAgent(btn.dataset.expand);
@@ -3699,8 +3704,10 @@
3699
3704
  async function expandAgent(id) {
3700
3705
  const box = document.getElementById(`cmds-${id}`);
3701
3706
  if (!box) return;
3702
- if (!box.hidden) { box.hidden = true; return; }
3707
+ const card = box.closest('.lib-card');
3708
+ if (!box.hidden) { box.hidden = true; if (card) card.classList.remove('expanded'); return; }
3703
3709
  box.hidden = false;
3710
+ if (card) card.classList.add('expanded');
3704
3711
  box.innerHTML = '<div class="cmd-desc">loading…</div>';
3705
3712
  try {
3706
3713
  const { agent } = await api(`/api/agent/${encodeURIComponent(id)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floless/app",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
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": {