Skip to content

Refactor/pure mcp runtime - #139

Open
ssfxx0923 wants to merge 4 commits into
Waishnav:mainfrom
ssfxx0923:refactor/pure-mcp-runtime
Open

Refactor/pure mcp runtime#139
ssfxx0923 wants to merge 4 commits into
Waishnav:mainfrom
ssfxx0923:refactor/pure-mcp-runtime

Conversation

@ssfxx0923

@ssfxx0923 ssfxx0923 commented Aug 7, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Added a streamlined local coding runtime with workspace, file, patch, shell, process, worktree, authentication, and review capabilities.
    • Native tool mode is now the default, including support for unsandboxed local shell operations where configured.
  • Updates

    • Removed local agent, subagent, and model-provider workflows from the product experience.
    • Existing codex tool-mode settings are automatically mapped to native.
    • Updated the minimum supported Node.js version and refreshed user-facing documentation.
    • Added automated validation to ensure refactoring changes remain buildable and tested.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

DevSpace becomes a pure MCP execution runtime. The refactor removes local-agent providers, profiles, subagent configuration, and agent CLI commands. Native mode becomes the default, with legacy codex compatibility. A workflow applies and verifies the refactor.

Changes

Pure MCP runtime

Layer / File(s) Summary
Architecture cleanup
docs/pure-mcp-refactor-plan.md, scripts/refactor-pure-mcp.mjs
Defines the pure MCP runtime plan and removes provider dependencies, local-agent sources, and packaged skills.
Configuration, CLI, and workspace state
scripts/refactor-pure-mcp.mjs, src/config.ts
Makes native the default mode, maps legacy codex to native, disables subagents in native mode, removes agent settings and CLI commands, raises the Node.js range, and removes model profiles from workspace state.
Native server surface
scripts/refactor-pure-mcp.mjs
Removes server-side agent metadata and provider data. Native tools expose host-driven process operations with unsandboxed shell descriptions.
Validation and documentation
scripts/refactor-pure-mcp.mjs
Updates tests and project guidance for the pure MCP architecture and adds a source scan for remaining agent references.
Automated refactor application
.github/workflows/pure-mcp-refactor.yml
Runs the deterministic refactor, installs dependencies, verifies the project, and commits and pushes the result.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: waishnav

Poem

A rabbit checks the native trail,
MCP tools now guide the way.
Old agent paths leave no trace,
Codex maps to native space,
And tests keep watch today.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: refactoring the project into a pure MCP runtime.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a plan and a one-shot migration script intended to convert DevSpace from a local-agent orchestrator into a pure MCP execution runtime.

  • Removes model-provider dependencies, source modules, CLI commands, configuration, and workspace metadata.
  • Renames the Codex-style tool mode to native while preserving codex as a compatibility alias.
  • Rewrites tests and project-facing documentation for the host-driven runtime.

Confidence Score: 3/5

This PR should not merge until the refactor is applied through the repository workflow and its dependency lockfile remains synchronized.

Normal builds never execute the migration, so the advertised runtime changes are absent, while manually executing it produces package metadata that npm ci cannot install.

Files Needing Attention: scripts/refactor-pure-mcp.mjs

Important Files Changed

Filename Overview
scripts/refactor-pure-mcp.mjs Implements the migration, but is not invoked by repository workflows and leaves the npm lockfile inconsistent after dependency removal.
docs/pure-mcp-refactor-plan.md Clearly documents the intended pure-MCP architecture, compatibility alias, and shell security boundary.

Reviews (1): Last reviewed commit: "docs: add pure MCP refactor notes" | Re-trigger Greptile

}

// package.json: remove model-provider runtimes. DevSpace remains a pure MCP execution layer.
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Refactor never reaches build workflows

Normal install, build, test, and publish workflows never invoke this standalone script, so they continue using the existing local-agent runtime, provider dependencies, agents command, and old tool-mode behavior instead of producing the pure-MCP runtime described by this PR.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +32 to +39
for (const dependency of [
"@agentclientprotocol/sdk",
"@anthropic-ai/claude-agent-sdk",
"@openai/codex-sdk",
"@opencode-ai/sdk",
]) {
delete pkg.dependencies[dependency];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Dependency lockfile becomes inconsistent

When a developer runs this refactor and then uses the documented npm ci workflow, the script removes four root dependencies from package.json without updating package-lock.json, causing npm to reject the inconsistent manifests and block installation and CI.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/refactor-pure-mcp.mjs`:
- Around line 27-45: Run scripts/refactor-pure-mcp.mjs from a clean checkout and
commit all generated runtime, test, documentation, and lockfile changes so
packaged npm/npx usage, CLI startup, and server startup no longer expose the
removed model-provider runtimes. In docs/pure-mcp-refactor-plan.md lines 3-34,
retain the completed-refactor statements only after those generated changes are
included; otherwise rewrite them as a future migration plan. Verify the actual
packaged user path and real MCP host behavior.
- Around line 362-371: Update the source scan around remainingSourceRefs to
recursively walk all files under src, including nested directories, while
limiting checks to .ts and .tsx files. Ensure every local-agent-* import
discovered at any depth is included in the existing replacement flow, preserving
the current subagents and agentProfiles checks.
- Around line 284-354: Extend the generated test coverage beyond source-level
tsx tests to install and invoke the packaged dist/cli.js entry from
package.json. Add MCP host/session tests covering connection, restart behavior,
and exec_command file mutations in both checkout and worktree modes, and
validate rendered artifact or workspace-card payloads when affected by these
changes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8021b35d-78bb-40f7-aca9-6086d6c89396

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd0378 and 6f365b1.

📒 Files selected for processing (2)
  • docs/pure-mcp-refactor-plan.md
  • scripts/refactor-pure-mcp.mjs

Comment on lines +27 to +45
// package.json: remove model-provider runtimes. DevSpace remains a pure MCP execution layer.
{
const path = "package.json";
const pkg = JSON.parse(read(path));
pkg.description = "Pure local MCP coding runtime for ChatGPT and other MCP hosts.";
for (const dependency of [
"@agentclientprotocol/sdk",
"@anthropic-ai/claude-agent-sdk",
"@openai/codex-sdk",
"@opencode-ai/sdk",
]) {
delete pkg.dependencies[dependency];
}
pkg.files = pkg.files.filter((entry) => entry !== "skills");
pkg.scripts.test = pkg.scripts.test
.split(" && ")
.filter((command) => !command.includes("local-agent-"))
.join(" && ");
write(path, JSON.stringify(pkg, null, 2));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Commit the generated runtime refactor before merge.

This PR supplies a standalone mutation script, but normal npm/npx use, CLI startup, and server startup do not run it. The supplied src/config.ts and src/cli.ts context still exposes "codex" and devspace agents, so users will continue to receive the old runtime.

  • scripts/refactor-pure-mcp.mjs#L27-L45: Run the migration from a clean checkout and commit every generated runtime, test, documentation, and lockfile change.
  • docs/pure-mcp-refactor-plan.md#L3-L34: Keep these statements only after the generated runtime changes are present in the PR; otherwise describe this file as a future migration plan.

As per coding guidelines, verify the actual user-consumption path, including packaged npm/npx usage and real MCP hosts.

📍 Affects 2 files
  • scripts/refactor-pure-mcp.mjs#L27-L45 (this comment)
  • docs/pure-mcp-refactor-plan.md#L3-L34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/refactor-pure-mcp.mjs` around lines 27 - 45, Run
scripts/refactor-pure-mcp.mjs from a clean checkout and commit all generated
runtime, test, documentation, and lockfile changes so packaged npm/npx usage,
CLI startup, and server startup no longer expose the removed model-provider
runtimes. In docs/pure-mcp-refactor-plan.md lines 3-34, retain the
completed-refactor statements only after those generated changes are included;
otherwise rewrite them as a future migration plan. Verify the actual packaged
user path and real MCP host behavior.

Source: Coding guidelines

Comment on lines +284 to +354
// Tests: preserve behavior coverage while removing model-provider expectations.
{
const path = "src/cli.test.ts";
write(path, `import assert from "node:assert/strict";\nimport { execFileSync } from "node:child_process";\nimport { readFileSync } from "node:fs";\n\nconst packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")) as {\n version: string;\n};\n\nfor (const flag of ["-v", "--version"]) {\n const output = execFileSync("node", ["--import", "tsx", "src/cli.ts", flag], {\n encoding: "utf8",\n env: { ...process.env, DEVSPACE_CONFIG_DIR: "/tmp/devspace-cli-version-test" },\n }).trim();\n assert.equal(output, packageJson.version);\n}\n\nconst help = execFileSync("node", ["--import", "tsx", "src/cli.ts", "--help"], {\n encoding: "utf8",\n env: { ...process.env, DEVSPACE_CONFIG_DIR: "/tmp/devspace-cli-help-test" },\n});\nassert.doesNotMatch(help, /devspace agents/);\n`);
}

{
const path = "src/config.test.ts";
let source = read(path);
source = replaceOnce(source, 'import { existsSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";', 'import { mkdtempSync, writeFileSync } from "node:fs";', "config test fs import");
source = replaceOnce(source, 'import { ensureDevspaceDefaultSkills, resolveSubagentsFlag } from "./user-config.js";\n', "", "config test subagent import");
source = replaceOnce(source, 'assert.equal(loadConfig(baseEnv).toolMode, "minimal");', 'assert.equal(loadConfig(baseEnv).toolMode, "native");', "default native test");
source = replaceOnce(source, 'assert.equal(loadConfig({ ...baseEnv, DEVSPACE_TOOL_MODE: "codex" }).toolMode, "codex");', 'assert.equal(loadConfig({ ...baseEnv, DEVSPACE_TOOL_MODE: "native" }).toolMode, "native");\nassert.equal(loadConfig({ ...baseEnv, DEVSPACE_TOOL_MODE: "codex" }).toolMode, "native");', "native and legacy codex test");
source = replaceRegex(
source,
/assert\.equal\(loadConfig\(baseEnv\)\.devspaceAgentsDir[\s\S]*?assert\.deepEqual\(ensureDevspaceDefaultSkills\([^\n]*\), \[\]\);\n/,
"",
"config subagent tests",
);
source = source.replace(' subagents: true,\n', "");
source = source.replace('assert.equal(fileConfig.subagents, true);\n', "");
write(path, source);
}

{
const path = "src/workspaces.test.ts";
let source = read(path);
source = replaceRegex(
source,
/\n assert\.deepEqual\(\n opened\.workspace\.agentProfiles[\s\S]*?\n \);\n/,
"\n",
"workspace profile assertion",
);
write(path, source);
}

{
const path = "src/workspace-conversation.test.ts";
let source = read(path);
source = source.replace(' assert.deepEqual(second.workspace.agentProfiles, first.workspace.agentProfiles);\n', "");
source = replaceRegex(
source,
/test\("a failed first context load[\s\S]*?(?=\ntest\("a context-loading failure)/,
"",
"conversation failed profile load test",
);
source = replaceRegex(
source,
/test\("a context-loading failure[\s\S]*?(?=\ntest\("a deleted checkout)/,
"",
"conversation profile recovery test",
);
write(path, source);
}

{
const path = "src/server.test.ts";
let source = read(path);
source = source.replace(/^.*\.agentProviders\b.*\n/gm, "");
source = source.replace(/^.*\.agents\b.*\n/gm, "");
source = source.replace(/(new ProcessSessionManager\(\),\n\s*)\[\],\n\s*\[\],/g, "$1[],");
source = replaceOnce(source, 'async function fixture(t: TestContext, options: { git?: boolean } = {}): Promise<ServerFixture> {', 'async function fixture(t: TestContext, options: { git?: boolean; toolMode?: "full" | "native" } = {}): Promise<ServerFixture> {', "server fixture options");
source = replaceOnce(source, ' DEVSPACE_TOOL_MODE: "full",', ' DEVSPACE_TOOL_MODE: options.toolMode ?? "full",', "server fixture tool mode");
source = replaceOnce(
source,
'\ninterface ServerFixture {',
`\ntest("native mode exposes host-driven CLI tools without subagent metadata", async (t) => {\n const context = await fixture(t, { toolMode: "native" });\n const tools = await context.client.listTools();\n const names = new Set(tools.tools.map((tool) => tool.name));\n\n for (const name of ["open_workspace", "read", "grep", "glob", "ls", "apply_patch", "exec_command", "write_stdin"]) {\n assert.equal(names.has(name), true, \`missing native tool: \${name}\`);\n }\n for (const name of ["bash", "write", "edit"]) {\n assert.equal(names.has(name), false, \`unexpected legacy tool: \${name}\`);\n }\n const execTool = tools.tools.find((tool) => tool.name === "exec_command");\n assert.match(execTool?.description ?? "", /rm, mv, cp, mkdir/);\n});\n\ninterface ServerFixture {`,
"native server surface test",
);
write(path, source);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Add release-path coverage for the npm package and MCP runtime.

The added tests only exercise uncompiled src/cli.ts through tsx and check listed tool names/descriptions. Add coverage that installs the built artifact from package.json (dist/cli.js), invokes the published CLI entry point, connects through an MCP host/session, exercises restart behavior, and executes exec_command file mutations in checkout and worktree modes. Include rendered artifact or workspace-card payload validation if these changes affect those fields.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/refactor-pure-mcp.mjs` around lines 284 - 354, Extend the generated
test coverage beyond source-level tsx tests to install and invoke the packaged
dist/cli.js entry from package.json. Add MCP host/session tests covering
connection, restart behavior, and exec_command file mutations in both checkout
and worktree modes, and validate rendered artifact or workspace-card payloads
when affected by these changes.

Comment on lines +362 to +371
const remainingSourceRefs = readdirSync("src")
.filter((name) => name.endsWith(".ts") || name.endsWith(".tsx"))
.flatMap((name) => {
const content = read(join("src", name));
const hits = [];
if (content.includes("local-agent-")) hits.push(`${name}: local-agent import`);
if (/\bsubagents\b/.test(content)) hits.push(`${name}: subagents`);
if (/\bagentProfiles\b/.test(content)) hits.push(`${name}: agentProfiles`);
return hits;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "All TypeScript source files:"
find src -type f \( -name '*.ts' -o -name '*.tsx' \) -print | sort

echo "Files covered by the current flat scan:"
find src -maxdepth 1 -type f \( -name '*.ts' -o -name '*.tsx' \) -print | sort

Repository: Waishnav/devspace

Length of output: 3099


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Candidate files:"
fd -a 'refactor-pure-mcp\.mjs$' . || true

file="$(fd 'refactor-pure-mcp\.mjs$' . | head -n 1)"
if [ -n "$file" ]; then
  echo "File: $file"
  wc -l "$file"
  echo
  echo "Context around lines 330-385:"
  sed -n '330,385p' "$file" | cat -n | sed 's/^/  /'
  echo
  echo "Occurrences of remainingSourceRefs:"
  rg -n "remainingSourceRefs|readdirSync\\(\"src\"" "$file" || true
fi

echo
echo "Search all files for removed-agent artifacts that may be active in nested directories:"
for term in "local-agent-|subagents agentProfiles"; do
  echo "### $term"
  rg -n "$term" src .github scripts --glob '!**/node_modules/**' | head -n 120 || true
done

Repository: Waishnav/devspace

Length of output: 11857


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from os import readlink, walk
from pathlib import PurePath

root = "src"
files = (path for _, _, fnames in walk(root) for fname in fnames if fname.endswith((".ts", ".tsx")))
print("Nested TypeScript files:")
for path in sorted(files):
    p = PurePath(path)
    if len(p.parts) > 2:
        print(path)

print("\nDirectories nested under src:")
nested = sorted(dirpath for dirpath, _, _ in walk(root) if dirpath != root)
for dirpath in nested:
    print(dirpath)
PY

echo
echo "Readlink/resolve behavior for existing src/ui symlink, if present:"
if [ -L src/ui ]; then
  readlink -f src/ui
  find src/ui -type f \( -name '*.ts' -o -name '*.tsx' \) -maxdepth 3 | sort
else
  echo "src/ui is not a symlink"
fi

Repository: Waishnav/devspace

Length of output: 330


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import PurePath
from os import walk

root = "src"
files = []
for dirpath, _, fnames in walk(root):
    files.extend(PurePath(dirpath) / fname for fname in fnames if fname.endswith((".ts", ".tsx")))

print("Nested TypeScript files:")
for p in sorted(files):
    if len(p.parts) > 2:
        print(str(p))

print("\nDirectories nested under src:")
for dirpath in sorted(dirpath for dirpath, _, _ in walk(root) if dirpath != root):
    print(dirpath)
PY

echo
echo "Check src/ui symlink behavior, if present:"
if [ -L src/ui ]; then
  readlink -f src/ui
  find src/ui -maxdepth 2 -type f \( -name '*.ts' -o -name '*.tsx' \) | sort
else
  echo "src/ui is not a symlink"
fi

Repository: Waishnav/devspace

Length of output: 675


Scan nested source files.

readdirSync("src") only returns direct children, so this check skips src/db, src/ui, and any future nested TypeScript files. Use a recursive source walk and replace each local-agent-* import found under src.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/refactor-pure-mcp.mjs` around lines 362 - 371, Update the source scan
around remainingSourceRefs to recursively walk all files under src, including
nested directories, while limiting checks to .ts and .tsx files. Ensure every
local-agent-* import discovered at any depth is included in the existing
replacement flow, preserving the current subagents and agentProfiles checks.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/pure-mcp-refactor.yml:
- Around line 19-22: Update the actions/checkout step in the workflow to set
persist-credentials to false, preventing the write token from being stored
during npm ci and node scripts/refactor-pure-mcp.mjs. Pass the token explicitly
only to the final git push command.
- Around line 46-52: Update the “Commit verified refactor” step so it checks
whether staging via git add -A produced any changes before running git commit.
When the staged diff is empty, skip the commit and push path and exit
successfully; retain the existing commit and push behavior when changes are
present.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: be4c709c-6a79-4bef-8ef5-9a1e9283ce31

📥 Commits

Reviewing files that changed from the base of the PR and between 6f365b1 and 537b165.

📒 Files selected for processing (1)
  • .github/workflows/pure-mcp-refactor.yml

Comment on lines +19 to +22
- uses: actions/checkout@v4
with:
ref: refactor/pure-mcp-runtime
fetch-depth: 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not persist the write token during repository script execution.

actions/checkout persists the contents: write token in Git configuration. node scripts/refactor-pure-mcp.mjs and npm ci then run before the intended push step. Set persist-credentials: false. Provide the token only to the final git push command.

🧰 Tools
🪛 zizmor (1.29.0)

[warning] 19-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pure-mcp-refactor.yml around lines 19 - 22, Update the
actions/checkout step in the workflow to set persist-credentials to false,
preventing the write token from being stored during npm ci and node
scripts/refactor-pure-mcp.mjs. Pass the token explicitly only to the final git
push command.

Source: Linters/SAST tools

Comment on lines +46 to +52
- name: Commit verified refactor
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "refactor: make DevSpace a pure MCP runtime"
git push origin HEAD:refactor/pure-mcp-runtime

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle an already-applied refactor before committing.

A push that changes only this workflow still triggers the job. If the refactor and lockfile are already current, git commit exits with status 1 and marks the workflow as failed. Exit successfully when the staged diff is empty.

Proposed fix
           git config user.email "41898282+github-actions[bot]`@users.noreply.github.com`"
           git add -A
+          if git diff --cached --quiet; then
+            echo "No refactor changes to commit"
+            exit 0
+          fi
           git commit -m "refactor: make DevSpace a pure MCP runtime"
           git push origin HEAD:refactor/pure-mcp-runtime
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Commit verified refactor
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A
git commit -m "refactor: make DevSpace a pure MCP runtime"
git push origin HEAD:refactor/pure-mcp-runtime
- name: Commit verified refactor
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]`@users.noreply.github.com`"
git add -A
if git diff --cached --quiet; then
echo "No refactor changes to commit"
exit 0
fi
git commit -m "refactor: make DevSpace a pure MCP runtime"
git push origin HEAD:refactor/pure-mcp-runtime
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pure-mcp-refactor.yml around lines 46 - 52, Update the
“Commit verified refactor” step so it checks whether staging via git add -A
produced any changes before running git commit. When the staged diff is empty,
skip the commit and push path and exit successfully; retain the existing commit
and push behavior when changes are present.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/config.ts`:
- Line 89: Unify native-mode handling in the configuration flow around the mode
mapping that returns "codex": ensure the same flag determines both tool mode and
subagent availability, so DEVSPACE_TOOL_MODE=native and DEVSPACE_TOOL_MODE=codex
follow the documented compatibility behavior. Add regression coverage for both
environment values and preserve the intended non-native behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 64f533ec-ad24-412b-bc48-a16969482ce0

📥 Commits

Reviewing files that changed from the base of the PR and between 537b165 and 81d43b2.

📒 Files selected for processing (1)
  • src/config.ts

Comment thread src/config.ts

function parseToolMode(env: NodeJS.ProcessEnv): ToolMode {
const mode = env.DEVSPACE_TOOL_MODE;
if (mode === "native") return "codex";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 --glob '*.ts' \
  'DEVSPACE_TOOL_MODE|toolMode|subagents|loadConfig\(' src

Repository: Waishnav/devspace

Length of output: 43710


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant config section =="
sed -n '70,270p' src/config.ts

echo
echo "== relevant server/tool registration sections =="
sed -n '180,215p' src/server.ts
sed -n '1035,1060p' src/server.ts
sed -n '1200,1220p' src/server.ts
sed -n '1336,1348p' src/server.ts
sed -n '1545,1563p' src/server.ts
sed -n '1640,1650p' src/server.ts
sed -n '1686,1694p' src/server.ts

echo
echo "== local-agent-profiles =="
sed -n '1,70p' src/local-agent-profiles.ts

echo
echo "== skills =="
sed -n '1,90p' src/skills.ts

echo
echo "== test assertions around native/codex/subagents =="
rg -n -C 3 --glob '*test.ts' \
  'DEVSPACE_TOOL_MODE|native|codex|subagents|resolveSubagentsFlag|loadLocalAgentProfiles|subagent-delegation' src

Repository: Waishnav/devspace

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

config = Path("src/config.ts").read_text()

parse_config = {}
for m in re.finditer(r"`function\(([^)]*)\)(?:=>[^;]*|.*?{(?P<body>\{(?:[^{}]|(?P<body_nested>\{(?P<body_deep>\{)*\})*\}")*})*);", config, re.S):
    if "function parseToolMode(env: NodeJS.ProcessEnv)" in m.group(0):
        parse_config["tool_mode_fn"] = m.group(0)

config = Path("src/config.ts").read_text()

def parse_tool_mode_mode(env_mode, min_tools=None):
    value = env_mode
    if value == "native":
        return "codex"
    if value in ("minimal", "full", "codex"):
        return value
    if min_tools is not None:
        return "minimal" if min_tools == "true" or min_tools == "1" else "full"
    return "minimal"

cases = [
    ("natural", "codex", None),
    ("codex", "codex", None),
    ("native", None, None),
    ("native", None, "1"),
    ("codex", None, "1"),
    ("native", None, "0"),
]

config = Path("src/config.ts").read_text()
native_mode_re = re.search(r"const nativeMode = env\.DEVSPACE_TOOL_MODE === \"native\";", config)
subagents_re = re.search(r"(?ms)^    subagents: nativeMode .*?^    agentDir:", config)
server_calls = "        .map((skill) => ({\n        name: skill.name,\n        description: skill.description,\n        path: formatPathForPrompt(skill.filePath),\n      }));\n      const cardAgentProviders = config.subagents ? localAgentProviders : [];" in Path("src/server.ts").read_text()

print("tool_mode_native_maps_to_codex", parse_tool_mode_mode("native") == "codex")
print("codex_direct", parse_tool_mode_mode("codex") == "codex")
print("native_mode_bool", bool(native_mode_re))
print("subagents_guard_uses_native_mode", "subagents: nativeMode" in subagents_re.group(0) if subagents_re else False)
print("native_subagent_guard_false", parse_tool_mode_mode("native") != True and subagents_re.group(0).count("False") > 0)
print("server_subagents_from_config", "if (config.subagents" in Path("src/server.ts").read_text())
print("local_agent_profiles_disabled_when_subagents_disabled", "if (!config.subagents) return [];" in Path("src/local-agent-profiles.ts").read_text())
print("skills_filter_subagent_delegation_when_subagents_disabled", "if (!config.subagents) return result;" in Path("src/skills.ts").read_text() and "skills: result.skills.filter((skill) => skill.name !== SUBAGENT_DELEGATION_NAME)" in Path("src/skills.ts").read_text())

def parse_tool_mode(env):
    value = env.get("DEVSPACE_TOOL_MODE")
    if value == "native":
        return "codex"
    if value in ("minimal", "full", "codex"):
        return value
    if env.get("DEVSPACE_TOOL_MODE") is not None:
        raise ValueError(f"Invalid DEVSPACE_TOOL_MODE: {env['DEVSPACE_TOOL_MODE']}")
    if env.get("DEVSPACE_MINIMAL_TOOLS") is not None:
        return "minimal" if env["DEVSPACE_MINIMAL_TOOLS"] in ("1",) else "full"
    return "minimal"

print("env_native_toggles_mode_codex_and_guard_disable", parse_tool_mode({"DEVSPACE_TOOL_MODE": "native"}) == "codex")
print("env_codex_toggles_mode_codex_and_guard_disable", parse_tool_mode({"DEVSPACE_TOOL_MODE": "codex"}) == "codex")
PY

Repository: Waishnav/devspace

Length of output: 486


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== static behavior probe from source text =="
python3 - <<'PY'
from pathlib import Path
import re

config = Path("src/config.ts").read_text()
server = Path("src/server.ts").read_text()
profiles = Path("src/local-agent-profiles.ts").read_text()
skills = Path("src/skills.ts").read_text()

def parse_tool_mode(env_mode):
    value = env_mode
    if value == "native":
        return "codex"
    if value in ("minimal", "full", "codex"):
        return value
    return "minimal"

def subagent_value(env_mode):
    native_mode = env_mode == "native"
    return False if native_mode else ("files" if env_mode is None else True)

for env_mode in [None, "native", "codex", "minimal", "full"]:
    print(f"toolMode(DEVSPACE_TOOL_MODE={env_mode!r})={parse_tool_mode(env_mode)} subagents={subagent_value(env_mode)}")

print()
print("nativeMode_constant_present", "const nativeMode = env.DEVSPACE_TOOL_MODE === \"native\";" in config)
print("nativeMode_only_used_for_subagents_guard", config.count("nativeMode") == 1)
print("server_subagent_paths_use_config_subagents", ("localAgentProviders = config.subagents" in server or "getLocalAgentProviderAvailabilitySnapshot()" in server) and "if (config.subagents)" in server)
print("profiles_disabled_when_config_subagents_false", "if (!config.subagents) return [];" in profiles)
print("skills_filter_subagent_delegation_when_config_subagents_false", "if (!config.subagents) return result;" in skills and "skill.name !== SUBAGENT_DELEGATION_NAME" in skills)
PY

echo
echo "== deterministic subagent guard probe =="
node - <<'JS'
function parseToolMode(envMode) {
  let mode = envMode;
  if (mode === "native") return "codex";
  if (mode === "minimal" || mode === "full" || mode === "codex") return mode;
  return "minimal";
}

for (const mode of [undefined, "native", "codex", "minimal", "full"]) {
  const nativeMode = mode === "native";
  const subagents = nativeMode
    ? false
    : (mode === undefined ? "file" : true);
  console.log(JSON.stringify({
    input: mode,
    toolMode: parseToolMode(mode),
    nativeMode,
    subagents
  }));
}
JS

Repository: Waishnav/devspace

Length of output: 1140


Use one native-mode flag for tool mode and subagents.

DEVSPACE_TOOL_MODE=native sets toolMode to codex but also disables subagents through a separate nativeMode flag, while DEVSPACE_TOOL_MODE=codex leaves subagents enabled. Either document codex as the native compatibility mode and use the same flag for both contract points, or expose native as an explicit mode value. Add regression tests for both values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config.ts` at line 89, Unify native-mode handling in the configuration
flow around the mode mapping that returns "codex": ensure the same flag
determines both tool mode and subagent availability, so
DEVSPACE_TOOL_MODE=native and DEVSPACE_TOOL_MODE=codex follow the documented
compatibility behavior. Add regression coverage for both environment values and
preserve the intended non-native behavior.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant