Ctrl K
ComunidadGuías…

src/ui/index.html

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      name="description"
      content="Connect self-hosted n8n using an authorized ChatGPT plan account and a private Docker sidecar."
    />
    <title>Relmio | n8n Setup</title>
    <link rel="icon" href="/relmio-icon-rounded.svg" type="image/svg+xml" />
    <link rel="stylesheet" href="/relmio-ui.css" />
    <link rel="stylesheet" href="/styles.css" />
    <link rel="stylesheet" href="/siwc.css" />
    <link rel="stylesheet" href="/guide.css" />
    <script src="/session-bootstrap.js"></script>
    <script src="/theme.js" type="module"></script>
    <script src="/app.js" type="module"></script>
    <script src="/guide.js" type="module"></script>
  </head>
  <body class="rm-app rm-app--fit setup-wizard" data-current-step="1" data-guide-page="vps">
    <a class="rm-skip-link" href="#main-content">Skip to setup</a>

    <header class="rm-topbar">
      <div class="rm-topbar__inner">
        <a class="rm-brand" href="/" data-wizard-route="/" aria-label="Relmio home">
          <img class="rm-brand__logo" src="/relmio-icon-96.png" width="32" height="32" alt="" />
          <span>Relmio</span>
        </a>
        <nav class="rm-nav" aria-label="Primary">
          <ul class="rm-nav__list">
            <li><a class="rm-nav__link" href="/" data-wizard-route="/" aria-current="page">Setup</a></li>
            <li><a class="rm-nav__link" href="/local" data-wizard-route="/local">This computer</a></li>
            <li><a class="rm-nav__link" href="/hosting" data-wizard-route="/hosting">Hosting options</a></li>
            <li><a class="rm-nav__link" href="https://relmio.jpfusin.tech/docs" target="_blank" rel="noopener noreferrer">Docs<span class="rm-icon rm-icon--external rm-icon--xs" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a></li>
          </ul>
        </nav>
        <div class="rm-topbar__actions">
          <span class="rm-status rm-topbar__wide" data-tone="success"><span class="rm-status__dot"></span>Runs on this computer</span>
          <button id="guide-toggle" class="rm-icon-button" type="button" aria-pressed="false" aria-label="Setup guide" title="Setup guide" hidden><span class="rm-icon rm-icon--help" aria-hidden="true"></span></button>
          <fieldset class="rm-segmented">
            <legend class="rm-visually-hidden">Color theme</legend>
            <label class="rm-segmented__item" title="System"><input class="rm-segmented__input" type="radio" name="color-theme" value="system" checked /><span class="rm-icon rm-icon--monitor rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden">System</span></label>
            <label class="rm-segmented__item" title="Light"><input class="rm-segmented__input" type="radio" name="color-theme" value="light" /><span class="rm-icon rm-icon--sun rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden">Light</span></label>
            <label class="rm-segmented__item" title="Dark"><input class="rm-segmented__input" type="radio" name="color-theme" value="dark" /><span class="rm-icon rm-icon--moon rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden">Dark</span></label>
          </fieldset>
          <a class="rm-chip rm-topbar__wide" data-rm-repo-link href="https://github.com/Demonbane18/relmio" target="_blank" rel="noopener noreferrer" aria-label="Open Relmio version __RELMIO_PACKAGE_VERSION__ on GitHub. Opens in a new tab.">
            <span class="rm-icon rm-icon--github rm-icon--sm" aria-hidden="true"></span>GitHub
            <span class="rm-chip__meta"><span class="rm-icon rm-icon--star rm-icon--xs" aria-hidden="true"></span><span data-rm-repo-stars>?</span></span>
            <span class="rm-chip__meta">v__RELMIO_PACKAGE_VERSION__</span>
          </a>
          <a class="rm-icon-button rm-topbar__wide" href="https://ko-fi.com/paldogies" target="_blank" rel="noopener noreferrer" aria-label="Support Relmio on Ko-fi (opens in a new tab)" title="Support Relmio on Ko-fi"><span class="rm-icon rm-icon--coffee" aria-hidden="true"></span></a>
          <details class="rm-menu">
            <summary class="rm-icon-button" aria-label="Menu"><span class="rm-icon rm-icon--menu" aria-hidden="true"></span></summary>
            <div class="rm-menu__panel">
              <nav aria-label="Primary">
                <ul class="rm-menu__list">
                  <li><a class="rm-menu__link" href="/" data-wizard-route="/" aria-current="page">Setup</a></li>
                  <li><a class="rm-menu__link" href="/local" data-wizard-route="/local">This computer</a></li>
                  <li><a class="rm-menu__link" href="/hosting" data-wizard-route="/hosting">Hosting options</a></li>
                  <li><a class="rm-menu__link" href="https://relmio.jpfusin.tech/docs" target="_blank" rel="noopener noreferrer"><span class="rm-icon rm-icon--book rm-icon--sm" aria-hidden="true"></span>Docs<span class="rm-visually-hidden"> (opens in a new tab)</span></a></li>
                </ul>
              </nav>
              <ul class="rm-menu__list rm-menu__section">
                <li><button class="rm-menu__link" type="button" data-guide-toggle aria-pressed="false" hidden><span class="rm-icon rm-icon--help rm-icon--sm" aria-hidden="true"></span>Setup guide</button></li>
                <li><a class="rm-menu__link" href="https://github.com/Demonbane18/relmio" target="_blank" rel="noopener noreferrer"><span class="rm-icon rm-icon--github rm-icon--sm" aria-hidden="true"></span>GitHub<span class="rm-visually-hidden"> (opens in a new tab)</span></a></li>
                <li><a class="rm-menu__link" href="https://ko-fi.com/paldogies" target="_blank" rel="noopener noreferrer"><span class="rm-icon rm-icon--coffee rm-icon--sm" aria-hidden="true"></span>Support on Ko-fi<span class="rm-visually-hidden"> (opens in a new tab)</span></a></li>
              </ul>
            </div>
          </details>
        </div>
      </div>
    </header>

    <main id="main-content" class="rm-app__main" tabindex="-1">
      <div class="rm-split setup-layout">
        <aside class="rm-split__rail setup-rail" aria-label="Setup status">
          <h1 id="page-title" class="rm-visually-hidden">Set up a private n8n connection</h1>

          <nav aria-label="Setup progress">
            <p id="setup-progress-label" class="rm-visually-hidden">Step 1 of 5 · Choose setup</p>
            <ol class="rm-stepper rm-stepper--track">
              <li class="rm-stepper__item" data-step-marker="1" aria-current="step"><button class="rm-stepper__link" type="button" data-step-target="1" disabled><span class="rm-stepper__marker">1</span><span class="rm-stepper__label">Choose setup</span></button></li>
              <li class="rm-stepper__item" data-step-marker="2"><button class="rm-stepper__link" type="button" data-step-target="2" disabled><span class="rm-stepper__marker">2</span><span class="rm-stepper__label">Check server</span></button></li>
              <li class="rm-stepper__item" data-step-marker="3"><button class="rm-stepper__link" type="button" data-step-target="3" disabled><span class="rm-stepper__marker">3</span><span class="rm-stepper__label">Choose n8n</span></button></li>
              <li class="rm-stepper__item" data-step-marker="4"><button class="rm-stepper__link" type="button" data-step-target="4" disabled><span class="rm-stepper__marker">4</span><span class="rm-stepper__label">Review</span></button></li>
              <li class="rm-stepper__item" data-step-marker="5"><button class="rm-stepper__link" type="button" data-step-target="5" disabled><span class="rm-stepper__marker">5</span><span class="rm-stepper__label">Ready</span></button></li>
            </ol>
          </nav>

          <section
            id="operation-progress"
            class="operation-progress"
            role="status"
            aria-live="polite"
            aria-atomic="false"
            tabindex="-1"
            hidden
          >
            <div class="setup-progress__head">
              <p id="operation-progress-label" class="setup-progress__label">No operation is running.</p>
              <p class="setup-progress__elapsed" aria-live="off">
                <span class="rm-visually-hidden">Elapsed</span>
                <time id="operation-progress-elapsed" datetime="PT0S">00:00</time>
              </p>
            </div>
            <div
              id="operation-progress-bar"
              class="rm-progress rm-progress--indeterminate"
              role="progressbar"
              aria-label="Current setup operation"
              aria-valuetext="No operation is running."
            >
              <span class="rm-progress__bar" aria-hidden="true"></span>
            </div>
            <p id="operation-progress-note" class="setup-progress__note">
              Timing varies with your remote server and network. Keep this page open until this step finishes.
            </p>
          </section>
        </aside>

        <div id="setup-steps" class="rm-split__content setup-content" aria-busy="false">
          <div class="rm-panel setup-panel">
            <div id="global-error" class="rm-callout rm-callout--danger setup-error" role="alert" tabindex="-1" hidden>
              <span class="rm-icon rm-icon--alert rm-callout__icon" aria-hidden="true"></span>
              <div class="rm-callout__content">
                <p id="global-error-text"></p>
                <a id="global-error-recovery" class="rm-button rm-button--primary" href="https://chatgpt.com/settings/usage" target="_blank" rel="noopener noreferrer" hidden>Manage usage (opens in a new tab)</a>
              </div>
              <button class="rm-icon-button rm-icon-button--sm rm-callout__close" type="button" data-dismiss-toast="global-error" aria-label="Dismiss error"><span class="rm-icon rm-icon--x rm-icon--sm" aria-hidden="true"></span></button>
            </div>

            <section class="setup-step" data-step="1" aria-labelledby="signin-title">
              <header class="rm-panel__header">
                <div class="rm-panel__heading">
                  <span class="rm-eyebrow">Step 1 of 5</span>
                  <h2 id="signin-title" class="rm-h1" tabindex="-1">Choose your setup</h2>
                  <p class="rm-muted">Choose where you want to connect n8n.</p>
                </div>
              </header>

              <div id="setup-choices" class="setup-view">
                <div class="rm-panel__body">
                  <noscript>
                    <p class="rm-callout rm-callout--warning">This setup needs JavaScript to check server identity and show the plan. Enable JavaScript, then reload before continuing.</p>
                  </noscript>
                  <div class="setup-routes">
                    <div class="setup-route">
                      <button id="openai-vps-route" class="rm-choice" type="button" aria-controls="chatgpt-setup" aria-expanded="false" aria-describedby="openai-vps-route-detail">
                        <span class="rm-choice__icon"><span class="rm-icon rm-icon--message rm-icon--lg" aria-hidden="true"></span></span>
                        <span class="rm-choice__title">n8n with ChatGPT sign-in <span class="rm-badge rm-badge--accent">Experimental</span></span>
                        <span id="openai-vps-route-detail" class="rm-choice__text">For n8n on your own server, using your ChatGPT plan.</span>
                        <span class="rm-choice__meta">You need a VPS that runs n8n in Docker, a root login to it and a ChatGPT plan.</span>
                      </button>
                      <details class="rm-disclosure rm-disclosure--plain">
                        <summary aria-label="More details about n8n with ChatGPT sign-in">More details</summary>
                        <div class="rm-disclosure__body"><p>Sign in on this computer first. Review the plan before any write.</p></div>
                      </details>
                    </div>
                    <div class="setup-route">
                      <a id="vps-supergrok-start" class="rm-choice" aria-describedby="supergrok-vps-route-detail">
                        <span class="rm-choice__icon"><span class="rm-icon rm-icon--bot rm-icon--lg" aria-hidden="true"></span></span>
                        <span class="rm-choice__title">Grok on my server <span class="rm-badge">Official sign-in</span> <span class="rm-badge rm-badge--accent">Experimental</span></span>
                        <span id="supergrok-vps-route-detail" class="rm-choice__text">For n8n on your own server, using your Grok sign-in.</span>
                        <span class="rm-choice__meta">You need a VPS that runs n8n in Docker, a root login to it and a SuperGrok subscription.</span>
                      </a>
                      <details class="rm-disclosure rm-disclosure--plain">
                        <summary aria-label="More details about Grok on my server">More details</summary>
                        <div class="rm-disclosure__body"><p>Grok signs in on your server. ChatGPT sign-in is not used.</p></div>
                      </details>
                    </div>
                    <div class="setup-route">
                      <a id="vps-claude-start" class="rm-choice" aria-describedby="claude-vps-route-detail">
                        <span class="rm-choice__icon"><span class="rm-icon rm-icon--message rm-icon--lg" aria-hidden="true"></span></span>
                        <span class="rm-choice__title">Claude on my server <span class="rm-badge">Official sign-in</span> <span class="rm-badge rm-badge--accent">Experimental</span></span>
                        <span id="claude-vps-route-detail" class="rm-choice__text">For text workflows in n8n, using your own Claude plan.</span>
                        <span class="rm-choice__meta">You need a VPS that runs n8n in Docker, a root login to it and a Claude Pro or Max plan.</span>
                      </a>
                      <details class="rm-disclosure rm-disclosure--plain">
                        <summary aria-label="More details about Claude on my server">More details</summary>
                        <div class="rm-disclosure__body"><p>Experimental. Not affiliated with or endorsed by Anthropic. Uses the official Claude Code that you sign in to yourself; Relmio never sees your Claude login. Personal use only; Anthropic's terms apply and this may stop working.</p><p>Sign in in your own terminal. Use Basic LLM Chain + OpenAI Chat Model, Use Responses API off, Max Retries 0, Timeout at least 135000 ms and Batch Size 1. Text only, one request at a time; not AI Agent tools or the n8n AI Assistant. Renew approval in the wizard within 7 days.</p></div>
                      </details>
                    </div>
                    <div class="setup-route">
                      <a id="vps-local-model-start" class="rm-choice" aria-describedby="local-model-vps-route-detail">
                        <span class="rm-choice__icon"><span class="rm-icon rm-icon--box rm-icon--lg" aria-hidden="true"></span></span>
                        <span class="rm-choice__title">Self-hosted model on my server <span class="rm-badge">No sign-in</span></span>
                        <span id="local-model-vps-route-detail" class="rm-choice__text">For a private model with no account. It runs on the server's processor, so answers can be slow.</span>
                        <span class="rm-choice__meta">You need a VPS that runs n8n in Docker, an admin login to it and enough memory and disk.</span>
                      </a>
                    </div>
                    <div class="setup-route">
                      <a id="local-endpoint-link" class="rm-choice" aria-describedby="local-route-detail">
                        <span class="rm-choice__icon"><span class="rm-icon rm-icon--laptop rm-icon--lg" aria-hidden="true"></span></span>
                        <span class="rm-choice__title">Set up on this computer <span class="rm-badge">No VPS needed</span></span>
                        <span id="local-route-detail" class="rm-choice__text">For apps and n8n on this computer. You can also start a new n8n here.</span>
                        <span class="rm-choice__meta">You need Docker on this computer.</span>
                      </a>
                    </div>
                  </div>
                  <p class="setup-hosting rm-small rm-muted">
                    <span id="hosting-route-detail">Need another hosting option?</span>
                    <a id="hosting-options-link" class="rm-link rm-link--standalone" aria-describedby="hosting-route-detail">Compare hosting routes</a>
                  </p>
                </div>
              </div>

              <div id="chatgpt-setup" class="setup-view" hidden>
                <div class="rm-panel__body setup-signin">
                  <div class="setup-signin__column">
                    <div class="setup-subhead">
                      <p class="rm-muted">Relmio opens ChatGPT sign-in on this computer and keeps each registration separate. It never imports your personal Codex login or asks for a Platform API key.</p>
                      <p class="setup-warning"><span class="rm-icon rm-icon--alert rm-icon--sm" aria-hidden="true"></span>On a server, this transfers one selected registration to the user-controlled installation. The destination owns future refreshes; local access stops after transfer. Review the exact server and background use before approving.</p>
                    </div>
                    <div class="rm-callout rm-callout--neutral setup-auth" role="status" aria-live="polite">
                      <span id="auth-indicator" class="rm-status__dot setup-auth__dot" aria-hidden="true"></span>
                      <div class="rm-callout__content">
                        <strong id="auth-title" class="rm-callout__title">Checking account…</strong>
                        <p id="auth-detail" class="rm-callout__body">Checking selected ChatGPT registration.</p>
                        <button id="signin-help" class="rm-button rm-button--ghost rm-button--sm" type="button" data-guide-help>Help with Check the server</button>
                        <p id="auth-updated" class="rm-callout__body" hidden><time id="auth-updated-time"></time></p>
                      </div>
                    </div>
                  </div>
                  <div class="setup-signin__column">
                    <section id="vps-siwc" class="rm-card rm-card--muted rm-card--compact siwc-controls" aria-labelledby="vps-siwc-title">
                      <div class="siwc-account">
                        <label class="rm-field" for="vps-siwc-account"><span id="vps-siwc-title" class="rm-field__label">ChatGPT account</span>
                          <select id="vps-siwc-account" class="rm-select" data-siwc="account"></select>
                        </label>
                        <div data-siwc="pending-row" class="siwc-pending" hidden>
                          <label class="rm-field" for="vps-siwc-pending"><span class="rm-field__label">Unfinished sign-in</span>
                            <select id="vps-siwc-pending" class="rm-select" data-siwc="pending"></select>
                          </label>
                          <button type="button" class="rm-button rm-button--sm" data-siwc="finish">Finish sign-in</button>
                        </div>
                        <ul data-siwc="transferred" class="rm-small rm-muted" aria-label="Accounts managed at other installations" hidden></ul>
                      </div>
                      <div data-siwc="state" class="siwc-state" role="status" aria-live="polite" tabindex="-1">
                        <p data-siwc="plan-badge" class="rm-status" data-tone="success" hidden><span class="rm-status__dot" aria-hidden="true"></span>Using ChatGPT plan</p>
                        <p data-siwc="status" class="rm-small"></p>
                        <p data-siwc="owner" class="rm-small rm-muted"></p>
                      </div>
                      <div class="rm-cluster siwc-actions">
                        <button type="button" class="rm-button" data-siwc="welcome-open" hidden>Review plan notice</button>
                        <button type="button" class="rm-button rm-button--primary" data-siwc="new">Continue with ChatGPT</button>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="return" hidden>Sign in again</button>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="grant" hidden>Allow ChatGPT plan use</button>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="resume" hidden>Use ChatGPT plan</button>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="pause" hidden>Pause plan use</button>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="logout" hidden>Sign out of ChatGPT</button>
                        <a data-siwc="usage" class="rm-link rm-link--standalone" target="_blank" rel="noopener noreferrer" hidden>Manage usage<span class="rm-icon rm-icon--external rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a>
                        <button type="button" class="rm-button rm-button--sm" data-siwc="recover">Recover or manage an installation</button>
                      </div>
                      <dialog data-siwc="welcome" class="siwc-dialog" aria-labelledby="vps-siwc-welcome-title">
                        <h3 id="vps-siwc-welcome-title" class="rm-h3">You're using your ChatGPT plan</h3>
                        <p>Eligible text requests in Relmio use this account's ChatGPT plan. You can pause plan use in Relmio at any time. OpenAI applies your account limits. If you allowed apps to use credits in ChatGPT, credits can be used after the plan limit. n8n background workflows need a separate approval before installation.</p>
                        <p><a href="https://chatgpt.com/settings/usage" target="_blank" rel="noopener noreferrer">Manage usage (opens in a new tab)</a></p>
                        <button type="button" class="rm-button rm-button--primary" data-siwc="welcome-accept">Got it</button>
                      </dialog>
                    </section>
                    <details class="rm-disclosure">
                      <summary>Connection and consent details</summary>
                      <div class="rm-disclosure__body">
                        <p>Identity sign-in may succeed without permission to use your ChatGPT plan. Allow that permission in a separate ChatGPT consent step before using models. Email is a label, not a way to merge registrations.</p>
                        <p>Relmio requests the account's public model catalog. A listed model does not guarantee admission or a completed response. This route supports text requests using Responses; it does not support image generation, audio, video, Files uploads, or stored conversations.</p>
                        <p>OpenAI receives model requests. ChatGPT plan limits and credits apply to the selected account. This local setup does not grant hosted website chat access or switch to Platform billing.</p>
                      </div>
                    </details>
                  </div>
                </div>
              </div>
            </section>

            <section class="setup-step" data-step="2" aria-labelledby="vps-title" hidden>
              <header class="rm-panel__header">
                <div class="rm-panel__heading">
                  <span class="rm-eyebrow">Step 2 of 5</span>
                  <h2 id="vps-title" class="rm-h1" tabindex="-1">Check your server</h2>
                  <p class="rm-muted">Check the server identity before you connect to the server.</p>
                </div>
              </header>

              <form id="vps-form" class="setup-view">
                <div class="rm-panel__body">
                  <fieldset class="rm-fieldset">
                    <legend class="rm-visually-hidden">Server identity</legend>
                    <div class="setup-server-row">
                      <label class="rm-field setup-server-row__host">
                        <span class="rm-field__label">Server address</span>
                        <input id="host" name="host" class="rm-input" inputmode="url" autocomplete="off" placeholder="your-vps-ip-or-hostname" aria-describedby="host-hint" required />
                        <span id="host-hint" class="rm-field__hint">Use the full IP address or hostname. Do not add <code>ssh root@</code>. Tested on Hostinger KVM VPS. Other Linux VPS hosts are experimental.</span>
                      </label>
                      <label class="rm-field setup-server-row__port">
                        <span class="rm-field__label">Connection port</span>
                        <input id="port" name="port" class="rm-input" type="number" min="1" max="65535" value="22" aria-describedby="port-hint" required />
                        <span id="port-hint" class="rm-field__hint">Technical name: SSH port.</span>
                      </label>
                      <button id="fingerprint-button" class="rm-button setup-server-row__check" type="button">Check this server</button>
                    </div>
                    <div id="fingerprint-box" class="setup-fingerprint" hidden>
                      <label class="rm-check rm-check--boxed">
                        <input id="fingerprint-confirm" type="checkbox" aria-describedby="fingerprint-hint" />
                        <span>
                          <span class="setup-fingerprint__label">I checked this server identity. This is the server I mean to use.</span>
                          <span class="setup-fingerprint__value"><span class="setup-fingerprint__name">SSH fingerprint</span> <code id="fingerprint-value"></code></span>
                          <span id="fingerprint-hint" class="rm-check__hint">Compare this fingerprint with a trusted record for your server before you approve it.</span>
                        </span>
                      </label>
                    </div>
                  </fieldset>

                  <fieldset class="rm-fieldset">
                    <legend class="rm-visually-hidden">Sign in</legend>
                    <div class="setup-signin-row">
                      <label class="rm-field setup-signin-row__name">
                        <span class="rm-field__label">Sign-in name</span>
                        <input id="username" name="username" class="rm-input" autocomplete="username" value="root" aria-describedby="username-hint" disabled required />
                        <span id="username-hint" class="rm-field__hint">Needs a root account (UID 0).</span>
                      </label>
                      <label class="rm-field setup-signin-row__method">
                        <span class="rm-field__label">SSH authentication</span>
                        <select id="ssh-authentication" class="rm-select" disabled><option value="password">Password</option><option value="agent">Local SSH agent</option></select>
                      </label>
                      <label class="rm-field setup-signin-row__password">
                        <span class="rm-field__label">Server password</span>
                        <input id="password" name="password" class="rm-input" type="password" autocomplete="current-password" aria-describedby="password-hint" disabled required />
                        <span id="password-hint" class="rm-field__hint">Unlocks after the identity check. Clears after you connect.</span>
                      </label>
                      <div class="setup-signin-row__agent">
                        <p id="ssh-agent-status" class="rm-field__hint" role="status">Checking local SSH agent configuration…</p>
                      </div>
                    </div>
                    <div class="setup-signin-notes">
                      <p id="ssh-session" class="setup-session" role="status"></p>
                      <details class="rm-disclosure rm-disclosure--plain rm-disclosure--compact" data-host-report hidden><summary>Server check</summary><div class="rm-disclosure__body"></div></details>
                      <details class="rm-disclosure rm-disclosure--plain">
                        <summary>More details about SSH sign-in</summary>
                        <div class="rm-disclosure__body">
                          <p>Passwordless sudo works only on the local model page.</p>
                          <p>For agent sign-in, load keys into your local agent before you open Relmio. A persistent dashboard keeps its launch environment, so relaunch it after you change the agent. No key files, passphrases, or forwarded agent are sent to the server.</p>
                        </div>
                      </details>
                    </div>
                  </fieldset>
                </div>
              </form>
            </section>

            <section class="setup-step" data-step="3" aria-labelledby="n8n-title" hidden>
              <header class="rm-panel__header">
                <div class="rm-panel__heading">
                  <span class="rm-eyebrow">Step 3 of 5</span>
                  <h2 id="n8n-title" class="rm-h1" tabindex="-1">Choose your n8n</h2>
                  <p class="rm-muted">Choose the n8n to connect. This step only looks.</p>
                </div>
              </header>

              <div class="rm-panel__body">
                <div class="setup-n8n-fields">
                  <div class="rm-field">
                    <label class="rm-field__label" for="container-select">Your n8n</label>
                    <select id="container-select" class="rm-select"></select>
                    <details class="rm-disclosure rm-disclosure--plain setup-n8n-details" data-host-report>
                      <summary>More details about the server check</summary>
                      <div class="rm-disclosure__body"><p>Relmio uses read-only Docker commands here. It does not run commands inside n8n, change its image, or restart its container.</p></div>
                    </details>
                  </div>
                  <label class="rm-field">
                    <span class="rm-field__label">Private connection network</span>
                    <select id="network-select" class="rm-select" aria-describedby="network-hint"></select>
                    <span id="network-hint" class="rm-field__hint">The connection joins this network. Your n8n stays unchanged.</span>
                  </label>
                </div>

                <section
                  id="detected-vps-integration-management"
                  class="setup-manage"
                  aria-labelledby="detected-vps-integration-management-title"
                  hidden
                >
                  <div class="setup-manage__head">
                    <h3 id="detected-vps-integration-management-title" class="rm-h3">Manage detected self-hosted n8n</h3>
                    <p class="rm-small rm-muted">
                      Other companions:
                      <a id="vps-supergrok-manage" class="rm-link">SuperGrok</a>
                      <span aria-hidden="true">·</span>
                      <a id="vps-claude-manage" class="rm-link">Claude</a>
                      <span aria-hidden="true">·</span>
                      <a id="vps-local-model-manage" class="rm-link">Local model</a>
                    </p>
                    <p class="setup-manage__intro rm-small rm-muted">Review a Relmio-managed companion. This does not edit, rebuild, stop, recreate, or restart n8n.</p>
                  </div>
                  <fieldset class="rm-fieldset">
                    <legend class="rm-visually-hidden">Companion to manage</legend>
                    <div class="setup-manage__options">
                      <label class="rm-check rm-check--boxed">
                        <input id="manage-vps-sidecar" name="vps-integration" type="radio" value="sidecar" checked />
                        <span>
                          <strong>ChatGPT plan sidecar</strong>
                          <span class="rm-check__hint">Review a new, separately authorized session and an owned installation.</span>
                        </span>
                      </label>
                      <label class="rm-check rm-check--boxed">
                        <input id="manage-vps-assistant" name="vps-integration" type="radio" value="assistant" />
                        <span>
                          <strong>Assistant companion</strong>
                          <span class="rm-check__hint">Manage the sandbox and optional private search only.</span>
                        </span>
                      </label>
                      <label id="manage-vps-searxng-row" class="rm-check rm-check--boxed" hidden>
                        <input id="manage-vps-searxng" type="checkbox" />
                        <span>
                          <strong>Include SearXNG JSON web search</strong>
                          <span class="rm-check__hint">Off by default. It stays on the private network.</span>
                        </span>
                      </label>
                    </div>
                  </fieldset>
                  <div class="setup-manage__actions">
                    <button id="manage-vps-integration" class="rm-button rm-button--sm" type="button">Manage selected integration</button>
                    <button id="refresh-vps-chatgpt" class="rm-button rm-button--sm rm-button--ghost" type="button">Set up another ChatGPT account</button>
                  </div>
                  <details id="vps-siwc-owner" class="rm-disclosure">
                    <summary>Manage the installed ChatGPT session</summary>
                    <div class="rm-disclosure__body">
                      <p>Read the owner on the verified server. A transferred registration cannot be signed out from this computer.</p>
                      <button id="vps-owner-check" class="rm-button rm-button--sm" type="button">Check installed account</button>
                      <p id="vps-owner-status" class="rm-small" role="status" aria-live="polite">Choose the n8n container and network, then check the installed account.</p>
                      <label id="vps-owner-inspect-row" class="rm-check" hidden>
                        <input id="vps-owner-inspect-confirm" type="checkbox" />
                        <span>I approve a temporary one-off read of this stopped Relmio sidecar to inspect its owner. This writes a temporary Docker resource, not n8n.</span>
                      </label>
                      <button id="vps-owner-inspect" class="rm-button rm-button--sm" type="button" hidden>Inspect stopped owner</button>
                      <div id="vps-owner-actions" hidden>
                        <p id="vps-owner-refresh-next" class="rm-small" hidden></p>
                        <label class="rm-check">
                          <input id="vps-owner-confirm" type="checkbox" />
                          <span>I approve stopping only this owned sidecar to change its ChatGPT session. n8n will not be stopped or restarted.</span>
                        </label>
                        <label id="vps-owner-background-row" class="rm-check" hidden>
                          <input id="vps-owner-background-confirm" type="checkbox" />
                          <span>I again authorize this account's plan for my n8n background workflows on this reviewed server.</span>
                        </label>
                        <div class="rm-cluster">
                          <button id="vps-owner-enable" class="rm-button rm-button--sm" type="button" disabled hidden>Use ChatGPT plan</button>
                          <button id="vps-owner-disable" class="rm-button rm-button--sm" type="button" disabled>Pause plan use</button>
                          <button id="vps-owner-logout" class="rm-button rm-button--sm" type="button" disabled>Sign out and revoke</button>
                        </div>
                      </div>
                      <div id="vps-owner-update" hidden>
                        <p id="vps-owner-update-status" class="rm-small" role="status" aria-live="polite"></p>
                        <button id="vps-owner-update-review" class="rm-button rm-button--sm" type="button">Review sidecar update</button>
                        <div id="vps-owner-update-plan" hidden>
                          <p id="vps-owner-update-summary" class="rm-small"></p>
                          <label class="rm-check">
                            <input id="vps-owner-update-confirm" type="checkbox" />
                            <span id="vps-owner-update-confirm-label">I approve rebuilding and restarting only this owned sidecar.</span>
                          </label>
                          <button id="vps-owner-update-apply" class="rm-button rm-button--sm" type="button" disabled>Update the sidecar</button>
                        </div>
                      </div>
                      <div id="vps-owner-refresh-row" hidden>
                        <p id="vps-owner-refresh-hint" class="rm-small">Sign in again on this computer with the same ChatGPT account and workspace. ChatGPT treats it as a new Relmio connection, and the old connection's usage settings do not carry over. Then sign out the old sign-in here and review the replacement. n8n needs the new Relmio key afterward.</p>
                        <button id="vps-owner-refresh" class="rm-button rm-button--sm" type="button" aria-describedby="vps-owner-refresh-hint">Refresh ChatGPT sign-in</button>
                      </div>
                      <section id="vps-usage" class="usage-panel usage-panel--divided" aria-labelledby="vps-usage-title" hidden>
                        <div class="usage-panel__head">
                          <h4 id="vps-usage-title" class="rm-h3">Plan and usage</h4>
                          <button id="vps-usage-refresh" class="rm-button rm-button--sm" type="button">Refresh usage</button>
                        </div>
                        <p id="vps-usage-status" class="rm-small" role="status" aria-live="polite">Press Refresh usage to read this sidecar's request counts.</p>
                        <div id="vps-usage-view" class="usage-panel__view"></div>
                      </section>
                      <div id="vps-owner-images" hidden>
                        <p id="vps-owner-images-status" class="rm-small" role="status" aria-live="polite"></p>
                        <p class="rm-small rm-muted">Image generation uses a separate Codex sign-in, the way Hermes Agent does it. It isn't the official Sign in with ChatGPT, and OpenAI doesn't document this route for other apps, so it can stop working at any time. OpenAI recommends an API key for automation.</p>
                        <ul class="rm-small rm-muted">
                          <li>Images use your plan's Codex limits 3 to 5 times faster than text, then credits. Free plans can't use it.</li>
                          <li>This server stores a full Codex sign-in for the account. Anyone with root or Docker access on it can read it.</li>
                          <li>Device code sign-in must be on in ChatGPT security settings, or allowed by your workspace admin.</li>
                          <li>Sign in with the same ChatGPT account as this sidecar. In n8n, choose the model gpt-image-2.</li>
                        </ul>
                        <div id="vps-owner-images-off" hidden>
                          <label class="rm-check">
                            <input id="vps-owner-images-confirm" type="checkbox" />
                            <span id="vps-owner-images-confirm-label">I understand. Sign in to Codex for images on this server.</span>
                          </label>
                          <button id="vps-owner-images-start" class="rm-button rm-button--sm" type="button" disabled>Sign in for images</button>
                        </div>
                        <div id="vps-owner-images-pending" hidden>
                          <p class="rm-small">Enter this code on the Codex sign-in page: <code id="vps-owner-images-code"></code></p>
                          <p class="rm-small">Only enter this code at auth.openai.com. Never share it.</p>
                          <div class="rm-cluster">
                            <a id="vps-owner-images-link" class="rm-link rm-link--standalone" target="_blank" rel="noopener noreferrer">Open the Codex sign-in page<span class="rm-icon rm-icon--external rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a>
                            <button id="vps-owner-images-cancel" class="rm-button rm-button--sm rm-button--ghost" type="button">Cancel image sign-in</button>
                          </div>
                          <p id="vps-owner-images-expiry" class="rm-small rm-muted"></p>
                        </div>
                        <div id="vps-owner-images-on" hidden>
                          <label class="rm-check">
                            <input id="vps-owner-images-signout-confirm" type="checkbox" />
                            <span>I approve signing out of images on this server. Relmio deletes the Codex sign-in here and asks OpenAI to revoke it.</span>
                          </label>
                          <button id="vps-owner-images-signout" class="rm-button rm-button--sm" type="button" disabled>Sign out of images</button>
                        </div>
                      </div>
                      <div id="vps-owner-models" hidden>
                        <p id="vps-owner-models-status" class="rm-small" role="status" aria-live="polite"></p>
                        <div id="vps-owner-models-view" hidden>
                          <p class="rm-small rm-muted">Models marked In n8n show up in n8n's OpenAI nodes. Relmio asks OpenAI's catalog as the newest Codex release, checked from npm about every 12 hours.</p>
                          <dl id="vps-owner-models-list" class="rm-dl"></dl>
                          <div id="vps-owner-models-checks-off" hidden>
                            <p class="rm-small rm-muted">When on, the sidecar sends one short test request ('Reply with OK') to models in your catalog: now for up to 12 of them, then for each new model, and again once a day for a model that failed. A test that gets no answer is tried again after an hour. n8n lists a model only after it answers; until any model has answered, n8n shows the full catalog except models that recently failed. Each test uses a small amount of your plan.</p>
                            <label class="rm-check">
                              <input id="vps-owner-models-confirm" type="checkbox" />
                              <span id="vps-owner-models-confirm-label">I approve model checks on this server.</span>
                            </label>
                            <button id="vps-owner-models-on" class="rm-button rm-button--sm" type="button" disabled>Turn on model checks</button>
                          </div>
                          <div id="vps-owner-models-checks-on" hidden>
                            <label class="rm-check">
                              <input id="vps-owner-models-off-confirm" type="checkbox" />
                              <span>I approve turning off model checks. New models then show in n8n without a test request.</span>
                            </label>
                            <button id="vps-owner-models-off" class="rm-button rm-button--sm" type="button" disabled>Turn off model checks</button>
                          </div>
                          <p id="vps-owner-models-assistant" class="rm-small rm-muted">n8n's AI Assistant can't list these models. To try one, choose Self-hosted or OpenAI-compatible endpoint in its settings, use the Base URL <code>http://n8n-openai-oauth:10531/v1</code> with the same Relmio key as your n8n OpenAI credential, and paste a model ID. Only do this if nobody else uses this n8n: their Assistant chats would use your ChatGPT plan. Relmio hasn't tested the Assistant with this sidecar, and OpenAI hasn't said whether this use fits its Sign in with ChatGPT terms.</p>
                        </div>
                      </div>
                      <button id="vps-owner-replace" class="rm-button rm-button--sm" type="button" hidden>Review replacement with a fresh account</button>
                    </div>
                  </details>
                  <div id="vps-siwc-recovery"></div>
                </section>
              </div>
            </section>

            <section class="setup-step" data-step="4" aria-labelledby="review-title" hidden>
              <header class="rm-panel__header">
                <div class="rm-panel__heading">
                  <span class="rm-eyebrow">Step 4 of 5</span>
                  <h2 id="review-title" class="rm-h1" tabindex="-1">Review the plan</h2>
                  <p id="review-intro" class="rm-muted">Nothing is written until you approve this plan.</p>
                </div>
              </header>

              <div class="rm-panel__body">
                <dl class="rm-dl setup-review-facts">
                  <div class="setup-review-facts__server">
                    <dt>Server</dt>
                    <dd id="ssh-review-identity"></dd>
                  </div>
                  <div>
                    <dt>Docker network</dt>
                    <dd id="review-network">Not selected</dd>
                  </div>
                  <div id="review-account-row">
                    <dt>ChatGPT account</dt>
                    <dd id="review-account"></dd>
                  </div>
                  <div id="review-destination-row">
                    <dt>Reviewed n8n / network IDs</dt>
                    <dd id="review-destination"></dd>
                  </div>
                  <div>
                    <dt id="review-endpoint-label">Private hostname</dt>
                    <dd><code id="review-endpoint">n8n-openai-oauth</code></dd>
                  </div>
                </dl>
                <div id="review-warnings" class="rm-callout rm-callout--warning" role="note" aria-label="Plan warnings" hidden>
                  <span class="rm-icon rm-icon--alert rm-icon--sm rm-callout__icon" aria-hidden="true"></span>
                  <ul id="review-warnings-list" class="rm-callout__content setup-warnings"></ul>
                </div>

                <div class="setup-review-lists">
                  <section aria-labelledby="will-title">
                    <h3 id="will-title" class="rm-h3">The wizard will</h3>
                    <ul id="review-will-list" class="setup-list setup-list--will">
                      <li>Create or update only <code>/docker/n8n-openai-oauth</code></li>
                      <li>Transfer one selected registration to its user-controlled runtime</li>
                      <li>Build and start only the private sidecar</li>
                      <li>Keep 31 days of request and token counts here</li>
                    </ul>
                  </section>
                  <section aria-labelledby="wont-title">
                    <h3 id="wont-title" class="rm-h3">The wizard will not</h3>
                    <ul id="review-wont-list" class="setup-list setup-list--wont">
                      <li>Edit or rebuild the n8n image</li>
                      <li>Stop, restart, or recreate n8n</li>
                      <li>Publish port <code>10531</code></li>
                      <li>Create a Traefik route</li>
                    </ul>
                  </section>
                </div>

                <details id="review-build-details" class="rm-disclosure rm-disclosure--plain">
                  <summary id="review-build-summary">Host key, build and request count details</summary>
                  <div class="rm-disclosure__body">
                    <p class="rm-small setup-host-key">SSH host key <code id="ssh-review-fingerprint"></code></p>
                    <ul id="review-build-list" class="setup-list"></ul>
                  </div>
                </details>
                <details id="install-images-row" class="rm-disclosure rm-disclosure--plain" hidden>
                  <summary>Image generation (optional)</summary>
                  <div class="rm-disclosure__body">
                    <p class="rm-small">Uses a separate Codex sign-in, not the sidecar's Sign in with ChatGPT permission. OpenAI does not document this image route for other apps, so it may stop working. OpenAI recommends an API key for automation.</p>
                    <p class="rm-small">Leave this unchecked to install without image sign-in. If selected, Relmio starts Codex sign-in after installation. You still approve it on OpenAI's page.</p>
                    <ul class="rm-small rm-muted">
                      <li>Images use your Codex limits about 3 to 5 times faster on average than similar turns without images, then credits. Free plans cannot use them. <a href="https://chatgpt.com/codex/settings/usage" target="_blank" rel="noopener noreferrer">Codex usage<span class="rm-visually-hidden"> (opens in a new tab)</span></a></li>
                      <li>This server stores a full Codex sign-in, including a refresh token. Root users, Docker users and backups can access it.</li>
                      <li>Anyone who can run workflows in this n8n can use your account for images. Turn this on only if nobody else uses it.</li>
                      <li>Device code sign-in must be enabled in ChatGPT security settings or allowed by your workspace admin.</li>
                      <li>Use the same ChatGPT account as this sidecar. Relmio does not verify that the accounts match.</li>
                      <li>Image requests send your prompt and any reference images to OpenAI.</li>
                    </ul>
                    <label class="rm-check setup-approval">
                      <input id="install-images-consent" type="checkbox" />
                      <span id="install-images-confirm-label">I understand. After installation, start Codex sign-in for images on this server.</span>
                    </label>
                    <p class="rm-small">Relmio keeps the SSH connection open while you complete image sign-in.</p>
                  </div>
                </details>
              </div>
            </section>

            <section class="setup-step" data-step="5" aria-labelledby="done-title" hidden>
              <header class="rm-panel__header">
                <div class="rm-panel__heading">
                  <span class="rm-eyebrow setup-done-eyebrow"><span class="rm-icon rm-icon--check-circle rm-icon--sm" aria-hidden="true"></span>Step 5 of 5</span>
                  <h2 id="done-title" class="rm-h1" tabindex="-1">Connect n8n</h2>
                  <p id="done-detail" class="rm-muted">Copy these values into n8n on the same private network.</p>
                </div>
              </header>

              <div class="rm-panel__body">
                <section id="assistant-result" class="setup-assistant-result" hidden aria-labelledby="assistant-result-title">
                  <div class="setup-results__head">
                    <h3 id="assistant-result-title" class="rm-h3">Assistant companion status</h3>
                  </div>
                  <div class="setup-results">
                    <dl class="rm-dl setup-values">
                      <div>
                        <dt>Code Sandbox URL</dt>
                        <dd class="setup-value">
                          <code id="assistant-result-sandbox-url"></code>
                          <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="assistant-result-sandbox-url" data-copy-label="Code Sandbox URL" aria-label="Copy Code Sandbox URL" title="Copy Code Sandbox URL"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                        </dd>
                      </div>
                      <div id="assistant-result-key-row">
                        <dt>Code Sandbox API key <span class="rm-badge rm-badge--warning">Shown once</span></dt>
                        <dd class="setup-value">
                          <code id="assistant-result-sandbox-key"></code>
                          <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="assistant-result-sandbox-key" data-copy-label="one-time Code Sandbox API key" aria-label="Copy one-time Code Sandbox API key" title="Copy one-time Code Sandbox API key"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                        </dd>
                      </div>
                      <div id="assistant-result-searxng-row" hidden>
                        <dt>SearXNG URL</dt>
                        <dd class="setup-value">
                          <code id="assistant-result-searxng-url"></code>
                          <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="assistant-result-searxng-url" data-copy-label="SearXNG URL" aria-label="Copy SearXNG URL" title="Copy SearXNG URL"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                        </dd>
                      </div>
                    </dl>
                    <div class="setup-settings">
                      <p class="rm-field__label">n8n environment settings</p>
                      <pre class="setup-code"><code id="assistant-result-settings"></code></pre>
                      <p id="assistant-result-key-note" class="rm-small rm-muted" hidden></p>
                    </div>
                  </div>
                  <p class="setup-warning">
                    <span class="rm-icon rm-icon--alert rm-icon--sm" aria-hidden="true"></span>Apply these values yourself. Relmio never edits its Compose file or restarts its container.
                  </p>
                </section>

                <div id="sidecar-ready-content" class="setup-results">
                  <div class="setup-results__main">
                    <p id="result-plan-badge" class="rm-status" data-tone="success">Using ChatGPT plan · <a href="https://chatgpt.com/settings/usage" target="_blank" rel="noopener noreferrer">Manage usage<span class="rm-icon rm-icon--external rm-icon--xs" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a></p>
                    <p id="result-account" class="rm-small"></p>
                    <p id="result-readiness" class="rm-small" role="status" aria-live="polite"></p>
                    <a id="result-readiness-usage" class="rm-button rm-button--primary" href="https://chatgpt.com/settings/usage" target="_blank" rel="noopener noreferrer" hidden>Manage usage (opens in a new tab)</a>
                    <section aria-labelledby="credential-title">
                      <div class="setup-results__head">
                        <h3 id="credential-title" class="rm-h3">1. Add the Relmio client credential</h3>
                        <button
                          id="copy-settings"
                          class="rm-button rm-button--sm copy-value"
                          type="button"
                          data-copy-group="credential"
                          data-copy-label="OpenAI credential settings"
                          aria-label="Copy all OpenAI credential settings"
                          title="Copy all OpenAI credential settings"
                        ><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span>Copy all</button>
                      </div>
                      <dl class="rm-dl setup-values">
                        <div>
                          <dt>Base URL</dt>
                          <dd class="setup-value">
                            <code id="result-url">http://n8n-openai-oauth:10531/v1</code>
                            <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-url" data-copy-label="Base URL" aria-label="Copy Base URL" title="Copy Base URL"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                          </dd>
                        </div>
                        <div>
                          <dt>One-time Relmio client key</dt>
                          <dd class="setup-value">
                            <code id="result-key"></code>
                            <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-key" data-copy-label="Relmio client key" aria-label="Copy Relmio client key" title="Copy Relmio client key"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                          </dd>
                        </div>
                        <div>
                          <dt>Organization ID</dt>
                          <dd>Leave empty</dd>
                        </div>
                        <div>
                          <dt>Custom header</dt>
                          <dd>Off</dd>
                        </div>
                      </dl>
                    </section>

                    <p class="rm-small rm-muted">This key is not an OpenAI OAuth token.</p>
                    <p id="result-usage" class="rm-small rm-muted"><strong>Plan and usage:</strong> Relmio counts the text requests n8n sends through it, but not model checks or images. See them later under Manage the installed ChatGPT session.</p>
                    <section id="result-images" aria-labelledby="result-images-title" hidden>
                      <p class="rm-small"><strong id="result-images-title">Image generation:</strong> <span id="result-images-status" role="status" aria-live="polite"></span></p>
                      <details id="result-images-pending" class="rm-disclosure rm-disclosure--plain" hidden>
                        <summary>Enter the Codex sign-in code</summary>
                        <div class="rm-disclosure__body">
                          <p class="rm-small">Open the Codex sign-in page and enter this code. Only enter it at auth.openai.com. Never share it.</p>
                          <div class="rm-cluster">
                            <code id="result-images-code"></code>
                            <a id="result-images-link" class="rm-link rm-link--standalone" target="_blank" rel="noopener noreferrer">Open the Codex sign-in page<span class="rm-icon rm-icon--external rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a>
                            <button id="result-images-cancel" class="rm-button rm-button--sm rm-button--ghost" type="button">Cancel image sign-in</button>
                          </div>
                          <p class="rm-small rm-muted"><span id="result-images-expiry"></span> <span id="result-images-ssh">SSH is still connected for image sign-in. Keep this Relmio tab open until you finish or cancel.</span></p>
                        </div>
                      </details>
                    </section>
                  </div>

                  <div class="setup-results__side">
                    <aside id="responses-api-notice" class="rm-callout setup-responses" aria-label="Provider-specific n8n setting">
                      <span class="rm-icon rm-icon--info rm-callout__icon" aria-hidden="true"></span>
                      <div class="rm-callout__content">
                        <strong class="rm-callout__title">ChatGPT plan: Use Responses API on</strong>
                        <p class="rm-callout__body">This private sidecar uses the public Responses API. Its Chat Completions route translates supported text messages only. A model list does not guarantee a completed workflow.</p>
                      </div>
                      <button class="rm-icon-button rm-icon-button--sm rm-callout__close" type="button" data-dismiss-toast="responses-api-notice" aria-label="Dismiss Responses API reminder"><span class="rm-icon rm-icon--x rm-icon--sm" aria-hidden="true"></span></button>
                    </aside>

                    <details class="rm-disclosure">
                      <summary>2. OpenAI Chat Model for AI Agent or Basic LLM Chain</summary>
                      <div class="rm-disclosure__body">
                        <dl class="rm-dl setup-values">
                          <div>
                            <dt>Selected model</dt>
                            <dd class="setup-value">
                              <label class="rm-visually-hidden" for="result-model-picker">Choose a model</label>
                              <select id="result-model-picker" class="rm-select"></select>
                              <code id="result-model"></code>
                              <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-model" data-copy-label="model ID" aria-label="Copy model ID" title="Copy model ID"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                            </dd>
                          </div>
                          <div>
                            <dt>Responses API</dt>
                            <dd>On for Chat Model node version 1.3</dd>
                          </div>
                        </dl>
                        <p>Models listed for this registration: <span id="result-models"></span></p>
                        <p>Select a model from this account's catalog. A listed model can still be unavailable for a specific request or serving region.</p>
                      </div>
                    </details>

                    <details class="rm-disclosure">
                      <summary>HTTP Request node</summary>
                      <div class="rm-disclosure__body">
                        <dl class="rm-dl setup-values">
                          <div>
                            <dt>Method</dt>
                            <dd><code>POST</code></dd>
                          </div>
                          <div>
                            <dt>URL</dt>
                            <dd class="setup-value">
                              <code id="result-http-url">http://n8n-openai-oauth:10531/v1/chat/completions</code>
                              <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-http-url" data-copy-label="HTTP endpoint" aria-label="Copy HTTP endpoint" title="Copy HTTP endpoint"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                            </dd>
                          </div>
                          <div>
                            <dt>Authentication</dt>
                            <dd>Generic Credential Type</dd>
                          </div>
                          <div>
                            <dt>Generic Auth Type</dt>
                            <dd>Bearer Auth</dd>
                          </div>
                          <div>
                            <dt>Credential</dt>
                            <dd><code>Relmio sidecar</code></dd>
                          </div>
                          <div>
                            <dt>Bearer token</dt>
                            <dd>Use the one-time Relmio client key shown above.</dd>
                          </div>
                          <div>
                            <dt>Authorization header</dt>
                            <dd class="setup-value">
                              <code id="result-http-auth"></code>
                              <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-http-auth" data-copy-label="Authorization header" aria-label="Copy Authorization header" title="Copy Authorization header"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                            </dd>
                          </div>
                          <div>
                            <dt>Content-Type</dt>
                            <dd><code>application/json</code></dd>
                          </div>
                          <div>
                            <dt>Send body</dt>
                            <dd>On · JSON · Using JSON</dd>
                          </div>
                          <div>
                            <dt>JSON body</dt>
                            <dd class="setup-value setup-value--block">
                              <pre class="setup-code"><code id="result-http-body"></code></pre>
                              <button class="rm-icon-button rm-icon-button--sm copy-value" type="button" data-copy-target="result-http-body" data-copy-label="HTTP JSON body" aria-label="Copy HTTP JSON body" title="Copy HTTP JSON body"><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span></button>
                            </dd>
                          </div>
                        </dl>
                        <p>
                          <button
                            id="copy-http-recipe"
                            class="rm-button rm-button--sm copy-value"
                            type="button"
                            data-copy-group="http"
                            data-copy-label="HTTP request recipe"
                            aria-label="Copy recipe for the HTTP Request node"
                            title="Copy recipe for the HTTP Request node"
                          ><span class="rm-icon rm-icon--copy rm-icon--sm" aria-hidden="true"></span>Copy recipe</button>
                        </p>
                      </div>
                    </details>

                    <details class="rm-disclosure">
                      <summary>n8n examples</summary>
                      <div class="rm-disclosure__body"><p>The README has AI Agent, Basic LLM Chain, JSON, and cURL examples. Start with no built-in tools.</p></div>
                    </details>

                    <p class="rm-small rm-muted">You can close this wizard with Control+C. The connection on your server keeps running.</p>
                  </div>
                </div>
              </div>
            </section>

            <footer class="rm-panel__footer setup-footer">
              <div id="global-message" class="rm-status setup-message" data-tone="accent" role="status" aria-live="polite">
                <span class="rm-status__dot" aria-hidden="true"></span>
                <span id="global-message-text">Choose a setup route to begin.</span>
              </div>

              <div class="setup-actions" data-step-actions="1">
                <button id="change-setup-button" class="rm-button rm-button--ghost" type="button" data-subview="chatgpt"><span class="rm-icon rm-icon--arrow-left rm-icon--sm" aria-hidden="true"></span>Change setup</button>
                <button id="login-button" class="rm-button" type="button" data-subview="chatgpt" hidden>Continue with ChatGPT</button>
                <a id="login-link" class="rm-button" target="_blank" rel="noopener noreferrer" data-subview="chatgpt" hidden>Open fresh ChatGPT sign-in<span class="rm-icon rm-icon--external rm-icon--sm" aria-hidden="true"></span><span class="rm-visually-hidden"> (opens in a new tab)</span></a>
                <button id="stop-login-button" class="rm-button" type="button" data-subview="chatgpt" hidden>Stop ChatGPT sign-in</button>
                <button id="signin-next" class="rm-button rm-button--primary rm-push" type="button" data-subview="chatgpt" aria-describedby="auth-detail" disabled>Check the server</button>
              </div>

              <div class="setup-actions" data-step-actions="2">
                <button class="rm-button rm-button--ghost back-button" data-back="1" type="button"><span class="rm-icon rm-icon--arrow-left rm-icon--sm" aria-hidden="true"></span>Back</button>
                <button id="ssh-disconnect" class="rm-button" type="button" hidden>Disconnect from VPS</button>
                <button id="connect-button" class="rm-button rm-button--primary rm-push" type="submit" form="vps-form" disabled>Connect</button>
              </div>

              <div class="setup-actions" data-step-actions="3">
                <button class="rm-button rm-button--ghost back-button" data-back="2" type="button"><span class="rm-icon rm-icon--arrow-left rm-icon--sm" aria-hidden="true"></span>Back</button>
                <button id="disconnect-vps-button" class="rm-button" type="button">Disconnect from VPS</button>
                <button id="review-button" class="rm-button rm-button--primary rm-push" type="button">Review</button>
              </div>

              <div class="setup-actions" data-step-actions="4">
                <label class="rm-check setup-approval">
                  <input id="install-confirm" type="checkbox" />
                  <span id="install-confirm-copy">I approve the reviewed transfer and service-only write under <code>/docker/n8n-openai-oauth</code>. Existing n8n stays unchanged.</span>
                </label>
                <label id="background-consent-row" class="rm-check setup-approval">
                  <input id="background-consent" type="checkbox" />
                  <span>I authorize this selected account's ChatGPT plan for my n8n background workflows on this destination. I will set the one-time local client key in n8n myself.</span>
                </label>
                <label id="vps-migration-row" class="rm-check setup-approval" hidden>
                  <input id="vps-migration-consent" type="checkbox" />
                  <span>I approve stopping only the attested old Relmio sidecar. Preserve its old credential offline and install a fresh SIWC runtime; I will enter the new local client key in n8n.</span>
                </label>
                <label id="vps-replacement-row" class="rm-check setup-approval" hidden>
                  <input id="vps-replacement-consent" type="checkbox" />
                  <span>I approve replacing the signed-out owned sidecar with this separately authorized account. Keep the old signed-out mapping offline; do not reuse its token or history.</span>
                </label>
                <button class="rm-button rm-button--ghost back-button" data-back="3" type="button"><span class="rm-icon rm-icon--arrow-left rm-icon--sm" aria-hidden="true"></span>Back</button>
                <button id="install-button" class="rm-button rm-button--primary rm-push" type="button" disabled>Install</button>
              </div>

              <div class="setup-actions" data-step-actions="5">
                <a id="setup-another-vps" class="rm-button rm-push">Set up another option</a>
              </div>
            </footer>
          </div>
        </div>

        <div id="global-safety" class="rm-card rm-card--muted rm-card--compact setup-safety" role="note" aria-label="Safety">
          <p class="rm-status" data-tone="success"><span class="rm-status__dot" aria-hidden="true"></span>n8n stays unchanged. No restart, rebuild or public port.</p>
          <p class="rm-status" data-tone="warning"><span class="rm-status__dot" aria-hidden="true"></span>Back up your n8n workflows first. Setup still writes to your server.</p>
          <p class="rm-status" data-tone="accent"><span class="rm-status__dot" aria-hidden="true"></span>Nothing is written until you approve the exact plan.</p>
        </div>

        <div id="ready-quest" class="rm-card rm-card--muted rm-card--compact rm-guide-finish" data-guide-finish hidden>
          <div>
            <h3 class="rm-guide-finish__title">Badges earned</h3>
            <ul class="rm-guide-finish__badges" data-guide-badges></ul>
          </div>
          <details class="rm-disclosure rm-disclosure--plain">
            <summary>Next steps</summary>
            <ol class="rm-disclosure__body rm-guide-finish__next" data-guide-next></ol>
          </details>
        </div>
      </div>
    </main>
  </body>
</html>