contextos-agents 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/AGENTS.md +421 -0
- package/.agents/adapters/aider/export.js +137 -0
- package/.agents/adapters/claude/export.js +55 -0
- package/.agents/adapters/copilot/export.js +107 -0
- package/.agents/adapters/cursor/export.js +210 -0
- package/.agents/adapters/gemini/export.js +115 -0
- package/.agents/adapters/shared.js +119 -0
- package/.agents/adapters/zed/export.js +111 -0
- package/.agents/core/profiles/backend.yaml +47 -0
- package/.agents/core/profiles/enterprise.yaml +46 -0
- package/.agents/core/profiles/frontend.yaml +46 -0
- package/.agents/core/profiles/hackathon.yaml +45 -0
- package/.agents/core/profiles/mvp.yaml +43 -0
- package/.agents/core/profiles/startup.yaml +48 -0
- package/.agents/core/skills/adapters/EXAMPLES.md +19 -0
- package/.agents/core/skills/adapters/SKILL.md +105 -0
- package/.agents/core/skills/adapters/TROUBLESHOOTING.md +7 -0
- package/.agents/core/skills/adapters/VALIDATION.json +12 -0
- package/.agents/core/skills/adapters/skill.yaml +10 -0
- package/.agents/core/skills/architecture-diagrams/SKILL.md +108 -0
- package/.agents/core/skills/architecture-diagrams/VALIDATION.json +12 -0
- package/.agents/core/skills/architecture-diagrams/skill.yaml +8 -0
- package/.agents/core/skills/brutalist-design/SKILL.md +150 -0
- package/.agents/core/skills/brutalist-design/VALIDATION.json +12 -0
- package/.agents/core/skills/brutalist-design/skill.yaml +8 -0
- package/.agents/core/skills/context-manager/EXAMPLES.md +19 -0
- package/.agents/core/skills/context-manager/SKILL.md +126 -0
- package/.agents/core/skills/context-manager/TROUBLESHOOTING.md +7 -0
- package/.agents/core/skills/context-manager/VALIDATION.json +12 -0
- package/.agents/core/skills/context-manager/skill.yaml +10 -0
- package/.agents/core/skills/context-os/EXAMPLES.md +21 -0
- package/.agents/core/skills/context-os/SKILL.md +169 -0
- package/.agents/core/skills/context-os/TROUBLESHOOTING.md +7 -0
- package/.agents/core/skills/context-os/VALIDATION.json +12 -0
- package/.agents/core/skills/context-os/packs.yaml +59 -0
- package/.agents/core/skills/context-os/references/context-rules.md +68 -0
- package/.agents/core/skills/context-os/references/pipeline.md +119 -0
- package/.agents/core/skills/context-os/references/project-graph.md +103 -0
- package/.agents/core/skills/context-os/rules.yaml +135 -0
- package/.agents/core/skills/context-os/skill.yaml +10 -0
- package/.agents/core/skills/database/EXAMPLES.md +74 -0
- package/.agents/core/skills/database/SKILL.md +101 -0
- package/.agents/core/skills/database/TROUBLESHOOTING.md +18 -0
- package/.agents/core/skills/database/VALIDATION.json +11 -0
- package/.agents/core/skills/database/skill.yaml +25 -0
- package/.agents/core/skills/ddd/EXAMPLES.md +42 -0
- package/.agents/core/skills/ddd/SKILL.md +247 -0
- package/.agents/core/skills/ddd/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/ddd/VALIDATION.json +12 -0
- package/.agents/core/skills/ddd/ddd.md +178 -0
- package/.agents/core/skills/ddd/skill.yaml +10 -0
- package/.agents/core/skills/decisions/EXAMPLES.md +35 -0
- package/.agents/core/skills/decisions/SKILL.md +90 -0
- package/.agents/core/skills/decisions/TROUBLESHOOTING.md +13 -0
- package/.agents/core/skills/decisions/VALIDATION.json +12 -0
- package/.agents/core/skills/decisions/skill.yaml +10 -0
- package/.agents/core/skills/docker/EXAMPLES.md +56 -0
- package/.agents/core/skills/docker/SKILL.md +63 -0
- package/.agents/core/skills/docker/TROUBLESHOOTING.md +18 -0
- package/.agents/core/skills/docker/VALIDATION.json +11 -0
- package/.agents/core/skills/docker/skill.yaml +23 -0
- package/.agents/core/skills/engineering-workflow/EXAMPLES.md +57 -0
- package/.agents/core/skills/engineering-workflow/SKILL.md +343 -0
- package/.agents/core/skills/engineering-workflow/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/engineering-workflow/VALIDATION.json +12 -0
- package/.agents/core/skills/engineering-workflow/skill.yaml +13 -0
- package/.agents/core/skills/fastapi/EXAMPLES.md +36 -0
- package/.agents/core/skills/fastapi/SKILL.md +148 -0
- package/.agents/core/skills/fastapi/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/fastapi/VALIDATION.json +12 -0
- package/.agents/core/skills/fastapi/fastapi.md +112 -0
- package/.agents/core/skills/fastapi/skill.yaml +10 -0
- package/.agents/core/skills/gemini-precision/SKILL.md +169 -0
- package/.agents/core/skills/gemini-precision/VALIDATION.json +12 -0
- package/.agents/core/skills/gemini-precision/skill.yaml +9 -0
- package/.agents/core/skills/generators/EXAMPLES.md +19 -0
- package/.agents/core/skills/generators/SKILL.md +112 -0
- package/.agents/core/skills/generators/TROUBLESHOOTING.md +7 -0
- package/.agents/core/skills/generators/VALIDATION.json +12 -0
- package/.agents/core/skills/generators/skill.yaml +10 -0
- package/.agents/core/skills/generators/templates/API.md +77 -0
- package/.agents/core/skills/generators/templates/ARCHITECTURE.md +70 -0
- package/.agents/core/skills/generators/templates/DATABASE.md +42 -0
- package/.agents/core/skills/generators/templates/DECISION.md +46 -0
- package/.agents/core/skills/generators/templates/PRD.md +67 -0
- package/.agents/core/skills/generators/templates/PROJECT_GRAPH.md +56 -0
- package/.agents/core/skills/generators/templates/ROADMAP.md +51 -0
- package/.agents/core/skills/generators/templates/TASKS.md +43 -0
- package/.agents/core/skills/generators/templates/UI.md +73 -0
- package/.agents/core/skills/graphify/EXAMPLES.md +73 -0
- package/.agents/core/skills/graphify/SKILL.md +130 -0
- package/.agents/core/skills/graphify/VALIDATION.json +12 -0
- package/.agents/core/skills/graphify/skill.yaml +13 -0
- package/.agents/core/skills/gstack-roles/EXAMPLES.md +23 -0
- package/.agents/core/skills/gstack-roles/SKILL.md +152 -0
- package/.agents/core/skills/gstack-roles/TROUBLESHOOTING.md +13 -0
- package/.agents/core/skills/gstack-roles/VALIDATION.json +12 -0
- package/.agents/core/skills/gstack-roles/skill.yaml +12 -0
- package/.agents/core/skills/impeccable-design/EXAMPLES.md +26 -0
- package/.agents/core/skills/impeccable-design/SKILL.md +201 -0
- package/.agents/core/skills/impeccable-design/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/impeccable-design/VALIDATION.json +12 -0
- package/.agents/core/skills/impeccable-design/skill.yaml +14 -0
- package/.agents/core/skills/interview-me/SKILL.md +97 -0
- package/.agents/core/skills/interview-me/VALIDATION.json +12 -0
- package/.agents/core/skills/interview-me/skill.yaml +8 -0
- package/.agents/core/skills/microservices/EXAMPLES.md +38 -0
- package/.agents/core/skills/microservices/SKILL.md +164 -0
- package/.agents/core/skills/microservices/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/microservices/VALIDATION.json +12 -0
- package/.agents/core/skills/microservices/microservices.md +119 -0
- package/.agents/core/skills/microservices/skill.yaml +10 -0
- package/.agents/core/skills/minimalist-design/SKILL.md +113 -0
- package/.agents/core/skills/minimalist-design/VALIDATION.json +12 -0
- package/.agents/core/skills/minimalist-design/skill.yaml +8 -0
- package/.agents/core/skills/nestjs/EXAMPLES.md +40 -0
- package/.agents/core/skills/nestjs/SKILL.md +139 -0
- package/.agents/core/skills/nestjs/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/nestjs/VALIDATION.json +12 -0
- package/.agents/core/skills/nestjs/nestjs.md +103 -0
- package/.agents/core/skills/nestjs/skill.yaml +10 -0
- package/.agents/core/skills/nextjs/EXAMPLES.md +40 -0
- package/.agents/core/skills/nextjs/SKILL.md +163 -0
- package/.agents/core/skills/nextjs/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/nextjs/VALIDATION.json +12 -0
- package/.agents/core/skills/nextjs/nextjs.md +67 -0
- package/.agents/core/skills/nextjs/skill.yaml +10 -0
- package/.agents/core/skills/node/EXAMPLES.md +80 -0
- package/.agents/core/skills/node/SKILL.md +128 -0
- package/.agents/core/skills/node/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/node/VALIDATION.json +12 -0
- package/.agents/core/skills/node/node.md +87 -0
- package/.agents/core/skills/node/skill.yaml +10 -0
- package/.agents/core/skills/performance/EXAMPLES.md +30 -0
- package/.agents/core/skills/performance/SKILL.md +75 -0
- package/.agents/core/skills/performance/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/performance/VALIDATION.json +12 -0
- package/.agents/core/skills/performance/performance.md +52 -0
- package/.agents/core/skills/performance/skill.yaml +10 -0
- package/.agents/core/skills/ponytail-mindset/EXAMPLES.md +45 -0
- package/.agents/core/skills/ponytail-mindset/SKILL.md +193 -0
- package/.agents/core/skills/ponytail-mindset/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/ponytail-mindset/VALIDATION.json +12 -0
- package/.agents/core/skills/ponytail-mindset/skill.yaml +14 -0
- package/.agents/core/skills/react/EXAMPLES.md +79 -0
- package/.agents/core/skills/react/SKILL.md +132 -0
- package/.agents/core/skills/react/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/react/VALIDATION.json +12 -0
- package/.agents/core/skills/react/react.md +93 -0
- package/.agents/core/skills/react/skill.yaml +10 -0
- package/.agents/core/skills/react-best-practices/SKILL.md +155 -0
- package/.agents/core/skills/react-best-practices/VALIDATION.json +12 -0
- package/.agents/core/skills/react-best-practices/skill.yaml +10 -0
- package/.agents/core/skills/redesign-audit/SKILL.md +117 -0
- package/.agents/core/skills/redesign-audit/VALIDATION.json +12 -0
- package/.agents/core/skills/redesign-audit/skill.yaml +8 -0
- package/.agents/core/skills/security/EXAMPLES.md +64 -0
- package/.agents/core/skills/security/SKILL.md +158 -0
- package/.agents/core/skills/security/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/security/VALIDATION.json +12 -0
- package/.agents/core/skills/security/security.md +106 -0
- package/.agents/core/skills/security/skill.yaml +10 -0
- package/.agents/core/skills/soft-design/SKILL.md +108 -0
- package/.agents/core/skills/soft-design/VALIDATION.json +12 -0
- package/.agents/core/skills/soft-design/skill.yaml +8 -0
- package/.agents/core/skills/state-management/EXAMPLES.md +56 -0
- package/.agents/core/skills/state-management/SKILL.md +48 -0
- package/.agents/core/skills/state-management/TROUBLESHOOTING.md +18 -0
- package/.agents/core/skills/state-management/VALIDATION.json +11 -0
- package/.agents/core/skills/state-management/skill.yaml +22 -0
- package/.agents/core/skills/subagent-orchestrator/SKILL.md +100 -0
- package/.agents/core/skills/subagent-orchestrator/VALIDATION.json +12 -0
- package/.agents/core/skills/subagent-orchestrator/skill.yaml +8 -0
- package/.agents/core/skills/system-design/EXAMPLES.md +75 -0
- package/.agents/core/skills/system-design/SKILL.md +419 -0
- package/.agents/core/skills/system-design/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/system-design/VALIDATION.json +12 -0
- package/.agents/core/skills/system-design/skill.yaml +13 -0
- package/.agents/core/skills/system-design/system-design.md +112 -0
- package/.agents/core/skills/testing/EXAMPLES.md +71 -0
- package/.agents/core/skills/testing/SKILL.md +70 -0
- package/.agents/core/skills/testing/TROUBLESHOOTING.md +18 -0
- package/.agents/core/skills/testing/VALIDATION.json +11 -0
- package/.agents/core/skills/testing/skill.yaml +26 -0
- package/.agents/core/skills/typescript/EXAMPLES.md +64 -0
- package/.agents/core/skills/typescript/SKILL.md +112 -0
- package/.agents/core/skills/typescript/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/typescript/VALIDATION.json +12 -0
- package/.agents/core/skills/typescript/skill.yaml +10 -0
- package/.agents/core/skills/typescript/typescript.md +71 -0
- package/.agents/core/skills/ui-design/EXAMPLES.md +21 -0
- package/.agents/core/skills/ui-design/SKILL.md +124 -0
- package/.agents/core/skills/ui-design/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/ui-design/VALIDATION.json +12 -0
- package/.agents/core/skills/ui-design/skill.yaml +10 -0
- package/.agents/core/skills/ui-design/ui.md +88 -0
- package/.agents/core/skills/ui-ux-pro/EXAMPLES.md +62 -0
- package/.agents/core/skills/ui-ux-pro/SKILL.md +375 -0
- package/.agents/core/skills/ui-ux-pro/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/ui-ux-pro/VALIDATION.json +12 -0
- package/.agents/core/skills/ui-ux-pro/skill.yaml +13 -0
- package/.agents/core/skills/ux-design/EXAMPLES.md +36 -0
- package/.agents/core/skills/ux-design/SKILL.md +116 -0
- package/.agents/core/skills/ux-design/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/ux-design/VALIDATION.json +12 -0
- package/.agents/core/skills/ux-design/skill.yaml +10 -0
- package/.agents/core/skills/ux-design/ux.md +80 -0
- package/.agents/core/skills/vercel-optimize/SKILL.md +83 -0
- package/.agents/core/skills/vercel-optimize/VALIDATION.json +12 -0
- package/.agents/core/skills/vercel-optimize/skill.yaml +10 -0
- package/.agents/core/skills/web-accessibility/EXAMPLES.md +39 -0
- package/.agents/core/skills/web-accessibility/SKILL.md +170 -0
- package/.agents/core/skills/web-accessibility/TROUBLESHOOTING.md +19 -0
- package/.agents/core/skills/web-accessibility/VALIDATION.json +12 -0
- package/.agents/core/skills/web-accessibility/accessibility.md +63 -0
- package/.agents/core/skills/web-accessibility/skill.yaml +10 -0
- package/.agents/ctx.js +370 -0
- package/.agents/generated/claude/skills/adapters/SKILL.md +126 -0
- package/.agents/generated/claude/skills/architecture-diagrams/SKILL.md +101 -0
- package/.agents/generated/claude/skills/brutalist-design/SKILL.md +145 -0
- package/.agents/generated/claude/skills/context-manager/SKILL.md +147 -0
- package/.agents/generated/claude/skills/context-os/SKILL.md +191 -0
- package/.agents/generated/claude/skills/database/SKILL.md +191 -0
- package/.agents/generated/claude/skills/ddd/SKILL.md +305 -0
- package/.agents/generated/claude/skills/decisions/SKILL.md +134 -0
- package/.agents/generated/claude/skills/docker/SKILL.md +135 -0
- package/.agents/generated/claude/skills/engineering-workflow/SKILL.md +414 -0
- package/.agents/generated/claude/skills/fastapi/SKILL.md +200 -0
- package/.agents/generated/claude/skills/gemini-precision/SKILL.md +161 -0
- package/.agents/generated/claude/skills/generators/SKILL.md +133 -0
- package/.agents/generated/claude/skills/graphify/SKILL.md +198 -0
- package/.agents/generated/claude/skills/gstack-roles/SKILL.md +184 -0
- package/.agents/generated/claude/skills/impeccable-design/SKILL.md +241 -0
- package/.agents/generated/claude/skills/interview-me/SKILL.md +90 -0
- package/.agents/generated/claude/skills/microservices/SKILL.md +218 -0
- package/.agents/generated/claude/skills/minimalist-design/SKILL.md +108 -0
- package/.agents/generated/claude/skills/nestjs/SKILL.md +195 -0
- package/.agents/generated/claude/skills/nextjs/SKILL.md +219 -0
- package/.agents/generated/claude/skills/node/SKILL.md +224 -0
- package/.agents/generated/claude/skills/performance/SKILL.md +121 -0
- package/.agents/generated/claude/skills/ponytail-mindset/SKILL.md +252 -0
- package/.agents/generated/claude/skills/react/SKILL.md +227 -0
- package/.agents/generated/claude/skills/react-best-practices/SKILL.md +146 -0
- package/.agents/generated/claude/skills/redesign-audit/SKILL.md +112 -0
- package/.agents/generated/claude/skills/security/SKILL.md +237 -0
- package/.agents/generated/claude/skills/soft-design/SKILL.md +103 -0
- package/.agents/generated/claude/skills/state-management/SKILL.md +120 -0
- package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +93 -0
- package/.agents/generated/claude/skills/system-design/SKILL.md +507 -0
- package/.agents/generated/claude/skills/testing/SKILL.md +157 -0
- package/.agents/generated/claude/skills/typescript/SKILL.md +192 -0
- package/.agents/generated/claude/skills/ui-design/SKILL.md +161 -0
- package/.agents/generated/claude/skills/ui-ux-pro/SKILL.md +451 -0
- package/.agents/generated/claude/skills/ux-design/SKILL.md +168 -0
- package/.agents/generated/claude/skills/vercel-optimize/SKILL.md +76 -0
- package/.agents/generated/claude/skills/web-accessibility/SKILL.md +225 -0
- package/.agents/generated/gemini/skills/adapters/SKILL.md +135 -0
- package/.agents/generated/gemini/skills/architecture-diagrams/SKILL.md +107 -0
- package/.agents/generated/gemini/skills/brutalist-design/SKILL.md +151 -0
- package/.agents/generated/gemini/skills/context-manager/SKILL.md +156 -0
- package/.agents/generated/gemini/skills/context-os/SKILL.md +200 -0
- package/.agents/generated/gemini/skills/database/SKILL.md +200 -0
- package/.agents/generated/gemini/skills/ddd/SKILL.md +314 -0
- package/.agents/generated/gemini/skills/decisions/SKILL.md +143 -0
- package/.agents/generated/gemini/skills/docker/SKILL.md +144 -0
- package/.agents/generated/gemini/skills/engineering-workflow/SKILL.md +423 -0
- package/.agents/generated/gemini/skills/fastapi/SKILL.md +209 -0
- package/.agents/generated/gemini/skills/gemini-precision/SKILL.md +167 -0
- package/.agents/generated/gemini/skills/generators/SKILL.md +142 -0
- package/.agents/generated/gemini/skills/graphify/SKILL.md +205 -0
- package/.agents/generated/gemini/skills/gstack-roles/SKILL.md +193 -0
- package/.agents/generated/gemini/skills/impeccable-design/SKILL.md +250 -0
- package/.agents/generated/gemini/skills/interview-me/SKILL.md +96 -0
- package/.agents/generated/gemini/skills/microservices/SKILL.md +227 -0
- package/.agents/generated/gemini/skills/minimalist-design/SKILL.md +114 -0
- package/.agents/generated/gemini/skills/nestjs/SKILL.md +204 -0
- package/.agents/generated/gemini/skills/nextjs/SKILL.md +298 -0
- package/.agents/generated/gemini/skills/node/SKILL.md +323 -0
- package/.agents/generated/gemini/skills/performance/SKILL.md +185 -0
- package/.agents/generated/gemini/skills/ponytail-mindset/SKILL.md +261 -0
- package/.agents/generated/gemini/skills/react/SKILL.md +332 -0
- package/.agents/generated/gemini/skills/react-best-practices/SKILL.md +152 -0
- package/.agents/generated/gemini/skills/redesign-audit/SKILL.md +118 -0
- package/.agents/generated/gemini/skills/security/SKILL.md +355 -0
- package/.agents/generated/gemini/skills/soft-design/SKILL.md +109 -0
- package/.agents/generated/gemini/skills/state-management/SKILL.md +129 -0
- package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +99 -0
- package/.agents/generated/gemini/skills/system-design/SKILL.md +631 -0
- package/.agents/generated/gemini/skills/testing/SKILL.md +166 -0
- package/.agents/generated/gemini/skills/typescript/SKILL.md +275 -0
- package/.agents/generated/gemini/skills/ui-design/SKILL.md +170 -0
- package/.agents/generated/gemini/skills/ui-ux-pro/SKILL.md +460 -0
- package/.agents/generated/gemini/skills/ux-design/SKILL.md +177 -0
- package/.agents/generated/gemini/skills/vercel-optimize/SKILL.md +82 -0
- package/.agents/generated/gemini/skills/web-accessibility/SKILL.md +300 -0
- package/.agents/mcp/runtime.py +454 -0
- package/.agents/mcp/server.mjs +189373 -0
- package/.agents/plugins.js +574 -0
- package/.agents/profiles.js +267 -0
- package/.agents/resolver.js +336 -0
- package/.agents/skills-index.json +200 -0
- package/.agents/skills.json +6 -0
- package/.agents/validate.js +500 -0
- package/LICENSE +21 -0
- package/README.md +415 -0
- package/benchmarks/gemini-issues.js +533 -0
- package/bin/index.js +458 -0
- package/package.json +70 -0
- package/registry.json +53 -0
- package/registry.schema.json +32 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Swarm Runtime — Python-side helpers for the swarm-cli orchestrator.
|
|
3
|
+
|
|
4
|
+
Extends the RLM runtime with thread spawning primitives:
|
|
5
|
+
- `thread(task, context, agent, model, files)`: spawn a coding agent thread
|
|
6
|
+
- `async_thread(...)`: async version for asyncio.gather()
|
|
7
|
+
- `merge_threads()`: merge all completed thread branches
|
|
8
|
+
|
|
9
|
+
Communication protocol (line-delimited JSON over stdio):
|
|
10
|
+
-> stdout: {"type":"llm_query","sub_context":"...","instruction":"...","id":"..."}
|
|
11
|
+
<- stdin: {"type":"llm_result","id":"...","result":"..."}
|
|
12
|
+
-> stdout: {"type":"thread_request","id":"...","task":"...","context":"...","agent_backend":"...","model":"...","files":[]}
|
|
13
|
+
<- stdin: {"type":"thread_result","id":"...","result":"...","success":true,"files_changed":[],"duration_ms":0}
|
|
14
|
+
-> stdout: {"type":"merge_request","id":"..."}
|
|
15
|
+
<- stdin: {"type":"merge_result","id":"...","result":"...","success":true}
|
|
16
|
+
-> stdout: {"type":"exec_done","stdout":"...","stderr":"...","has_final":bool,"final_value":"..."|null}
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import sys
|
|
21
|
+
import uuid
|
|
22
|
+
import io
|
|
23
|
+
import traceback
|
|
24
|
+
import asyncio
|
|
25
|
+
import threading
|
|
26
|
+
import queue
|
|
27
|
+
import ast
|
|
28
|
+
|
|
29
|
+
class SecurityError(Exception):
|
|
30
|
+
"""Raised when code execution attempts an unauthorized or dangerous operation."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
_ALLOWED_MODULES = {'json', 'math', 're', 'datetime', 'random', 'collections'}
|
|
34
|
+
# asyncio removed from _ALLOWED_MODULES: it allows socket/network access.
|
|
35
|
+
# asyncio is still available via _runtime_symbols() for async_thread/async_llm_query.
|
|
36
|
+
_FORBIDDEN_ATTRIBUTES = {
|
|
37
|
+
'__class__', '__subclasses__', '__bases__', '__mro__',
|
|
38
|
+
'__globals__', '__code__', '__builtins__', '__import__',
|
|
39
|
+
'__getattr__', '__setattr__', '__delattr__',
|
|
40
|
+
'__reduce__', '__reduce_ex__', # pickle-based escapes
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def _safe_import(name, globals=None, locals=None, fromlist=(), level=0):
|
|
44
|
+
root_pkg = name.split('.')[0]
|
|
45
|
+
if root_pkg not in _ALLOWED_MODULES:
|
|
46
|
+
raise SecurityError(f"Security error: import of module '{name}' is forbidden in sandboxed runtime")
|
|
47
|
+
return __import__(name, globals, locals, fromlist, level)
|
|
48
|
+
|
|
49
|
+
_SAFE_BUILTINS = {
|
|
50
|
+
'abs': abs,
|
|
51
|
+
'all': all,
|
|
52
|
+
'any': any,
|
|
53
|
+
'ascii': ascii,
|
|
54
|
+
'bin': bin,
|
|
55
|
+
'bool': bool,
|
|
56
|
+
'bytearray': bytearray,
|
|
57
|
+
'bytes': bytes,
|
|
58
|
+
'callable': callable,
|
|
59
|
+
'chr': chr,
|
|
60
|
+
'complex': complex,
|
|
61
|
+
'dict': dict,
|
|
62
|
+
'divmod': divmod,
|
|
63
|
+
'enumerate': enumerate,
|
|
64
|
+
'filter': filter,
|
|
65
|
+
'float': float,
|
|
66
|
+
'format': format,
|
|
67
|
+
'frozenset': frozenset,
|
|
68
|
+
'hash': hash,
|
|
69
|
+
'hex': hex,
|
|
70
|
+
'int': int,
|
|
71
|
+
'isinstance': isinstance,
|
|
72
|
+
'issubclass': issubclass,
|
|
73
|
+
'iter': iter,
|
|
74
|
+
'len': len,
|
|
75
|
+
'list': list,
|
|
76
|
+
'map': map,
|
|
77
|
+
'max': max,
|
|
78
|
+
'min': min,
|
|
79
|
+
'next': next,
|
|
80
|
+
'oct': oct,
|
|
81
|
+
'ord': ord,
|
|
82
|
+
'pow': pow,
|
|
83
|
+
'print': print,
|
|
84
|
+
'range': range,
|
|
85
|
+
'repr': repr,
|
|
86
|
+
'reversed': reversed,
|
|
87
|
+
'round': round,
|
|
88
|
+
'set': set,
|
|
89
|
+
'slice': slice,
|
|
90
|
+
'sorted': sorted,
|
|
91
|
+
'str': str,
|
|
92
|
+
'sum': sum,
|
|
93
|
+
'tuple': tuple,
|
|
94
|
+
# type() with 1 arg is safe (type checking), but type('X', bases, dict)
|
|
95
|
+
# creates arbitrary classes that can call __import__ — block it.
|
|
96
|
+
'type': lambda *args: type(*args) if len(args) == 1 else (_ for _ in ()).throw(
|
|
97
|
+
SecurityError("type() with 3 arguments is forbidden in sandboxed runtime")
|
|
98
|
+
),
|
|
99
|
+
'zip': zip,
|
|
100
|
+
'True': True,
|
|
101
|
+
'False': False,
|
|
102
|
+
'None': None,
|
|
103
|
+
'Exception': Exception,
|
|
104
|
+
'ValueError': ValueError,
|
|
105
|
+
'TypeError': TypeError,
|
|
106
|
+
'KeyError': KeyError,
|
|
107
|
+
'IndexError': IndexError,
|
|
108
|
+
'RuntimeError': RuntimeError,
|
|
109
|
+
'SyntaxError': SyntaxError,
|
|
110
|
+
'SecurityError': SecurityError,
|
|
111
|
+
'__import__': _safe_import,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
def _validate_ast(code: str) -> None:
|
|
115
|
+
"""Validate python code AST to reject dangerous imports, attributes, and calls."""
|
|
116
|
+
try:
|
|
117
|
+
tree = ast.parse(code)
|
|
118
|
+
except SyntaxError:
|
|
119
|
+
return
|
|
120
|
+
for node in ast.walk(tree):
|
|
121
|
+
if isinstance(node, ast.Import):
|
|
122
|
+
for alias in node.names:
|
|
123
|
+
root_pkg = alias.name.split('.')[0]
|
|
124
|
+
if root_pkg not in _ALLOWED_MODULES:
|
|
125
|
+
raise SecurityError(f"Security error: import of module '{alias.name}' is forbidden in sandboxed runtime")
|
|
126
|
+
elif isinstance(node, ast.ImportFrom):
|
|
127
|
+
if node.module:
|
|
128
|
+
root_pkg = node.module.split('.')[0]
|
|
129
|
+
if root_pkg not in _ALLOWED_MODULES:
|
|
130
|
+
raise SecurityError(f"Security error: import from module '{node.module}' is forbidden in sandboxed runtime")
|
|
131
|
+
elif isinstance(node, ast.Attribute):
|
|
132
|
+
if node.attr in _FORBIDDEN_ATTRIBUTES:
|
|
133
|
+
raise SecurityError(f"Security error: access to dangerous attribute '{node.attr}' is forbidden")
|
|
134
|
+
elif isinstance(node, ast.Call):
|
|
135
|
+
# Block type('X', bases, dict) class creation at AST level
|
|
136
|
+
if isinstance(node.func, ast.Name) and node.func.id == 'type' and len(node.args) == 3:
|
|
137
|
+
raise SecurityError("Security error: type() with 3 arguments is forbidden in sandboxed runtime")
|
|
138
|
+
|
|
139
|
+
# Real stdio handles — saved before exec() can redirect sys.stdout/sys.stderr.
|
|
140
|
+
_real_stdout = sys.stdout
|
|
141
|
+
_real_stdin = sys.stdin
|
|
142
|
+
|
|
143
|
+
# Lock for stdout writes only
|
|
144
|
+
_write_lock = threading.Lock()
|
|
145
|
+
|
|
146
|
+
# Per-request events and results for concurrent llm_query/thread calls
|
|
147
|
+
_pending_results: dict[str, threading.Event] = {}
|
|
148
|
+
_result_store: dict[str, str] = {}
|
|
149
|
+
|
|
150
|
+
# Queue for commands (exec, set_context, etc.) dispatched by the reader thread
|
|
151
|
+
_command_queue: queue.Queue = queue.Queue()
|
|
152
|
+
|
|
153
|
+
# Will be set by the TypeScript host before each execution
|
|
154
|
+
context: str = ""
|
|
155
|
+
|
|
156
|
+
# Sentinel — when set to a non-None value, the loop terminates
|
|
157
|
+
__final_result__ = None
|
|
158
|
+
|
|
159
|
+
# User execution namespace — isolates LLM code from REPL internals
|
|
160
|
+
_user_ns: dict = {}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def FINAL(x):
|
|
164
|
+
"""Set the final answer as a string and terminate the RLM loop."""
|
|
165
|
+
global __final_result__
|
|
166
|
+
if __final_result__ is not None:
|
|
167
|
+
print(f"[Warning] FINAL() called again — overwriting previous answer", file=sys.stderr)
|
|
168
|
+
__final_result__ = str(x)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def FINAL_VAR(x):
|
|
172
|
+
"""Set the final answer from a variable and terminate the RLM loop."""
|
|
173
|
+
global __final_result__
|
|
174
|
+
if __final_result__ is not None and x is not None:
|
|
175
|
+
print(f"[Warning] FINAL_VAR() called again — overwriting previous answer", file=sys.stderr)
|
|
176
|
+
__final_result__ = str(x) if x is not None else None
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _stdin_reader_loop() -> None:
|
|
180
|
+
"""Dedicated thread: reads all stdin lines and dispatches them.
|
|
181
|
+
|
|
182
|
+
- llm_result/thread_result/merge_result messages go to waiting threads
|
|
183
|
+
- All other messages (exec, set_context, etc.) go to _command_queue
|
|
184
|
+
"""
|
|
185
|
+
while True:
|
|
186
|
+
try:
|
|
187
|
+
line = _real_stdin.readline()
|
|
188
|
+
except Exception:
|
|
189
|
+
break
|
|
190
|
+
if not line:
|
|
191
|
+
# stdin closed — wake all pending threads and signal main loop
|
|
192
|
+
for event in list(_pending_results.values()):
|
|
193
|
+
event.set()
|
|
194
|
+
_command_queue.put(None)
|
|
195
|
+
break
|
|
196
|
+
line = line.strip()
|
|
197
|
+
if not line:
|
|
198
|
+
continue
|
|
199
|
+
try:
|
|
200
|
+
msg = json.loads(line)
|
|
201
|
+
except json.JSONDecodeError:
|
|
202
|
+
continue
|
|
203
|
+
|
|
204
|
+
msg_type = msg.get("type")
|
|
205
|
+
if msg_type in ("llm_result", "thread_result", "merge_result"):
|
|
206
|
+
rid = msg.get("id", "")
|
|
207
|
+
if rid in _pending_results:
|
|
208
|
+
_result_store[rid] = json.dumps(msg) if msg_type != "llm_result" else msg.get("result", "")
|
|
209
|
+
_pending_results[rid].set()
|
|
210
|
+
elif msg_type == "shutdown":
|
|
211
|
+
_command_queue.put(None)
|
|
212
|
+
break
|
|
213
|
+
else:
|
|
214
|
+
_command_queue.put(msg)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def llm_query(sub_context: str, instruction: str = "") -> str:
|
|
218
|
+
"""Send a sub-context and instruction to the parent LLM and return the response."""
|
|
219
|
+
if not instruction:
|
|
220
|
+
instruction = ""
|
|
221
|
+
|
|
222
|
+
request_id = uuid.uuid4().hex[:12]
|
|
223
|
+
event = threading.Event()
|
|
224
|
+
_pending_results[request_id] = event
|
|
225
|
+
|
|
226
|
+
request = {
|
|
227
|
+
"type": "llm_query",
|
|
228
|
+
"sub_context": sub_context,
|
|
229
|
+
"instruction": instruction,
|
|
230
|
+
"id": request_id,
|
|
231
|
+
}
|
|
232
|
+
with _write_lock:
|
|
233
|
+
_real_stdout.write(json.dumps(request) + "\n")
|
|
234
|
+
_real_stdout.flush()
|
|
235
|
+
|
|
236
|
+
event.wait()
|
|
237
|
+
_pending_results.pop(request_id, None)
|
|
238
|
+
result = _result_store.pop(request_id, None)
|
|
239
|
+
if result is None:
|
|
240
|
+
raise RuntimeError("Host process disconnected during llm_query — stdin closed")
|
|
241
|
+
return result
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async def async_llm_query(sub_context: str, instruction: str = "") -> str:
|
|
245
|
+
"""Async wrapper around llm_query for use with asyncio.gather()."""
|
|
246
|
+
return await asyncio.get_event_loop().run_in_executor(None, llm_query, sub_context, instruction)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def thread(task: str, context: str = "", agent: str = "opencode", model: str = "", files=None) -> str:
|
|
250
|
+
"""Spawn a coding agent thread in an isolated git worktree.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
task: What the agent should do (be specific)
|
|
254
|
+
context: Additional context to pass to the agent
|
|
255
|
+
agent: Agent backend name ("opencode", "direct-llm", etc.)
|
|
256
|
+
model: Model ID in provider/model-id format (e.g., "anthropic/claude-sonnet-4-6")
|
|
257
|
+
files: List of relevant file paths (hints for the agent)
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
Compressed result string with status, files changed, diff, and output summary.
|
|
261
|
+
"""
|
|
262
|
+
if files is None:
|
|
263
|
+
files = []
|
|
264
|
+
|
|
265
|
+
request_id = uuid.uuid4().hex[:12]
|
|
266
|
+
event = threading.Event()
|
|
267
|
+
_pending_results[request_id] = event
|
|
268
|
+
|
|
269
|
+
request = {
|
|
270
|
+
"type": "thread_request",
|
|
271
|
+
"id": request_id,
|
|
272
|
+
"task": task,
|
|
273
|
+
"context": context,
|
|
274
|
+
"agent_backend": agent,
|
|
275
|
+
"model": model,
|
|
276
|
+
"files": files,
|
|
277
|
+
}
|
|
278
|
+
with _write_lock:
|
|
279
|
+
_real_stdout.write(json.dumps(request) + "\n")
|
|
280
|
+
_real_stdout.flush()
|
|
281
|
+
|
|
282
|
+
event.wait()
|
|
283
|
+
_pending_results.pop(request_id, None)
|
|
284
|
+
|
|
285
|
+
raw = _result_store.pop(request_id, None)
|
|
286
|
+
if raw is None:
|
|
287
|
+
raise RuntimeError("Host process disconnected during thread() — stdin closed")
|
|
288
|
+
try:
|
|
289
|
+
result_msg = json.loads(raw)
|
|
290
|
+
return result_msg.get("result", raw)
|
|
291
|
+
except (json.JSONDecodeError, AttributeError):
|
|
292
|
+
return raw
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
async def async_thread(task: str, context: str = "", agent: str = "opencode", model: str = "", files=None) -> str:
|
|
296
|
+
"""Async version of thread() for use with asyncio.gather().
|
|
297
|
+
|
|
298
|
+
Usage:
|
|
299
|
+
import asyncio
|
|
300
|
+
results = await asyncio.gather(
|
|
301
|
+
async_thread("fix auth", files=["src/auth.ts"]),
|
|
302
|
+
async_thread("fix routing", files=["src/router.ts"]),
|
|
303
|
+
)
|
|
304
|
+
"""
|
|
305
|
+
if files is None:
|
|
306
|
+
files = []
|
|
307
|
+
return await asyncio.get_event_loop().run_in_executor(
|
|
308
|
+
None, lambda: thread(task, context, agent, model, files)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def merge_threads() -> str:
|
|
313
|
+
"""Merge all completed thread branches back into the main branch.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Merge status string.
|
|
317
|
+
"""
|
|
318
|
+
request_id = uuid.uuid4().hex[:12]
|
|
319
|
+
event = threading.Event()
|
|
320
|
+
_pending_results[request_id] = event
|
|
321
|
+
|
|
322
|
+
request = {
|
|
323
|
+
"type": "merge_request",
|
|
324
|
+
"id": request_id,
|
|
325
|
+
}
|
|
326
|
+
with _write_lock:
|
|
327
|
+
_real_stdout.write(json.dumps(request) + "\n")
|
|
328
|
+
_real_stdout.flush()
|
|
329
|
+
|
|
330
|
+
event.wait()
|
|
331
|
+
_pending_results.pop(request_id, None)
|
|
332
|
+
|
|
333
|
+
raw = _result_store.pop(request_id, None)
|
|
334
|
+
if raw is None:
|
|
335
|
+
raise RuntimeError("Host process disconnected during merge_threads() — stdin closed")
|
|
336
|
+
try:
|
|
337
|
+
result_msg = json.loads(raw)
|
|
338
|
+
return result_msg.get("result", raw)
|
|
339
|
+
except (json.JSONDecodeError, AttributeError):
|
|
340
|
+
return raw
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _runtime_symbols() -> dict:
|
|
344
|
+
"""Return the dict of runtime symbols injected into the user namespace."""
|
|
345
|
+
return {
|
|
346
|
+
'__builtins__': _SAFE_BUILTINS,
|
|
347
|
+
'context': context,
|
|
348
|
+
'llm_query': llm_query,
|
|
349
|
+
'async_llm_query': async_llm_query,
|
|
350
|
+
'thread': thread,
|
|
351
|
+
'async_thread': async_thread,
|
|
352
|
+
'merge_threads': merge_threads,
|
|
353
|
+
'FINAL': FINAL,
|
|
354
|
+
'FINAL_VAR': FINAL_VAR,
|
|
355
|
+
'asyncio': asyncio,
|
|
356
|
+
'json': json,
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _refresh_user_ns() -> None:
|
|
361
|
+
"""Ensure the user namespace has the latest runtime symbols."""
|
|
362
|
+
_user_ns.update(_runtime_symbols())
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _execute_code(code: str) -> None:
|
|
366
|
+
"""Execute a code snippet in a sandboxed namespace, capturing output."""
|
|
367
|
+
global __final_result__
|
|
368
|
+
_refresh_user_ns()
|
|
369
|
+
captured_stdout = io.StringIO()
|
|
370
|
+
captured_stderr = io.StringIO()
|
|
371
|
+
old_stdout = sys.stdout
|
|
372
|
+
old_stderr = sys.stderr
|
|
373
|
+
|
|
374
|
+
try:
|
|
375
|
+
sys.stdout = captured_stdout
|
|
376
|
+
sys.stderr = captured_stderr
|
|
377
|
+
# Enforce AST security validation
|
|
378
|
+
_validate_ast(code)
|
|
379
|
+
try:
|
|
380
|
+
compiled = compile(code, "<repl>", "exec")
|
|
381
|
+
exec(compiled, _user_ns)
|
|
382
|
+
except SyntaxError as e:
|
|
383
|
+
if "await" in str(code):
|
|
384
|
+
_protected = set(_runtime_symbols().keys())
|
|
385
|
+
async_code = "async def __async_exec__():\n"
|
|
386
|
+
for line in code.split("\n"):
|
|
387
|
+
async_code += f" {line}\n"
|
|
388
|
+
async_code += " return {k: v for k, v in locals().items()}\n"
|
|
389
|
+
_validate_ast(async_code)
|
|
390
|
+
compiled_async = compile(async_code, "<repl>", "exec")
|
|
391
|
+
exec(compiled_async, _user_ns)
|
|
392
|
+
async_fn = _user_ns.pop("__async_exec__")
|
|
393
|
+
_async_locals = asyncio.run(async_fn())
|
|
394
|
+
for k, v in _async_locals.items():
|
|
395
|
+
if k not in _protected:
|
|
396
|
+
_user_ns[k] = v
|
|
397
|
+
else:
|
|
398
|
+
raise e
|
|
399
|
+
except Exception:
|
|
400
|
+
traceback.print_exc(file=captured_stderr)
|
|
401
|
+
finally:
|
|
402
|
+
sys.stdout = old_stdout
|
|
403
|
+
sys.stderr = old_stderr
|
|
404
|
+
|
|
405
|
+
stdout_val = captured_stdout.getvalue()
|
|
406
|
+
stderr_val = captured_stderr.getvalue()
|
|
407
|
+
|
|
408
|
+
result = {
|
|
409
|
+
"type": "exec_done",
|
|
410
|
+
"stdout": stdout_val,
|
|
411
|
+
"stderr": stderr_val,
|
|
412
|
+
"has_final": __final_result__ is not None,
|
|
413
|
+
"final_value": str(__final_result__) if __final_result__ is not None else None,
|
|
414
|
+
}
|
|
415
|
+
with _write_lock:
|
|
416
|
+
_real_stdout.write(json.dumps(result) + "\n")
|
|
417
|
+
_real_stdout.flush()
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _main_loop() -> None:
|
|
421
|
+
"""Process commands from the queue (fed by the stdin reader thread)."""
|
|
422
|
+
while True:
|
|
423
|
+
msg = _command_queue.get()
|
|
424
|
+
if msg is None:
|
|
425
|
+
break
|
|
426
|
+
|
|
427
|
+
if msg.get("type") == "exec":
|
|
428
|
+
_execute_code(msg.get("code", ""))
|
|
429
|
+
elif msg.get("type") == "set_context":
|
|
430
|
+
global context
|
|
431
|
+
context = msg.get("value", "")
|
|
432
|
+
ack = {"type": "context_set"}
|
|
433
|
+
with _write_lock:
|
|
434
|
+
_real_stdout.write(json.dumps(ack) + "\n")
|
|
435
|
+
_real_stdout.flush()
|
|
436
|
+
elif msg.get("type") == "reset_final":
|
|
437
|
+
global __final_result__
|
|
438
|
+
__final_result__ = None
|
|
439
|
+
ack = {"type": "final_reset"}
|
|
440
|
+
with _write_lock:
|
|
441
|
+
_real_stdout.write(json.dumps(ack) + "\n")
|
|
442
|
+
_real_stdout.flush()
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
if __name__ == "__main__":
|
|
446
|
+
ready = {"type": "ready"}
|
|
447
|
+
_real_stdout.write(json.dumps(ready) + "\n")
|
|
448
|
+
_real_stdout.flush()
|
|
449
|
+
|
|
450
|
+
# Start dedicated stdin reader thread
|
|
451
|
+
reader = threading.Thread(target=_stdin_reader_loop, daemon=True)
|
|
452
|
+
reader.start()
|
|
453
|
+
|
|
454
|
+
_main_loop()
|