mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-11 10:33:18 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
195
runtime/hooks/hook_manifest_core.py
Normal file
195
runtime/hooks/hook_manifest_core.py
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HookInstallSpec:
|
||||
kind: str
|
||||
id: str | None = None
|
||||
label: str | None = None
|
||||
package: str | None = None
|
||||
repository: str | None = None
|
||||
bins: tuple[str, ...] = ()
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
out: dict[str, Any] = {"kind": self.kind}
|
||||
if self.id:
|
||||
out["id"] = self.id
|
||||
if self.label:
|
||||
out["label"] = self.label
|
||||
if self.package:
|
||||
out["package"] = self.package
|
||||
if self.repository:
|
||||
out["repository"] = self.repository
|
||||
if self.bins:
|
||||
out["bins"] = list(self.bins)
|
||||
return out
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HookRequiresSpec:
|
||||
bins: tuple[str, ...] = ()
|
||||
any_bins: tuple[str, ...] = ()
|
||||
env: tuple[str, ...] = ()
|
||||
config: tuple[str, ...] = ()
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
out: dict[str, Any] = {}
|
||||
if self.bins:
|
||||
out["bins"] = list(self.bins)
|
||||
if self.any_bins:
|
||||
out["anyBins"] = list(self.any_bins)
|
||||
if self.env:
|
||||
out["env"] = list(self.env)
|
||||
if self.config:
|
||||
out["config"] = list(self.config)
|
||||
return out
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HookMetadataSpec:
|
||||
events: tuple[str, ...] = ()
|
||||
always: bool | None = None
|
||||
emoji: str | None = None
|
||||
homepage: str | None = None
|
||||
hook_key: str | None = None
|
||||
export: str | None = None
|
||||
os: tuple[str, ...] = ()
|
||||
requires: HookRequiresSpec | None = None
|
||||
install: tuple[HookInstallSpec, ...] = ()
|
||||
hook_mode: str | None = None
|
||||
node_script: bool | None = None
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
out: dict[str, Any] = {"events": list(self.events)}
|
||||
if self.always is not None:
|
||||
out["always"] = bool(self.always)
|
||||
if self.emoji:
|
||||
out["emoji"] = self.emoji
|
||||
if self.homepage:
|
||||
out["homepage"] = self.homepage
|
||||
if self.hook_key:
|
||||
out["hookKey"] = self.hook_key
|
||||
if self.export:
|
||||
out["export"] = self.export
|
||||
if self.os:
|
||||
out["os"] = list(self.os)
|
||||
if self.requires:
|
||||
req = self.requires.as_dict()
|
||||
if req:
|
||||
out["requires"] = req
|
||||
if self.install:
|
||||
out["install"] = [row.as_dict() for row in self.install]
|
||||
if self.hook_mode is not None:
|
||||
out["hookMode"] = str(self.hook_mode)
|
||||
if self.node_script is not None:
|
||||
out["nodeScript"] = bool(self.node_script)
|
||||
return out
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParsedHookManifest:
|
||||
name: str
|
||||
description: str
|
||||
invocation_enabled: bool
|
||||
metadata: HookMetadataSpec = field(default_factory=HookMetadataSpec)
|
||||
|
||||
|
||||
def _read_str(value: Any) -> str | None:
|
||||
if isinstance(value, str):
|
||||
s = value.strip()
|
||||
return s if s else None
|
||||
return None
|
||||
|
||||
|
||||
def _normalize_str_list(value: Any) -> tuple[str, ...]:
|
||||
if not isinstance(value, list):
|
||||
return ()
|
||||
out: list[str] = []
|
||||
for row in value:
|
||||
s = _read_str(row)
|
||||
if s:
|
||||
out.append(s)
|
||||
return tuple(out)
|
||||
|
||||
|
||||
def _parse_install_spec(row: Any) -> HookInstallSpec | None:
|
||||
if not isinstance(row, dict):
|
||||
return None
|
||||
kind = (_read_str(row.get("kind")) or "").lower()
|
||||
if kind not in {"bundled", "npm", "git"}:
|
||||
return None
|
||||
return HookInstallSpec(
|
||||
kind=kind,
|
||||
id=_read_str(row.get("id")),
|
||||
label=_read_str(row.get("label")),
|
||||
package=_read_str(row.get("package")),
|
||||
repository=_read_str(row.get("repository")),
|
||||
bins=_normalize_str_list(row.get("bins")),
|
||||
)
|
||||
|
||||
|
||||
def _resolve_raw_oclaw_metadata(frontmatter: dict[str, Any]) -> dict[str, Any]:
|
||||
meta = frontmatter.get("metadata")
|
||||
if isinstance(meta, str):
|
||||
try:
|
||||
parsed = json.loads(meta)
|
||||
meta = parsed if isinstance(parsed, dict) else None
|
||||
except Exception:
|
||||
meta = None
|
||||
if not isinstance(meta, dict):
|
||||
return {}
|
||||
oc = meta.get("oclaw")
|
||||
return oc if isinstance(oc, dict) else {}
|
||||
|
||||
|
||||
def parse_hook_manifest(*, frontmatter: dict[str, Any], default_name: str) -> ParsedHookManifest:
|
||||
name = _read_str(frontmatter.get("name")) or default_name
|
||||
description = _read_str(frontmatter.get("description")) or ""
|
||||
enabled_raw = frontmatter.get("enabled")
|
||||
invocation_enabled = bool(enabled_raw) if isinstance(enabled_raw, bool) else True
|
||||
|
||||
oc = _resolve_raw_oclaw_metadata(frontmatter)
|
||||
requires_obj = oc.get("requires") if isinstance(oc.get("requires"), dict) else {}
|
||||
requires = HookRequiresSpec(
|
||||
bins=_normalize_str_list(requires_obj.get("bins")),
|
||||
any_bins=_normalize_str_list(requires_obj.get("anyBins")),
|
||||
env=_normalize_str_list(requires_obj.get("env")),
|
||||
config=_normalize_str_list(requires_obj.get("config")),
|
||||
)
|
||||
install_rows: list[HookInstallSpec] = []
|
||||
if isinstance(oc.get("install"), list):
|
||||
for row in oc["install"]:
|
||||
parsed = _parse_install_spec(row)
|
||||
if parsed:
|
||||
install_rows.append(parsed)
|
||||
|
||||
node_script: bool | None
|
||||
if "nodeScript" in oc:
|
||||
node_script = bool(oc.get("nodeScript"))
|
||||
else:
|
||||
node_script = None
|
||||
|
||||
metadata = HookMetadataSpec(
|
||||
events=_normalize_str_list(oc.get("events")),
|
||||
always=bool(oc["always"]) if isinstance(oc.get("always"), bool) else None,
|
||||
emoji=_read_str(oc.get("emoji")),
|
||||
homepage=_read_str(oc.get("homepage")),
|
||||
hook_key=_read_str(oc.get("hookKey")),
|
||||
export=_read_str(oc.get("export")),
|
||||
os=_normalize_str_list(oc.get("os")),
|
||||
requires=requires if requires.as_dict() else None,
|
||||
install=tuple(install_rows),
|
||||
hook_mode=_read_str(oc.get("hookMode")),
|
||||
node_script=node_script,
|
||||
)
|
||||
return ParsedHookManifest(
|
||||
name=name,
|
||||
description=description,
|
||||
invocation_enabled=invocation_enabled,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue