Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ to upgrade, `… | sh -s -- remove` to uninstall.
moshcode engines # list installable engines
moshcode engines --json # machine-readable install status for automation
moshcode install opencode # install opencode (curl … | bash)
moshcode install privacycode # curl -fsSL https://getprivacycode.com/install | sh
moshcode install claude # npm i -g @anthropic-ai/claude-code
moshcode install codex # npm i -g @openai/codex
```
Expand All @@ -34,6 +35,7 @@ use this only in an isolated container, VM, or workspace you trust:
```sh
moshcode agents claude # claude agents --dangerously-skip-permissions (agent view)
moshcode agents opencode # opencode agent list (agent view)
moshcode agents privacycode # privacycode agent list (agent view)
moshcode agents codex # codex --dangerously-bypass-approvals-and-sandbox (autonomous)
moshcode agents gemini # gemini --approval-mode=yolo (autonomous)
moshcode agents aider # aider --yes-always (autonomous)
Expand Down
17 changes: 15 additions & 2 deletions src/engines.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ export const ENGINES = {
install: { cmd: "bash", args: ["-c", "curl -fsSL https://opencode.ai/install | bash"] },
upgrade: { cmd: "opencode", args: ["upgrade"] },
},
privacycode: {
desc: "privacycode — privacy-first coding agent (profullstack)",
bin: "privacycode",
// An opencode derivative, so it speaks the same flags/subcommands.
agentArgs: ["--auto"],
agentsView: ["agent", "list"],
install: { cmd: "sh", args: ["-c", "curl -fsSL https://getprivacycode.com/install | sh"] },
upgrade: { cmd: "privacycode", args: ["upgrade"] },
},
claude: {
desc: "Claude Code — Anthropic's agentic CLI",
bin: "claude",
Expand Down Expand Up @@ -72,7 +81,10 @@ export function upgradeSpec(engine) {
}

/** Aliases so `/agents cc` etc. resolve. */
const ALIASES = { cc: "claude", "claude-code": "claude", openai: "codex", gpt: "codex", google: "gemini" };
const ALIASES = {
cc: "claude", "claude-code": "claude", openai: "codex", gpt: "codex", google: "gemini",
pc: "privacycode", getprivacycode: "privacycode", privacy: "privacycode",
};

/** Resolve a name/alias to `[key, engine]`, or null. */
export function resolveEngine(token) {
Expand Down Expand Up @@ -143,6 +155,7 @@ const AI_EXEC = {
codex: (p) => ["exec", p], // codex non-interactive
gemini: (p) => ["-p", p], // gemini prompt mode
opencode: (p) => ["run", p], // opencode one-shot
privacycode: (p) => ["run", p], // privacycode one-shot (opencode-derived)
aider: (p) => ["--message", p, "--yes", "--no-auto-commits"], // aider single message
};

Expand All @@ -155,7 +168,7 @@ export function aiExecArgs(engine, prompt) {

/** First installed engine that supports headless ai(), honoring a preference. */
export function pickAiEngine(preferred) {
const order = preferred ? [preferred] : ["claude", "codex", "opencode", "gemini", "aider"];
const order = preferred ? [preferred] : ["claude", "codex", "opencode", "privacycode", "gemini", "aider"];
for (const key of order) {
if (Object.hasOwn(ENGINES, key) && Object.hasOwn(AI_EXEC, key) && isInstalled(ENGINES[key].bin)) return key;
}
Expand Down
9 changes: 6 additions & 3 deletions src/mcp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { ENGINES, isInstalled, ranOk, runCmd } from "./engines.mjs";

// Coding engines that can register MCP servers. Aider has no MCP support.
export const MCP_ENGINES = ["claude", "gemini", "codex", "opencode"];
export const MCP_ENGINES = ["claude", "gemini", "codex", "opencode", "privacycode"];

/** Is this target a remote server URL (vs a local stdio command)? */
export function isRemoteTarget(target) {
Expand Down Expand Up @@ -84,9 +84,12 @@ export function mcpAddArgs(key, spec) {
else argv.push("--", target, ...args);
return { argv };
}
case "opencode": {
// privacycode is opencode-derived, so it shares opencode's `mcp add` surface
// — including the "remote servers only, non-interactively" limitation.
case "opencode":
case "privacycode": {
if (!remote) {
return { skip: "OpenCode CLI adds only remote (--url) servers non-interactively" };
return { skip: `${key === "privacycode" ? "privacycode" : "OpenCode"} CLI adds only remote (--url) servers non-interactively` };
}
const argv = ["mcp", "add", name, "--url", target];
for (const [k, v] of env) argv.push("--env", `${k}=${v}`);
Expand Down
2 changes: 2 additions & 0 deletions test/engines.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const BIN = fileURLToPath(new URL("../bin/moshcode.mjs", import.meta.url));
// The autonomous-session bypass flags each engine declares (engine.agentArgs).
const EXPECTED_AGENT_ARGS = {
opencode: ["--auto"],
privacycode: ["--auto"],
claude: ["--dangerously-skip-permissions"],
codex: ["--dangerously-bypass-approvals-and-sandbox"],
gemini: ["--approval-mode=yolo"],
Expand All @@ -30,6 +31,7 @@ const EXPECTED_AGENT_ARGS = {
// agents-view invocation where it has one, else its autonomous bypass flags.
const EXPECTED_LAUNCH_ARGS = {
opencode: ["agent", "list"],
privacycode: ["agent", "list"],
claude: ["agents", "--dangerously-skip-permissions"],
codex: ["--dangerously-bypass-approvals-and-sandbox"],
gemini: ["--approval-mode=yolo"],
Expand Down
Loading