mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 04:40:45 +08:00
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
113 lines
4.3 KiB
Python
113 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
import subprocess
|
|
from typing import Any
|
|
|
|
from oclaw.platform.config.paths import db_path
|
|
from oclaw.platform.persistence.sqlite_store import SqliteStore
|
|
from oclaw.runtime.tools.base import ToolSpec
|
|
from oclaw.runtime.tools.experts.workspace.workspace_base import resolve_workspace_path, truncate_text
|
|
|
|
|
|
def run_command_tool() -> ToolSpec:
|
|
def _run_command_enabled() -> bool:
|
|
import os
|
|
|
|
try:
|
|
raw_setting = str(SqliteStore(db_path()).get_setting("AIA_ENABLE_RUN_COMMAND") or "").strip().lower()
|
|
if raw_setting in ("0", "false", "no", "off"):
|
|
return False
|
|
if raw_setting in ("1", "true", "yes", "on"):
|
|
return True
|
|
except Exception:
|
|
pass
|
|
|
|
raw_env = str(os.getenv("AIA_ENABLE_RUN_COMMAND") or "").strip().lower()
|
|
if raw_env in ("0", "false", "no", "off"):
|
|
return False
|
|
if raw_env in ("1", "true", "yes", "on"):
|
|
return True
|
|
# Default disabled when unset (explicit opt-in only).
|
|
return False
|
|
|
|
def handler(args: dict[str, Any]) -> dict[str, Any]:
|
|
import os
|
|
|
|
if not _run_command_enabled():
|
|
return {
|
|
"ok": False,
|
|
"error": "disabled",
|
|
"hint": "Enable run_command in Admin -> Plugins -> Tool Policy.",
|
|
}
|
|
command = str(args.get("command") or "").strip()
|
|
cwd = str(args.get("cwd") or "").strip()
|
|
timeout_s = float(args.get("timeout_s") or 30.0)
|
|
max_output_chars = int(args.get("max_output_chars") or 20000)
|
|
if not command:
|
|
return {"ok": False, "error": "command_required"}
|
|
workdir = resolve_workspace_path(cwd or ".")
|
|
try:
|
|
run_kwargs: dict[str, Any] = {
|
|
"cwd": str(workdir),
|
|
"shell": True,
|
|
"capture_output": True,
|
|
"text": True,
|
|
"timeout": max(1.0, min(timeout_s, 600.0)),
|
|
}
|
|
if os.name == "nt":
|
|
startupinfo = subprocess.STARTUPINFO()
|
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
startupinfo.wShowWindow = 0 # SW_HIDE
|
|
run_kwargs["startupinfo"] = startupinfo
|
|
run_kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
|
|
cp = subprocess.run(
|
|
command,
|
|
**run_kwargs,
|
|
)
|
|
out = (cp.stdout or "") + (("\n" + cp.stderr) if cp.stderr else "")
|
|
out = truncate_text(out, limit=max(1000, min(max_output_chars, 200000)))
|
|
return {
|
|
"ok": True,
|
|
"command": command,
|
|
"cwd": str(workdir),
|
|
"exit_code": int(cp.returncode),
|
|
"output": out,
|
|
}
|
|
except subprocess.TimeoutExpired as e:
|
|
partial = ""
|
|
try:
|
|
partial = ((e.stdout or "") + ("\n" + (e.stderr or "") if e.stderr else "")).strip()
|
|
except Exception:
|
|
partial = ""
|
|
return {
|
|
"ok": False,
|
|
"error": "timeout",
|
|
"command": command,
|
|
"cwd": str(workdir),
|
|
"timeout_s": timeout_s,
|
|
"output": truncate_text(partial, limit=max_output_chars),
|
|
}
|
|
except Exception as e:
|
|
return {"ok": False, "error": f"{type(e).__name__}: {e}", "command": command, "cwd": str(workdir)}
|
|
|
|
return ToolSpec(
|
|
name="run_command",
|
|
description="Run a shell command inside the workspace (captured output, timeout).",
|
|
parameters={
|
|
"type": "object",
|
|
"properties": {
|
|
"command": {"type": "string", "description": "Shell command to run."},
|
|
"cwd": {"type": "string", "description": "Working directory relative to workspace.", "default": "."},
|
|
"timeout_s": {"type": "number", "default": 30.0, "description": "Command timeout in seconds."},
|
|
"max_output_chars": {"type": "integer", "default": 20000, "description": "Max characters to return."},
|
|
},
|
|
"required": ["command"],
|
|
"additionalProperties": False,
|
|
},
|
|
handler=handler,
|
|
tags=frozenset({"workspace", "exec"}),
|
|
)
|
|
|
|
|
|
__all__ = ["run_command_tool"]
|
|
|