diff --git a/src/resources/extensions/gsd/bootstrap/system-context.ts b/src/resources/extensions/gsd/bootstrap/system-context.ts index 8fe3890df..bad24512d 100644 --- a/src/resources/extensions/gsd/bootstrap/system-context.ts +++ b/src/resources/extensions/gsd/bootstrap/system-context.ts @@ -19,6 +19,7 @@ import { deriveState } from "../state.js"; import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile, parseContinue, parseSummary } from "../files.js"; import { toPosixPath } from "../../shared/mod.js"; import { markCmuxPromptShown, shouldPromptToEnableCmux } from "../../cmux/index.js"; +import { autoEnableCmuxPreferences } from "../commands-cmux.js"; const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd"); @@ -76,13 +77,16 @@ export async function buildBeforeAgentStartResult( shortcutDashboard: formatShortcut("Ctrl+Alt+G"), shortcutShell: formatShortcut("Ctrl+Alt+B"), }); - const loadedPreferences = loadEffectiveGSDPreferences(); + let loadedPreferences = loadEffectiveGSDPreferences(); if (shouldPromptToEnableCmux(loadedPreferences?.preferences)) { markCmuxPromptShown(); - ctx.ui.notify( - "cmux detected. Run /gsd cmux on to enable sidebar metadata, notifications, and visual subagent splits for this project.", - "info", - ); + if (autoEnableCmuxPreferences()) { + loadedPreferences = loadEffectiveGSDPreferences(); + ctx.ui.notify( + "cmux detected — auto-enabled. Run /gsd cmux off to disable.", + "info", + ); + } } let preferenceBlock = ""; diff --git a/src/resources/extensions/gsd/commands-cmux.ts b/src/resources/extensions/gsd/commands-cmux.ts index e00f2dea2..a1b8f5ee4 100644 --- a/src/resources/extensions/gsd/commands-cmux.ts +++ b/src/resources/extensions/gsd/commands-cmux.ts @@ -1,5 +1,5 @@ import type { ExtensionCommandContext } from "@gsd/pi-coding-agent"; -import { existsSync, readFileSync } from "node:fs"; +import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { clearCmuxSidebar, CmuxClient, detectCmuxEnvironment, resolveCmuxConfig } from "../cmux/index.js"; import { saveFile } from "./files.js"; import { @@ -9,6 +9,37 @@ import { } from "./preferences.js"; import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js"; +/** + * Auto-enable cmux in project preferences when detected but never configured. + * Called at boot (before agent start) — no ExtensionCommandContext needed. + * Returns true if preferences were written, false if skipped. + */ +export function autoEnableCmuxPreferences(): boolean { + const path = getProjectGSDPreferencesPath(); + if (!existsSync(path)) return false; + + const existing = loadProjectGSDPreferences(); + const prefs: Record = existing?.preferences ? { ...existing.preferences } : { version: 1 }; + prefs.cmux = { + enabled: true, + notifications: true, + sidebar: true, + splits: false, + browser: false, + ...((prefs.cmux as Record | undefined) ?? {}), + }; + (prefs.cmux as Record).enabled = true; + prefs.version = prefs.version || 1; + + const frontmatter = serializePreferencesToFrontmatter(prefs); + let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n"; + const preserved = extractBodyAfterFrontmatter(readFileSync(path, "utf-8")); + if (preserved) body = preserved; + + writeFileSync(path, `---\n${frontmatter}---${body}`, "utf-8"); + return true; +} + function extractBodyAfterFrontmatter(content: string): string | null { const start = content.startsWith("---\n") ? 4 : content.startsWith("---\r\n") ? 5 : -1; if (start === -1) return null;