#!/usr/bin/env node

// bin/picktime.mjs
import fs2 from "node:fs";
import path3 from "node:path";
import { fileURLToPath as fileURLToPath2 } from "node:url";

// bin/picktime-client.mjs
import path2 from "node:path";
import { spawn } from "node:child_process";
import { fileURLToPath } from "node:url";

// bin/picktime-shared.mjs
import fs from "node:fs";
import os from "node:os";
import path from "node:path";

// bin/picktime-command-policy.mjs
var LEGACY_SHELL_BLOCKED_EXECUTABLES = Object.freeze([
  "cmd",
  "powershell",
  "pwsh",
  "sh",
  "bash",
  "zsh"
]);
var DEFAULT_BLOCKED_EXECUTABLES = Object.freeze(["rm -rf"]);
var DEFAULT_COMMAND_APPROVAL_PATTERNS = Object.freeze([
  "destructive-delete"
]);
function normalizeWhitespace(value) {
  return String(value || "").replace(/\s+/g, " ").trim();
}
function normalizePattern(value) {
  return normalizeWhitespace(value).toLowerCase();
}
function normalizeCommandPatternList(value) {
  const source = Array.isArray(value) ? value : [];
  const normalized = [];
  const seen = /* @__PURE__ */ new Set();
  for (const item of source) {
    const pattern = normalizePattern(item);
    if (!pattern || seen.has(pattern)) {
      continue;
    }
    seen.add(pattern);
    normalized.push(pattern);
  }
  return normalized;
}
function isLegacyShellBlockedList(value) {
  const normalized = normalizeCommandPatternList(value);
  return normalized.length === LEGACY_SHELL_BLOCKED_EXECUTABLES.length && LEGACY_SHELL_BLOCKED_EXECUTABLES.every((item) => normalized.includes(item));
}
function normalizeCommandPolicyConfig(commandPolicy = {}) {
  const hadBlockedExecutables = Array.isArray(
    commandPolicy?.blockedExecutables
  );
  const usedLegacyBlockedDefaults = !hadBlockedExecutables || isLegacyShellBlockedList(commandPolicy?.blockedExecutables || []);
  const blockedExecutables = usedLegacyBlockedDefaults ? [...DEFAULT_BLOCKED_EXECUTABLES] : normalizeCommandPatternList(commandPolicy?.blockedExecutables);
  const approvalPatterns = Array.isArray(commandPolicy?.approvalPatterns) ? normalizeCommandPatternList(commandPolicy.approvalPatterns) : [...DEFAULT_COMMAND_APPROVAL_PATTERNS];
  return {
    blockedExecutables,
    approvalPatterns,
    usedLegacyBlockedDefaults
  };
}

// bin/picktime-shared.mjs
var stateDir = process.env.PICKTIME_HOME || path.join(os.homedir(), ".picktime");
var skillsDir = path.join(stateDir, "skills");
var configPath = path.join(stateDir, "config.json");
var mcpConfigPath = path.join(stateDir, "mcp.json");
var runtimePath = path.join(stateDir, "runtime.json");
var logsDir = path.join(stateDir, "logs");
var auditLogPath = path.join(logsDir, "agentd-audit.jsonl");
var daemonLogPath = path.join(logsDir, "agentd.log");
var venvsDir = path.join(stateDir, "venvs");
var defaultDaemonPort = Number(
  process.env.PICKTIME_AGENTD_PORT || "43110"
);
var DEFAULT_CLIENT_VERSION = "0.0.18";
var FILESYSTEM_ACCESS_MODES = Object.freeze({
  standard: "standard",
  allowlist: "allowlist",
  unrestricted: "unrestricted"
});
var capabilityProfileCatalog = {
  white_collar: {
    label: "\u767D\u9886\u9ED8\u8BA4\u6863",
    description: "\u4F18\u5148\u8986\u76D6\u529E\u516C\u8D44\u6599\u6574\u7406\u548C\u7814\u7A76\u6C47\u603B\u3002",
    enabledPacks: ["office_bridge", "research_assistant"]
  },
  student: {
    label: "\u5B66\u751F\u9ED8\u8BA4\u6863",
    description: "\u4F18\u5148\u8986\u76D6\u8BFE\u7A0B\u8D44\u6599\u6574\u7406\u548C\u5B66\u4E60\u7814\u7A76\u3002",
    enabledPacks: ["learning_capture", "research_assistant"]
  },
  custom: {
    label: "\u81EA\u5B9A\u4E49",
    description: "\u4FDD\u7559\u624B\u52A8\u914D\u7F6E\u7684\u80FD\u529B\u5305\u7EC4\u5408\u3002",
    enabledPacks: ["office_bridge", "research_assistant"]
  }
};
function normalizeFilesystemRootList(value) {
  if (!Array.isArray(value)) {
    return [];
  }
  const seen = /* @__PURE__ */ new Set();
  const roots = [];
  for (const item of value) {
    const rawValue = String(item || "").trim();
    if (!rawValue) {
      continue;
    }
    const normalizedRoot = path.resolve(rawValue);
    const dedupeKey = normalizedRoot.toLowerCase();
    if (seen.has(dedupeKey)) {
      continue;
    }
    seen.add(dedupeKey);
    roots.push(normalizedRoot);
  }
  return roots;
}
function defaultFilesystemAllowedRoots(homeDir = os.homedir()) {
  return normalizeFilesystemRootList([
    path.join(homeDir, "Desktop"),
    path.join(homeDir, "Documents"),
    path.join(homeDir, "Downloads"),
    stateDir
  ]);
}
function defaultProtectedWriteRoots({
  platform = process.platform,
  homeDir = os.homedir(),
  env = process.env
} = {}) {
  const roots = [];
  const addRoot = (value) => {
    const rawValue = String(value || "").trim();
    if (!rawValue) {
      return;
    }
    roots.push(rawValue);
  };
  if (platform === "win32") {
    const systemDriveRoot = path.parse(homeDir).root || "C:\\";
    addRoot(
      env.SystemRoot || env.WINDIR || path.join(systemDriveRoot, "Windows")
    );
    addRoot(env.ProgramFiles);
    addRoot(env["ProgramFiles(x86)"]);
    addRoot(env.ProgramW6432);
  } else if (platform === "darwin") {
    addRoot("/System");
    addRoot("/Library");
    addRoot("/Applications");
    addRoot("/bin");
    addRoot("/sbin");
    addRoot("/usr");
  } else {
    addRoot("/bin");
    addRoot("/sbin");
    addRoot("/usr");
    addRoot("/etc");
    addRoot("/lib");
    addRoot("/opt");
  }
  return normalizeFilesystemRootList(roots);
}
function normalizeFilesystemAccessMode(value) {
  const candidate = String(value || "").trim().toLowerCase();
  if (candidate === FILESYSTEM_ACCESS_MODES.allowlist || candidate === FILESYSTEM_ACCESS_MODES.unrestricted) {
    return candidate;
  }
  return FILESYSTEM_ACCESS_MODES.standard;
}
function rootsMatchExactly(leftRoots, rightRoots) {
  if (leftRoots.length !== rightRoots.length) {
    return false;
  }
  const rightSet = new Set(rightRoots.map((item) => item.toLowerCase()));
  return leftRoots.every((item) => rightSet.has(item.toLowerCase()));
}
function inferFilesystemAccessMode({
  rawMode,
  allowedRoots,
  legacyDefaultRoots
}) {
  if (typeof rawMode === "string" && rawMode.trim()) {
    return normalizeFilesystemAccessMode(rawMode);
  }
  if (allowedRoots.length === 0 || rootsMatchExactly(allowedRoots, legacyDefaultRoots)) {
    return FILESYSTEM_ACCESS_MODES.standard;
  }
  return FILESYSTEM_ACCESS_MODES.allowlist;
}
function normalizeFilesystemPolicyConfig(filesystemPolicy = {}) {
  const legacyDefaultRoots = defaultFilesystemAllowedRoots();
  const allowedRoots = normalizeFilesystemRootList(
    filesystemPolicy.allowedRoots
  );
  const mode = inferFilesystemAccessMode({
    rawMode: filesystemPolicy.mode,
    allowedRoots,
    legacyDefaultRoots
  });
  const allowedRootsProvided = Array.isArray(filesystemPolicy.allowedRoots);
  const protectedWriteRootsProvided = Array.isArray(
    filesystemPolicy.protectedWriteRoots
  );
  const normalizedProtectedWriteRoots = normalizeFilesystemRootList(
    filesystemPolicy.protectedWriteRoots
  );
  return {
    ...filesystemPolicy,
    mode,
    allowedRoots: allowedRoots.length > 0 || allowedRootsProvided && mode === FILESYSTEM_ACCESS_MODES.allowlist ? allowedRoots : legacyDefaultRoots,
    protectedWriteRoots: normalizedProtectedWriteRoots.length > 0 || protectedWriteRootsProvided ? normalizedProtectedWriteRoots : mode === FILESYSTEM_ACCESS_MODES.unrestricted ? [] : defaultProtectedWriteRoots(),
    requireApprovalForOverwrite: typeof filesystemPolicy.requireApprovalForOverwrite === "boolean" ? filesystemPolicy.requireApprovalForOverwrite : false,
    maxWriteBytes: Number(filesystemPolicy.maxWriteBytes || 1024 * 1024),
    maxReadBytes: Number(filesystemPolicy.maxReadBytes || 1024 * 1024),
    allowWatch: filesystemPolicy.allowWatch !== false
  };
}
function normalizeCapabilityProfile(value) {
  const candidate = String(value || "white_collar").trim();
  return capabilityProfileCatalog[candidate] ? candidate : "white_collar";
}
function defaultCapabilityPacksForProfile(profile) {
  const normalizedProfile = normalizeCapabilityProfile(profile);
  return [
    ...capabilityProfileCatalog[normalizedProfile]?.enabledPacks || capabilityProfileCatalog.white_collar.enabledPacks
  ];
}
function defaultPolicies() {
  return {
    commands: {
      blockedExecutables: [...DEFAULT_BLOCKED_EXECUTABLES],
      approvalPatterns: [...DEFAULT_COMMAND_APPROVAL_PATTERNS],
      allowedExecutables: [],
      maxOutputBytes: 65536,
      maxStoredBytes: 4 * 1024 * 1024,
      defaultTimeoutMs: 12e4,
      defaultNoOutputTimeoutMs: 6e4,
      forceKillGraceMs: 2e3,
      maxEnvVars: 64
    },
    filesystem: normalizeFilesystemPolicyConfig(),
    processes: {
      maxOutputBytes: 65536,
      maxStoredBytes: 16 * 1024 * 1024,
      defaultTimeoutMs: 24 * 60 * 60 * 1e3,
      defaultNoOutputTimeoutMs: 6e4,
      finishedEntryTtlMs: 30 * 60 * 1e3,
      forceKillGraceMs: 2e3
    },
    system: {
      clipboardEnabled: true,
      notificationsEnabled: true
    }
  };
}
function readJson(file, fallback) {
  try {
    return JSON.parse(fs.readFileSync(file, "utf8"));
  } catch {
    return fallback;
  }
}
function normalizeLoadedConfig(config) {
  const normalized = config && typeof config === "object" ? { ...config } : {};
  const defaults = defaultPolicies();
  normalized.device ||= {};
  normalized.daemon ||= {};
  normalized.aiProviders ||= [];
  normalized.approvals ||= { autoApprove: false };
  normalized.capabilities ||= {};
  normalized.policies ||= {};
  normalized.policies.commands ||= {};
  normalized.policies.filesystem ||= {};
  normalized.policies.processes ||= {};
  normalized.policies.system ||= {};
  normalized.skills ||= { entries: {} };
  normalized.skills.entries ||= {};
  const normalizedCommandPolicy = normalizeCommandPolicyConfig(
    normalized.policies.commands
  );
  normalized.policies.commands = {
    ...defaults.commands,
    ...normalized.policies.commands,
    blockedExecutables: normalizedCommandPolicy.blockedExecutables,
    approvalPatterns: normalizedCommandPolicy.approvalPatterns
  };
  normalized.policies.filesystem = normalizeFilesystemPolicyConfig(
    normalized.policies.filesystem
  );
  if (normalizedCommandPolicy.usedLegacyBlockedDefaults) {
    normalized.policies.filesystem.requireApprovalForOverwrite = false;
  }
  normalized.policies.processes = {
    ...defaults.processes,
    ...normalized.policies.processes
  };
  normalized.policies.system = {
    ...defaults.system,
    ...normalized.policies.system
  };
  return normalized;
}
function loadConfig() {
  return normalizeLoadedConfig(
    readJson(configPath, {
      debug: false,
      device: {
        serverUrl: "",
        deviceId: "",
        deviceToken: "",
        name: os.hostname(),
        platform: process.platform,
        deviceFamily: process.platform === "darwin" ? "mac" : process.platform,
        clientVersion: DEFAULT_CLIENT_VERSION,
        autoConnect: true,
        heartbeatIntervalMs: 3e4
      },
      daemon: {
        port: defaultDaemonPort
      },
      aiProviders: [],
      approvals: {
        autoApprove: false
      },
      capabilities: {
        profile: "white_collar",
        enabledPacks: defaultCapabilityPacksForProfile("white_collar")
      },
      policies: defaultPolicies(),
      skills: {
        entries: {}
      }
    })
  );
}
function loadRuntime() {
  return readJson(runtimePath, null);
}

// bin/picktime-client.mjs
var daemonScriptPath = path2.join(path2.dirname(fileURLToPath(import.meta.url)), "picktime-agentd.mjs");
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
function getRuntimeMeta() {
  const runtime = loadRuntime();
  if (runtime?.port && runtime?.token) {
    return runtime;
  }
  const config = loadConfig();
  return {
    port: Number(config.daemon?.port || defaultDaemonPort),
    token: String(config.daemon?.authToken || "")
  };
}
async function isDaemonHealthy(runtime = getRuntimeMeta()) {
  if (!runtime?.port) {
    return false;
  }
  try {
    const response = await fetch(`http://127.0.0.1:${runtime.port}/health`);
    return response.ok;
  } catch {
    return false;
  }
}
async function startDaemon() {
  let runtime = getRuntimeMeta();
  if (await isDaemonHealthy(runtime)) {
    return runtime;
  }
  for (let attempt = 0; attempt < 8; attempt += 1) {
    await sleep(125);
    runtime = getRuntimeMeta();
    if (await isDaemonHealthy(runtime)) {
      return runtime;
    }
  }
  const child = spawn(process.execPath, [daemonScriptPath], {
    detached: true,
    stdio: "ignore"
  });
  child.unref();
  for (let attempt = 0; attempt < 40; attempt += 1) {
    await sleep(150);
    runtime = getRuntimeMeta();
    if (await isDaemonHealthy(runtime)) {
      return runtime;
    }
  }
  throw new Error(`agentd_start_failed:${runtimePath}`);
}
async function callDaemon(method, params = {}, { autoStart = true } = {}) {
  let runtime = getRuntimeMeta();
  if (!await isDaemonHealthy(runtime)) {
    if (!autoStart) {
      throw new Error("agentd_not_running");
    }
    runtime = await startDaemon();
  }
  const response = await fetch(`http://127.0.0.1:${runtime.port}/rpc`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Picktime-Token": runtime.token
    },
    body: JSON.stringify({
      method,
      params
    })
  });
  const body = await response.json().catch(() => ({}));
  if (!response.ok || body.ok === false) {
    throw new Error(body.error || `agentd_rpc_failed:${response.status}`);
  }
  return body.result;
}
async function stopDaemon() {
  try {
    await callDaemon("shutdown", {}, { autoStart: false });
    return { ok: true };
  } catch (error) {
    if (String(error?.message || error) === "agentd_not_running") {
      return { ok: true, alreadyStopped: true };
    }
    throw error;
  }
}

// bin/picktime.mjs
var currentDir = path3.dirname(fileURLToPath2(import.meta.url));
function resolveCliVersion() {
  try {
    const packageJson = JSON.parse(
      fs2.readFileSync(path3.join(currentDir, "package.json"), "utf8")
    );
    if (typeof packageJson.version === "string" && packageJson.version.trim()) {
      return packageJson.version.trim();
    }
  } catch {
  }
  return DEFAULT_CLIENT_VERSION;
}
function print(value) {
  process.stdout.write(
    `${typeof value === "string" ? value : JSON.stringify(value, null, 2)}
`
  );
}
function usage() {
  print(`picktime status
picktime doctor
picktime service start|stop|restart|status|logs
picktime skills list|inspect|install|uninstall|enable|disable|set-runner|setup-python|run
picktime mcp list|inspect|tools|call|add|add-http|remove|enable|disable
picktime device status|pair|set-credentials|clear|sync
picktime runs list
picktime approvals list|approve|deny`);
}
async function main() {
  const args = process.argv.slice(2);
  const [group, action, ...rest] = args;
  if (args.length === 1 && (group === "--version" || group === "-v" || group === "version")) {
    print(resolveCliVersion());
    return;
  }
  if (args.length === 1 && (group === "--help" || group === "-h" || group === "help")) {
    usage();
    return;
  }
  if (!group) {
    usage();
    process.exitCode = 1;
    return;
  }
  if (group === "service") {
    if (action === "start") {
      print(await startDaemon());
      return;
    }
    if (action === "stop") {
      print(await stopDaemon());
      return;
    }
    if (action === "restart") {
      await stopDaemon();
      print(await startDaemon());
      return;
    }
    if (action === "status") {
      print({
        runtime: loadRuntime(),
        healthy: await isDaemonHealthy(loadRuntime())
      });
      return;
    }
    if (action === "logs") {
      print(
        await callDaemon(
          "get_logs",
          { lines: Number(rest[0] || 100) },
          { autoStart: false }
        )
      );
      return;
    }
  }
  if (group === "status") {
    print(await callDaemon("get_status"));
    return;
  }
  if (group === "doctor") {
    print(await callDaemon("doctor"));
    return;
  }
  if (group === "skills") {
    if (action === "list" || action === "--list" || action === "-l") {
      print(await callDaemon("list_skills"));
      return;
    }
    if (action === "inspect") {
      print(await callDaemon("inspect_skill", { name: rest[0] }));
      return;
    }
    if (action === "install") {
      print(
        await callDaemon("install_skill", {
          sourcePath: rest[0],
          installDeps: rest.includes("--install-deps"),
          allowSuspicious: rest.includes("--allow-suspicious")
        })
      );
      return;
    }
    if (action === "uninstall") {
      print(await callDaemon("uninstall_skill", { name: rest[0] }));
      return;
    }
    if (action === "enable" || action === "disable") {
      print(
        await callDaemon("set_skill_enabled", {
          name: rest[0],
          enabled: action === "enable"
        })
      );
      return;
    }
    if (action === "set-runner") {
      const [name, command, ...args2] = rest;
      if (!name || !command) {
        throw new Error("skill_set_runner_requires_name_and_command");
      }
      print(
        await callDaemon("set_skill_runner", {
          name,
          runner: {
            command,
            args: args2
          }
        })
      );
      return;
    }
    if (action === "setup-python") {
      print(await callDaemon("setup_python_skill_env", { name: rest[0] }));
      return;
    }
    if (action === "run") {
      const [name, ...args2] = rest;
      print(await callDaemon("run_skill", { name, args: args2 }));
      return;
    }
  }
  if (group === "mcp") {
    if (action === "list" || action === "--list" || action === "-l") {
      print(await callDaemon("list_mcp_servers"));
      return;
    }
    if (action === "inspect") {
      print(await callDaemon("inspect_mcp_server", { name: rest[0] }));
      return;
    }
    if (action === "tools") {
      const targetName = rest.find((item) => !item.startsWith("-"));
      print(
        await callDaemon("get_mcp_catalog", {
          name: targetName,
          refresh: rest.includes("--refresh")
        })
      );
      return;
    }
    if (action === "call") {
      const [name, toolName, argumentsJson] = rest;
      if (!name || !toolName) {
        throw new Error("mcp_call_requires_name_and_tool_name");
      }
      let argumentsPayload = {};
      if (typeof argumentsJson === "string" && argumentsJson.trim()) {
        try {
          argumentsPayload = JSON.parse(argumentsJson);
        } catch {
          throw new Error("mcp_call_arguments_json_invalid");
        }
      }
      print(
        await callDaemon("run_mcp_tool", {
          serverName: name,
          toolName,
          arguments: argumentsPayload
        })
      );
      return;
    }
    if (action === "add") {
      const [name, command, ...args2] = rest;
      if (!name || !command) {
        throw new Error("mcp_add_requires_name_and_command");
      }
      print(await callDaemon("add_mcp_stdio", { name, command, args: args2 }));
      return;
    }
    if (action === "add-http") {
      const [name, url] = rest;
      if (!name || !url) {
        throw new Error("mcp_add_http_requires_name_and_url");
      }
      print(await callDaemon("add_mcp_http", { name, url }));
      return;
    }
    if (action === "remove") {
      print(await callDaemon("remove_mcp_server", { name: rest[0] }));
      return;
    }
    if (action === "enable" || action === "disable") {
      print(
        await callDaemon("set_mcp_enabled", {
          name: rest[0],
          enabled: action === "enable"
        })
      );
      return;
    }
  }
  if (group === "device") {
    if (action === "status") {
      print(await callDaemon("get_device_status"));
      return;
    }
    if (action === "pair") {
      const [serverUrl, accessToken, name] = rest;
      print(await callDaemon("pair_device", { serverUrl, accessToken, name }));
      return;
    }
    if (action === "set-credentials") {
      const [serverUrl, deviceId, deviceToken, name] = rest;
      print(
        await callDaemon("set_device_credentials", {
          serverUrl,
          deviceId,
          deviceToken,
          name
        })
      );
      return;
    }
    if (action === "clear") {
      print(await callDaemon("clear_device_credentials"));
      return;
    }
    if (action === "sync") {
      print(await callDaemon("sync_capabilities"));
      return;
    }
  }
  if (group === "runs" && (action === "list" || action === "--list" || action === "-l")) {
    print(
      await callDaemon("list_run_history", { limit: Number(rest[0] || 20) })
    );
    return;
  }
  if (group === "approvals") {
    if (action === "list" || action === "--list" || action === "-l") {
      print(await callDaemon("list_approvals"));
      return;
    }
    if (action === "approve") {
      print(
        await callDaemon("resolve_approval", {
          approvalId: rest[0],
          decision: "approve"
        })
      );
      return;
    }
    if (action === "deny") {
      print(
        await callDaemon("resolve_approval", {
          approvalId: rest[0],
          decision: "deny"
        })
      );
      return;
    }
  }
  usage();
  process.exitCode = 1;
}
main().catch((error) => {
  process.stderr.write(
    `${error instanceof Error ? error.message : String(error)}
`
  );
  process.exitCode = 1;
});
