Code

/**
 * mcp/skills/syncSystemTime.ts — sync_system_time
 *
 * Forces an immediate NTP resync.  The identity-auth-repair skill calls
 * this after check_ntp_status reports significant drift.
 *
 * Platform strategy
 * -----------------
 * darwin  `sudo sntp -sS <server>` — requires admin; writes the clock.
 * win32   `w32tm /resync /force`  — requires admin; nudges W32Time to
 *         re-query its time source.
 *
 * Large time jumps can trigger endpoint security software alerts and
 * break TLS sessions mid-flight — hence requiresConsent + supportsDryRun.
 * Dry-run reports the exact command that would run.
 */
 
import { z } from "zod";
 
import { execAsync, isDarwin, isWin32 } from "./_shared/platform";
 
// -- Meta ---------------------------------------------------------------------
 
export const meta = {
  name: "sync_system_time",
  description:
    "Forces an immediate NTP clock resync on the endpoint. Use ONLY after " +
    "check_ntp_status reports significant drift. Requires admin privileges. " +
    "Large time jumps can break in-flight TLS sessions and trigger endpoint " +
    "security software alerts — always run dry-run first so the user can see " +
    "the command.",
  riskLevel:       "medium",
  destructive:     false,
  requiresConsent: true,
  supportsDryRun:  true,
  affectedScope:   ["system"],
  auditRequired:   true,
  schema: {
    server: z
      .string()
      .optional()
      .describe(
        "Reference NTP server. Defaults to 'time.apple.com' on macOS, " +
        "the configured peer on Windows.",
      ),
    dryRun: z
      .boolean()
      .optional()
      .describe("When true, report the command that would run without executing."),
  },
} as const;
 
// -- Types --------------------------------------------------------------------
 
export interface SyncTimeResult {
  platform: "darwin" | "win32" | "other";
  command:  string;
  dryRun:   boolean;
  success:  boolean;
  stdout?:  string;
  error?:   string;
  message:  string;
}
 
// -- Implementation -----------------------------------------------------------
 
async function syncDarwin(server: string, dryRun: boolean): Promise<SyncTimeResult> {
  const command = `sudo sntp -sS ${shellQuote(server)}`;
  if (dryRun) {
    return {
      platform: "darwin", command, dryRun: true, success: true,
      message: `Would run \`${command}\` (requires admin). No changes yet.`,
    };
  }
  try {
    const { stdout } = await execAsync(command, {
      maxBuffer: 1 * 1024 * 1024, timeout: 10_000,
    });
    return {
      platform: "darwin", command, dryRun: false, success: true,
      stdout,
      message: `System clock resync requested via ${server}.`,
    };
  } catch (err) {
    const msg = (err as Error).message;
    return {
      platform: "darwin", command, dryRun: false, success: false,
      error: msg,
      message: formatSyncError("darwin", msg, command),
    };
  }
}
 
async function syncWin32(dryRun: boolean): Promise<SyncTimeResult> {
  const command = `w32tm /resync /force`;
  if (dryRun) {
    return {
      platform: "win32", command, dryRun: true, success: true,
      message: `Would run \`${command}\` (requires admin). No changes yet.`,
    };
  }
  try {
    const { stdout } = await execAsync(command, {
      maxBuffer: 1 * 1024 * 1024, timeout: 10_000,
    });
    return {
      platform: "win32", command, dryRun: false, success: true,
      stdout,
      message: `Windows Time service resync requested.`,
    };
  } catch (err) {
    const msg = (err as Error).message;
    return {
      platform: "win32", command, dryRun: false, success: false,
      error: msg,
      message: formatSyncError("win32", msg, command),
    };
  }
}
 
function shellQuote(s: string): string {
  return `'${s.replace(/'/g, `'\\''`)}'`;
}
 
/**
 * Maps a raw error message to a user-friendly guidance message per
 * platform.  Extracted so the branch logic can be unit-tested without
 * mocking execAsync rejections (which vitest 4 flags as unhandled
 * rejections even inside try/catch).
 */
export function formatSyncError(platform: "darwin" | "win32", msg: string, command: string): string {
  if (platform === "darwin") {
    return /sudo/i.test(msg)
      ? `sudo authentication required. Ask the user to run \`${command}\` manually, or re-run this with elevated privileges.`
      : `sntp failed: ${msg}`;
  }
  if (/access is denied/i.test(msg) || /^5:/.test(msg)) {
    return `Admin rights required. Open an elevated Command Prompt and run \`${command}\`.`;
  }
  return `w32tm /resync /force failed: ${msg}`;
}
 
// Exported for unit tests.
export const __testing = { syncDarwin, syncWin32 };
 
// -- Exported run function ----------------------------------------------------
 
export async function run({
  server,
  dryRun = false,
}: {
  server?: string;
  dryRun?: boolean;
} = {}): Promise<SyncTimeResult> {
  const platform: "darwin" | "win32" | "other" =
    isDarwin() ? "darwin" : isWin32() ? "win32" : "other";
 
  if (platform === "darwin") {
    return syncDarwin(server ?? "time.apple.com", dryRun);
  }
  if (platform === "win32") {
    return syncWin32(dryRun);
  }
 
  return {
    platform: "other", command: "(unsupported)", dryRun, success: false,
    message: "Unsupported platform — cannot sync system time.",
  };
}
 
// -- CLI smoke test -----------------------------------------------------------
 
if (false) {
  run({ dryRun: true })
    .then((r) => console.log(JSON.stringify(r, null, 2)))
    .catch((err: Error) => { console.error(err.message); process.exit(1); });
}