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.
Files changed (128) hide show
  1. package/AGENTS.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1013 -0
  4. package/bin/pantheon-init.mjs +183 -0
  5. package/commands/pantheon-audit.md +25 -0
  6. package/commands/pantheon-bg.md +10 -0
  7. package/commands/pantheon-consolidate.md +11 -0
  8. package/commands/pantheon-deepwork.md +128 -0
  9. package/commands/pantheon-doc.md +10 -0
  10. package/commands/pantheon-focus.md +9 -0
  11. package/commands/pantheon-forget.md +58 -0
  12. package/commands/pantheon-hash.md +11 -0
  13. package/commands/pantheon-optimize.md +79 -0
  14. package/commands/pantheon-remember.md +44 -0
  15. package/commands/pantheon-search.md +48 -0
  16. package/commands/pantheon-status.md +71 -0
  17. package/commands/pantheon-todo.md +11 -0
  18. package/commands/pantheon.md +49 -0
  19. package/docs/AGENT-MCP.md +194 -0
  20. package/docs/ARCHITECTURE.md +384 -0
  21. package/docs/BRANCH-PROTECTION.md +142 -0
  22. package/docs/INDEX.md +81 -0
  23. package/docs/INSTALLATION.md +217 -0
  24. package/docs/MCP.md +238 -0
  25. package/docs/MEMORY.md +471 -0
  26. package/docs/MIGRATION-MEMORY-BANK.md +139 -0
  27. package/docs/PLATFORMS.md +5 -0
  28. package/docs/QUICKSTART.md +49 -0
  29. package/docs/README.md +18 -0
  30. package/docs/RELEASING.md +256 -0
  31. package/docs/SETUP.md +5 -0
  32. package/docs/UPGRADING.md +41 -0
  33. package/docs/mcp-recommendations.md +439 -0
  34. package/docs/mcp-tools.md +156 -0
  35. package/docs/mcp-user-guide.md +204 -0
  36. package/docs/persistence-mcp.md +111 -0
  37. package/package.json +72 -0
  38. package/pantheon.schema.json +158 -0
  39. package/scripts/__init__.py +0 -0
  40. package/scripts/_pantheon_paths.py +68 -0
  41. package/scripts/check-version-consistency.sh +23 -0
  42. package/scripts/code_mode_server.py +202 -0
  43. package/scripts/doctor.mjs +763 -0
  44. package/scripts/generate-prompts.sh +222 -0
  45. package/scripts/generate-routing-docs.mjs +104 -0
  46. package/scripts/hash_verify.py +192 -0
  47. package/scripts/init-pantheon-mcp.sh +118 -0
  48. package/scripts/install/agents-md.mjs +214 -0
  49. package/scripts/install/health-check.mjs +196 -0
  50. package/scripts/install/migrate.mjs +209 -0
  51. package/scripts/install/opencode.mjs +645 -0
  52. package/scripts/install/shared.mjs +655 -0
  53. package/scripts/install/venv.mjs +116 -0
  54. package/scripts/install-mcp.mjs +885 -0
  55. package/scripts/install.mjs +26 -0
  56. package/scripts/manifest.mjs +622 -0
  57. package/scripts/mcp_persistence_server.py +459 -0
  58. package/scripts/mcp_resources_server.py +206 -0
  59. package/scripts/memory_cache.py +78 -0
  60. package/scripts/memory_mcp_server.py +605 -0
  61. package/scripts/paths.py +64 -0
  62. package/scripts/prune_context.py +72 -0
  63. package/scripts/release-bundle.mjs +109 -0
  64. package/scripts/scrub-secrets.py +282 -0
  65. package/scripts/scrub_secrets.py +281 -0
  66. package/scripts/test-context-compression.sh +166 -0
  67. package/scripts/themis_heuristic_scan.py +287 -0
  68. package/scripts/todo_enforcer.py +242 -0
  69. package/scripts/uninstall.mjs +1057 -0
  70. package/scripts/validate-routing.mjs +160 -0
  71. package/scripts/validate_agent_frontmatter.py +226 -0
  72. package/scripts/versioning.mjs +254 -0
  73. package/skills-lock.json +16 -0
  74. package/src/agents/aphrodite.md +162 -0
  75. package/src/agents/apollo.md +109 -0
  76. package/src/agents/athena.md +226 -0
  77. package/src/agents/demeter.md +146 -0
  78. package/src/agents/gaia.md +82 -0
  79. package/src/agents/hephaestus.md +105 -0
  80. package/src/agents/hermes.md +302 -0
  81. package/src/agents/iris.md +99 -0
  82. package/src/agents/mnemosyne.md +226 -0
  83. package/src/agents/nyx.md +87 -0
  84. package/src/agents/prometheus.md +199 -0
  85. package/src/agents/talos.md +93 -0
  86. package/src/agents/themis.md +187 -0
  87. package/src/agents/zeus.md +209 -0
  88. package/src/instructions/agent-return-format.instructions.md +26 -0
  89. package/src/instructions/backend-standards.instructions.md +45 -0
  90. package/src/instructions/documentation-standards.instructions.md +53 -0
  91. package/src/instructions/frontend-standards.instructions.md +46 -0
  92. package/src/instructions/memory-protocol.instructions.md +67 -0
  93. package/src/instructions/yagni.instructions.md +21 -0
  94. package/src/instructions/zeus-anti-stall.instructions.md +72 -0
  95. package/src/instructions/zeus-communication-rules.instructions.md +15 -0
  96. package/src/instructions/zeus-council-synthesis.instructions.md +105 -0
  97. package/src/instructions/zeus-timeout-retry.instructions.md +127 -0
  98. package/src/mcp/_pantheon_paths.py +67 -0
  99. package/src/mcp/code_mode_server.py +202 -0
  100. package/src/mcp/init-pantheon-mcp.sh +118 -0
  101. package/src/mcp/install-mcp.mjs +885 -0
  102. package/src/mcp/mcp_persistence_server.py +458 -0
  103. package/src/mcp/mcp_resources_server.py +205 -0
  104. package/src/mcp/memory_mcp_server.py +604 -0
  105. package/src/mcp/requirements-mcp-core.txt +5 -0
  106. package/src/mcp/requirements-mcp.txt +5 -0
  107. package/src/plugin.ts +19 -0
  108. package/src/plugins/tui/dist/tui.js +143 -0
  109. package/src/plugins/tui/dist/tui.tsx +144 -0
  110. package/src/plugins/tui/package.json +32 -0
  111. package/src/plugins/tui/src/index.tsx +144 -0
  112. package/src/plugins/tui/tsdown.config.ts +22 -0
  113. package/src/routing.yml +499 -0
  114. package/src/skills/README.md +230 -0
  115. package/src/skills/agent-coordination/SKILL.md +95 -0
  116. package/src/skills/artifact-management/SKILL.md +118 -0
  117. package/src/skills/auto-continue/SKILL.md +280 -0
  118. package/src/skills/code-review-checklist/SKILL.md +139 -0
  119. package/src/skills/context-compression/SKILL.md +861 -0
  120. package/src/skills/git-workflow-and-versioning/SKILL.md +32 -0
  121. package/src/skills/incremental-implementation/SKILL.md +27 -0
  122. package/src/skills/memory-bank/SKILL.md +165 -0
  123. package/src/skills/orchestration-workflow/SKILL.md +311 -0
  124. package/src/skills/security-hardening/SKILL.md +36 -0
  125. package/src/skills/session-goal/SKILL.md +138 -0
  126. package/src/skills/spec-driven-development/SKILL.md +23 -0
  127. package/src/skills/tdd-with-agents/SKILL.md +170 -0
  128. 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()