feat(core): platform-aware runtime default (tmux on Unix, process on Windows)

B04: Config and docs now reflect platform-specific defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Priyanshu Choudhary 2026-04-08 01:41:54 +05:30
parent 3b7248da6d
commit b180802c7f
6 changed files with 36 additions and 5 deletions

View File

@ -14,8 +14,9 @@ port: 3000
# directTerminalPort: 14801
# Default plugins (these are the defaults — you can omit this section)
# runtime defaults to 'tmux' on Linux/macOS, 'process' on Windows
defaults:
runtime: tmux # tmux | process
# runtime: tmux # tmux (Linux/macOS default) | process (Windows default)
agent: claude-code # claude-code | codex | aider | opencode
# orchestrator:
# agent: claude-code

View File

@ -31,6 +31,7 @@ import {
isOrchestratorSession,
isTerminalSession,
ConfigNotFoundError,
getDefaultRuntime,
type OrchestratorConfig,
type ProjectConfig,
type ParsedRepoUrl,
@ -579,7 +580,7 @@ async function autoCreateConfig(workingDir: string): Promise<OrchestratorConfig>
const config: Record<string, unknown> = {
port: port ?? DEFAULT_PORT,
defaults: {
runtime: "tmux",
runtime: getDefaultRuntime(),
agent,
workspace: "worktree",
notifiers: [],

View File

@ -18,6 +18,7 @@ import {
resolveCloneTarget,
sanitizeProjectId,
} from "../config-generator.js";
import { getDefaultRuntime } from "../platform.js";
// =============================================================================
// isRepoUrl
@ -252,7 +253,7 @@ describe("generateConfigFromUrl", () => {
// Check top-level structure
expect(config.port).toBe(3000);
expect(config.defaults).toEqual({
runtime: "tmux",
runtime: getDefaultRuntime(),
agent: "claude-code",
workspace: "worktree",
notifiers: [],

View File

@ -0,0 +1,26 @@
import { describe, it, expect, vi, afterEach } from "vitest";
describe("config defaults", () => {
const originalPlatform = process.platform;
afterEach(() => {
Object.defineProperty(process, "platform", { value: originalPlatform, writable: true });
vi.resetModules();
});
it("defaults runtime to 'process' on win32", async () => {
vi.resetModules();
Object.defineProperty(process, "platform", { value: "win32", writable: true });
const { getDefaultConfig } = await import("../config.js");
const config = getDefaultConfig();
expect(config.defaults.runtime).toBe("process");
});
it("defaults runtime to 'tmux' on linux", async () => {
vi.resetModules();
Object.defineProperty(process, "platform", { value: "linux", writable: true });
const { getDefaultConfig } = await import("../config.js");
const config = getDefaultConfig();
expect(config.defaults.runtime).toBe("tmux");
});
});

View File

@ -9,6 +9,7 @@ import { existsSync, readFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { stringify as yamlStringify } from "yaml";
import { generateSessionPrefix } from "./paths.js";
import { getDefaultRuntime } from "./platform.js";
// =============================================================================
// URL PARSING
@ -240,7 +241,7 @@ export function generateConfigFromUrl(options: GenerateConfigOptions): Record<st
return {
port,
defaults: {
runtime: "tmux",
runtime: getDefaultRuntime(),
agent: "claude-code",
workspace: "worktree",
notifiers: [],

View File

@ -17,6 +17,7 @@ import { parse as parseYaml } from "yaml";
import { z } from "zod";
import { ConfigNotFoundError, type ExternalPluginEntryRef, type OrchestratorConfig } from "./types.js";
import { generateSessionPrefix } from "./paths.js";
import { getDefaultRuntime } from "./platform.js";
function inferScmPlugin(project: {
repo: string;
@ -208,7 +209,7 @@ const ProjectConfigSchema = z.object({
});
const DefaultPluginsSchema = z.object({
runtime: z.string().default("tmux"),
runtime: z.string().default(getDefaultRuntime()),
agent: z.string().default("claude-code"),
workspace: z.string().default("worktree"),
notifiers: z.array(z.string()).default([]),