Extract agent setup tooling seam

This commit is contained in:
OpenPets Dev 2026-06-19 04:40:37 +00:00
parent 6bb7d4ddf7
commit d5c907016f
10 changed files with 219 additions and 165 deletions

View file

@ -67,6 +67,7 @@ const behaviorTests = [
".test-dist/tests/integrations-view-state.test.js",
".test-dist/tests/familiars-view-state.test.js",
".test-dist/tests/agent-setup-actions.test.js",
".test-dist/tests/agent-setup-actions-tooling.test.js",
".test-dist/tests/agent-setup-command-runner.test.js",
".test-dist/tests/agent-setup-command-context.test.js",
".test-dist/tests/agent-setup-support.test.js",

View file

@ -0,0 +1,157 @@
import { app } from "electron";
import type { ClaudeCommandSpec, FamiliarOSCommandMode } from "@familiaros/claude";
import {
buildCursorSetupSnapshot,
buildOpenCodeSetupSnapshot,
installCursorGlobalConfig,
installOpenCodeGlobalConfig,
removeCursorGlobalConfig,
removeOpenCodeGlobalConfig,
replaceCursorGlobalConfig,
type CursorSetupPreview,
type CursorSetupStatus,
type OpenCodeSetupPreview,
type OpenCodeSetupStatus,
} from "./agent-setup-editor-tools.js";
import { buildFamiliarOSMcpServerPreview } from "./agent-setup-support.js";
import {
getAgentSetupCliEntryPath,
getCliPackageVersion,
getMcpPackageVersion,
getOpenCodePackageVersion,
getPreferredNodeCommand,
getPreferredOpenCodeCommand,
} from "./agent-setup-command-context.js";
import type { AgentSetupCommandResult } from "./agent-setup-command-runner.js";
import type { AgentSetupActionResult, FamiliarOSMcpServerHealth } from "./agent-setup.js";
type CommandResult = AgentSetupCommandResult;
export async function getOpenCodeSetup(
commandMode: FamiliarOSCommandMode,
selectedPetId: string | undefined,
runCommandFn: (spec: ClaudeCommandSpec) => Promise<CommandResult>,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<{ readonly status: OpenCodeSetupStatus; readonly preview: OpenCodeSetupPreview }> {
const detected = await runCommandFn({ command: getPreferredOpenCodeCommand(), args: ["--version"] });
return buildOpenCodeSetupSnapshot({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
selectedPetId,
commandMode,
cliVersion: getCliPackageVersion(),
pluginVersion: getOpenCodePackageVersion(),
cliEntryPath: commandMode === "published" ? undefined : getAgentSetupCliEntryPath(commandMode),
detectedOk: detected.ok,
preferredOpenCodeCommand: getPreferredOpenCodeCommand(),
formatUserPath,
});
}
export async function getCursorSetup(
commandMode: FamiliarOSCommandMode,
selectedPetId: string | undefined,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<{ readonly status: CursorSetupStatus; readonly preview: CursorSetupPreview }> {
void commandMode;
return buildCursorSetupSnapshot({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
export async function runAgentSetupMcpServerHealthCheck(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
runCommandFn: (spec: ClaudeCommandSpec) => Promise<CommandResult>,
): Promise<FamiliarOSMcpServerHealth> {
const preview = buildFamiliarOSMcpServerPreview(selectedPetId, commandMode);
const result = await runCommandFn({ command: preview.command, args: [...preview.args, "--version"] });
if (result.ok) {
return { ok: true, output: result.stdout.trim() || "MCP server responded." };
}
const errorMessage = result.error || result.stderr.trim() || `Command exited with code ${result.exitCode ?? "unknown"}.`;
return { ok: false, output: "", error: errorMessage };
}
export async function installOpenCodeGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
helpers: {
readonly runCommand: (spec: ClaudeCommandSpec) => Promise<CommandResult>;
readonly summarizeCommandResult: (result: CommandResult) => string;
readonly formatUserPath: (path: string | undefined) => string | undefined;
},
): Promise<AgentSetupActionResult> {
if (commandMode === "bundled") {
const node = await helpers.runCommand({ command: getPreferredNodeCommand(), args: ["--version"] });
if (!node.ok) {
return {
ok: false,
action: "opencode-install",
message: `Node.js is required for packaged FamiliarOS commands. Open OpenCode configuration, set the Node.js command path, then try again. ${helpers.summarizeCommandResult(node)}`,
changed: false,
};
}
}
return installOpenCodeGlobalConfig({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
selectedPetId,
commandMode,
cliVersion: getCliPackageVersion(),
pluginVersion: getOpenCodePackageVersion(),
cliEntryPath: commandMode === "published" ? undefined : getAgentSetupCliEntryPath(commandMode),
formatUserPath: helpers.formatUserPath,
});
}
export async function removeOpenCodeGlobal(): Promise<AgentSetupActionResult> {
return removeOpenCodeGlobalConfig({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
});
}
export async function installCursorGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
void commandMode;
return installCursorGlobalConfig({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
export async function replaceCursorGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
void commandMode;
return replaceCursorGlobalConfig({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
export async function removeCursorGlobal(
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
return removeCursorGlobalConfig({
homeDir: app.getPath("home"),
formatUserPath,
});
}

View file

@ -9,20 +9,18 @@ import {
} from "@familiaros/claude";
import {
buildCursorSetupSnapshot,
buildOpenCodeSetupSnapshot,
installCursorGlobalConfig,
installOpenCodeGlobalConfig,
removeCursorGlobalConfig,
removeOpenCodeGlobalConfig,
replaceCursorGlobalConfig,
type CursorSetupPreview,
type CursorSetupStatus,
type OpenCodeSetupPreview,
type OpenCodeSetupStatus,
} from "./agent-setup-editor-tools.js";
installCursorGlobal,
installOpenCodeGlobal,
removeCursorGlobal,
removeOpenCodeGlobal,
replaceCursorGlobal,
} from "./agent-setup-actions-tooling.js";
export {
getCursorSetup,
getOpenCodeSetup,
runAgentSetupMcpServerHealthCheck,
} from "./agent-setup-actions-tooling.js";
import {
buildFamiliarOSMcpServerPreview,
createHookJournalCommand,
safeInstallClaudeMemory,
safeUninstallClaudeMemory,
@ -32,12 +30,7 @@ import {
type JournalAction,
} from "./agent-setup-support.js";
import {
getAgentSetupCliEntryPath,
getCliPackageVersion,
getMcpPackageVersion,
getPreferredClaudeCommand,
getOpenCodePackageVersion,
getPreferredOpenCodeCommand,
getPreferredNodeCommand,
} from "./agent-setup-command-context.js";
import type { AgentSetupCommandResult } from "./agent-setup-command-runner.js";
@ -45,7 +38,6 @@ import type {
AgentSetupAction,
AgentSetupActionResult,
ClaudeCodeStatus,
FamiliarOSMcpServerHealth,
} from "./agent-setup.js";
type CommandResult = AgentSetupCommandResult;
@ -89,56 +81,6 @@ export async function executeAgentSetupResolvedAction(
return runClaudeMcpAction(action, previewResult.preview, helpers);
}
export async function getOpenCodeSetup(
commandMode: FamiliarOSCommandMode,
selectedPetId: string | undefined,
runCommandFn: (spec: ClaudeCommandSpec) => Promise<CommandResult>,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<{ readonly status: OpenCodeSetupStatus; readonly preview: OpenCodeSetupPreview }> {
const detected = await runCommandFn({ command: getPreferredOpenCodeCommand(), args: ["--version"] });
return buildOpenCodeSetupSnapshot({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
selectedPetId,
commandMode,
cliVersion: getCliPackageVersion(),
pluginVersion: getOpenCodePackageVersion(),
cliEntryPath: commandMode === "published" ? undefined : getAgentSetupCliEntryPath(commandMode),
detectedOk: detected.ok,
preferredOpenCodeCommand: getPreferredOpenCodeCommand(),
formatUserPath,
});
}
export async function getCursorSetup(
commandMode: FamiliarOSCommandMode,
selectedPetId: string | undefined,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<{ readonly status: CursorSetupStatus; readonly preview: CursorSetupPreview }> {
void commandMode;
return buildCursorSetupSnapshot({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
export async function runAgentSetupMcpServerHealthCheck(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
runCommandFn: (spec: ClaudeCommandSpec) => Promise<CommandResult>,
): Promise<FamiliarOSMcpServerHealth> {
const preview = buildFamiliarOSMcpServerPreview(selectedPetId, commandMode);
const result = await runCommandFn({ command: preview.command, args: [...preview.args, "--version"] });
if (result.ok) {
return { ok: true, output: result.stdout.trim() || "MCP server responded." };
}
const errorMessage = result.error || result.stderr.trim() || `Command exited with code ${result.exitCode ?? "unknown"}.`;
return { ok: false, output: "", error: errorMessage };
}
async function runImmediateAction(
action: AgentSetupAction,
helpers: AgentSetupActionHelpers,
@ -315,80 +257,6 @@ function runConfigureClaudeMcpAction(
return runAdd(preview, previousStatus, "configure", helpers);
}
async function installOpenCodeGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
helpers: Pick<AgentSetupActionHelpers, "runCommand" | "summarizeCommandResult" | "formatUserPath">,
): Promise<AgentSetupActionResult> {
if (commandMode === "bundled") {
const node = await helpers.runCommand({ command: getPreferredNodeCommand(), args: ["--version"] });
if (!node.ok) {
return {
ok: false,
action: "opencode-install",
message: `Node.js is required for packaged FamiliarOS commands. Open OpenCode configuration, set the Node.js command path, then try again. ${helpers.summarizeCommandResult(node)}`,
changed: false,
};
}
}
return installOpenCodeGlobalConfig({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
selectedPetId,
commandMode,
cliVersion: getCliPackageVersion(),
pluginVersion: getOpenCodePackageVersion(),
cliEntryPath: commandMode === "published" ? undefined : getAgentSetupCliEntryPath(commandMode),
formatUserPath: helpers.formatUserPath,
});
}
async function removeOpenCodeGlobal(): Promise<AgentSetupActionResult> {
return removeOpenCodeGlobalConfig({
env: process.env,
homeDir: app.getPath("home"),
processPlatform: process.platform,
});
}
async function installCursorGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
void commandMode;
return installCursorGlobalConfig({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
async function replaceCursorGlobal(
selectedPetId: string | undefined,
commandMode: FamiliarOSCommandMode,
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
void commandMode;
return replaceCursorGlobalConfig({
homeDir: app.getPath("home"),
selectedPetId,
mcpVersion: getMcpPackageVersion(),
formatUserPath,
});
}
async function removeCursorGlobal(
formatUserPath: (path: string | undefined) => string | undefined,
): Promise<AgentSetupActionResult> {
return removeCursorGlobalConfig({
homeDir: app.getPath("home"),
formatUserPath,
});
}
async function runAdd(
preview: ClaudeMcpPreview,
previousStatus: string,

View file

@ -159,6 +159,7 @@ const appStateFamiliarRecordsSource = readFileSync(join(appDir, "src", "app-stat
const appStateStorageSource = readFileSync(join(appDir, "src", "app-state-storage.ts"), "utf8");
const agentSetupSource = readFileSync(join(appDir, "src", "agent-setup.ts"), "utf8");
const agentSetupActionsSource = readFileSync(join(appDir, "src", "agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(join(appDir, "src", "agent-setup-actions-tooling.ts"), "utf8");
const agentSetupCommandRunnerSource = readFileSync(join(appDir, "src", "agent-setup-command-runner.ts"), "utf8");
const agentSetupCommandContextSource = readFileSync(join(appDir, "src", "agent-setup-command-context.ts"), "utf8");
const agentSetupEditorToolsSource = readFileSync(join(appDir, "src", "agent-setup-editor-tools.ts"), "utf8");
@ -413,9 +414,10 @@ assert.match(agentSetupCommandRunnerSource, /export async function runAgentSetup
assert.match(agentSetupCommandRunnerSource, /export function createAgentSetupCommandEnv/, "agent-setup command-runner seam must export PATH environment shaping.");
assert.match(agentSetupCommandRunnerSource, /export function summarizeAgentSetupCommandResult/, "agent-setup command-runner seam must export command result summarization.");
assert.match(agentSetupActionsSource, /export async function executeAgentSetupResolvedAction/, "agent-setup action seam must export action execution.");
assert.match(agentSetupActionsSource, /export async function getOpenCodeSetup/, "agent-setup action seam must export OpenCode setup loading.");
assert.match(agentSetupActionsSource, /export async function getCursorSetup/, "agent-setup action seam must export Cursor setup loading.");
assert.match(agentSetupActionsSource, /export async function runAgentSetupMcpServerHealthCheck/, "agent-setup action seam must export MCP server health checks.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-actions-tooling(?:\.js)?"/, "agent-setup action seam must import the extracted tooling seam.");
assert.match(agentSetupActionsToolingSource, /export async function getOpenCodeSetup/, "agent-setup tooling seam must export OpenCode setup loading.");
assert.match(agentSetupActionsToolingSource, /export async function getCursorSetup/, "agent-setup tooling seam must export Cursor setup loading.");
assert.match(agentSetupActionsToolingSource, /export async function runAgentSetupMcpServerHealthCheck/, "agent-setup tooling seam must export MCP server health checks.");
assert.match(pluginServiceDefaultPetSource, /export async function buildDefaultPetPluginCommands/, "plugin-service default-pet helper must export default familiar command shaping.");
assert.match(pluginServiceSupportSource, /from "\.\/plugin-service-actions(?:\.js)?"/, "plugin-service support barrel must re-export the service action seam.");
assert.match(pluginServiceActionsSource, /export async function buildPluginCatalogSnapshot/, "plugin-service action seam must export catalog snapshot shaping.");
@ -595,10 +597,10 @@ assert.match(enCatalogSource, /OpenCode/, "Control Center integrations must incl
assert.match(enCatalogSource, /Cursor/, "Control Center integrations must include Cursor.");
assert.match(enCatalogSource, /Pi/, "Control Center integrations must include Pi.");
assert.match(agentSetupSource, /from "\.\/agent-setup-command-context\.js"/, "Agent setup must import the extracted command context helper seam.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-editor-tools\.js"/, "Agent setup action seam must import the extracted editor setup helper seam.");
assert.match(agentSetupActionsToolingSource, /from "\.\/agent-setup-editor-tools\.js"/, "Agent setup tooling seam must import the extracted editor setup helper seam.");
assert.match(agentSetupSource, /agent-setup-support\.js/, "Agent setup must import and re-export the extracted support helper seam.");
assert.match(agentSetupActionsSource, /getCliPackageVersion/, "Agent setup action seam must compose package version metadata through the command context helper.");
assert.match(agentSetupActionsSource, /buildOpenCodeSetupSnapshot/, "Agent setup action seam must delegate OpenCode previews through the editor setup helper.");
assert.match(agentSetupActionsToolingSource, /getCliPackageVersion/, "Agent setup tooling seam must compose package version metadata through the command context helper.");
assert.match(agentSetupActionsToolingSource, /buildOpenCodeSetupSnapshot/, "Agent setup tooling seam must delegate OpenCode previews through the editor setup helper.");
assert.match(agentSetupActionsSource, /writeActionJournal/, "Agent setup action seam must delegate journal writes through the support helper.");
assert.match(petWindowRenderSource, /from "\.\/familiar-window-render-bubbles(?:\.js)?"/, "familiar-window-render must compose the extracted bubble helper seam.");
assert.match(petWindowRenderBubblesSource, /export function createBubbleMarkup/, "familiar-window render bubble seam must export the shared bubble markup builder.");

View file

@ -67,8 +67,7 @@ windows.ts (IPC handlers)
├── detectClaudeCodeStatus() (claude --version, claude mcp list)
├── agent-setup-actions.ts
│ ├── runAgentSetupResolvedAction() (configure/replace/remove, install-memory, hook actions)
│ ├── getOpenCodeSetup() / getCursorSetup() (editor setup snapshots)
│ └── runAgentSetupMcpServerHealthCheck() (FamiliarOS MCP server health)
│ └── agent-setup-actions-tooling.ts (OpenCode/Cursor setup snapshots, global config actions, and FamiliarOS MCP server health)
├── agent-setup-command-context.ts
│ ├── persisted command path preferences
│ └── CLI/package version resolution for agent setup
@ -199,7 +198,8 @@ plugin-service-local-support.ts → plugin-local-loader.ts validates selected fo
- `control-center-ipc-plugin.ts`: Plugin snapshot/config/catalog/platform IPC routes for the Control Center
- `control-center-ipc-pets.ts`: Familiar/catalog/Codex import and default familiar IPC routes for the Control Center
- `control-center-ipc-agent.ts`: Agent setup, toolkit, and FamiliarOS MCP preview/test IPC routes for the Control Center
- `agent-setup-actions.ts`: Extracted action execution, OpenCode/Cursor setup loading, hook handling, Claude MCP add/remove orchestration, and FamiliarOS MCP health checks
- `agent-setup-actions.ts`: Extracted action execution shell for hook handling plus Claude MCP add/remove orchestration
- `agent-setup-actions-tooling.ts`: Extracted OpenCode/Cursor setup loading, global config actions, and FamiliarOS MCP server health checks
- `agent-setup-support.ts`: Extracted MCP preview, Claude memory safety wrappers, and bounded action journal helpers for agent setup
- `assets.ts`: Tray icon loading with generated fallback
- `display.ts`: Screen geometry helpers, familiar window positioning
@ -288,7 +288,8 @@ plugin-service-local-support.ts → plugin-local-loader.ts validates selected fo
**Agent Integration**:
- `agent-setup.ts`: Claude detection, snapshot assembly, selected-pet validation, command wrappers, and public agent-setup API entry points
- `agent-setup-actions.ts`: Extracted action execution, editor setup loading, Claude MCP add/remove orchestration, and FamiliarOS MCP server health checks
- `agent-setup-actions.ts`: Extracted action execution shell plus Claude MCP add/remove orchestration
- `agent-setup-actions-tooling.ts`: Extracted editor setup loading, global config actions, and FamiliarOS MCP server health checks
- `agent-setup-command-context.ts`: Agent setup command path persistence, preferred command resolution, and workspace package metadata helpers
- `agent-setup-command-runner.ts`: Extracted agent-setup command execution, PATH shaping, Claude command candidate selection, and sanitized command result summarization
- `agent-setup-editor-tools.ts`: OpenCode/Cursor global setup status, previews, and config write helpers

View file

@ -0,0 +1,18 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
const agentSetupActionsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions-tooling.ts"), "utf8");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-actions-tooling(?:\.js)?"/, "Agent setup action shell must import the extracted tooling seam.");
assert.match(agentSetupActionsToolingSource, /export async function installOpenCodeGlobal/, "Agent setup tooling seam must export OpenCode global config installation.");
assert.match(agentSetupActionsToolingSource, /export async function removeOpenCodeGlobal/, "Agent setup tooling seam must export OpenCode global config removal.");
assert.match(agentSetupActionsToolingSource, /export async function installCursorGlobal/, "Agent setup tooling seam must export Cursor global config installation.");
assert.match(agentSetupActionsToolingSource, /export async function replaceCursorGlobal/, "Agent setup tooling seam must export Cursor global config replacement.");
assert.match(agentSetupActionsToolingSource, /export async function removeCursorGlobal/, "Agent setup tooling seam must export Cursor global config removal.");
assert.match(agentSetupActionsToolingSource, /buildFamiliarOSMcpServerPreview/, "Agent setup tooling seam must own FamiliarOS MCP server health preview shaping.");
console.error("Agent setup tooling seam validation passed.");

View file

@ -6,12 +6,14 @@ import { fileURLToPath } from "node:url";
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
const agentSetupSource = readFileSync(resolve(desktopRoot, "src/agent-setup.ts"), "utf8");
const agentSetupActionsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions-tooling.ts"), "utf8");
assert.match(agentSetupSource, /from "\.\/agent-setup-actions\.js"/, "Agent setup must import the extracted action seam.");
assert.match(agentSetupActionsSource, /export async function executeAgentSetupResolvedAction/, "Agent setup action seam must export the action executor.");
assert.match(agentSetupActionsSource, /export async function getOpenCodeSetup/, "Agent setup action seam must export OpenCode setup loading.");
assert.match(agentSetupActionsSource, /export async function getCursorSetup/, "Agent setup action seam must export Cursor setup loading.");
assert.match(agentSetupActionsSource, /export async function runAgentSetupMcpServerHealthCheck/, "Agent setup action seam must export MCP server health checks.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-actions-tooling(?:\.js)?"/, "Agent setup action seam must compose the extracted tooling seam.");
assert.match(agentSetupActionsToolingSource, /export async function getOpenCodeSetup/, "Agent setup tooling seam must export OpenCode setup loading.");
assert.match(agentSetupActionsToolingSource, /export async function getCursorSetup/, "Agent setup tooling seam must export Cursor setup loading.");
assert.match(agentSetupActionsToolingSource, /export async function runAgentSetupMcpServerHealthCheck/, "Agent setup tooling seam must export MCP server health checks.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-support\.js"/, "Agent setup action seam must compose the extracted support helper seam.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-command-context\.js"/, "Agent setup action seam must compose the extracted command context seam.");

View file

@ -6,14 +6,16 @@ import { fileURLToPath } from "node:url";
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
const agentSetupSource = readFileSync(resolve(desktopRoot, "src/agent-setup.ts"), "utf8");
const agentSetupActionsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions-tooling.ts"), "utf8");
const agentSetupCommandContextSource = readFileSync(resolve(desktopRoot, "src/agent-setup-command-context.ts"), "utf8");
assert.match(agentSetupSource, /from "\.\/agent-setup-command-context\.js"/, "Agent setup must import the extracted command context helper module.");
assert.match(agentSetupSource, /updateStoredAgentSetupCommandPaths/, "Agent setup must delegate command path persistence through the extracted command context helper.");
assert.match(agentSetupSource, /getPreferredNodeCommand/, "Agent setup must resolve preferred command paths through the extracted command context helper.");
assert.match(agentSetupActionsSource, /getCliPackageVersion/, "Agent setup action seam must resolve package version metadata through the extracted command context helper.");
assert.match(agentSetupActionsSource, /getAgentSetupCliEntryPath/, "Agent setup action seam must resolve packaged CLI entry metadata through the extracted command context helper.");
assert.match(agentSetupActionsSource, /getPreferredOpenCodeCommand/, "Agent setup action seam must resolve preferred OpenCode command paths through the extracted command context helper.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-actions-tooling(?:\.js)?"/, "Agent setup action shell must compose the extracted tooling seam.");
assert.match(agentSetupActionsToolingSource, /getCliPackageVersion/, "Agent setup tooling seam must resolve package version metadata through the extracted command context helper.");
assert.match(agentSetupActionsToolingSource, /getAgentSetupCliEntryPath/, "Agent setup tooling seam must resolve packaged CLI entry metadata through the extracted command context helper.");
assert.match(agentSetupActionsToolingSource, /getPreferredOpenCodeCommand/, "Agent setup tooling seam must resolve preferred OpenCode command paths through the extracted command context helper.");
assert.match(agentSetupCommandContextSource, /export function getStoredAgentSetupCommandPaths/, "Agent setup command context helper must own stored command path reads.");
assert.match(agentSetupCommandContextSource, /export function updateStoredAgentSetupCommandPaths/, "Agent setup command context helper must own command path validation and writes.");

View file

@ -6,14 +6,16 @@ import { fileURLToPath } from "node:url";
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
const agentSetupSource = readFileSync(resolve(desktopRoot, "src/agent-setup.ts"), "utf8");
const agentSetupActionsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions-tooling.ts"), "utf8");
const agentSetupEditorToolsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-editor-tools.ts"), "utf8");
assert.match(agentSetupSource, /from "\.\/agent-setup-actions\.js"/, "Agent setup must import the extracted action seam.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-editor-tools\.js"/, "Agent setup action seam must import the extracted editor setup helper module.");
assert.match(agentSetupActionsSource, /buildOpenCodeSetupSnapshot/, "Agent setup action seam must delegate OpenCode status/preview building through the extracted helper.");
assert.match(agentSetupActionsSource, /buildCursorSetupSnapshot/, "Agent setup action seam must delegate Cursor status/preview building through the extracted helper.");
assert.match(agentSetupActionsSource, /installOpenCodeGlobalConfig/, "Agent setup action seam must delegate OpenCode config writes through the extracted helper.");
assert.match(agentSetupActionsSource, /replaceCursorGlobalConfig/, "Agent setup action seam must delegate Cursor replace writes through the extracted helper.");
assert.match(agentSetupActionsSource, /from "\.\/agent-setup-actions-tooling(?:\.js)?"/, "Agent setup action shell must compose the extracted tooling seam.");
assert.match(agentSetupActionsToolingSource, /from "\.\/agent-setup-editor-tools\.js"/, "Agent setup tooling seam must import the extracted editor setup helper module.");
assert.match(agentSetupActionsToolingSource, /buildOpenCodeSetupSnapshot/, "Agent setup tooling seam must delegate OpenCode status/preview building through the extracted helper.");
assert.match(agentSetupActionsToolingSource, /buildCursorSetupSnapshot/, "Agent setup tooling seam must delegate Cursor status/preview building through the extracted helper.");
assert.match(agentSetupActionsToolingSource, /installOpenCodeGlobalConfig/, "Agent setup tooling seam must delegate OpenCode config writes through the extracted helper.");
assert.match(agentSetupActionsToolingSource, /replaceCursorGlobalConfig/, "Agent setup tooling seam must delegate Cursor replace writes through the extracted helper.");
assert.match(agentSetupEditorToolsSource, /export function buildOpenCodeSetupSnapshot/, "Agent setup editor helper must own the OpenCode preview/status seam.");
assert.match(agentSetupEditorToolsSource, /export function buildCursorSetupSnapshot/, "Agent setup editor helper must own the Cursor preview/status seam.");

View file

@ -6,12 +6,13 @@ import { fileURLToPath } from "node:url";
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
const agentSetupSource = readFileSync(resolve(desktopRoot, "src/agent-setup.ts"), "utf8");
const agentSetupActionsSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions.ts"), "utf8");
const agentSetupActionsToolingSource = readFileSync(resolve(desktopRoot, "src/agent-setup-actions-tooling.ts"), "utf8");
const agentSetupSupportSource = readFileSync(resolve(desktopRoot, "src/agent-setup-support.ts"), "utf8");
assert.match(agentSetupSource, /from "\.\/agent-setup-support\.js"/, "Agent setup must import the extracted support helper seam.");
assert.match(agentSetupActionsSource, /safeInstallClaudeMemory\(app\.getPath\("home"\)\)/, "Agent setup action seam must delegate Claude memory installs through the extracted support helper.");
assert.match(agentSetupActionsSource, /writeActionJournal\(\{\s*entry:/, "Agent setup action seam must delegate action journaling through the extracted support helper.");
assert.match(agentSetupActionsSource, /buildFamiliarOSMcpServerPreview/, "Agent setup action seam must delegate MCP server preview shaping through the extracted support helper.");
assert.match(agentSetupActionsToolingSource, /buildFamiliarOSMcpServerPreview/, "Agent setup tooling seam must delegate MCP server preview shaping through the extracted support helper.");
assert.match(agentSetupSupportSource, /export function buildFamiliarOSMcpServerPreview/, "Agent setup support helper must own FamiliarOS MCP preview shaping.");
assert.match(agentSetupSupportSource, /export function safeInstallClaudeMemory/, "Agent setup support helper must own Claude memory install safety wrappers.");