<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>RNS Server</title>
<link rel="stylesheet" href="/assets/app.css">
</head>
<body>
<main>
<section class="hero">
<h1>RNS Server</h1>
<p>Minimal control surface for the supervised node. Enter a bearer token once, then this page polls <code>/api/node</code> and <code>/api/processes</code>.</p>
<div class="row">
<input id="token" class="token" placeholder="Bearer token" spellcheck="false" />
<button id="saveToken">Save Token</button>
<span id="status" class="muted">Waiting for token</span>
</div>
</section>
<section class="grid">
<article class="panel">
<h2>Server Mode</h2>
<div id="serverMode" class="stat">-</div>
</article>
<article class="panel">
<h2>Uptime</h2>
<div id="uptime" class="stat">-</div>
</article>
<article class="panel">
<h2>Running Processes</h2>
<div id="running" class="stat">-</div>
</article>
<article class="panel">
<h2>Ready Processes</h2>
<div id="ready" class="stat">-</div>
</article>
<article class="panel">
<h2>Config Converged</h2>
<div id="configConverged" class="stat">-</div>
<p id="configStatusSummary" class="muted">No config status yet.</p>
</article>
</section>
<section class="panel" style="margin-top: 18px;">
<h2>Config Runtime Status</h2>
<div class="status-grid">
<article class="status-card">
<div class="status-label">Saved Vs Runtime</div>
<div id="configRuntimeBadge" class="pill">unknown</div>
<p id="configRuntimeDetail" class="muted">No config status yet.</p>
</article>
<article class="status-card">
<div class="status-label">Child Restarts</div>
<div id="configRestartBadge" class="pill">unknown</div>
<p id="configRestartDetail" class="muted">No process restart information yet.</p>
</article>
<article class="status-card">
<div class="status-label">Control Plane</div>
<div id="configControlPlaneBadge" class="pill">unknown</div>
<p id="configControlPlaneDetail" class="muted">No control-plane restart information yet.</p>
</article>
</div>
<table style="margin-top: 16px;">
<tbody>
<tr><th>Last Action</th><td id="configLastAction">-</td></tr>
<tr><th>Last Save</th><td id="configLastSaved">-</td></tr>
<tr><th>Last Apply</th><td id="configLastApplied">-</td></tr>
</tbody>
</table>
</section>
<section class="panel">
<h2>Processes</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Ready</th>
<th>PID</th>
<th>Uptime</th>
<th>Last Change</th>
<th>Last Exit</th>
<th>Detail</th>
<th>Action</th>
<th>Logs</th>
</tr>
</thead>
<tbody id="processRows"></tbody>
</table>
<div class="process-detail-panel" style="margin-top: 18px;">
<div class="row" style="justify-content: space-between; align-items: flex-start;">
<div>
<h3 id="selectedProcessName">No process selected</h3>
<p id="selectedProcessSummary" class="muted">Select a process to inspect its runtime detail, recent events, and logs.</p>
</div>
<div id="selectedProcessStatusBadge" class="pill info">idle</div>
</div>
<div class="process-detail-grid" style="margin-top: 12px;">
<article class="status-card">
<div class="status-label">Readiness</div>
<div id="selectedProcessReady" class="stat">-</div>
<p id="selectedProcessReadyDetail" class="muted">No process selected.</p>
</article>
<article class="status-card">
<div class="status-label">Restarts</div>
<div id="selectedProcessRestarts" class="stat">0</div>
<p id="selectedProcessTransition" class="muted">No transition data yet.</p>
</article>
<article class="status-card">
<div class="status-label">Last Exit</div>
<div id="selectedProcessLastExit" class="stat">-</div>
<p id="selectedProcessLastError" class="muted">No recorded process error.</p>
</article>
<article class="status-card">
<div class="status-label">Logs</div>
<div id="selectedProcessLogCount" class="stat">0</div>
<p id="selectedProcessLogMeta" class="muted">No log metadata yet.</p>
</article>
</div>
<div style="margin-top: 16px;">
<strong>Recent Events For Selected Process</strong>
</div>
<table style="margin-top: 10px;">
<thead>
<tr>
<th>Event</th>
<th>Age</th>
<th>Detail</th>
</tr>
</thead>
<tbody id="selectedProcessEventRows"></tbody>
</table>
</div>
</section>
<section class="panel" style="margin-top: 18px;">
<h2>Process Logs</h2>
<div class="row" style="margin-bottom: 12px;">
<strong id="logProcessName">No process selected</strong>
<span id="logStatus" class="muted">Choose a process log stream</span>
</div>
<pre id="processLogOutput" class="json-block"></pre>
</section>
<section class="panel" style="margin-top: 18px;">
<h2>Config</h2>
<table>
<tbody>
<tr><th>Config Path</th><td id="configPath">-</td></tr>
<tr><th>Resolved Config Dir</th><td id="configDir">-</td></tr>
<tr><th>Server Config File</th><td id="serverConfigFile">-</td></tr>
<tr><th>Stats DB</th><td id="statsDb">-</td></tr>
<tr><th>rnsd Bin</th><td id="rnsdBin">-</td></tr>
<tr><th>rns-sentineld Bin</th><td id="sentineldBin">-</td></tr>
<tr><th>rns-statsd Bin</th><td id="statsdBin">-</td></tr>
<tr><th>HTTP Bind</th><td id="httpBind">-</td></tr>
<tr><th>HTTP Auth</th><td id="httpAuth">-</td></tr>
</tbody>
</table>
<table style="margin-top: 16px;">
<thead>
<tr>
<th>Process</th>
<th>Executable</th>
<th>Args</th>
</tr>
</thead>
<tbody id="launchPlanRows"></tbody>
</table>
<div style="margin-top: 18px;">
<h3>Guided Config Workflow</h3>
<p>The guided editor is the primary workflow for common <code>rns-server.json</code> changes. It keeps the generated JSON in sync automatically, so the raw editor is only needed for advanced cases.</p>
<div class="config-builder">
<div class="config-group">
<div class="group-title">Process Paths</div>
<label class="field">
<span>Stats DB Path</span>
<input id="builderStatsDbPath" class="token field-input" spellcheck="false" placeholder="stats.db" />
</label>
<label class="field">
<span>rnsd Bin</span>
<input id="builderRnsdBin" class="token field-input" spellcheck="false" placeholder="rnsd" />
</label>
<label class="field">
<span>rns-sentineld Bin</span>
<input id="builderSentineldBin" class="token field-input" spellcheck="false" placeholder="rns-sentineld" />
</label>
<label class="field">
<span>rns-statsd Bin</span>
<input id="builderStatsdBin" class="token field-input" spellcheck="false" placeholder="rns-statsd" />
</label>
</div>
<div class="config-group">
<div class="group-title">HTTP Control Plane</div>
<label class="toggle">
<input id="builderHttpEnabled" type="checkbox" />
<span>Enable embedded HTTP control plane</span>
</label>
<label class="field">
<span>HTTP Host</span>
<input id="builderHttpHost" class="token field-input" spellcheck="false" placeholder="127.0.0.1" />
</label>
<label class="field">
<span>HTTP Port</span>
<input id="builderHttpPort" class="token field-input" type="number" min="1" max="65535" placeholder="8080" />
</label>
<label class="toggle">
<input id="builderHttpDisableAuth" type="checkbox" />
<span>Disable bearer token auth</span>
</label>
<label class="field">
<span>HTTP Auth Token</span>
<input id="builderHttpAuthToken" class="token field-input" spellcheck="false" placeholder="optional fixed token" />
</label>
</div>
</div>
<div class="row" style="margin-top: 12px;">
<button id="loadCurrentConfig" class="secondary">Load Current</button>
<button id="loadExampleConfig" class="secondary">Load Example</button>
<button id="syncBuilderFromJson" class="secondary">Import JSON Into Builder</button>
<button id="syncJsonFromBuilder" class="secondary">Export Builder To JSON</button>
<button id="formatConfig" class="secondary">Format JSON</button>
</div>
<div class="callout" style="margin-top: 12px;">
Blank text fields are omitted so runtime defaults still apply. The builder writes explicit booleans for HTTP enablement and auth mode, and updates the candidate JSON automatically as you edit.
</div>
<div class="workflow-strip" style="margin-top: 12px;">
<div class="workflow-step"><strong>1.</strong> Edit guided fields</div>
<div class="workflow-step"><strong>2.</strong> Validate the generated plan</div>
<div class="workflow-step"><strong>3.</strong> Save draft or apply</div>
</div>
<div style="margin-top: 16px;">
<strong>Result Summary</strong>
<div id="configActionSummary" class="muted" style="margin-top: 6px;">No config action run yet</div>
</div>
<ul id="configWarningList" class="warning-list"></ul>
<div class="advanced-toggle" style="margin-top: 16px;">
<button id="toggleAdvancedConfig" class="secondary" type="button">Show Advanced JSON</button>
<span class="muted">Use this only if you need fields the guided workflow does not cover yet.</span>
</div>
<div id="advancedConfigSection" class="advanced-section hidden" style="margin-top: 16px;">
<strong>Advanced JSON Editor</strong>
<p>Paste or edit a candidate <code>rns-server.json</code> payload directly for advanced cases. You can import it back into the builder when the fields overlap.</p>
<textarea id="configCandidate" class="candidate" spellcheck="false" placeholder='{"http":{"port":8080},"stats_db_path":"stats.db"}'></textarea>
<div class="row" style="margin-top: 12px;">
<button id="formatConfig" class="secondary">Format JSON</button>
<span id="configValidationStatus" class="muted">Builder is the primary workflow</span>
</div>
</div>
<div class="row" style="margin-top: 12px;">
<button id="validateConfig">Validate Plan</button>
<button id="saveConfig" class="secondary">Save Draft</button>
<button id="applyConfig" class="secondary">Save + Apply</button>
<span id="builderDirtyState" class="muted">Builder is in sync</span>
</div>
<div style="margin-top: 12px;">
<strong>Plan Summary</strong>
<div id="configPlanSummary" class="muted" style="margin-top: 6px;">No plan yet</div>
</div>
<div class="plan-grid" style="margin-top: 12px;">
<article class="plan-card">
<div class="status-label">Action Class</div>
<div id="configPlanAction" class="pill info">unknown</div>
<p id="configPlanImpact" class="muted">Validate a config change to preview its operational impact.</p>
</article>
<article class="plan-card">
<div class="status-label">Targets</div>
<div id="configPlanTargets" class="muted">No targets yet.</div>
</article>
<article class="plan-card">
<div class="status-label">Changed Fields</div>
<div id="configPlanChangeCount" class="stat">0</div>
<p class="muted">Number of config fields that will change if this plan is saved or applied.</p>
</article>
</div>
<table style="margin-top: 12px;">
<thead>
<tr>
<th>Field</th>
<th>Before</th>
<th>After</th>
<th>Effect</th>
</tr>
</thead>
<tbody id="configChangeRows"></tbody>
</table>
<div style="margin-top: 16px;">
<strong>Schema Notes</strong>
<div id="configSchemaNotes" class="muted" style="margin-top: 6px;">No schema loaded yet</div>
</div>
<table style="margin-top: 12px;">
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Default</th>
<th>Effect</th>
</tr>
</thead>
<tbody id="configSchemaRows"></tbody>
</table>
<pre id="configValidationResult" class="json-block"></pre>
</div>
</section>
<section class="panel links" style="margin-top: 18px;">
<h2>Recent Process Events</h2>
<table>
<thead>
<tr>
<th>Process</th>
<th>Event</th>
<th>Age</th>
<th>Detail</th>
</tr>
</thead>
<tbody id="processEventRows"></tbody>
</table>
</section>
<section class="panel links" style="margin-top: 18px;">
<h2>JSON Endpoints</h2>
<p><a href="/api/node">/api/node</a>, <a href="/api/config">/api/config</a>, <a href="/api/config/schema">/api/config/schema</a>, <a href="/api/processes">/api/processes</a>, <a href="/api/process_events">/api/process_events</a>, <code>POST /api/config</code>, <code>POST /api/config/apply</code>, and <code>POST /api/config/validate</code></p>
</section>
</main>
<script src="/assets/app.js"></script>
</body>
</html>