Files
hermes-agent-home/hermes-agent-web/templates/docker_terminal.html
T
carlandCursor 5341a7617b Initial commit: Hermes Agent 多实例管理与 Web 控制台
基于官方 nousresearch/hermes-agent 镜像的 CLI、Docker Compose 与 Web 管理界面,支持多实例部署;敏感配置与实例数据由 .gitignore 排除。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 13:56:04 +08:00

78 lines
3.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}实例 {{ iid }} · Docker 终端 · Hermes Agent Web{% endblock %}
{% block body %}
<p><a href="{{ url_for('index') }}">← 返回实例列表</a></p>
<h2 style="margin-top:0;">实例 <code>{{ iid }}</code> · Docker 终端</h2>
<p class="muted">打开本页后会连接到该实例<strong>运行中的</strong> Hermes <code>gateway</code> 容器 shell(/opt/data)。
若容器尚未启动,请先返回列表页点「启动」;退出终端可输入 <code>exit</code>。</p>
<div style="margin:1rem 0 1.1rem;padding:0.9rem 1rem;border:1px solid var(--border);border-radius:10px;background:#111723;">
<div style="font-size:0.95rem;font-weight:600;margin-bottom:0.65rem;">常用指令</div>
<div style="display:grid;gap:0.65rem;">
<div>
<div class="muted" style="margin-bottom:0.25rem;">切换到 Codex Provider 登录</div>
<code style="display:block;padding:0.65rem 0.8rem;white-space:pre-wrap;">hermes config</code>
</div>
</div>
</div>
<div id="term-wrap" style="height:min(75vh,620px);border:1px solid var(--border);border-radius:8px;padding:2px;background:#0c1017;"></div>
<p class="muted" style="margin-top:0.75rem;">关闭本页请先退出容器 shell。需联网加载 xterm(CDN)。</p>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.min.css" crossorigin="anonymous" />
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0.11.0/lib/addon-fit.min.js" crossorigin="anonymous"></script>
<script>
(function () {
var wrap = document.getElementById('term-wrap');
var term = new Terminal({
cursorBlink: true,
fontSize: 14,
fontFamily: 'ui-monospace, SF Mono, Menlo, Consolas, monospace',
theme: { background: '#0c1017', foreground: '#e7edf4' }
});
var FitCtor = (typeof FitAddon !== 'undefined' && FitAddon.FitAddon) ? FitAddon.FitAddon : FitAddon;
var fit = new FitCtor();
term.loadAddon(fit);
term.open(wrap);
fit.fit();
term.writeln('\x1b[90m正在连接 Docker 终端…\x1b[0m');
var proto = (location.protocol === 'https:') ? 'wss:' : 'ws:';
var tok = {{ ws_token | tojson }};
var ws = new WebSocket(proto + '//' + location.host + '/ws/instance/{{ iid }}/docker-pty?token=' + encodeURIComponent(tok));
ws.onopen = function () {
term.reset();
fit.fit();
sendResize();
};
ws.onmessage = function (ev) {
var d = ev.data;
if (typeof d === 'string') term.write(d);
else term.write(new Uint8Array(d));
};
ws.onerror = function () {
term.write('\r\n\x1b[31m[WebSocket 错误]\x1b[0m\r\n');
};
ws.onclose = function (ev) {
term.write('\r\n\x1b[33m[连接已关闭' + (ev && ev.code ? ' code=' + ev.code : '') + ']\x1b[0m\r\n');
};
term.onData(function (data) {
if (ws.readyState === WebSocket.OPEN) ws.send(data);
});
function sendResize() {
if (ws.readyState !== WebSocket.OPEN) return;
try {
fit.fit();
ws.send(JSON.stringify({ t: 'resize', cols: term.cols, rows: term.rows }));
} catch (e) {}
}
window.addEventListener('resize', function () {
fit.fit();
sendResize();
});
new ResizeObserver(sendResize).observe(wrap);
setTimeout(sendResize, 100);
})();
</script>
{% endblock %}