pipcode 2.1.5 → 2.1.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipcode",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "description": "PipCode — architecture, security and quality rules for your AI coding assistants (MCP server).",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,35 @@
1
+ // src/cli/claude-desktop.js — Config de Claude Desktop. Installé depuis le Microsoft Store (MSIX), Windows isole sa config dans
2
+ // %LOCALAPPDATA%\Packages\Claude_<id>\LocalCache\Roaming\Claude : l'ancien %APPDATA%\Claude n'existe pas et l'app n'y lit rien.
3
+ // On vise le dossier réellement utilisé. Zero Trust : racine bornée sous home, nom du paquet validé (aucune traversée de chemin).
4
+
5
+ import { existsSync, readdirSync, statSync } from "node:fs";
6
+ import path from "node:path";
7
+ import { boundRoot } from "../fs/config-path.js";
8
+
9
+ const FILE = "claude_desktop_config.json";
10
+ const STORE_ID = /^Claude_[a-z0-9]+$/i;
11
+
12
+ /** @param {Record<string, string | undefined>} env @param {string} home @returns {string | null} */
13
+ function storeDir(env, home) {
14
+ const pkgs = path.join(boundRoot(env.LOCALAPPDATA, home, path.join(home, "AppData", "Local")), "Packages");
15
+ try {
16
+ const name = readdirSync(pkgs).find((n) => STORE_ID.test(n));
17
+ const dir = name ? path.join(pkgs, name, "LocalCache", "Roaming", "Claude") : "";
18
+ return dir && existsSync(dir) ? dir : null;
19
+ } catch { return null; } // pas de dossier Packages : aucune installation Store (cas normal hors Windows)
20
+ }
21
+
22
+ /** @param {string} f @returns {number} */
23
+ const mtime = (f) => { try { return statSync(f).mtimeMs; } catch { return 0; } }; // fichier absent : jamais « plus récent »
24
+
25
+ // Chemin de la config : Store (MSIX) si présent, sauf si la config classique a été modifiée plus récemment (les deux coexistent).
26
+ /** @param {string} osName @param {Record<string, string | undefined>} env @param {string} home @param {string} configRoot @returns {string} */
27
+ export function claudeDesktopPath(osName, env, home, configRoot) {
28
+ const classic = path.join(configRoot, "Claude", FILE);
29
+ if (osName !== "windows") return classic;
30
+ const dir = storeDir(env, home);
31
+ if (!dir) return classic;
32
+ const store = path.join(dir, FILE);
33
+ return existsSync(classic) && mtime(classic) > mtime(store) ? classic : store;
34
+ }
35
+ // MODULE_COMPLETE
@@ -11,6 +11,7 @@ import { detectOS } from "./detect-os.js";
11
11
  import { ideConfigRoot } from "./ide-roots.js";
12
12
  import { coreIdeEntries, uiIdeEntries } from "./ide-entries.js";
13
13
  import { jetbrainsCandidates } from "./jetbrains.js";
14
+ import { claudeDesktopPath } from "./claude-desktop.js";
14
15
 
15
16
  /** @typedef {{ id: string, name: string, path: string, parentExists: boolean, configExists: boolean, schema?: "mcpServers" | "servers" | "context_servers" | "toml" }} IdeConfigEntry */
16
17
 
@@ -24,7 +25,7 @@ export function ideConfigPaths(osName = detectOS(), env = process.env, home = os
24
25
  const { configRoot, codeUser } = ideConfigRoot(osName, env || {}, home);
25
26
  /** @type {Array<{ id: string, name: string, path: string, schema?: "mcpServers" | "servers" | "context_servers" | "toml" }>} */
26
27
  const entries = [
27
- ...coreIdeEntries(home, configRoot),
28
+ ...coreIdeEntries(home, configRoot).map((e) => (e.id === "claude-desktop" ? { ...e, path: claudeDesktopPath(osName, env || {}, home, configRoot) } : e)),
28
29
  ...uiIdeEntries(osName, codeUser, home, configRoot),
29
30
  ...jetbrainsCandidates(osName, env || {}, home, configRoot),
30
31
  ];