rns-ctl 0.2.4

Reticulum Network Stack control tool
Documentation
<!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>