mirror of
https://github.com/dtzp555-max/ocm.git
synced 2026-07-22 05:25:08 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ae5fdb20c | ||
|
|
c3ed4c9c8f | ||
|
|
0a5f963b14 | ||
|
|
9e3ec7b616 | ||
|
|
55bfdcdbc8 |
@@ -56,10 +56,13 @@ OCM gives you a **local control panel** for the things that become painful first
|
||||
These are the highest-value surfaces for first-time users:
|
||||
|
||||
<p>
|
||||
<img src="docs/redacted-screenshots-refresh/dashboard-2026-03-07.jpg" width="240" />
|
||||
<img src="docs/redacted-screenshots-refresh/agents-2026-03-07.jpg" width="240" />
|
||||
<img src="docs/redacted-screenshots/actions.jpg" width="240" />
|
||||
<img src="docs/redacted-screenshots-refresh/cli-2026-03-07.jpg" width="240" />
|
||||
<img src="docs/redacted-screenshots-refresh/dashboard-2026-03-07.jpg" width="860" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="docs/redacted-screenshots-refresh/agents-2026-03-07.jpg" width="280" />
|
||||
<img src="docs/redacted-screenshots-refresh/cli-2026-03-07.jpg" width="280" />
|
||||
<img src="docs/redacted-screenshots/actions.jpg" width="180" />
|
||||
</p>
|
||||
|
||||
More screenshots: see the [full usage guide](docs/USAGE_GUIDE.en.md) or the gallery below.
|
||||
|
||||
+66
-10
@@ -24,7 +24,7 @@ const SCRIPT_DIR = __dirname;
|
||||
const MANAGER_CONFIG = path.join(SCRIPT_DIR, 'manager-config.json');
|
||||
let PORT = 3333;
|
||||
let HOST = '0.0.0.0';
|
||||
const APP_VERSION = '0.9.0';
|
||||
const APP_VERSION = '0.9.3';
|
||||
// --port 参数
|
||||
const portIdx = process.argv.indexOf('--port');
|
||||
if (portIdx !== -1 && process.argv[portIdx + 1]) PORT = parseInt(process.argv[portIdx + 1]) || 3333;
|
||||
@@ -315,6 +315,28 @@ ${hasMemory ? initialMemory : '> 暂无初始记录。记忆将通过日常对
|
||||
`;
|
||||
}
|
||||
|
||||
function generateCurrentStateMd() {
|
||||
return `# CURRENT_STATE
|
||||
|
||||
_Last updated: TBD Australia/Brisbane_
|
||||
|
||||
## In Flight
|
||||
- none
|
||||
|
||||
## Blocked / Waiting
|
||||
- none
|
||||
|
||||
## Recently Finished
|
||||
- none
|
||||
|
||||
## Next
|
||||
- none
|
||||
|
||||
## Reset Summary
|
||||
- No active summary yet.
|
||||
`;
|
||||
}
|
||||
|
||||
// ── 请求解析 ──────────────────────────────────────────────────
|
||||
function parseBody(req) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -497,6 +519,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
const agentName = name || agentId;
|
||||
await fsp.writeFile(path.join(wsPath, 'SOUL.md'), generateSoulMd(agentName, purpose || '', personality || ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'MEMORY.md'), generateMemoryMd(agentName, ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'memory', 'CURRENT_STATE.md'), generateCurrentStateMd(), 'utf8');
|
||||
// Create agents/<id>/ runtime directory (required by OpenClaw gateway)
|
||||
const agentRuntimeDir = path.join(OPENCLAW_DIR, 'agents', agentId);
|
||||
await fsp.mkdir(agentRuntimeDir, { recursive: true });
|
||||
@@ -506,7 +529,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
ok: true, agentId, workspacePath: wsPath, configBackup: bakPath,
|
||||
notes: [
|
||||
'Agent created with its own bot token',
|
||||
'Workspace directory created with SOUL.md and MEMORY.md',
|
||||
'Workspace directory created with SOUL.md, MEMORY.md, and memory/CURRENT_STATE.md',
|
||||
'Runtime directory created at agents/' + agentId + '/',
|
||||
'Configuration updated and backed up',
|
||||
'Restart gateway to load new bot: openclaw gateway restart'
|
||||
@@ -565,6 +588,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
await fsp.mkdir(path.join(wsPath, 'memory'), { recursive: true });
|
||||
await fsp.writeFile(path.join(wsPath, 'SOUL.md'), generateSoulMd(name || agentId, purpose || '', personality || ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'MEMORY.md'), generateMemoryMd(name || agentId, ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'memory', 'CURRENT_STATE.md'), generateCurrentStateMd(), 'utf8');
|
||||
|
||||
const agentRuntimeDir = path.join(OPENCLAW_DIR, 'agents', agentId);
|
||||
await fsp.mkdir(agentRuntimeDir, { recursive: true });
|
||||
@@ -575,7 +599,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
notes: [
|
||||
'Discord agent created (single Discord bot)',
|
||||
'Channel binding added',
|
||||
'Workspace + runtime directories created',
|
||||
'Workspace + runtime directories created (including memory/CURRENT_STATE.md)',
|
||||
'Configuration updated and backed up',
|
||||
'Restart gateway to apply: openclaw gateway restart'
|
||||
]
|
||||
@@ -634,6 +658,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
const name = displayName || agentId;
|
||||
await fsp.writeFile(path.join(wsPath, 'SOUL.md'), generateSoulMd(name, purpose || '', personality || ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'MEMORY.md'), generateMemoryMd(name, initialMemory || ''), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'memory', 'CURRENT_STATE.md'), generateCurrentStateMd(), 'utf8');
|
||||
|
||||
const agentRuntimeDir = path.join(OPENCLAW_DIR, 'agents', agentId);
|
||||
await fsp.mkdir(agentRuntimeDir, { recursive: true });
|
||||
@@ -643,7 +668,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
res.end(JSON.stringify({ ok: true, agentId, workspacePath: wsPath, configBackup: bakPath,
|
||||
notes: [
|
||||
'Discord sub-agent created (thread-only binding)',
|
||||
'Workspace + runtime directories created',
|
||||
'Workspace + runtime directories created (including memory/CURRENT_STATE.md)',
|
||||
'Configuration updated and backed up',
|
||||
'Restart gateway to apply: openclaw gateway restart'
|
||||
]
|
||||
@@ -707,6 +732,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
const name = displayName || agentId;
|
||||
await fsp.writeFile(path.join(wsPath, 'SOUL.md'), generateSoulMd(name, purpose, personality), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'MEMORY.md'), generateMemoryMd(name, initialMemory), 'utf8');
|
||||
await fsp.writeFile(path.join(wsPath, 'memory', 'CURRENT_STATE.md'), generateCurrentStateMd(), 'utf8');
|
||||
// Create agents/<id>/ runtime directory (required by OpenClaw gateway)
|
||||
const agentRuntimeDir = path.join(OPENCLAW_DIR, 'agents', agentId);
|
||||
await fsp.mkdir(agentRuntimeDir, { recursive: true });
|
||||
@@ -715,7 +741,7 @@ async function handleApi(req, res, urlObj, body) {
|
||||
res.end(JSON.stringify({ ok: true, agentId, workspacePath: wsPath, configBackup: bakPath,
|
||||
notes: [
|
||||
'Sub-agent created and shares parent bot',
|
||||
'Workspace and runtime directories created',
|
||||
'Workspace and runtime directories created (including memory/CURRENT_STATE.md)',
|
||||
'Configuration updated and backed up',
|
||||
'Restart gateway to apply: openclaw gateway restart'
|
||||
],
|
||||
@@ -2030,6 +2056,16 @@ const MAIN_HTML_BODY = String.raw`
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-gauges" id="dashGauges"><div class="empty">Loading...</div></div>
|
||||
<div class="card dash-notice">
|
||||
<h3 data-i18n="dash.firstRunTitle">🚀 First-run checklist</h3>
|
||||
<ul class="dash-note-list">
|
||||
<li data-i18n="dash.firstRun1">Confirm OCM is pointed at the correct OpenClaw directory.</li>
|
||||
<li data-i18n="dash.firstRun2">Check this Dashboard first: make sure Gateway is running and the system looks healthy.</li>
|
||||
<li data-i18n="dash.firstRun3">Open Agents / Routing and confirm the bindings you expect are actually there.</li>
|
||||
<li data-i18n="dash.firstRun4">Use the built-in Terminal to run <code>openclaw doctor</code> once so you catch environment/auth issues early.</li>
|
||||
<li data-i18n="dash.firstRun5">Before bigger edits, make a backup or check rollback so recovery is nearby if something goes wrong.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dash-sections">
|
||||
<div class="card dash-card" id="dashSystem">
|
||||
<h3>🖥️ System Info</h3>
|
||||
@@ -2175,6 +2211,7 @@ const MAIN_HTML_BODY = String.raw`
|
||||
<select id="cliPreset" onchange="onCliPresetSelect()" style="font-size:11px;padding:3px 6px;max-width:180px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text)">
|
||||
<option value="" data-i18n="cli.presets">── 常用命令 ──</option>
|
||||
</select>
|
||||
<button class="btn-secondary" style="font-size:11px;padding:3px 10px" onclick="copyCliCommand()" data-i18n="cli.copy">复制命令</button>
|
||||
<button class="btn-secondary" style="font-size:11px;padding:3px 10px" onclick="clearCliOutput()" data-i18n="cli.clear">清空</button>
|
||||
<button class="btn-secondary" style="font-size:11px;padding:3px 10px" onclick="toggleCliPanel()" data-i18n="cli.collapse">▼ 收起</button>
|
||||
</div>
|
||||
@@ -2439,6 +2476,12 @@ const I18N = {
|
||||
'models.onlyCliHint':'模型下拉仅显示 openclaw models list 返回的模型。',
|
||||
'models.modelListErr':'读取 openclaw models list 失败:',
|
||||
'models.modelListEmpty':'未从 openclaw models list 解析到模型。请先运行 openclaw onboard 并确认模型可用。',
|
||||
'dash.firstRunTitle':'🚀 首次使用检查清单',
|
||||
'dash.firstRun1':'先确认 OCM 指向的是正确的 OpenClaw 数据目录。',
|
||||
'dash.firstRun2':'先看 Dashboard:确认 Gateway 正在运行,系统状态看起来正常。',
|
||||
'dash.firstRun3':'打开 Agents / Routing,确认你期望的绑定确实已经存在。',
|
||||
'dash.firstRun4':'用内置终端先运行一次 <code>openclaw doctor</code>,尽早发现环境或认证问题。',
|
||||
'dash.firstRun5':'在做较大改动前,先做一次备份或确认回滚入口,出问题时更容易恢复。',
|
||||
'dash.noticeTitle':'📌 Telegram 使用说明(重要)',
|
||||
'dash.notice1':'OCM 主要面向 Telegram:通过群组绑定 Agent,让每个 Agent 拥有独立 Workspace / SOUL.md / MEMORY.md。',
|
||||
'dash.notice2':'请确保你已有基本 OpenClaw 操作经验。OCM 主要负责可视化更新 openclaw.json,方便增删主 Agent 与 Sub-Agent,并支持多条 Agent 树。',
|
||||
@@ -2534,7 +2577,7 @@ const I18N = {
|
||||
'ch.peerId':'Peer ID','ch.peerIdHint':'(群组 ID 或用户 ID)','ch.peerIdTip':'留空则匹配所有对应类型的 Peer',
|
||||
'ch.submit':'添加绑定',
|
||||
'l.sub':'选择运行模式',
|
||||
'cli.open':'⌨️ 终端','cli.title':'⌨️ CLI 终端','cli.clear':'清空','cli.collapse':'▼ 收起',
|
||||
'cli.open':'⌨️ 终端','cli.title':'⌨️ CLI 终端','cli.copy':'复制命令','cli.clear':'清空','cli.collapse':'▼ 收起',
|
||||
'cli.ready':'── 终端就绪,等待命令 ──','cli.cleared':'── 已清空 ──',
|
||||
'cli.presets':'── 常用命令 ──','cli.builtins':'内置命令','cli.favs':'我的收藏',
|
||||
'cli.run':'▶ 执行','cli.stop':'■ 停止','cli.star':'⭐','cli.manage':'管理',
|
||||
@@ -2573,6 +2616,12 @@ const I18N = {
|
||||
'models.onlyCliHint':'Model dropdowns only show IDs returned by openclaw models list.',
|
||||
'models.modelListErr':'Failed to load openclaw models list: ',
|
||||
'models.modelListEmpty':'No model IDs were parsed from openclaw models list. Run openclaw onboard first.',
|
||||
'dash.firstRunTitle':'🚀 First-run checklist',
|
||||
'dash.firstRun1':'Confirm OCM is pointed at the correct OpenClaw directory.',
|
||||
'dash.firstRun2':'Check Dashboard first: make sure Gateway is running and the system looks healthy.',
|
||||
'dash.firstRun3':'Open Agents / Routing and confirm the bindings you expect are actually there.',
|
||||
'dash.firstRun4':'Use the built-in Terminal to run <code>openclaw doctor</code> once so you catch environment or auth issues early.',
|
||||
'dash.firstRun5':'Before bigger edits, make a backup or check rollback so recovery is nearby if something goes wrong.',
|
||||
'dash.noticeTitle':'📌 Telegram Usage Notes (Important)',
|
||||
'dash.notice1':'OCM is primarily for Telegram workflows: bind agents to groups so each agent has isolated Workspace / SOUL.md / MEMORY.md.',
|
||||
'dash.notice2':'Basic OpenClaw CLI experience is required. OCM focuses on visual openclaw.json updates for easier main-agent/sub-agent management and multiple agent trees.',
|
||||
@@ -2669,7 +2718,7 @@ const I18N = {
|
||||
'ch.peerId':'Peer ID','ch.peerIdHint':'(Group ID or User ID)','ch.peerIdTip':'Leave blank to match all peers of this type',
|
||||
'ch.submit':'Add Binding',
|
||||
'l.sub':'Select Mode',
|
||||
'cli.open':'⌨️ Terminal','cli.title':'⌨️ CLI Terminal','cli.clear':'Clear','cli.collapse':'▼ Collapse',
|
||||
'cli.open':'⌨️ Terminal','cli.title':'⌨️ CLI Terminal','cli.copy':'Copy cmd','cli.clear':'Clear','cli.collapse':'▼ Collapse',
|
||||
'cli.ready':'── Terminal Ready ──','cli.cleared':'── Cleared ──',
|
||||
'cli.presets':'── Presets ──','cli.builtins':'Built-in','cli.favs':'My Favorites',
|
||||
'cli.run':'▶ Run','cli.stop':'■ Stop','cli.star':'⭐','cli.manage':'Manage',
|
||||
@@ -3668,7 +3717,14 @@ async function deleteAuth(key){
|
||||
}
|
||||
|
||||
function copyText(txt){
|
||||
navigator.clipboard.writeText(txt).then(()=>toast('已复制','success')).catch(()=>toast('复制失败','error'));
|
||||
navigator.clipboard.writeText(txt).then(()=>toast(lang==='en'?'Copied':'已复制','success')).catch(()=>toast(lang==='en'?'Copy failed':'复制失败','error'));
|
||||
}
|
||||
|
||||
function copyCliCommand(){
|
||||
const inp=document.getElementById('cliInput');
|
||||
const cmd=(inp&&inp.value?inp.value:'').trim();
|
||||
if(!cmd){ toast(lang==='en'?'Nothing to copy (CLI input is empty)':'没有可复制的命令(输入框为空)','error'); return; }
|
||||
copyText(cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -3908,8 +3964,8 @@ function runCli(){
|
||||
es.addEventListener('done',e=>{
|
||||
try{
|
||||
const d=JSON.parse(e.data);
|
||||
if(d.code===0) cliAppend('\\n✅ 完成 (exit 0)\\n','cli-done-ok');
|
||||
else cliAppend('\\n❌ 退出码 '+d.code+'\\n','cli-done-err');
|
||||
if(d.code===0) cliAppend('\\n✅ Done (exit 0)\\n','cli-done-ok');
|
||||
else cliAppend('\\n❌ Exit code '+d.code+'\\n','cli-done-err');
|
||||
}catch(_){}
|
||||
es.close(); cliEvt=null; setCliRunning(false);
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openclaw-manager",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.3",
|
||||
"description": "A local web UI for managing OpenClaw AI agents \u2014 no npm install required",
|
||||
"main": "openclaw-manager.js",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user