@tekmidian/pai 0.13.2 → 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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/ts/user-prompt/whisper-rules.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n\n/**\n * whisper-rules.ts\n *\n * UserPromptSubmit hook that injects:\n * 1. User-defined whisper rules from ~/.claude/whisper-rules.md\n * 2. Budget-aware model tiering guidance from ~/.claude/advisor-mode.json\n *\n * The advisor mode implements the \"advisor strategy\" pattern:\n * - Normal (budget < 70%): use any model freely\n * - Conservative (70-85%): prefer haiku for subagents, sonnet for main work\n * - Strict (85-95%): haiku only for subagents, main context stays on current model\n * - Critical (>95%): minimize all subagent spawning, essential work only\n *\n * Budget percentage is written by the statusline or manually to advisor-mode.json.\n * If the file doesn't exist, no advisor guidance is injected.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst WHISPER_FILE = join(homedir(), \".claude\", \"whisper-rules.md\");\nconst ADVISOR_FILE = join(homedir(), \".claude\", \"advisor-mode.json\");\n\nfunction getWhisperRules(): string {\n if (existsSync(WHISPER_FILE)) {\n try {\n const content = readFileSync(WHISPER_FILE, \"utf-8\").trim();\n if (content) return content;\n } catch { /* ignore */ }\n }\n return \"\";\n}\n\ninterface AdvisorConfig {\n weeklyBudgetPercent?: number; // 0-100, written by statusline or manually\n mode?: \"normal\" | \"conservative\" | \"strict\" | \"critical\" | \"auto\";\n forceModel?: string; // override: always use this model for subagents\n}\n\nfunction getAdvisorGuidance(): string {\n if (!existsSync(ADVISOR_FILE)) return \"\";\n\n let config: AdvisorConfig;\n try {\n config = JSON.parse(readFileSync(ADVISOR_FILE, \"utf-8\"));\n } catch {\n return \"\";\n }\n\n // Determine mode\n let mode = config.mode ?? \"auto\";\n if (mode === \"auto\" && typeof config.weeklyBudgetPercent === \"number\") {\n const pct = config.weeklyBudgetPercent;\n if (pct < 60) mode = \"normal\";\n else if (pct < 80) mode = \"conservative\";\n else if (pct < 92) mode = \"strict\";\n else mode = \"critical\";\n }\n\n // Force model override\n if (config.forceModel) {\n return `ADVISOR MODE: Use model \"${config.forceModel}\" for ALL subagents (Agent tool calls). This is a manual override.`;\n }\n\n switch (mode) {\n case \"normal\":\n return \"\"; // No constraints \u2014 use models freely\n\n case \"conservative\":\n return [\n `ADVISOR MODE (conservative \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"Main context is opus (most expensive \u2014 20x haiku, 5x sonnet). Delegate aggressively to subagents.\",\n \"Default subagents to SONNET (Agent tool, model: sonnet). Use haiku for simple lookups/verification.\",\n \"For substantial tasks, use swarm mode: spawn a sonnet orchestrator that delegates to haiku workers.\",\n \"Keep main context responses short \u2014 the goal is to minimize opus token burn.\",\n ].join(\" \");\n\n case \"strict\":\n return [\n `ADVISOR MODE (strict \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"Main context is opus (most expensive \u2014 20x haiku, 5x sonnet). Minimize work done here.\",\n \"Default subagents to SONNET (Agent tool, model: sonnet) for implementation and research. Use haiku for simple tasks.\",\n \"For any substantial task, use swarm mode: spawn ONE sonnet orchestrator that delegates to haiku workers.\",\n \"Keep main context responses short \u2014 receive results from agents, summarize briefly, done.\",\n \"Never spawn opus subagents. Every line of opus output costs 5x what sonnet costs.\",\n ].join(\" \");\n\n case \"critical\":\n return [\n `ADVISOR MODE (critical \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"MINIMIZE ALL TOKEN USAGE. Main context is opus \u2014 the most expensive model (20x haiku, 5x sonnet).\",\n \"For ANY non-trivial task, immediately spawn a sonnet orchestrator agent and let it handle everything.\",\n \"Main context should only send the task and receive the final result \u2014 do not do work here.\",\n \"Keep main context responses extremely concise \u2014 short answers, minimal explanation.\",\n \"Use sonnet for orchestration, haiku for workers. Never spawn opus subagents. Skip spotchecks.\",\n \"The user is near their weekly limit \u2014 do as little as possible in opus main context.\",\n ].join(\" \");\n\n default:\n return \"\";\n }\n}\n\nfunction main() {\n const parts: string[] = [];\n\n const rules = getWhisperRules();\n if (rules) parts.push(rules);\n\n const advisor = getAdvisorGuidance();\n if (advisor) parts.push(advisor);\n\n if (parts.length === 0) return;\n\n console.log(`<system-reminder>\\n${parts.join(\"\\n\")}\\n</system-reminder>`);\n}\n\nmain();\n"],
5
- "mappings": ";;;AAmBA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,eAAe;AAExB,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,kBAAkB;AAClE,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,mBAAmB;AAEnE,SAAS,kBAA0B;AACjC,MAAI,WAAW,YAAY,GAAG;AAC5B,QAAI;AACF,YAAM,UAAU,aAAa,cAAc,OAAO,EAAE,KAAK;AACzD,UAAI,QAAS,QAAO;AAAA,IACtB,QAAQ;AAAA,IAAe;AAAA,EACzB;AACA,SAAO;AACT;AAQA,SAAS,qBAA6B;AACpC,MAAI,CAAC,WAAW,YAAY,EAAG,QAAO;AAEtC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,OAAO,QAAQ;AAC1B,MAAI,SAAS,UAAU,OAAO,OAAO,wBAAwB,UAAU;AACrE,UAAM,MAAM,OAAO;AACnB,QAAI,MAAM,GAAI,QAAO;AAAA,aACZ,MAAM,GAAI,QAAO;AAAA,aACjB,MAAM,GAAI,QAAO;AAAA,QACrB,QAAO;AAAA,EACd;AAGA,MAAI,OAAO,YAAY;AACrB,WAAO,4BAA4B,OAAO,UAAU;AAAA,EACtD;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA;AAAA,IAET,KAAK;AACH,aAAO;AAAA,QACL,sDAAiD,OAAO,uBAAuB,GAAG;AAAA,QAClF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ,KAAK;AACH,aAAO;AAAA,QACL,gDAA2C,OAAO,uBAAuB,GAAG;AAAA,QAC5E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ,KAAK;AACH,aAAO;AAAA,QACL,kDAA6C,OAAO,uBAAuB,GAAG;AAAA,QAC9E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,OAAO;AACd,QAAM,QAAkB,CAAC;AAEzB,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,MAAO,OAAM,KAAK,KAAK;AAE3B,QAAM,UAAU,mBAAmB;AACnC,MAAI,QAAS,OAAM,KAAK,OAAO;AAE/B,MAAI,MAAM,WAAW,EAAG;AAExB,UAAQ,IAAI;AAAA,EAAsB,MAAM,KAAK,IAAI,CAAC;AAAA,mBAAsB;AAC1E;AAEA,KAAK;",
4
+ "sourcesContent": ["#!/usr/bin/env node\n\n/**\n * whisper-rules.ts\n *\n * UserPromptSubmit hook that injects:\n * 1. User-defined whisper rules from ~/.claude/whisper-rules.md\n * 2. Budget-aware model tiering guidance from ~/.claude/advisor-mode.json\n *\n * The advisor mode implements the \"advisor strategy\" pattern:\n * - Normal (budget < 70%): use any model freely\n * - Conservative (70-85%): prefer haiku for subagents, sonnet for main work\n * - Strict (85-95%): haiku only for subagents, main context stays on current model\n * - Critical (>95%): minimize all subagent spawning, essential work only\n *\n * Budget percentage is written by the statusline or manually to advisor-mode.json.\n * If the file doesn't exist, no advisor guidance is injected.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst WHISPER_FILE = join(homedir(), \".claude\", \"whisper-rules.md\");\nconst ADVISOR_FILE = join(homedir(), \".claude\", \"advisor-mode.json\");\n\nfunction getWhisperRules(): string {\n if (existsSync(WHISPER_FILE)) {\n try {\n const content = readFileSync(WHISPER_FILE, \"utf-8\").trim();\n if (content) return content;\n } catch { /* ignore */ }\n }\n return \"\";\n}\n\ninterface AdvisorConfig {\n weeklyBudgetPercent?: number; // 0-100, written by statusline or manually\n mode?: \"normal\" | \"conservative\" | \"strict\" | \"critical\" | \"auto\";\n forceModel?: string; // override: always use this model for subagents\n}\n\nfunction getAdvisorGuidance(): string {\n if (!existsSync(ADVISOR_FILE)) return \"\";\n\n let config: AdvisorConfig;\n try {\n config = JSON.parse(readFileSync(ADVISOR_FILE, \"utf-8\"));\n } catch {\n return \"\";\n }\n\n // Determine mode.\n //\n // `??` only substitutes on null/undefined, so a config written as\n // {\"mode\": \"\"} \u2014 which is what the statusline produces when it has no manual\n // override \u2014 left mode as the empty string. That matched no case below, so\n // the advisor silently returned nothing regardless of budget. A budget guard\n // that quietly does nothing is worse than none, because you believe you have\n // one. Treat anything that is not a recognised mode as \"auto\".\n const VALID = [\"normal\", \"conservative\", \"strict\", \"critical\", \"auto\"] as const;\n let mode: string =\n config.mode && (VALID as readonly string[]).includes(config.mode) ? config.mode : \"auto\";\n if (mode === \"auto\" && typeof config.weeklyBudgetPercent === \"number\") {\n const pct = config.weeklyBudgetPercent;\n if (pct < 60) mode = \"normal\";\n else if (pct < 80) mode = \"conservative\";\n else if (pct < 92) mode = \"strict\";\n else mode = \"critical\";\n }\n\n // Force model override\n if (config.forceModel) {\n return `ADVISOR MODE: Use model \"${config.forceModel}\" for ALL subagents (Agent tool calls). This is a manual override.`;\n }\n\n switch (mode) {\n case \"normal\":\n return \"\"; // No constraints \u2014 use models freely\n\n case \"conservative\":\n return [\n `ADVISOR MODE (conservative \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"Main context is opus (most expensive \u2014 20x haiku, 5x sonnet). Delegate aggressively to subagents.\",\n \"Default subagents to SONNET (Agent tool, model: sonnet). Use haiku for simple lookups/verification.\",\n \"For substantial tasks, use swarm mode: spawn a sonnet orchestrator that delegates to haiku workers.\",\n \"Keep main context responses short \u2014 the goal is to minimize opus token burn.\",\n ].join(\" \");\n\n case \"strict\":\n return [\n `ADVISOR MODE (strict \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"Main context is opus (most expensive \u2014 20x haiku, 5x sonnet). Minimize work done here.\",\n \"Default subagents to SONNET (Agent tool, model: sonnet) for implementation and research. Use haiku for simple tasks.\",\n \"For any substantial task, use swarm mode: spawn ONE sonnet orchestrator that delegates to haiku workers.\",\n \"Keep main context responses short \u2014 receive results from agents, summarize briefly, done.\",\n \"Never spawn opus subagents. Every line of opus output costs 5x what sonnet costs.\",\n ].join(\" \");\n\n case \"critical\":\n return [\n `ADVISOR MODE (critical \u2014 weekly budget at ${config.weeklyBudgetPercent ?? \"?\"}%):`,\n \"MINIMIZE ALL TOKEN USAGE. Main context is opus \u2014 the most expensive model (20x haiku, 5x sonnet).\",\n \"For ANY non-trivial task, immediately spawn a sonnet orchestrator agent and let it handle everything.\",\n \"Main context should only send the task and receive the final result \u2014 do not do work here.\",\n \"Keep main context responses extremely concise \u2014 short answers, minimal explanation.\",\n \"Use sonnet for orchestration, haiku for workers. Never spawn opus subagents. Skip spotchecks.\",\n \"The user is near their weekly limit \u2014 do as little as possible in opus main context.\",\n ].join(\" \");\n\n default:\n return \"\";\n }\n}\n\nfunction main() {\n const parts: string[] = [];\n\n const rules = getWhisperRules();\n if (rules) parts.push(rules);\n\n const advisor = getAdvisorGuidance();\n if (advisor) parts.push(advisor);\n\n if (parts.length === 0) return;\n\n console.log(`<system-reminder>\\n${parts.join(\"\\n\")}\\n</system-reminder>`);\n}\n\nmain();\n"],
5
+ "mappings": ";;;AAmBA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,eAAe;AAExB,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,kBAAkB;AAClE,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,mBAAmB;AAEnE,SAAS,kBAA0B;AACjC,MAAI,WAAW,YAAY,GAAG;AAC5B,QAAI;AACF,YAAM,UAAU,aAAa,cAAc,OAAO,EAAE,KAAK;AACzD,UAAI,QAAS,QAAO;AAAA,IACtB,QAAQ;AAAA,IAAe;AAAA,EACzB;AACA,SAAO;AACT;AAQA,SAAS,qBAA6B;AACpC,MAAI,CAAC,WAAW,YAAY,EAAG,QAAO;AAEtC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AAUA,QAAM,QAAQ,CAAC,UAAU,gBAAgB,UAAU,YAAY,MAAM;AACrE,MAAI,OACF,OAAO,QAAS,MAA4B,SAAS,OAAO,IAAI,IAAI,OAAO,OAAO;AACpF,MAAI,SAAS,UAAU,OAAO,OAAO,wBAAwB,UAAU;AACrE,UAAM,MAAM,OAAO;AACnB,QAAI,MAAM,GAAI,QAAO;AAAA,aACZ,MAAM,GAAI,QAAO;AAAA,aACjB,MAAM,GAAI,QAAO;AAAA,QACrB,QAAO;AAAA,EACd;AAGA,MAAI,OAAO,YAAY;AACrB,WAAO,4BAA4B,OAAO,UAAU;AAAA,EACtD;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA;AAAA,IAET,KAAK;AACH,aAAO;AAAA,QACL,sDAAiD,OAAO,uBAAuB,GAAG;AAAA,QAClF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ,KAAK;AACH,aAAO;AAAA,QACL,gDAA2C,OAAO,uBAAuB,GAAG;AAAA,QAC5E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ,KAAK;AACH,aAAO;AAAA,QACL,kDAA6C,OAAO,uBAAuB,GAAG;AAAA,QAC9E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,IAEZ;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,OAAO;AACd,QAAM,QAAkB,CAAC;AAEzB,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,MAAO,OAAM,KAAK,KAAK;AAE3B,QAAM,UAAU,mBAAmB;AACnC,MAAI,QAAS,OAAM,KAAK,OAAO;AAE/B,MAAI,MAAM,WAAW,EAAG;AAExB,UAAQ,IAAI;AAAA,EAAsB,MAAM,KAAK,IAAI,CAAC;AAAA,mBAAsB;AAC1E;AAEA,KAAK;",
6
6
  "names": []
7
7
  }
@@ -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">
@@ -2259,7 +2305,7 @@ function cmdLogs(opts) {
2259
2305
  }
2260
2306
  function registerDaemonCommands(daemonCmd) {
2261
2307
  daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
2262
- const { serve } = await import("./daemon-D2aKb4mJ.mjs").then((n) => n.t);
2308
+ const { serve } = await import("./daemon-COSvHTNu.mjs").then((n) => n.t);
2263
2309
  const { loadConfig: lc, ensureConfigDir } = await import("./config-C8m-tPhP.mjs").then((n) => n.r);
2264
2310
  ensureConfigDir();
2265
2311
  await serve(lc());
@@ -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-C5ziUh1b.mjs.map
9064
+ //# sourceMappingURL=pick-CmG7SCtp.mjs.map