5fe8f228c1
Add a read-only /ecosystem page that consumes the sibling services' JSON APIs (Nexus entities, Praxis attention, Hexis capabilities), fetched concurrently with honest per-panel error states. Siblings stay headless — mavweb is their human surface (arch §16). Wired via mavweb -nexus/-praxis/-hexis flags; mavweb joins the ecosystem compose network. Fix mobile horizontal overflow across all pages: .content is a flex child with default min-width:auto, so it refused to shrink below the tables' intrinsic width. min-width:0 lets wide tables pan inside .scroll instead of dragging the page sideways. Verified via CDP geometry check (scrollWidth === clientWidth at 430px). Also includes in-progress Ethos UI redesign, ecosystem deploy compose, and planning docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
55 lines
2.3 KiB
HTML
55 lines
2.3 KiB
HTML
{{template "shellTop" "ecosystem"}}
|
|
<h1>Ecosystem</h1>
|
|
<p class=hint>The sibling services Maven coordinates — read-only. Identity, attention, capabilities. Enabling & execution live on the authed surfaces, never here.</p>
|
|
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>Nexus <span class=card-sub>identity</span></h2>
|
|
</div>
|
|
{{with .Nexus}}
|
|
{{if .Err}}<div class=empty>nexus — {{.Err}}</div>
|
|
{{else if not .Rows}}<div class=empty>no entities yet.</div>
|
|
{{else}}<div class=scroll><table class=mono><tr><th>id<th>type<th>name<th>state<th>updated</tr>
|
|
{{range .Rows}}<tr><td class=key>{{.ID}}<td><span class=badge>{{.Type}}</span><td class=en>{{.DisplayName}}<td>{{.State}}<td>{{ago .UpdatedAt}}</tr>{{end}}
|
|
</table></div>{{end}}
|
|
{{end}}
|
|
</section>
|
|
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>Praxis <span class=card-sub>attention</span></h2>
|
|
</div>
|
|
{{with .Praxis}}
|
|
{{if .Err}}<div class=empty>praxis — {{.Err}}</div>
|
|
{{else if not .Rows}}<div class=empty>nothing needs attention.</div>
|
|
{{else}}<div class=scroll><table class=mono><tr><th>imp<th>kind<th>title<th>state<th>last seen</tr>
|
|
{{range .Rows}}<tr><td>{{.Importance}}<td><span class=badge>{{.Kind}}</span><td class=en>{{.Title}}<td>{{.State}}<td>{{ago .LastSeenAt}}</tr>{{end}}
|
|
</table></div>{{end}}
|
|
{{end}}
|
|
</section>
|
|
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>Hexis <span class=card-sub>capabilities</span></h2>
|
|
</div>
|
|
{{with .Hexis}}
|
|
{{if .Err}}<div class=empty>hexis — {{.Err}}</div>
|
|
{{else if not .Rows}}<div class=empty>no capabilities registered.</div>
|
|
{{else}}<div class=scroll><table class=mono><tr><th>id<th>name<th>provider<th>operation<th>risk<th>access</tr>
|
|
{{range .Rows}}<tr><td class=key>{{.ID}}<td class=en>{{.Name}}<td><span class=badge>{{.Provider}}</span><td>{{.Operation}}<td>{{.Risk}}<td>{{if .ReadOnly}}<span class="badge badge-ok">read-only</span>{{else}}<span class="badge badge-warn">mutating</span>{{end}}</tr>{{end}}
|
|
</table></div>{{end}}
|
|
{{end}}
|
|
</section>
|
|
|
|
{{template "shellBottom"}}
|
|
<script>
|
|
setInterval(() => fetch('/ecosystem').then(r => r.text()).then(html => {
|
|
const d = new DOMParser().parseFromString(html, 'text/html');
|
|
document.querySelectorAll('main.content section.card').forEach((old, i) => {
|
|
const nu = d.querySelectorAll('main.content section.card')[i];
|
|
if (nu) old.replaceWith(nu);
|
|
});
|
|
}), 15000);
|
|
</script>
|
|
</html>
|