@tekmidian/pai 0.13.3 → 0.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import "../db-CmYbAVCD.mjs";
6
6
  import "../helpers-IjZkXBhj.mjs";
7
7
  import "../embeddings-BJPOcbik.mjs";
8
8
  import "../search-HcdKtMla.mjs";
9
- import "../pick-DhF8-WFT.mjs";
9
+ import "../pick-CmG7SCtp.mjs";
10
10
  import "../kg-extraction-C8DEUHTS.mjs";
11
11
  import "../factory-Q88X1bAN.mjs";
12
12
  import "../config-C8m-tPhP.mjs";
@@ -5,7 +5,7 @@ import "../db-CmYbAVCD.mjs";
5
5
  import "../helpers-IjZkXBhj.mjs";
6
6
  import "../embeddings-BJPOcbik.mjs";
7
7
  import "../search-HcdKtMla.mjs";
8
- import { C as registerDaemonCommands, D as registerProjectsCommands, E as registerRegistryCommands, O as findMovedPath, S as registerBackupCommands, T as registerMemoryCommands, _ as registerObservationCommands, a as cmdPauseAll, b as registerSetupCommand, c as cmdPause, d as registerKgCommands, f as registerTopicCommands, g as registerSkillCommands, h as registerUpdateCommand, i as cmdClearNames, k as resolveIdentifier, l as registerHelpCommand, m as registerNotifyCommands, n as cmdFind, o as cmdGoto, p as registerTaskCommands, r as cmdList, s as cmdEnd, t as cmdPick, u as registerDbCommands, v as registerZettelCommands, w as registerMcpCommands, x as registerRestoreCommands, y as registerObsidianCommands } from "../pick-DhF8-WFT.mjs";
8
+ import { C as registerDaemonCommands, D as registerProjectsCommands, E as registerRegistryCommands, O as findMovedPath, S as registerBackupCommands, T as registerMemoryCommands, _ as registerObservationCommands, a as cmdPauseAll, b as registerSetupCommand, c as cmdPause, d as registerKgCommands, f as registerTopicCommands, g as registerSkillCommands, h as registerUpdateCommand, i as cmdClearNames, k as resolveIdentifier, l as registerHelpCommand, m as registerNotifyCommands, n as cmdFind, o as cmdGoto, p as registerTaskCommands, r as cmdList, s as cmdEnd, t as cmdPick, u as registerDbCommands, v as registerZettelCommands, w as registerMcpCommands, x as registerRestoreCommands, y as registerObsidianCommands } from "../pick-CmG7SCtp.mjs";
9
9
  import "../kg-extraction-C8DEUHTS.mjs";
10
10
  import "../factory-Q88X1bAN.mjs";
11
11
  import "../config-C8m-tPhP.mjs";
@@ -1898,9 +1898,80 @@ function registerMemoryCommands(memoryCmd, getDb) {
1898
1898
  registerStatsCommands(memoryCmd, getDb);
1899
1899
  }
1900
1900
 
1901
+ //#endregion
1902
+ //#region src/config/claude-json.ts
1903
+ /**
1904
+ * claude-json.ts — safe read/write for ~/.claude.json
1905
+ *
1906
+ * This file is not ours. It holds every MCP server registration plus Claude
1907
+ * Code's own per-project state — on a working machine, hundreds of kilobytes
1908
+ * that no one can reconstruct by hand. PAI only ever adds one key to it.
1909
+ *
1910
+ * The previous implementation (duplicated in mcp.ts and daemon.ts) did:
1911
+ *
1912
+ * try { return JSON.parse(read(path)); } catch { return {}; }
1913
+ *
1914
+ * followed by a full-file write. A malformed or transiently unreadable file
1915
+ * therefore became an empty object, and the next write replaced the user's
1916
+ * entire config with just PAI's entry. No error, no backup, exit code 0.
1917
+ *
1918
+ * The precondition is unlikely, which is exactly the problem: `pai setup` is
1919
+ * advertised as idempotent and safe to re-run, so it is what people run when
1920
+ * something is already broken — the state in which the file is most likely to
1921
+ * be malformed.
1922
+ */
1923
+ const CLAUDE_JSON_PATH = join(homedir(), ".claude.json");
1924
+ const BACKUP_PATH = `${CLAUDE_JSON_PATH}.bak-pai`;
1925
+ /**
1926
+ * Read ~/.claude.json.
1927
+ *
1928
+ * A missing file is a legitimate first-run state and yields {}. Anything else
1929
+ * — malformed JSON, permissions, a half-written file — throws. Returning {}
1930
+ * for an unreadable file is what turns a read problem into data loss on the
1931
+ * next write.
1932
+ */
1933
+ function readClaudeJson() {
1934
+ if (!existsSync(CLAUDE_JSON_PATH)) return {};
1935
+ let raw;
1936
+ try {
1937
+ raw = readFileSync(CLAUDE_JSON_PATH, "utf8");
1938
+ } catch (e) {
1939
+ throw new Error(`Could not read ${CLAUDE_JSON_PATH}: ${e instanceof Error ? e.message : String(e)}\nRefusing to continue — writing now would replace your MCP registrations with PAI's alone.`);
1940
+ }
1941
+ try {
1942
+ return JSON.parse(raw);
1943
+ } catch (e) {
1944
+ throw new Error(`${CLAUDE_JSON_PATH} is not valid JSON: ${e instanceof Error ? e.message : String(e)}\nRefusing to continue — overwriting it would destroy every MCP server registration it holds.\nFix the file, or move it aside and let Claude Code recreate it, then re-run this command.`);
1945
+ }
1946
+ }
1947
+ /**
1948
+ * Write ~/.claude.json, keeping a backup and never leaving it half-written.
1949
+ *
1950
+ * Writes to a temp file and renames: rename is atomic within a filesystem, so
1951
+ * a crash mid-write leaves the original intact rather than truncated. The
1952
+ * previous direct writeFileSync could truncate the file and then fail.
1953
+ */
1954
+ function writeClaudeJson(data) {
1955
+ const serialized = JSON.stringify(data, null, 2) + "\n";
1956
+ if (existsSync(CLAUDE_JSON_PATH)) try {
1957
+ copyFileSync(CLAUDE_JSON_PATH, BACKUP_PATH);
1958
+ } catch (e) {
1959
+ throw new Error(`Could not back up ${CLAUDE_JSON_PATH} to ${BACKUP_PATH}: ${e instanceof Error ? e.message : String(e)}\nRefusing to write without a backup.`);
1960
+ }
1961
+ const tmp = `${CLAUDE_JSON_PATH}.tmp-pai-${process.pid}`;
1962
+ try {
1963
+ writeFileSync(tmp, serialized, "utf8");
1964
+ renameSync(tmp, CLAUDE_JSON_PATH);
1965
+ } catch (e) {
1966
+ try {
1967
+ if (existsSync(tmp)) unlinkSync(tmp);
1968
+ } catch {}
1969
+ throw new Error(`Failed to write ${CLAUDE_JSON_PATH}: ${e instanceof Error ? e.message : String(e)}\nThe original is unchanged${existsSync(BACKUP_PATH) ? `; a backup is at ${BACKUP_PATH}` : ""}.`);
1970
+ }
1971
+ }
1972
+
1901
1973
  //#endregion
1902
1974
  //#region src/cli/commands/mcp.ts
1903
- const CLAUDE_JSON_PATH$1 = join(homedir(), ".claude.json");
1904
1975
  /**
1905
1976
  * Resolve the absolute path to the built MCP entry point.
1906
1977
  *
@@ -1911,21 +1982,9 @@ const CLAUDE_JSON_PATH$1 = join(homedir(), ".claude.json");
1911
1982
  function getMcpBinPath() {
1912
1983
  return join(dirname(fileURLToPath(import.meta.url)), "../mcp/index.mjs");
1913
1984
  }
1914
- function readClaudeJson$1() {
1915
- if (!existsSync(CLAUDE_JSON_PATH$1)) return {};
1916
- try {
1917
- const raw = readFileSync(CLAUDE_JSON_PATH$1, "utf8");
1918
- return JSON.parse(raw);
1919
- } catch {
1920
- return {};
1921
- }
1922
- }
1923
- function writeClaudeJson$1(data) {
1924
- writeFileSync(CLAUDE_JSON_PATH$1, JSON.stringify(data, null, 2) + "\n", "utf8");
1925
- }
1926
1985
  function cmdInstall$1() {
1927
1986
  const mcpBin = getMcpBinPath();
1928
- const config = readClaudeJson$1();
1987
+ const config = readClaudeJson();
1929
1988
  if (typeof config.mcpServers !== "object" || config.mcpServers === null) config.mcpServers = {};
1930
1989
  const servers = config.mcpServers;
1931
1990
  if ("pai" in servers) {
@@ -1939,7 +1998,7 @@ function cmdInstall$1() {
1939
1998
  args: [mcpBin]
1940
1999
  };
1941
2000
  try {
1942
- writeClaudeJson$1(config);
2001
+ writeClaudeJson(config);
1943
2002
  } catch (e) {
1944
2003
  console.error(err(`Failed to write ~/.claude.json: ${e}`));
1945
2004
  process.exit(1);
@@ -1958,7 +2017,7 @@ function cmdInstall$1() {
1958
2017
  }
1959
2018
  function cmdStatus$3() {
1960
2019
  const mcpBin = getMcpBinPath();
1961
- const config = readClaudeJson$1();
2020
+ const config = readClaudeJson();
1962
2021
  const servers = typeof config.mcpServers === "object" && config.mcpServers !== null ? config.mcpServers : {};
1963
2022
  const registered = "pai" in servers;
1964
2023
  const binExists = existsSync(mcpBin);
@@ -1997,7 +2056,6 @@ function registerMcpCommands(mcpCmd) {
1997
2056
  //#endregion
1998
2057
  //#region src/cli/commands/daemon.ts
1999
2058
  const HOME$2 = homedir();
2000
- const CLAUDE_JSON_PATH = join(HOME$2, ".claude.json");
2001
2059
  const PLIST_LABEL = "com.pai.pai-daemon";
2002
2060
  const LAUNCH_AGENTS_DIR = join(HOME$2, "Library", "LaunchAgents");
2003
2061
  const PLIST_PATH = join(LAUNCH_AGENTS_DIR, `${PLIST_LABEL}.plist`);
@@ -2017,18 +2075,6 @@ function getDaemonBinPath() {
2017
2075
  function getShimBinPath() {
2018
2076
  return join(dirname(fileURLToPath(import.meta.url)), "../daemon-mcp/index.mjs");
2019
2077
  }
2020
- function readClaudeJson() {
2021
- if (!existsSync(CLAUDE_JSON_PATH)) return {};
2022
- try {
2023
- const raw = readFileSync(CLAUDE_JSON_PATH, "utf8");
2024
- return JSON.parse(raw);
2025
- } catch {
2026
- return {};
2027
- }
2028
- }
2029
- function writeClaudeJson(data) {
2030
- writeFileSync(CLAUDE_JSON_PATH, JSON.stringify(data, null, 2) + "\n", "utf8");
2031
- }
2032
2078
  function generatePlist(daemonBin) {
2033
2079
  return `<?xml version="1.0" encoding="UTF-8"?>
2034
2080
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -6048,7 +6094,7 @@ function stepVerifyRepo() {
6048
6094
  const gitDir = capture("git rev-parse --show-toplevel", getPaiSrcDir());
6049
6095
  if (!gitDir) {
6050
6096
  error("Not a git repository. Cannot update automatically.");
6051
- info("Install PAI via npm to get automatic updates: npm install -g @mnott/pai");
6097
+ info("Install PAI via npm to get automatic updates: npm install -g @tekmidian/pai");
6052
6098
  return null;
6053
6099
  }
6054
6100
  const remote = capture("git remote get-url origin", gitDir);
@@ -9015,4 +9061,4 @@ async function cmdPick(db, opts = {}) {
9015
9061
 
9016
9062
  //#endregion
9017
9063
  export { registerDaemonCommands as C, registerProjectsCommands as D, registerRegistryCommands as E, findMovedPath as O, registerBackupCommands as S, registerMemoryCommands as T, registerObservationCommands as _, cmdPauseAll as a, registerSetupCommand as b, cmdPause as c, registerKgCommands as d, registerTopicCommands as f, registerSkillCommands as g, registerUpdateCommand as h, cmdClearNames as i, resolveIdentifier as k, registerHelpCommand as l, registerNotifyCommands as m, cmdFind as n, cmdGoto as o, registerTaskCommands as p, cmdList as r, cmdEnd as s, cmdPick as t, registerDbCommands as u, registerZettelCommands as v, registerMcpCommands as w, registerRestoreCommands as x, registerObsidianCommands as y };
9018
- //# sourceMappingURL=pick-DhF8-WFT.mjs.map
9064
+ //# sourceMappingURL=pick-CmG7SCtp.mjs.map