pipcode 2.1.2 → 2.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipcode",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
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/auth-simple.js — Parcours par défaut de `npx pipcode setup` : UNE question (clé de licence ou Entrée = essai gratuit 5 jours),
2
+ // sans navigateur ni recherche e-mail (comme dans l'extension VS Code). Le menu complet reste disponible via `setup --advanced`.
3
+
4
+ import { existingLicenseInfo } from "./auth-interactive.js";
5
+ import { KEY_RE } from "./setup-args.js";
6
+ import { link, supportsLinks } from "./term-link.js";
7
+ import { PRO_UPGRADE_URL } from "../core/constants.js";
8
+
9
+ const MAX_TRIES = 3;
10
+
11
+ /** @typedef {{ ask: (q: string) => Promise<string> }} AskPrompt */
12
+ /** @typedef {{ licenseKey: string, email: string }} AuthResult */
13
+
14
+ /** @param {AskPrompt} p @param {import("./auth-interactive.js").SharedConfig} [existingConfig] @param {boolean} [links] @returns {Promise<AuthResult>} */
15
+ export async function collectAuthSimple(p, existingConfig = {}, links = supportsLinks()) {
16
+ const { existingLicense, existingEmail } = existingLicenseInfo(existingConfig);
17
+ const keep = { licenseKey: existingLicense, email: existingEmail };
18
+ console.log("\n Votre licence PipCode");
19
+ if (existingLicense) {
20
+ console.log(" Une licence est déjà enregistrée" + (existingEmail ? " (" + existingEmail + ")" : "") + " : Entrée pour la conserver, ou collez une autre clé.");
21
+ } else {
22
+ console.log(` Collez votre ${link("clé de licence", PRO_UPGRADE_URL, links)} (reçue par e-mail après l'achat),`);
23
+ console.log(" ou appuyez sur Entrée pour l'essai gratuit de 5 jours.");
24
+ if (!links) console.log(` Pas encore de licence ? Achat : ${PRO_UPGRADE_URL}`);
25
+ }
26
+ for (let i = 0; i < MAX_TRIES; i++) {
27
+ const key = (await p.ask("\n Clé : ")).trim();
28
+ if (!key) return keep;
29
+ if (KEY_RE.test(key)) return { licenseKey: key, email: "" };
30
+ console.log(" ⚠️ Clé non reconnue (8 à 128 caractères : lettres, chiffres, - et _). Réessayez, ou Entrée pour continuer sans.");
31
+ }
32
+ console.log(" Poursuite sans nouvelle clé.");
33
+ return keep;
34
+ }
35
+ // MODULE_COMPLETE
package/src/cli/banner.js CHANGED
@@ -1,20 +1,11 @@
1
- // src/cli/banner.js — Bannière de démarrage + liste des candidats IDE détectés.
2
- // Affiche l'en-tête PipCode, le système détecté et chaque candidat avec son
3
- // drapeau de détection (✓ installé / non installé).
1
+ // src/cli/banner.js — Bannière de démarrage : titre et éditeurs/agents réellement détectés (les autres ne sont pas listés : du bruit).
4
2
 
5
3
  /** @typedef {{ id: string, name: string, path: string, parentExists: boolean, configExists: boolean, schema?: "mcpServers" | "servers" | "context_servers" | "toml" }} IdeConfigEntry */
6
4
 
7
- // Affiche l'en-tête + la liste des candidats IDE (détectés ou non).
8
- /** @param {string} osName @param {IdeConfigEntry[]} candidates */
9
- export function printBanner(osName, candidates) {
10
- console.log("╔══════════════════════════════════════════════════════════╗");
11
- console.log("║ PipCode — auto-configuration MCP (Zero-Click, BYOK) ║");
12
- console.log("╚══════════════════════════════════════════════════════════╝");
13
- console.log(`\n Système détecté : ${osName}`);
14
- console.log(" IDE candidats :");
15
- candidates.forEach((c) => {
16
- const tag = c.parentExists ? "✓ détecté" : " non installé";
17
- console.log(` • ${c.name.padEnd(16)} ${tag} ${c.path}`);
18
- });
5
+ /** @param {IdeConfigEntry[]} candidates */
6
+ export function printBanner(candidates) {
7
+ const found = candidates.filter((c) => c.parentExists).map((c) => c.name);
8
+ console.log("\n PipCode — installation\n");
9
+ console.log(found.length ? ` Détecté sur votre machine : ${found.join(", ")}` : " Aucun éditeur ni agent compatible détecté pour le moment.");
19
10
  }
20
11
  // MODULE_COMPLETE
@@ -1,9 +1,11 @@
1
1
  // src/cli/collect-step.js — Étape collecte du setup (TTY interactive / non-TTY env).
2
- // TTY : readline + collectInteractive (config existante lue ; licence et e-mail seulement). Non-TTY : collectFromEnv (licence optionnelle : sans clé, 5 jours d'essai).
2
+ // TTY : une seule question (auth-simple) ; menu complet avec --advanced (collectInteractive). Config existante lue ; licence et e-mail seulement. Non-TTY : collectFromEnv (licence optionnelle : sans clé, 5 jours d'essai).
3
3
 
4
4
  import readline from "node:readline/promises";
5
5
  import { stdin, stdout } from "node:process";
6
6
  import { collectInteractive } from "./interactive.js";
7
+ import { collectAuthSimple } from "./auth-simple.js";
8
+ import { makePrompts } from "./prompts.js";
7
9
  import { collectFromEnv } from "../engine/collect.js";
8
10
  import { readSharedConfig } from "../fs/config-read.js";
9
11
 
@@ -16,10 +18,11 @@ export async function collectForSetup(isTTY) {
16
18
  const rl = readline.createInterface({ input: stdin, output: stdout });
17
19
  try {
18
20
  const existingConfig = await readSharedConfig().catch(() => ({}));
19
- return await collectInteractive(rl, { existingConfig });
21
+ if (process.argv.includes("--advanced")) return await collectInteractive(rl, { existingConfig });
22
+ return await collectAuthSimple(makePrompts(rl), existingConfig);
20
23
  } finally { rl.close(); }
21
24
  }
22
- console.log("\n (Mode non-interactif : lecture des variables d'environnement.)");
25
+ console.log("\n Mode automatique (aucune question) : essai gratuit de 5 jours, ou licence fournie avec --key.");
23
26
  return collectFromEnv();
24
27
  }
25
28
  // MODULE_COMPLETE
package/src/cli/help.js CHANGED
@@ -16,7 +16,8 @@ export function printAutoHelp() {
16
16
  export function printTopHelp() {
17
17
  console.log("PipCode — auto-configuration MCP (Zero-Click)\n");
18
18
  console.log("Usage :");
19
- console.log(" npx pipcode setup Configure le serveur MCP PipCode dans les IDE détectés.");
19
+ console.log(" npx pipcode setup Installe PipCode dans vos éditeurs et agents détectés (une question : votre clé, ou Entrée = essai 5 jours).");
20
+ console.log(" npx pipcode setup --advanced Menu complet : connexion par navigateur, par e-mail, clé manuelle ou essai.");
20
21
  console.log(" npx pipcode setup --key <CLÉ> Enregistre la clé de licence Pro (Polar.sh) —");
21
22
  console.log(" utilisable par un agent IA, sans interaction.");
22
23
  console.log(" npx pipcode teardown Retire PipCode de vos outils (seule l'entrée PipCode est supprimée).");
package/src/cli/main.js CHANGED
@@ -12,7 +12,6 @@ import { centralizeConfig } from "./centralize.js";
12
12
  import { selectTargets } from "./target-select.js";
13
13
  import { applyToTargets } from "./apply-loop.js";
14
14
  import { WELCOME_MESSAGE } from "./welcome.js";
15
- import { detectPackageManager } from "../core/pkg-manager.js";
16
15
  import { applyKeyToEnv } from "./setup-args.js";
17
16
  import { stableIndexJs } from "./runtime-copy.js";
18
17
 
@@ -26,16 +25,14 @@ export async function main() {
26
25
  const osName = detectOS();
27
26
  const candidates = ideConfigPaths(osName);
28
27
  const detected = candidates.filter((c) => c.parentExists);
29
- printBanner(osName, candidates);
30
- const pm = detectPackageManager();
31
- console.log(` 📦 Gestionnaire détecté : ${pm.label} — routines 100 % Node.js pur, indépendantes de npm/pnpm/yarn/bun.`);
28
+ printBanner(candidates);
32
29
  const isTTY = stdin.isTTY;
33
30
  const collected = await collectForSetup(isTTY);
34
31
  await centralizeConfig(collected);
35
32
  const targets = await selectTargets(detected, candidates, isTTY);
36
33
  if (!targets) { if (!isTTY) process.exit(0); return; }
37
34
  await applyToTargets(targets, collected, await stableIndexJs(INDEX_JS)); // chemin durable, jamais le cache jetable de npx
38
- console.log("\n ✅ Configuration terminée. Redémarrez l'IDE pour activer le serveur MCP PipCode.");
35
+ console.log("\n ✅ Configuration terminée. Fermez puis rouvrez votre éditeur ou votre agent pour activer PipCode.");
39
36
  console.log(`\n ${WELCOME_MESSAGE}`); // préenregistré : zéro token (exigence produit)
40
37
  if (!isTTY) process.exit(0);
41
38
  }
@@ -0,0 +1,25 @@
1
+ // src/cli/term-link.js — Lien cliquable dans le terminal (séquence OSC 8) quand le terminal le gère ; sinon le texte seul et l'appelant
2
+ // affiche l'adresse en clair. Zero Trust : seule une URL https sans caractère de contrôle devient un lien (jamais d'injection de séquence).
3
+
4
+ const OSC = "\u001b]8;;";
5
+ const ST = "\u001b\\";
6
+ const KNOWN_TERMS = /^(vscode|iTerm\.app|WezTerm|Hyper|ghostty)$/i;
7
+
8
+ /** @param {NodeJS.ProcessEnv} [env] @param {boolean} [isTTY] @returns {boolean} */
9
+ export function supportsLinks(env = process.env, isTTY = Boolean(process.stdout.isTTY)) {
10
+ if (!isTTY) return false;
11
+ return Boolean(env.WT_SESSION || env.KITTY_WINDOW_ID || env.WEZTERM_EXECUTABLE || env.FORCE_HYPERLINK === "1"
12
+ || KNOWN_TERMS.test(env.TERM_PROGRAM || "") || Number(env.VTE_VERSION) >= 5000);
13
+ }
14
+
15
+ /** @param {string} url @returns {boolean} */
16
+ export function isSafeUrl(url) {
17
+ if (/[\u0000-\u001f\u007f]/.test(url)) return false;
18
+ try { return new URL(url).protocol === "https:"; } catch { return false; }
19
+ }
20
+
21
+ /** @param {string} text @param {string} url @param {boolean} [enabled] @returns {string} */
22
+ export function link(text, url, enabled = supportsLinks()) {
23
+ return enabled && isSafeUrl(url) ? `${OSC}${url}${ST}${text}${OSC}${ST}` : text;
24
+ }
25
+ // MODULE_COMPLETE
@@ -1,35 +0,0 @@
1
- // src/core/pkg-manager.js — Agnosticisme des gestionnaires de paquets (Point #3).
2
- // Détection via npm_config_user_agent (renseigné par npm/pnpm/yarn/bun). Jamais
3
- // de conditionnement exclusif à npm : les routines setup/teardown sont 100 %
4
- // Node.js pur — la détection ne sert qu'à l'affichage et à l'aide contextuelle.
5
-
6
- /** @typedef {"npm" | "pnpm" | "yarn" | "bun" | "unknown"} PmName */
7
- /** @typedef {{ name: PmName, label: string }} PmInfo */
8
-
9
- // Étiquettes affichables + équivalent de `npx` par gestionnaire (aide dynamique).
10
- /** @type {{ [k: string]: { label: string, run: string } }} */
11
- const PM_META = {
12
- npm: { label: "npm", run: "npx" },
13
- pnpm: { label: "pnpm", run: "pnpm dlx" },
14
- yarn: { label: "yarn", run: "yarn dlx" },
15
- bun: { label: "bun", run: "bunx" },
16
- };
17
-
18
- // Détecte le gestionnaire actif : npm_config_user_agent commence par "<pm>/<version>".
19
- /** @param {NodeJS.ProcessEnv} [env] @returns {PmInfo} */
20
- export function detectPackageManager(env = process.env) {
21
- const ua = String(env.npm_config_user_agent || "");
22
- const name = (ua.match(/^(npm|pnpm|yarn|bun)\//) || [])[1] || "unknown";
23
- const meta = PM_META[name];
24
- return meta
25
- ? { name: /** @type {PmName} */ (name), label: meta.label }
26
- : { name: "unknown", label: "non détecté" };
27
- }
28
-
29
- // Commande d'exécution équivalente à `npx` pour le gestionnaire détecté.
30
- /** @param {PmInfo} [pm] @returns {string} */
31
- export function pmRunCommand(pm = detectPackageManager()) {
32
- const meta = PM_META[pm.name];
33
- return meta ? meta.run : "npx";
34
- }
35
- // MODULE_COMPLETE