pantheon-opencode 1.0.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.md +37 -0
- package/LICENSE +21 -0
- package/README.md +1013 -0
- package/bin/pantheon-init.mjs +183 -0
- package/commands/pantheon-audit.md +25 -0
- package/commands/pantheon-bg.md +10 -0
- package/commands/pantheon-consolidate.md +11 -0
- package/commands/pantheon-deepwork.md +128 -0
- package/commands/pantheon-doc.md +10 -0
- package/commands/pantheon-focus.md +9 -0
- package/commands/pantheon-forget.md +58 -0
- package/commands/pantheon-hash.md +11 -0
- package/commands/pantheon-optimize.md +79 -0
- package/commands/pantheon-remember.md +44 -0
- package/commands/pantheon-search.md +48 -0
- package/commands/pantheon-status.md +71 -0
- package/commands/pantheon-todo.md +11 -0
- package/commands/pantheon.md +49 -0
- package/docs/AGENT-MCP.md +194 -0
- package/docs/ARCHITECTURE.md +384 -0
- package/docs/BRANCH-PROTECTION.md +142 -0
- package/docs/INDEX.md +81 -0
- package/docs/INSTALLATION.md +217 -0
- package/docs/MCP.md +238 -0
- package/docs/MEMORY.md +471 -0
- package/docs/MIGRATION-MEMORY-BANK.md +139 -0
- package/docs/PLATFORMS.md +5 -0
- package/docs/QUICKSTART.md +49 -0
- package/docs/README.md +18 -0
- package/docs/RELEASING.md +256 -0
- package/docs/SETUP.md +5 -0
- package/docs/UPGRADING.md +41 -0
- package/docs/mcp-recommendations.md +439 -0
- package/docs/mcp-tools.md +156 -0
- package/docs/mcp-user-guide.md +204 -0
- package/docs/persistence-mcp.md +111 -0
- package/package.json +72 -0
- package/pantheon.schema.json +158 -0
- package/scripts/__init__.py +0 -0
- package/scripts/_pantheon_paths.py +68 -0
- package/scripts/check-version-consistency.sh +23 -0
- package/scripts/code_mode_server.py +202 -0
- package/scripts/doctor.mjs +763 -0
- package/scripts/generate-prompts.sh +222 -0
- package/scripts/generate-routing-docs.mjs +104 -0
- package/scripts/hash_verify.py +192 -0
- package/scripts/init-pantheon-mcp.sh +118 -0
- package/scripts/install/agents-md.mjs +214 -0
- package/scripts/install/health-check.mjs +196 -0
- package/scripts/install/migrate.mjs +209 -0
- package/scripts/install/opencode.mjs +645 -0
- package/scripts/install/shared.mjs +655 -0
- package/scripts/install/venv.mjs +116 -0
- package/scripts/install-mcp.mjs +885 -0
- package/scripts/install.mjs +26 -0
- package/scripts/manifest.mjs +622 -0
- package/scripts/mcp_persistence_server.py +459 -0
- package/scripts/mcp_resources_server.py +206 -0
- package/scripts/memory_cache.py +78 -0
- package/scripts/memory_mcp_server.py +605 -0
- package/scripts/paths.py +64 -0
- package/scripts/prune_context.py +72 -0
- package/scripts/release-bundle.mjs +109 -0
- package/scripts/scrub-secrets.py +282 -0
- package/scripts/scrub_secrets.py +281 -0
- package/scripts/test-context-compression.sh +166 -0
- package/scripts/themis_heuristic_scan.py +287 -0
- package/scripts/todo_enforcer.py +242 -0
- package/scripts/uninstall.mjs +1057 -0
- package/scripts/validate-routing.mjs +160 -0
- package/scripts/validate_agent_frontmatter.py +226 -0
- package/scripts/versioning.mjs +254 -0
- package/skills-lock.json +16 -0
- package/src/agents/aphrodite.md +162 -0
- package/src/agents/apollo.md +109 -0
- package/src/agents/athena.md +226 -0
- package/src/agents/demeter.md +146 -0
- package/src/agents/gaia.md +82 -0
- package/src/agents/hephaestus.md +105 -0
- package/src/agents/hermes.md +302 -0
- package/src/agents/iris.md +99 -0
- package/src/agents/mnemosyne.md +226 -0
- package/src/agents/nyx.md +87 -0
- package/src/agents/prometheus.md +199 -0
- package/src/agents/talos.md +93 -0
- package/src/agents/themis.md +187 -0
- package/src/agents/zeus.md +209 -0
- package/src/instructions/agent-return-format.instructions.md +26 -0
- package/src/instructions/backend-standards.instructions.md +45 -0
- package/src/instructions/documentation-standards.instructions.md +53 -0
- package/src/instructions/frontend-standards.instructions.md +46 -0
- package/src/instructions/memory-protocol.instructions.md +67 -0
- package/src/instructions/yagni.instructions.md +21 -0
- package/src/instructions/zeus-anti-stall.instructions.md +72 -0
- package/src/instructions/zeus-communication-rules.instructions.md +15 -0
- package/src/instructions/zeus-council-synthesis.instructions.md +105 -0
- package/src/instructions/zeus-timeout-retry.instructions.md +127 -0
- package/src/mcp/_pantheon_paths.py +67 -0
- package/src/mcp/code_mode_server.py +202 -0
- package/src/mcp/init-pantheon-mcp.sh +118 -0
- package/src/mcp/install-mcp.mjs +885 -0
- package/src/mcp/mcp_persistence_server.py +458 -0
- package/src/mcp/mcp_resources_server.py +205 -0
- package/src/mcp/memory_mcp_server.py +604 -0
- package/src/mcp/requirements-mcp-core.txt +5 -0
- package/src/mcp/requirements-mcp.txt +5 -0
- package/src/plugin.ts +19 -0
- package/src/plugins/tui/dist/tui.js +143 -0
- package/src/plugins/tui/dist/tui.tsx +144 -0
- package/src/plugins/tui/package.json +32 -0
- package/src/plugins/tui/src/index.tsx +144 -0
- package/src/plugins/tui/tsdown.config.ts +22 -0
- package/src/routing.yml +499 -0
- package/src/skills/README.md +230 -0
- package/src/skills/agent-coordination/SKILL.md +95 -0
- package/src/skills/artifact-management/SKILL.md +118 -0
- package/src/skills/auto-continue/SKILL.md +280 -0
- package/src/skills/code-review-checklist/SKILL.md +139 -0
- package/src/skills/context-compression/SKILL.md +861 -0
- package/src/skills/git-workflow-and-versioning/SKILL.md +32 -0
- package/src/skills/incremental-implementation/SKILL.md +27 -0
- package/src/skills/memory-bank/SKILL.md +165 -0
- package/src/skills/orchestration-workflow/SKILL.md +311 -0
- package/src/skills/security-hardening/SKILL.md +36 -0
- package/src/skills/session-goal/SKILL.md +138 -0
- package/src/skills/spec-driven-development/SKILL.md +23 -0
- package/src/skills/tdd-with-agents/SKILL.md +170 -0
- package/src/skills/visual-review-pipeline/SKILL.md +200 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Pantheon Code Mode MCP Server.
|
|
3
|
+
|
|
4
|
+
Provides a confined execution environment for orchestration scripts
|
|
5
|
+
via MCP tools and resources.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python scripts/code_mode_server.py
|
|
9
|
+
|
|
10
|
+
Or via MCP client (stdio transport):
|
|
11
|
+
pantheon-code-mode:
|
|
12
|
+
command: python
|
|
13
|
+
args: ["scripts/code_mode_server.py"]
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import asyncio
|
|
19
|
+
import os
|
|
20
|
+
import stat
|
|
21
|
+
from contextlib import suppress
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from _pantheon_paths import pantheon_home, pantheon_project
|
|
25
|
+
from mcp.server.fastmcp import FastMCP
|
|
26
|
+
|
|
27
|
+
# ── Constants ─────────────────────────────────────────────────────────────────
|
|
28
|
+
ALLOWED_EXTENSIONS: frozenset[str] = frozenset({".sh", ".py"})
|
|
29
|
+
SCRIPT_TIMEOUT: int = 30
|
|
30
|
+
|
|
31
|
+
# ── Scripts Directory Resolution ─────────────────────────────────────────────
|
|
32
|
+
# Priority:
|
|
33
|
+
# 1. $PANTHEON_HOME/.pantheon/code-mode/ (global install)
|
|
34
|
+
# 2. $PANTHEON_PROJECT/.opencode/.pantheon/code-mode/ (project install)
|
|
35
|
+
# 3. $PANTHEON_PROJECT/.pantheon/code-mode/ (legacy fallback)
|
|
36
|
+
_PANTHEON_HOME: Path = pantheon_home()
|
|
37
|
+
_SCRIPTS_DIR_CANDIDATES: list[Path] = []
|
|
38
|
+
_proj = pantheon_project()
|
|
39
|
+
if _proj is not None:
|
|
40
|
+
_SCRIPTS_DIR_CANDIDATES.append(_proj / ".opencode" / ".pantheon" / "code-mode")
|
|
41
|
+
_SCRIPTS_DIR_CANDIDATES.append(_proj / ".pantheon" / "code-mode")
|
|
42
|
+
_SCRIPTS_DIR_CANDIDATES.append(_PANTHEON_HOME / ".pantheon" / "code-mode")
|
|
43
|
+
|
|
44
|
+
SCRIPTS_DIR: Path = _PANTHEON_HOME / ".pantheon" / "code-mode" # default
|
|
45
|
+
for _candidate in _SCRIPTS_DIR_CANDIDATES:
|
|
46
|
+
if _candidate.is_dir():
|
|
47
|
+
SCRIPTS_DIR = _candidate
|
|
48
|
+
break
|
|
49
|
+
|
|
50
|
+
# ── FastMCP App ───────────────────────────────────────────────────────────────
|
|
51
|
+
mcp = FastMCP(
|
|
52
|
+
"Pantheon Code Mode",
|
|
53
|
+
instructions="Confined script execution for Pantheon orchestration. "
|
|
54
|
+
"Scripts live in .pantheon/code-mode/ and must be .sh or .py files.",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _validate_script_name(script_name: str) -> Path:
|
|
61
|
+
"""Validate a script name and return its resolved path.
|
|
62
|
+
|
|
63
|
+
Raises ValueError if the name is invalid, traverses paths, or
|
|
64
|
+
has a disallowed extension.
|
|
65
|
+
"""
|
|
66
|
+
if not script_name:
|
|
67
|
+
raise ValueError("Script name cannot be empty")
|
|
68
|
+
|
|
69
|
+
name = script_name.strip()
|
|
70
|
+
if name.startswith("."):
|
|
71
|
+
raise ValueError(f"Invalid script name: '{script_name}'")
|
|
72
|
+
if "/" in name or "\\" in name:
|
|
73
|
+
raise ValueError(f"Invalid script name: '{script_name}'")
|
|
74
|
+
|
|
75
|
+
ext = Path(name).suffix.lower()
|
|
76
|
+
if ext not in ALLOWED_EXTENSIONS:
|
|
77
|
+
allowed = ", ".join(sorted(ALLOWED_EXTENSIONS))
|
|
78
|
+
raise ValueError(f"Extension '{ext}' not allowed. Allowed: {allowed}")
|
|
79
|
+
|
|
80
|
+
script_path = (SCRIPTS_DIR / name).resolve()
|
|
81
|
+
if not str(script_path).startswith(str(SCRIPTS_DIR.resolve())):
|
|
82
|
+
raise ValueError(f"Invalid script name: '{script_name}'")
|
|
83
|
+
if not script_path.exists():
|
|
84
|
+
raise ValueError(f"Script '{script_name}' not found")
|
|
85
|
+
|
|
86
|
+
return script_path
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _format_output(
|
|
90
|
+
stdout: str, stderr: str, exit_code: int, timed_out: bool = False
|
|
91
|
+
) -> str:
|
|
92
|
+
"""Format script execution output into a readable string."""
|
|
93
|
+
parts: list[str] = []
|
|
94
|
+
if timed_out:
|
|
95
|
+
parts.append(f"[TIMEOUT] Script exceeded {SCRIPT_TIMEOUT}s limit")
|
|
96
|
+
if stdout:
|
|
97
|
+
parts.append(stdout)
|
|
98
|
+
if stderr:
|
|
99
|
+
parts.append(f"[stderr]\n{stderr}")
|
|
100
|
+
parts.append(f"--- exit code: {exit_code}")
|
|
101
|
+
return "\n".join(parts)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ── Static Resources ──────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@mcp.resource(
|
|
108
|
+
"pantheon://code-mode/scripts",
|
|
109
|
+
description="List of available code-mode scripts",
|
|
110
|
+
)
|
|
111
|
+
async def list_code_mode_scripts() -> str:
|
|
112
|
+
"""Return a list of available scripts in the code-mode directory."""
|
|
113
|
+
if not SCRIPTS_DIR.is_dir():
|
|
114
|
+
return "Code mode directory not found."
|
|
115
|
+
|
|
116
|
+
scripts: list[str] = []
|
|
117
|
+
for f in sorted(SCRIPTS_DIR.iterdir()):
|
|
118
|
+
if f.is_file() and f.suffix.lower() in ALLOWED_EXTENSIONS:
|
|
119
|
+
scripts.append(f"- {f.name}")
|
|
120
|
+
|
|
121
|
+
return "\n".join(scripts) if scripts else "No scripts found."
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# ── Template Resources ────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@mcp.resource(
|
|
128
|
+
"pantheon://code-mode/scripts/{script_name}",
|
|
129
|
+
description="Content of a code-mode script by name",
|
|
130
|
+
)
|
|
131
|
+
async def get_code_mode_script(script_name: str) -> str:
|
|
132
|
+
"""Return the source content of a code-mode script."""
|
|
133
|
+
try:
|
|
134
|
+
script_path = _validate_script_name(script_name)
|
|
135
|
+
return script_path.read_text(encoding="utf-8")
|
|
136
|
+
except ValueError as e:
|
|
137
|
+
return str(e)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ── Tools ─────────────────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@mcp.tool(
|
|
144
|
+
name="execute_code_script",
|
|
145
|
+
description="Run a .sh/.py script from .pantheon/code-mode/ "
|
|
146
|
+
"with optional args. 30s timeout.",
|
|
147
|
+
)
|
|
148
|
+
async def execute_code_script(script_name: str, args: list[str] | None = None) -> str:
|
|
149
|
+
"""Execute a code-mode script with confinement and timeout.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
script_name: Name of the script in the code-mode directory.
|
|
153
|
+
args: Optional CLI arguments forwarded to the subprocess (e.g.
|
|
154
|
+
``["compress", "--text", "..."]``). Defaults to no args.
|
|
155
|
+
"""
|
|
156
|
+
args = args or []
|
|
157
|
+
try:
|
|
158
|
+
script_path = _validate_script_name(script_name)
|
|
159
|
+
except ValueError as e:
|
|
160
|
+
return str(e)
|
|
161
|
+
|
|
162
|
+
# Ensure script is executable
|
|
163
|
+
if not os.access(script_path, os.X_OK):
|
|
164
|
+
with suppress(OSError):
|
|
165
|
+
mode = script_path.stat().st_mode
|
|
166
|
+
script_path.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
167
|
+
|
|
168
|
+
script_dir = script_path.parent
|
|
169
|
+
try:
|
|
170
|
+
proc = await asyncio.create_subprocess_exec(
|
|
171
|
+
str(script_path),
|
|
172
|
+
*args,
|
|
173
|
+
cwd=str(script_dir),
|
|
174
|
+
stdout=asyncio.subprocess.PIPE,
|
|
175
|
+
stderr=asyncio.subprocess.PIPE,
|
|
176
|
+
)
|
|
177
|
+
try:
|
|
178
|
+
stdout, stderr = await asyncio.wait_for(
|
|
179
|
+
proc.communicate(), timeout=SCRIPT_TIMEOUT
|
|
180
|
+
)
|
|
181
|
+
return _format_output(
|
|
182
|
+
stdout.decode("utf-8", errors="replace"),
|
|
183
|
+
stderr.decode("utf-8", errors="replace"),
|
|
184
|
+
proc.returncode or 0,
|
|
185
|
+
)
|
|
186
|
+
except TimeoutError:
|
|
187
|
+
proc.kill()
|
|
188
|
+
await proc.wait()
|
|
189
|
+
return _format_output("", "", -1, timed_out=True)
|
|
190
|
+
except FileNotFoundError:
|
|
191
|
+
return (
|
|
192
|
+
f"Script '{script_name}' not found "
|
|
193
|
+
f"or interpreter missing.\n--- exit code: -1"
|
|
194
|
+
)
|
|
195
|
+
except OSError as e:
|
|
196
|
+
return f"Failed to execute script: {e}\n--- exit code: -1"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# ── Main Entrypoint ───────────────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
if __name__ == "__main__":
|
|
202
|
+
mcp.run()
|