overseer-mcp 0.1.1
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/.env.example +40 -0
- package/LICENSE +21 -0
- package/README.md +231 -0
- package/configure-overseer.bat +239 -0
- package/dist/config.js +150 -0
- package/dist/index.js +64 -0
- package/dist/init/codexConfig.js +27 -0
- package/dist/init/codexConfigCommand.js +78 -0
- package/dist/init/command.js +98 -0
- package/dist/init/config.js +204 -0
- package/dist/init/instructions.js +137 -0
- package/dist/init/instructionsCommand.js +11 -0
- package/dist/prompts.js +144 -0
- package/dist/providers/anthropic.js +50 -0
- package/dist/providers/cli.js +52 -0
- package/dist/providers/openaiCompatible.js +42 -0
- package/dist/providers/types.js +12 -0
- package/dist/repo/files.js +47 -0
- package/dist/repo/findRoot.js +19 -0
- package/dist/repo/git.js +63 -0
- package/dist/repo/retrieve.js +118 -0
- package/dist/repo/tests.js +21 -0
- package/dist/tools/consultExpert.js +44 -0
- package/dist/tools/getPlan.js +82 -0
- package/dist/tools/requestReview.js +48 -0
- package/dist/tools/shared.js +35 -0
- package/package.json +44 -0
package/.env.example
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Core
|
|
2
|
+
OVERSEER_PROVIDER=openai
|
|
3
|
+
# OVERSEER_REPO_ROOT=/absolute/path/to/your/repo
|
|
4
|
+
# OVERSEER_TEST_COMMAND=npm test
|
|
5
|
+
|
|
6
|
+
# Context and validation caps
|
|
7
|
+
OVERSEER_MAX_FILES=12
|
|
8
|
+
# get_plan sends full bodies for this many top-relevant files; the rest go as signature-only outlines.
|
|
9
|
+
OVERSEER_PLAN_FULL_FILES=3
|
|
10
|
+
OVERSEER_MAX_FILE_BYTES=65536
|
|
11
|
+
OVERSEER_MAX_DIFF_BYTES=262144
|
|
12
|
+
OVERSEER_TEST_TIMEOUT_MS=300000
|
|
13
|
+
|
|
14
|
+
# Shared API provider options
|
|
15
|
+
# Either set the key directly, or point to another env var that the MCP client forwards.
|
|
16
|
+
OVERSEER_API_KEY=replace-with-your-key
|
|
17
|
+
# OVERSEER_API_KEY_ENV=OPENAI_API_KEY
|
|
18
|
+
OVERSEER_MODEL=replace-with-model-name
|
|
19
|
+
# OVERSEER_MAX_OUTPUT_TOKENS=2500
|
|
20
|
+
OVERSEER_TEMPERATURE=0.2
|
|
21
|
+
|
|
22
|
+
# OpenAI-compatible provider
|
|
23
|
+
# OVERSEER_PROVIDER=openai
|
|
24
|
+
OVERSEER_BASE_URL=https://api.openai.com/v1
|
|
25
|
+
# Custom OpenAI-compatible gateways, including opencode-go style API-key plans:
|
|
26
|
+
# OVERSEER_BASE_URL=https://your-gateway.example/v1
|
|
27
|
+
# OVERSEER_API_KEY_ENV=OPENCODE_API_KEY
|
|
28
|
+
# OVERSEER_MODEL=your-model-name
|
|
29
|
+
|
|
30
|
+
# Anthropic provider
|
|
31
|
+
# OVERSEER_PROVIDER=anthropic
|
|
32
|
+
# OVERSEER_BASE_URL=https://api.anthropic.com
|
|
33
|
+
|
|
34
|
+
# CLI provider
|
|
35
|
+
# OVERSEER_PROVIDER=cli
|
|
36
|
+
OVERSEER_CLI_COMMAND=codex
|
|
37
|
+
# JSON array is safest for args with spaces.
|
|
38
|
+
OVERSEER_CLI_ARGS=["exec"]
|
|
39
|
+
OVERSEER_CLI_PROMPT_VIA=stdin
|
|
40
|
+
OVERSEER_CLI_TIMEOUT_MS=120000
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 digisdatadigisdata-coder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# overseer-mcp
|
|
2
|
+
|
|
3
|
+
`overseer-mcp` is an MCP server for cheap executor agents that need a stronger expert only at the moments where they tend to derail: planning, mid-implementation decisions, and final review.
|
|
4
|
+
|
|
5
|
+
The expert is dormant between calls. When a tool is called, the server reads ground truth from git and disk, assembles the smallest useful context, asks the configured expert provider, and returns a compact contract.
|
|
6
|
+
|
|
7
|
+
## Why It Exists
|
|
8
|
+
|
|
9
|
+
Executor agents can bias an expert if they summarize the code incorrectly. `overseer-mcp` avoids that failure mode: the executor chooses which tool to call and which file paths matter, but file content, diffs, status, and validation output are read by the server.
|
|
10
|
+
|
|
11
|
+
The design is deliberately token-frugal:
|
|
12
|
+
|
|
13
|
+
- `get_plan` sends git status, a capped tracked-file map, the executor's named files, and a server-selected set of relevant files — full bodies for the top few, signature-only outlines for the rest.
|
|
14
|
+
- `consult_expert` sends named files, the real current diff, and literal error output.
|
|
15
|
+
- `request_review` sends real unstaged/staged diffs and optional validation output.
|
|
16
|
+
- File count, file bytes, diff bytes, temperature, and output tokens are capped.
|
|
17
|
+
- System prompts are static and first in the message order for provider prefix caching.
|
|
18
|
+
- Anthropic requests mark the system prompt with prompt-cache metadata.
|
|
19
|
+
- The executor should call the expert at three gates only: plan, blocker, review.
|
|
20
|
+
|
|
21
|
+
## Tools
|
|
22
|
+
|
|
23
|
+
`get_plan`
|
|
24
|
+
|
|
25
|
+
Call before writing code. Input: `task`, optional `focus_paths`, optional `mode` (`full` or `lite`). Returns a self-sufficient implementation contract.
|
|
26
|
+
|
|
27
|
+
`consult_expert`
|
|
28
|
+
|
|
29
|
+
Call before improvising on a non-trivial decision, unclear error, or ambiguity. Input: `question`, optional `file_paths`, `error_output`, `options_considered`. Returns `PROCEED`, `DECIDE`, `FIX`, `REDIRECT`, or `NEED_INFO`.
|
|
30
|
+
|
|
31
|
+
`request_review`
|
|
32
|
+
|
|
33
|
+
Call when implementation is done. Input: optional `task`, optional `run_tests` (default `true`). Returns `APPROVE` or `REQUEST_CHANGES`.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
Use it through any MCP client:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"overseer": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "overseer-mcp"],
|
|
45
|
+
"env": {
|
|
46
|
+
"OVERSEER_PROVIDER": "openai",
|
|
47
|
+
"OVERSEER_API_KEY": "YOUR_KEY",
|
|
48
|
+
"OVERSEER_MODEL": "gpt-5.5",
|
|
49
|
+
"OVERSEER_REPO_ROOT": "/absolute/path/to/your/repo",
|
|
50
|
+
"OVERSEER_TEST_COMMAND": "npm test"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For local development in this repo:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install
|
|
61
|
+
npm run build
|
|
62
|
+
OVERSEER_PROVIDER=cli OVERSEER_CLI_COMMAND=codex OVERSEER_CLI_ARGS='["exec"]' node dist/index.js
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Init Wizard
|
|
66
|
+
|
|
67
|
+
Generate MCP configuration with:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
overseer-mcp init
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
From this repo, use:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
node dist/index.js init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The wizard supports:
|
|
80
|
+
|
|
81
|
+
- OpenAI API (`OVERSEER_PROVIDER=openai`).
|
|
82
|
+
- Anthropic API (`OVERSEER_PROVIDER=anthropic`).
|
|
83
|
+
- Custom OpenAI-compatible APIs (`OVERSEER_PROVIDER=openai` plus `OVERSEER_BASE_URL`), including opencode-go style API-key subscriptions and GLM/gateway providers.
|
|
84
|
+
- CLI experts (`OVERSEER_PROVIDER=cli`) for Codex, Claude, or local CLIs, with optional login.
|
|
85
|
+
|
|
86
|
+
On Windows, the helper script walks through the same setup and writes both MCP config formats to `generated/`:
|
|
87
|
+
|
|
88
|
+
```bat
|
|
89
|
+
configure-overseer.bat
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
It builds the package, asks for the expert profile that Overseer will call, runs `init --print`, then writes:
|
|
93
|
+
|
|
94
|
+
- `generated\overseer-codex.toml`
|
|
95
|
+
- `generated\overseer-mcp.json`
|
|
96
|
+
- `generated\OVERSEER_AGENT_INSTRUCTIONS.md`
|
|
97
|
+
|
|
98
|
+
`OVERSEER_AGENT_INSTRUCTIONS.md` is for the cheap/operator agent, not for the expert model. It is generic AGENTS.md-style guidance that tells whichever executor you use (Codex, Mimo, Qoder, Cline, Roo, Trae, Claude Code, etc.) to call `get_plan`, `consult_expert`, and `request_review` at the right gates.
|
|
99
|
+
|
|
100
|
+
If the operator agent is Codex, the script can append the generated MCP block to the target repo `.codex\config.toml` after creating a backup. For Qoder, Mimo, Cline, Roo, or similar clients, paste/import the generated `overseer-mcp.json` where that client keeps MCP servers. Separately, the script can append the operator instructions to the target repo `AGENTS.md` after creating a backup. It never asks for the API key value; it asks for the environment variable name, such as `OPENCODE_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY`.
|
|
101
|
+
|
|
102
|
+
The Windows configurator also copies the JSON config into the target repo as `overseer-mcp.json` so the operator agent can find it from project context. Treat that file as local machine config because it contains absolute paths. Do not commit it to GitHub unless you intentionally convert it into a portable template such as `overseer-mcp.example.json`.
|
|
103
|
+
|
|
104
|
+
For non-interactive generation:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
node dist/index.js init --print \
|
|
108
|
+
--target codex \
|
|
109
|
+
--name overseer-opencode \
|
|
110
|
+
--expert openai-compatible \
|
|
111
|
+
--repo-root C:/Users/Usuario/automatizador-qoder- \
|
|
112
|
+
--api-key-env OPENCODE_API_KEY \
|
|
113
|
+
--base-url https://api.opencode.example/v1 \
|
|
114
|
+
--model opencode-go
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
That prints a Codex `config.toml` block. The key is not embedded. Codex forwards `OPENCODE_API_KEY`, and `overseer-mcp` reads it through `OVERSEER_API_KEY_ENV`.
|
|
118
|
+
|
|
119
|
+
Generate only the operator instructions:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
node dist/index.js instructions --print --mcp-name overseer-opencode > generated/OVERSEER_AGENT_INSTRUCTIONS.md
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Put those instructions where the **operator agent** reads persistent project guidance. For most coding agents, that means appending them to the target repo `AGENTS.md`.
|
|
126
|
+
|
|
127
|
+
To manage several expert profiles, generate one block per profile with a different `--name`:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
node dist/index.js init --print --target codex --name overseer-gpt --expert openai --api-key-env OPENAI_API_KEY --model gpt-5.5
|
|
131
|
+
node dist/index.js init --print --target codex --name overseer-claude --expert anthropic --api-key-env ANTHROPIC_API_KEY --model claude-your-model
|
|
132
|
+
node dist/index.js init --print --target codex --name overseer-opencode --expert openai-compatible --api-key-env OPENCODE_API_KEY --base-url https://api.opencode.example/v1 --model opencode-go
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
For JSON-style MCP clients such as Qoder/Mimo/Cline/Roo-style configs:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
node dist/index.js init --print --target json --name overseer-opencode --expert openai-compatible --api-key-env OPENCODE_API_KEY --base-url https://api.opencode.example/v1 --model opencode-go
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
For CLI plan providers:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
node dist/index.js init --print --target codex --name overseer-codex-cli --expert cli --cli-command codex --cli-args '["exec"]'
|
|
145
|
+
node dist/index.js init --print --target codex --name overseer-claude-cli --expert cli --cli-command claude --cli-args '["-p"]' --run-login
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`--run-login` uses the current terminal and runs the known login command for `codex` or `claude`. For other CLIs, pass an explicit login command:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
node dist/index.js init --print --expert cli --cli-command mycli --login-command '["mycli","login"]' --run-login
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
When the Windows configurator uses Codex CLI, it checks `~\.codex\config.toml` before login. If it finds an unsupported `service_tier` value such as `default`, it offers `flex`, `fast`, or removing the line, saves a backup, then continues.
|
|
155
|
+
|
|
156
|
+
CLI login is owned by the selected CLI, not by `overseer-mcp`. For example, `codex login` stores Codex auth in Codex's global files. Re-running `configure-overseer.bat` does not delete that login; answer `no` to the login prompt when the CLI is already authenticated.
|
|
157
|
+
|
|
158
|
+
## Configuration
|
|
159
|
+
|
|
160
|
+
| Variable | Required | Provider | Default | Meaning |
|
|
161
|
+
| --- | --- | --- | --- | --- |
|
|
162
|
+
| `OVERSEER_PROVIDER` | yes | all | none | `openai`, `anthropic`, or `cli`. |
|
|
163
|
+
| `OVERSEER_REPO_ROOT` | no | all | `process.cwd()` | Repo the server reads. |
|
|
164
|
+
| `OVERSEER_TEST_COMMAND` | no | all | none | Validation command for `request_review`. |
|
|
165
|
+
| `OVERSEER_MAX_FILES` | no | all | `12` | Max files read per tool call. |
|
|
166
|
+
| `OVERSEER_MAX_FILE_BYTES` | no | all | `65536` | Per-file byte cap. |
|
|
167
|
+
| `OVERSEER_MAX_DIFF_BYTES` | no | all | `262144` | Review diff byte cap. |
|
|
168
|
+
| `OVERSEER_TEST_TIMEOUT_MS` | no | all | `300000` | Validation timeout. |
|
|
169
|
+
| `OVERSEER_API_KEY` | yes | `openai`, `anthropic` | none | API key. |
|
|
170
|
+
| `OVERSEER_API_KEY_ENV` | no | `openai`, `anthropic` | none | Name of an env var containing the API key. Useful for MCP clients that forward secrets. |
|
|
171
|
+
| `OVERSEER_BASE_URL` | no | `openai`, `anthropic` | OpenAI/Anthropic default | API base URL. |
|
|
172
|
+
| `OVERSEER_MODEL` | yes | `openai`, `anthropic` | none | Expert model name. |
|
|
173
|
+
| `OVERSEER_MAX_OUTPUT_TOKENS` | no | `openai`, `anthropic` | tool-specific cap | Overrides output cap. |
|
|
174
|
+
| `OVERSEER_TEMPERATURE` | no | `openai`, `anthropic` | `0.2` | Deterministic output. |
|
|
175
|
+
| `OVERSEER_CLI_COMMAND` | yes | `cli` | none | CLI executable. |
|
|
176
|
+
| `OVERSEER_CLI_ARGS` | no | `cli` | empty | JSON string array or whitespace list. |
|
|
177
|
+
| `OVERSEER_CLI_PROMPT_VIA` | no | `cli` | `stdin` | `stdin` or `arg`. |
|
|
178
|
+
| `OVERSEER_CLI_TIMEOUT_MS` | no | `cli` | `120000` | CLI completion timeout. |
|
|
179
|
+
|
|
180
|
+
OpenAI-compatible endpoints include OpenAI, GLM/Zhipu gateways, opencode-style gateways, and local servers that implement chat completions.
|
|
181
|
+
|
|
182
|
+
## Executor System Instructions
|
|
183
|
+
|
|
184
|
+
Copy this block into the executor agent system prompt:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
You have an `overseer` expert advisor available via MCP tools. Use it like this:
|
|
188
|
+
1. Before writing any code, call get_plan with the user's request. Follow the plan.
|
|
189
|
+
2. While implementing, the moment you face a non-trivial design decision, an error you
|
|
190
|
+
don't fully understand, or an ambiguity - call consult_expert BEFORE improvising.
|
|
191
|
+
Attach the relevant file_paths and literal error_output. Do not guess on your own.
|
|
192
|
+
3. When done, call request_review. If it returns REQUEST_CHANGES, apply REQUIRED_FIXES
|
|
193
|
+
and review again. Only finish on APPROVE.
|
|
194
|
+
Always pass real file paths and real error text - the expert reads them from disk itself.
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Manual Smoke Test
|
|
198
|
+
|
|
199
|
+
Build first:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm install
|
|
203
|
+
npm run build
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Then inspect the server:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Use safe local env for listing tools, for example:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
OVERSEER_PROVIDER=cli OVERSEER_CLI_COMMAND=node OVERSEER_CLI_ARGS='["-e","process.stdin.resume()"]' npx @modelcontextprotocol/inspector node dist/index.js
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The tool list should contain exactly:
|
|
219
|
+
|
|
220
|
+
- `get_plan`
|
|
221
|
+
- `consult_expert`
|
|
222
|
+
- `request_review`
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm test
|
|
228
|
+
npm run build
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The tests cover config validation, path traversal refusal, prompt payload labels, tool context assembly, diff truncation, and stdio tool listing.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableExtensions EnableDelayedExpansion
|
|
3
|
+
|
|
4
|
+
cd /d "%~dp0"
|
|
5
|
+
|
|
6
|
+
echo.
|
|
7
|
+
echo overseer-mcp configurator
|
|
8
|
+
echo =========================
|
|
9
|
+
echo.
|
|
10
|
+
|
|
11
|
+
where node >nul 2>nul
|
|
12
|
+
if errorlevel 1 (
|
|
13
|
+
echo ERROR: node was not found in PATH.
|
|
14
|
+
exit /b 1
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
where npm >nul 2>nul
|
|
18
|
+
if errorlevel 1 (
|
|
19
|
+
echo ERROR: npm was not found in PATH.
|
|
20
|
+
exit /b 1
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if not exist "generated" mkdir "generated"
|
|
24
|
+
set "OUT_CODEX=generated\overseer-codex.toml"
|
|
25
|
+
set "OUT_JSON=generated\overseer-mcp.json"
|
|
26
|
+
set "REPO_JSON=overseer-mcp.json"
|
|
27
|
+
|
|
28
|
+
echo.
|
|
29
|
+
echo This wizard generates both MCP config formats:
|
|
30
|
+
echo - Codex operator: generated\overseer-codex.toml for project .codex\config.toml
|
|
31
|
+
echo - Generic JSON operator: generated\overseer-mcp.json for Qoder / Mimo / Cline / Roo / other MCP clients
|
|
32
|
+
echo The expert model is selected in the next step.
|
|
33
|
+
|
|
34
|
+
echo.
|
|
35
|
+
echo Expert profile:
|
|
36
|
+
echo 1. opencode-go or custom OpenAI-compatible API
|
|
37
|
+
echo 2. OpenAI API
|
|
38
|
+
echo 3. Anthropic API
|
|
39
|
+
echo 4. Codex CLI plan
|
|
40
|
+
echo 5. Claude CLI plan
|
|
41
|
+
set /p "EXPERT_CHOICE=Choose expert [1]: "
|
|
42
|
+
if "%EXPERT_CHOICE%"=="" set "EXPERT_CHOICE=1"
|
|
43
|
+
set "EXPERT_CHOICE=%EXPERT_CHOICE:~0,1%"
|
|
44
|
+
|
|
45
|
+
set "REPO_ROOT=%CD%\.."
|
|
46
|
+
for %%I in ("%REPO_ROOT%") do set "REPO_ROOT=%%~fI"
|
|
47
|
+
set /p "INPUT_REPO_ROOT=Repo root [%REPO_ROOT%]: "
|
|
48
|
+
if not "%INPUT_REPO_ROOT%"=="" set "REPO_ROOT=%INPUT_REPO_ROOT%"
|
|
49
|
+
|
|
50
|
+
set "TEST_COMMAND="
|
|
51
|
+
set /p "TEST_COMMAND=Validation command, empty to skip: "
|
|
52
|
+
|
|
53
|
+
if "%EXPERT_CHOICE%"=="1" goto custom_api
|
|
54
|
+
if "%EXPERT_CHOICE%"=="2" goto openai_api
|
|
55
|
+
if "%EXPERT_CHOICE%"=="3" goto anthropic_api
|
|
56
|
+
if "%EXPERT_CHOICE%"=="4" goto codex_cli
|
|
57
|
+
if "%EXPERT_CHOICE%"=="5" goto claude_cli
|
|
58
|
+
|
|
59
|
+
echo ERROR: invalid expert choice.
|
|
60
|
+
exit /b 1
|
|
61
|
+
|
|
62
|
+
:custom_api
|
|
63
|
+
set "PROFILE_NAME=overseer-opencode"
|
|
64
|
+
set "KEY_ENV_NAME=OPENCODE_API_KEY"
|
|
65
|
+
set "BASE_URL=https://api.opencode.example/v1"
|
|
66
|
+
set "MODEL_NAME=opencode-go"
|
|
67
|
+
set /p "INPUT_PROFILE=MCP profile name [%PROFILE_NAME%]: "
|
|
68
|
+
if not "%INPUT_PROFILE%"=="" set "PROFILE_NAME=%INPUT_PROFILE%"
|
|
69
|
+
set /p "INPUT_KEY_ENV=Secret env var name [%KEY_ENV_NAME%]: "
|
|
70
|
+
if not "%INPUT_KEY_ENV%"=="" set "KEY_ENV_NAME=%INPUT_KEY_ENV%"
|
|
71
|
+
set /p "INPUT_BASE_URL=OpenAI-compatible base URL [%BASE_URL%]: "
|
|
72
|
+
if not "%INPUT_BASE_URL%"=="" set "BASE_URL=%INPUT_BASE_URL%"
|
|
73
|
+
set /p "INPUT_MODEL=Model name [%MODEL_NAME%]: "
|
|
74
|
+
if not "%INPUT_MODEL%"=="" set "MODEL_NAME=%INPUT_MODEL%"
|
|
75
|
+
call :run_init_api openai-compatible "%PROFILE_NAME%" "%KEY_ENV_NAME%" "%BASE_URL%" "%MODEL_NAME%"
|
|
76
|
+
if errorlevel 1 goto fail
|
|
77
|
+
goto install
|
|
78
|
+
|
|
79
|
+
:openai_api
|
|
80
|
+
set "PROFILE_NAME=overseer-gpt"
|
|
81
|
+
set "KEY_ENV_NAME=OPENAI_API_KEY"
|
|
82
|
+
set "MODEL_NAME=gpt-5.5"
|
|
83
|
+
set /p "INPUT_PROFILE=MCP profile name [%PROFILE_NAME%]: "
|
|
84
|
+
if not "%INPUT_PROFILE%"=="" set "PROFILE_NAME=%INPUT_PROFILE%"
|
|
85
|
+
set /p "INPUT_KEY_ENV=Secret env var name [%KEY_ENV_NAME%]: "
|
|
86
|
+
if not "%INPUT_KEY_ENV%"=="" set "KEY_ENV_NAME=%INPUT_KEY_ENV%"
|
|
87
|
+
set /p "INPUT_MODEL=Model name [%MODEL_NAME%]: "
|
|
88
|
+
if not "%INPUT_MODEL%"=="" set "MODEL_NAME=%INPUT_MODEL%"
|
|
89
|
+
call :run_init_api openai "%PROFILE_NAME%" "%KEY_ENV_NAME%" "" "%MODEL_NAME%"
|
|
90
|
+
if errorlevel 1 goto fail
|
|
91
|
+
goto install
|
|
92
|
+
|
|
93
|
+
:anthropic_api
|
|
94
|
+
set "PROFILE_NAME=overseer-claude"
|
|
95
|
+
set "KEY_ENV_NAME=ANTHROPIC_API_KEY"
|
|
96
|
+
set "MODEL_NAME=claude-your-model"
|
|
97
|
+
set /p "INPUT_PROFILE=MCP profile name [%PROFILE_NAME%]: "
|
|
98
|
+
if not "%INPUT_PROFILE%"=="" set "PROFILE_NAME=%INPUT_PROFILE%"
|
|
99
|
+
set /p "INPUT_KEY_ENV=Secret env var name [%KEY_ENV_NAME%]: "
|
|
100
|
+
if not "%INPUT_KEY_ENV%"=="" set "KEY_ENV_NAME=%INPUT_KEY_ENV%"
|
|
101
|
+
set /p "INPUT_MODEL=Model name [%MODEL_NAME%]: "
|
|
102
|
+
if not "%INPUT_MODEL%"=="" set "MODEL_NAME=%INPUT_MODEL%"
|
|
103
|
+
call :run_init_api anthropic "%PROFILE_NAME%" "%KEY_ENV_NAME%" "" "%MODEL_NAME%"
|
|
104
|
+
if errorlevel 1 goto fail
|
|
105
|
+
goto install
|
|
106
|
+
|
|
107
|
+
:codex_cli
|
|
108
|
+
set "PROFILE_NAME=overseer-codex-cli"
|
|
109
|
+
set /p "INPUT_PROFILE=MCP profile name [%PROFILE_NAME%]: "
|
|
110
|
+
if not "%INPUT_PROFILE%"=="" set "PROFILE_NAME=%INPUT_PROFILE%"
|
|
111
|
+
call :run_init_cli "%PROFILE_NAME%" codex "[\"exec\"]"
|
|
112
|
+
if errorlevel 1 goto fail
|
|
113
|
+
goto install
|
|
114
|
+
|
|
115
|
+
:claude_cli
|
|
116
|
+
set "PROFILE_NAME=overseer-claude-cli"
|
|
117
|
+
set /p "INPUT_PROFILE=MCP profile name [%PROFILE_NAME%]: "
|
|
118
|
+
if not "%INPUT_PROFILE%"=="" set "PROFILE_NAME=%INPUT_PROFILE%"
|
|
119
|
+
call :run_init_cli "%PROFILE_NAME%" claude "[\"-p\"]"
|
|
120
|
+
if errorlevel 1 goto fail
|
|
121
|
+
goto install
|
|
122
|
+
|
|
123
|
+
:run_init_api
|
|
124
|
+
call :ensure_build
|
|
125
|
+
if errorlevel 1 goto fail
|
|
126
|
+
set "EXPERT=%~1"
|
|
127
|
+
set "PROFILE=%~2"
|
|
128
|
+
set "ENV_NAME=%~3"
|
|
129
|
+
set "URL=%~4"
|
|
130
|
+
set "MODEL=%~5"
|
|
131
|
+
set "BASE_ARGS=--print --name "%PROFILE%" --expert %EXPERT% --repo-root "%REPO_ROOT%" --api-key-env "%ENV_NAME%" --model "%MODEL%""
|
|
132
|
+
if not "%TEST_COMMAND%"=="" set "BASE_ARGS=%BASE_ARGS% --test-command "%TEST_COMMAND%""
|
|
133
|
+
if not "%URL%"=="" set "BASE_ARGS=%BASE_ARGS% --base-url "%URL%""
|
|
134
|
+
node dist\index.js init %BASE_ARGS% --target codex > "%OUT_CODEX%"
|
|
135
|
+
if errorlevel 1 goto fail
|
|
136
|
+
node dist\index.js init %BASE_ARGS% --target json > "%OUT_JSON%"
|
|
137
|
+
if errorlevel 1 goto fail
|
|
138
|
+
node dist\index.js instructions --print --mcp-name "%PROFILE%" > "generated\OVERSEER_AGENT_INSTRUCTIONS.md"
|
|
139
|
+
if errorlevel 1 goto fail
|
|
140
|
+
exit /b 0
|
|
141
|
+
|
|
142
|
+
:run_init_cli
|
|
143
|
+
call :ensure_build
|
|
144
|
+
if errorlevel 1 goto fail
|
|
145
|
+
set "PROFILE=%~1"
|
|
146
|
+
set "CLI_COMMAND=%~2"
|
|
147
|
+
set "CLI_ARGS=%~3"
|
|
148
|
+
set "LOGIN_FLAG="
|
|
149
|
+
if /I "%CLI_COMMAND%"=="codex" (
|
|
150
|
+
echo Checking Codex CLI config...
|
|
151
|
+
node dist\index.js codex-config
|
|
152
|
+
if errorlevel 1 exit /b 1
|
|
153
|
+
)
|
|
154
|
+
echo Login is stored by the CLI (%CLI_COMMAND%), not by overseer-mcp.
|
|
155
|
+
echo Re-running this configurator does not delete an existing CLI login.
|
|
156
|
+
echo If you are already logged in, answer no.
|
|
157
|
+
echo If login hangs, close this window and run "%CLI_COMMAND% login" manually in a terminal.
|
|
158
|
+
set /p "RUN_LOGIN=Run CLI login now? yes/no [no]: "
|
|
159
|
+
if /I "%RUN_LOGIN%"=="yes" set "LOGIN_FLAG=--run-login"
|
|
160
|
+
set "BASE_ARGS=--print --name "%PROFILE%" --expert cli --repo-root "%REPO_ROOT%" --cli-command "%CLI_COMMAND%" --cli-args "%CLI_ARGS%" %LOGIN_FLAG%"
|
|
161
|
+
if not "%TEST_COMMAND%"=="" set "BASE_ARGS=%BASE_ARGS% --test-command "%TEST_COMMAND%""
|
|
162
|
+
node dist\index.js init %BASE_ARGS% --target codex > "%OUT_CODEX%"
|
|
163
|
+
if errorlevel 1 goto fail
|
|
164
|
+
node dist\index.js init %BASE_ARGS% --target json > "%OUT_JSON%"
|
|
165
|
+
if errorlevel 1 goto fail
|
|
166
|
+
node dist\index.js instructions --print --mcp-name "%PROFILE%" > "generated\OVERSEER_AGENT_INSTRUCTIONS.md"
|
|
167
|
+
if errorlevel 1 goto fail
|
|
168
|
+
exit /b 0
|
|
169
|
+
|
|
170
|
+
:install
|
|
171
|
+
echo.
|
|
172
|
+
echo Generated MCP configs:
|
|
173
|
+
echo Codex operator: %CD%\%OUT_CODEX%
|
|
174
|
+
echo JSON operator: %CD%\%OUT_JSON%
|
|
175
|
+
echo Local MCP JSON: %REPO_ROOT%\%REPO_JSON%
|
|
176
|
+
echo Generated operator instructions:
|
|
177
|
+
echo %CD%\generated\OVERSEER_AGENT_INSTRUCTIONS.md
|
|
178
|
+
echo.
|
|
179
|
+
if exist "%REPO_ROOT%\%REPO_JSON%" (
|
|
180
|
+
copy "%REPO_ROOT%\%REPO_JSON%" "%REPO_ROOT%\%REPO_JSON%.backup-%RANDOM%" >nul
|
|
181
|
+
)
|
|
182
|
+
copy "%OUT_JSON%" "%REPO_ROOT%\%REPO_JSON%" >nul
|
|
183
|
+
echo Copied local MCP JSON to %REPO_ROOT%\%REPO_JSON%
|
|
184
|
+
echo.
|
|
185
|
+
echo JSON config preview:
|
|
186
|
+
type "%OUT_JSON%"
|
|
187
|
+
echo.
|
|
188
|
+
|
|
189
|
+
echo.
|
|
190
|
+
set /p "INSTALL_CODEX=If your cheap operator is Codex, append Codex MCP config to project .codex\config.toml with backup? yes/no [no]: "
|
|
191
|
+
if /I not "%INSTALL_CODEX%"=="yes" goto done
|
|
192
|
+
|
|
193
|
+
if not exist "%REPO_ROOT%\.codex" mkdir "%REPO_ROOT%\.codex"
|
|
194
|
+
if exist "%REPO_ROOT%\.codex\config.toml" (
|
|
195
|
+
copy "%REPO_ROOT%\.codex\config.toml" "%REPO_ROOT%\.codex\config.toml.backup-%RANDOM%" >nul
|
|
196
|
+
)
|
|
197
|
+
echo.>> "%REPO_ROOT%\.codex\config.toml"
|
|
198
|
+
type "%OUT_CODEX%" >> "%REPO_ROOT%\.codex\config.toml"
|
|
199
|
+
echo Installed in %REPO_ROOT%\.codex\config.toml
|
|
200
|
+
echo Restart Codex or run /mcp to verify the server appears.
|
|
201
|
+
goto done
|
|
202
|
+
|
|
203
|
+
:done
|
|
204
|
+
echo.
|
|
205
|
+
set /p "APPEND_AGENTS=Append operator instructions to repo AGENTS.md with backup? yes/no [no]: "
|
|
206
|
+
if /I "%APPEND_AGENTS%"=="yes" (
|
|
207
|
+
if exist "%REPO_ROOT%\AGENTS.md" (
|
|
208
|
+
copy "%REPO_ROOT%\AGENTS.md" "%REPO_ROOT%\AGENTS.md.backup-%RANDOM%" >nul
|
|
209
|
+
)
|
|
210
|
+
echo.>> "%REPO_ROOT%\AGENTS.md"
|
|
211
|
+
type "generated\OVERSEER_AGENT_INSTRUCTIONS.md" >> "%REPO_ROOT%\AGENTS.md"
|
|
212
|
+
echo Appended instructions to %REPO_ROOT%\AGENTS.md
|
|
213
|
+
)
|
|
214
|
+
echo.
|
|
215
|
+
echo Next checks:
|
|
216
|
+
echo 1. Ensure the secret env var exists in the environment that starts your agent.
|
|
217
|
+
echo 2. For Qoder / Mimo / Cline / Roo, import or paste %REPO_ROOT%\%REPO_JSON% into that client's MCP settings.
|
|
218
|
+
echo 3. Restart the agent or reload MCP servers.
|
|
219
|
+
echo 4. Ask the agent to list MCP tools and look for get_plan, consult_expert, request_review.
|
|
220
|
+
exit /b 0
|
|
221
|
+
|
|
222
|
+
:ensure_build
|
|
223
|
+
echo.
|
|
224
|
+
echo Installing dependencies and building overseer-mcp...
|
|
225
|
+
call npm install
|
|
226
|
+
if errorlevel 1 exit /b 1
|
|
227
|
+
call npm run build
|
|
228
|
+
if errorlevel 1 exit /b 1
|
|
229
|
+
exit /b 0
|
|
230
|
+
|
|
231
|
+
:fail
|
|
232
|
+
echo.
|
|
233
|
+
echo ERROR: configuration failed.
|
|
234
|
+
echo If this happened during CLI login, run the login command manually in a normal terminal to see the full error.
|
|
235
|
+
echo Example: codex login
|
|
236
|
+
echo.
|
|
237
|
+
echo Press any key to close this window.
|
|
238
|
+
pause >nul
|
|
239
|
+
exit /b 1
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { findGitRoot } from "./repo/findRoot.js";
|
|
3
|
+
import { AnthropicProvider } from "./providers/anthropic.js";
|
|
4
|
+
import { CliProvider } from "./providers/cli.js";
|
|
5
|
+
import { OpenAICompatibleProvider } from "./providers/openaiCompatible.js";
|
|
6
|
+
/** Returns a copy of `config` with `repoRoot` overridden to `newRoot`. */
|
|
7
|
+
export function withRepoRoot(config, newRoot) {
|
|
8
|
+
const resolved = findGitRoot(newRoot) ?? path.resolve(newRoot);
|
|
9
|
+
if (resolved === config.repoRoot)
|
|
10
|
+
return config;
|
|
11
|
+
return { ...config, repoRoot: resolved };
|
|
12
|
+
}
|
|
13
|
+
function required(env, name) {
|
|
14
|
+
const value = env[name];
|
|
15
|
+
if (!value) {
|
|
16
|
+
throw new Error(`Missing required environment variable: ${name}`);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function apiKey(env) {
|
|
21
|
+
if (env.OVERSEER_API_KEY) {
|
|
22
|
+
return env.OVERSEER_API_KEY;
|
|
23
|
+
}
|
|
24
|
+
const keyEnvName = env.OVERSEER_API_KEY_ENV;
|
|
25
|
+
if (!keyEnvName) {
|
|
26
|
+
throw new Error("Missing required environment variable: OVERSEER_API_KEY");
|
|
27
|
+
}
|
|
28
|
+
const value = env[keyEnvName];
|
|
29
|
+
if (!value) {
|
|
30
|
+
throw new Error(`Missing required environment variable: ${keyEnvName} (from OVERSEER_API_KEY_ENV)`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
function optionalNumber(env, name, fallback) {
|
|
35
|
+
const raw = env[name];
|
|
36
|
+
if (!raw)
|
|
37
|
+
return fallback;
|
|
38
|
+
const parsed = Number(raw);
|
|
39
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
40
|
+
throw new Error(`Invalid ${name}: expected a positive number`);
|
|
41
|
+
}
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
function optionalNumberAllowZero(env, name, fallback) {
|
|
45
|
+
const raw = env[name];
|
|
46
|
+
if (!raw)
|
|
47
|
+
return fallback;
|
|
48
|
+
const parsed = Number(raw);
|
|
49
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
50
|
+
throw new Error(`Invalid ${name}: expected a non-negative number`);
|
|
51
|
+
}
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
function optionalPositiveNumber(env, name) {
|
|
55
|
+
const raw = env[name];
|
|
56
|
+
if (!raw)
|
|
57
|
+
return undefined;
|
|
58
|
+
const parsed = Number(raw);
|
|
59
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
60
|
+
throw new Error(`Invalid ${name}: expected a positive number`);
|
|
61
|
+
}
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
function optionalTemperature(env) {
|
|
65
|
+
const raw = env.OVERSEER_TEMPERATURE;
|
|
66
|
+
if (!raw)
|
|
67
|
+
return undefined;
|
|
68
|
+
const parsed = Number(raw);
|
|
69
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 2) {
|
|
70
|
+
throw new Error("Invalid OVERSEER_TEMPERATURE: expected a number between 0 and 2");
|
|
71
|
+
}
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
function parseCliArgs(raw) {
|
|
75
|
+
if (!raw)
|
|
76
|
+
return [];
|
|
77
|
+
const trimmed = raw.trim();
|
|
78
|
+
if (!trimmed)
|
|
79
|
+
return [];
|
|
80
|
+
if (trimmed.startsWith("[")) {
|
|
81
|
+
const parsed = JSON.parse(trimmed);
|
|
82
|
+
if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === "string")) {
|
|
83
|
+
throw new Error("Invalid OVERSEER_CLI_ARGS: expected a JSON string array");
|
|
84
|
+
}
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
return trimmed.split(/\s+/);
|
|
88
|
+
}
|
|
89
|
+
function buildProvider(env, repoRoot) {
|
|
90
|
+
const provider = required(env, "OVERSEER_PROVIDER");
|
|
91
|
+
const maxTokens = optionalPositiveNumber(env, "OVERSEER_MAX_OUTPUT_TOKENS");
|
|
92
|
+
const temperature = optionalTemperature(env);
|
|
93
|
+
if (provider === "openai") {
|
|
94
|
+
return new OpenAICompatibleProvider({
|
|
95
|
+
apiKey: apiKey(env),
|
|
96
|
+
baseUrl: env.OVERSEER_BASE_URL ?? "https://api.openai.com/v1",
|
|
97
|
+
model: required(env, "OVERSEER_MODEL"),
|
|
98
|
+
maxTokens,
|
|
99
|
+
temperature,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (provider === "anthropic") {
|
|
103
|
+
return new AnthropicProvider({
|
|
104
|
+
apiKey: apiKey(env),
|
|
105
|
+
baseUrl: env.OVERSEER_BASE_URL,
|
|
106
|
+
model: required(env, "OVERSEER_MODEL"),
|
|
107
|
+
maxTokens,
|
|
108
|
+
temperature,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (provider === "cli") {
|
|
112
|
+
const promptVia = env.OVERSEER_CLI_PROMPT_VIA ?? "stdin";
|
|
113
|
+
if (promptVia !== "stdin" && promptVia !== "arg") {
|
|
114
|
+
throw new Error("Invalid OVERSEER_CLI_PROMPT_VIA: expected stdin or arg");
|
|
115
|
+
}
|
|
116
|
+
return new CliProvider({
|
|
117
|
+
command: required(env, "OVERSEER_CLI_COMMAND"),
|
|
118
|
+
args: parseCliArgs(env.OVERSEER_CLI_ARGS),
|
|
119
|
+
promptVia,
|
|
120
|
+
timeoutMs: optionalNumber(env, "OVERSEER_CLI_TIMEOUT_MS", 120000),
|
|
121
|
+
cwd: repoRoot,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
throw new Error("Invalid OVERSEER_PROVIDER: expected openai, anthropic, or cli");
|
|
125
|
+
}
|
|
126
|
+
export function loadConfig(env = process.env, cwd = process.cwd()) {
|
|
127
|
+
// Prefer the first candidate that actually sits inside a git repo. VSCODE_CWD
|
|
128
|
+
// can point at the IDE install directory (e.g. ...\Programs\Trae) rather than
|
|
129
|
+
// the open project, which would root the expert at the wrong/empty repo.
|
|
130
|
+
const candidates = [env.OVERSEER_REPO_ROOT, env.VSCODE_CWD, cwd].filter((value) => Boolean(value));
|
|
131
|
+
let repoRoot;
|
|
132
|
+
for (const candidate of candidates) {
|
|
133
|
+
const root = findGitRoot(candidate);
|
|
134
|
+
if (root) {
|
|
135
|
+
repoRoot = root;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
repoRoot ??= path.resolve(env.OVERSEER_REPO_ROOT ?? cwd);
|
|
140
|
+
return {
|
|
141
|
+
provider: buildProvider(env, repoRoot),
|
|
142
|
+
repoRoot,
|
|
143
|
+
testCommand: env.OVERSEER_TEST_COMMAND,
|
|
144
|
+
maxFiles: optionalNumber(env, "OVERSEER_MAX_FILES", 12),
|
|
145
|
+
planFullFiles: optionalNumberAllowZero(env, "OVERSEER_PLAN_FULL_FILES", 0),
|
|
146
|
+
maxFileBytes: optionalNumber(env, "OVERSEER_MAX_FILE_BYTES", 65536),
|
|
147
|
+
maxDiffBytes: optionalNumber(env, "OVERSEER_MAX_DIFF_BYTES", 262144),
|
|
148
|
+
testTimeoutMs: optionalNumber(env, "OVERSEER_TEST_TIMEOUT_MS", 300000),
|
|
149
|
+
};
|
|
150
|
+
}
|