diff --git a/README.md b/README.md index f0ed67e..c9bbb22 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ **One Command to Evolve All Your AI Agents**: OpenClaw, nanobot, Claude Code, Codex, Cursor and etc. +openspace --query your task + --- diff --git a/README_CN.md b/README_CN.md index a47342e..046e9ad 100644 --- a/README_CN.md +++ b/README_CN.md @@ -15,6 +15,10 @@ [![Feishu](https://img.shields.io/badge/Feishu-Group-E9DBFC?style=flat&logo=larksuite&logoColor=white)](./COMMUNICATION.md) [![WeChat](https://img.shields.io/badge/WeChat-Group-C5EAB4?style=flat&logo=wechat&logoColor=white)](./COMMUNICATION.md) +**一条命令,进化你所有的 AI Agent**:OpenClaw、nanobot、Claude Code、Codex、Cursor 等 + +openspace --query your task + --- diff --git a/assets/cli-typing.gif b/assets/cli-typing.gif new file mode 100644 index 0000000..ec67739 Binary files /dev/null and b/assets/cli-typing.gif differ diff --git a/openspace/mcp_server.py b/openspace/mcp_server.py index bca7a34..d6fa0d7 100644 --- a/openspace/mcp_server.py +++ b/openspace/mcp_server.py @@ -259,16 +259,13 @@ def _read_upload_meta(skill_dir: Path) -> Dict[str, Any]: async def _auto_register_skill_dirs(skill_dirs: List[str]) -> int: """Register bot skill directories into OpenSpace's SkillRegistry + DB. - Called automatically by ``execute_task`` when ``skill_dirs`` is provided. - Already-registered directories are skipped (idempotent within a session). + Called automatically by ``execute_task`` on every invocation. Directories + are re-scanned each time so that skills created by the host bot since the last call are discovered immediately. """ global _registered_skill_dirs - new_dirs = [ - Path(d) for d in skill_dirs - if d not in _registered_skill_dirs and Path(d).is_dir() - ] - if not new_dirs: + valid_dirs = [Path(d) for d in skill_dirs if Path(d).is_dir()] + if not valid_dirs: return 0 openspace = await _get_openspace() @@ -277,19 +274,21 @@ async def _auto_register_skill_dirs(skill_dirs: List[str]) -> int: logger.warning("_auto_register_skill_dirs: SkillRegistry not initialized") return 0 - added = registry.discover_from_dirs(new_dirs) + added = registry.discover_from_dirs(valid_dirs) db_created = 0 if added: store = _get_store() db_created = await store.sync_from_registry(added) + is_first = any(d not in _registered_skill_dirs for d in skill_dirs) for d in skill_dirs: _registered_skill_dirs.add(d) if added: + action = "Auto-registered" if is_first else "Re-scanned & found" logger.info( - f"Auto-registered {len(added)} skill(s) from {len(new_dirs)} dir(s), " + f"{action} {len(added)} skill(s) from {len(valid_dirs)} dir(s), " f"{db_created} new DB record(s)" ) return len(added) @@ -495,8 +494,9 @@ async def execute_task( workspace_dir: Working directory. Defaults to OPENSPACE_WORKSPACE env. max_iterations: Max agent iterations (default: 20). skill_dirs: Bot's skill directories to auto-register so OpenSpace - can select and track them. Already-registered dirs are - silently skipped. + can select and track them. Directories are re-scanned + on every call to discover skills created since the last + invocation. search_scope: Skill search scope before execution. "all" (default) — local + cloud; falls back to local if no API key is configured. @@ -505,7 +505,15 @@ async def execute_task( try: openspace = await _get_openspace() - # Auto-register bot skill directories + # Re-scan host skill directories (from env) to pick up skills + # created by the host bot since the last call. + host_skill_dirs_raw = os.environ.get("OPENSPACE_HOST_SKILL_DIRS", "") + if host_skill_dirs_raw: + env_dirs = [d.strip() for d in host_skill_dirs_raw.split(",") if d.strip()] + if env_dirs: + await _auto_register_skill_dirs(env_dirs) + + # Auto-register bot skill directories (from call parameter) if skill_dirs: await _auto_register_skill_dirs(skill_dirs)