diff --git a/README.md b/README.md index 279c1a6..5d3c98c 100644 --- a/README.md +++ b/README.md @@ -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 ``` @@ -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) diff --git a/src/engines.mjs b/src/engines.mjs index b42851c..8a64f19 100644 --- a/src/engines.mjs +++ b/src/engines.mjs @@ -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", @@ -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) { @@ -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 }; @@ -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; } diff --git a/src/mcp.mjs b/src/mcp.mjs index 254c38f..5eab442 100644 --- a/src/mcp.mjs +++ b/src/mcp.mjs @@ -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) { @@ -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}`); diff --git a/test/engines.test.mjs b/test/engines.test.mjs index 437e77d..f087802 100644 --- a/test/engines.test.mjs +++ b/test/engines.test.mjs @@ -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"], @@ -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"],