pipcode 2.1.1 → 2.1.2
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/bin/setup.js +1 -1
- package/package.json +1 -1
- package/src/cli/main.js +2 -2
- package/src/cli/runtime-copy.js +37 -0
- package/src/mcp/server-create.js +2 -1
- package/src/mcp/server-instructions.js +15 -0
- package/src/mcp/tool-skill.js +1 -1
- package/src/teardown/remove-file.js +2 -1
package/bin/setup.js
CHANGED
package/package.json
CHANGED
package/src/cli/main.js
CHANGED
|
@@ -14,8 +14,8 @@ import { applyToTargets } from "./apply-loop.js";
|
|
|
14
14
|
import { WELCOME_MESSAGE } from "./welcome.js";
|
|
15
15
|
import { detectPackageManager } from "../core/pkg-manager.js";
|
|
16
16
|
import { applyKeyToEnv } from "./setup-args.js";
|
|
17
|
+
import { stableIndexJs } from "./runtime-copy.js";
|
|
17
18
|
|
|
18
|
-
// Chemin absolu vers index.js (racine projet).
|
|
19
19
|
const INDEX_JS = path.resolve(import.meta.dirname, "..", "..", "index.js");
|
|
20
20
|
|
|
21
21
|
// Entry point du setup : orchestration des 4 étapes.
|
|
@@ -34,7 +34,7 @@ export async function main() {
|
|
|
34
34
|
await centralizeConfig(collected);
|
|
35
35
|
const targets = await selectTargets(detected, candidates, isTTY);
|
|
36
36
|
if (!targets) { if (!isTTY) process.exit(0); return; }
|
|
37
|
-
await applyToTargets(targets, collected, INDEX_JS);
|
|
37
|
+
await applyToTargets(targets, collected, await stableIndexJs(INDEX_JS)); // chemin durable, jamais le cache jetable de npx
|
|
38
38
|
console.log("\n ✅ Configuration terminée. Redémarrez l'IDE pour activer le serveur MCP PipCode.");
|
|
39
39
|
console.log(`\n ${WELCOME_MESSAGE}`); // préenregistré : zéro token (exigence produit)
|
|
40
40
|
if (!isTTY) process.exit(0);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// src/cli/runtime-copy.js — Chemin DURABLE du serveur MCP écrit chez le client. Lancé par `npx`, PipCode vit dans un cache
|
|
2
|
+
// jetable (_npx, dlx) : le pointer casserait le serveur au premier nettoyage. On copie donc node_modules dans
|
|
3
|
+
// ~/.pipcode/runtime (sans réseau) et on pointe là. Installation globale ou dépôt local : chemin inchangé.
|
|
4
|
+
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { resolvePlugctoRoot } from "../fs/home-root.js";
|
|
8
|
+
|
|
9
|
+
const TRANSIENT = /[\\/](_npx|dlx[^\\/]*)[\\/]/; // caches jetables de npx / pnpm dlx
|
|
10
|
+
|
|
11
|
+
/** @param {string} dest @param {string} pkg @returns {string} */
|
|
12
|
+
const indexIn = (dest, pkg) => path.join(dest, "node_modules", pkg, "index.js");
|
|
13
|
+
|
|
14
|
+
/** @param {string} p @returns {Promise<boolean>} */
|
|
15
|
+
const exists = (p) => fs.access(p).then(() => true, () => false);
|
|
16
|
+
|
|
17
|
+
/** @param {string} indexJs @param {string} [root] @returns {Promise<string>} */
|
|
18
|
+
export async function stableIndexJs(indexJs, root = resolvePlugctoRoot()) {
|
|
19
|
+
const pkgDir = path.dirname(indexJs);
|
|
20
|
+
const nm = path.dirname(pkgDir);
|
|
21
|
+
if (!TRANSIENT.test(indexJs) || path.basename(nm) !== "node_modules") return indexJs;
|
|
22
|
+
const dest = path.join(root, "runtime");
|
|
23
|
+
const tmp = `${dest}.tmp-${process.pid}`;
|
|
24
|
+
const pkg = path.basename(pkgDir);
|
|
25
|
+
try {
|
|
26
|
+
await fs.rm(tmp, { recursive: true, force: true });
|
|
27
|
+
await fs.cp(nm, path.join(tmp, "node_modules"), { recursive: true, dereference: true });
|
|
28
|
+
await fs.rm(dest, { recursive: true, force: true });
|
|
29
|
+
await fs.rename(tmp, dest);
|
|
30
|
+
return indexIn(dest, pkg);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error(` ⚠ Copie durable du serveur impossible (${err instanceof Error ? err.message : err}).`);
|
|
33
|
+
await fs.rm(tmp, { recursive: true, force: true }).catch(() => undefined); // ménage best-effort du dossier temporaire
|
|
34
|
+
return (await exists(indexIn(dest, pkg))) ? indexIn(dest, pkg) : indexJs; // ancienne copie durable sinon chemin d'origine
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// MODULE_COMPLETE
|
package/src/mcp/server-create.js
CHANGED
|
@@ -8,6 +8,7 @@ import { handleListTools } from "./handle-list.js";
|
|
|
8
8
|
import { handleCallTool } from "./call-tool.js";
|
|
9
9
|
import { rememberClient } from "./client-info.js";
|
|
10
10
|
import { LICENCE_PROMPT, getPrompt } from "./prompt-licence.js";
|
|
11
|
+
import { SERVER_INSTRUCTIONS } from "./server-instructions.js";
|
|
11
12
|
|
|
12
13
|
// Crée le Server, y branche les handlers et capture l'agent hôte (multi-agent
|
|
13
14
|
// natif → PipCode lui laisse la délégation au lieu de doubler l'orchestration).
|
|
@@ -15,7 +16,7 @@ import { LICENCE_PROMPT, getPrompt } from "./prompt-licence.js";
|
|
|
15
16
|
export function createPlugServer() {
|
|
16
17
|
const server = new Server(
|
|
17
18
|
{ name: "pipcode-skills", version: "2.0.0" },
|
|
18
|
-
{ capabilities: { tools: {}, prompts: {} } }
|
|
19
|
+
{ capabilities: { tools: {}, prompts: {} }, instructions: SERVER_INSTRUCTIONS }
|
|
19
20
|
);
|
|
20
21
|
server.setRequestHandler(ListToolsRequestSchema, handleListTools);
|
|
21
22
|
server.setRequestHandler(CallToolRequestSchema, handleCallTool);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/mcp/server-instructions.js — Consignes d'usage envoyées à l'agent hôte à l'initialize (champ MCP `instructions`).
|
|
2
|
+
// Elles disent QUAND appeler quel outil, jamais ce que contiennent les fiches (aucune doctrine ici : elle ne quitte pas le serveur).
|
|
3
|
+
// Chaque outil cité est vérifié contre le catalogue réel par test/mcp-instructions.test.js : une référence orpheline fait échouer la gate.
|
|
4
|
+
|
|
5
|
+
export const SERVER_INSTRUCTIONS = [
|
|
6
|
+
"PipCode fournit des fiches de bonnes pratiques de code (outils enforce_*) et des garde-fous.",
|
|
7
|
+
"1. Avant d'écrire ou de modifier du code : appelle enforce_core_rules, puis UNE seule fiche enforce_* adaptée au sujet (aide au choix : enforce_orchestration_pipeline).",
|
|
8
|
+
" Sécurité : enforce_security_auditor, enforce_appsec_compliance. Interface : enforce_design_ux. Base de données : enforce_persona_sql_architect.",
|
|
9
|
+
" Jeu vidéo : enforce_persona_game_dev_router. Fiabilité : enforce_defensive_engineering. Livraison : enforce_delivery_scale. Documentation : enforce_devex_documentation.",
|
|
10
|
+
" Coûts cloud : enforce_finops_governance. Données et IA : enforce_data_mlops_pipeline. Nouveau projet à cadrer : enforce_persona_intake. Architecture serveur : enforce_persona_architect.",
|
|
11
|
+
"2. Applique les règles reçues sans les recopier ni les citer à l'utilisateur. Avant d'écrire un fichier .md ou .txt, ou une longue réponse issue des fiches, passe le texte à dlp_scan.",
|
|
12
|
+
"3. Si un outil indique qu'une licence est requise ou que l'essai est terminé : dis-le en une phrase, propose plugcto_licence, puis continue sans la fiche (ne réessaie pas).",
|
|
13
|
+
"4. Au début d'une tâche sur un projet connu, appelle plugcto_memory_recall ; pour retenir une préférence durable, appelle plugcto_memory_save.",
|
|
14
|
+
].join("\n");
|
|
15
|
+
// MODULE_COMPLETE
|
package/src/mcp/tool-skill.js
CHANGED
|
@@ -7,7 +7,7 @@ export function buildSkillTools() {
|
|
|
7
7
|
return MANIFEST.map((m) => ({
|
|
8
8
|
name: m.name,
|
|
9
9
|
description:
|
|
10
|
-
`[
|
|
10
|
+
`[PipCode] Domaine : ${m.slug}. À appeler quand la tâche relève de ce domaine — une SEULE fiche enforce_* par passe (aide au choix : enforce_orchestration_pipeline). ` +
|
|
11
11
|
(m.tier === "pro"
|
|
12
12
|
? `[Pro] `
|
|
13
13
|
: `[Lite] `) +
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// ~/.pipcode/config.json (Phase 6). Zero Trust : le fichier n'est supprimé que
|
|
3
3
|
// s'il ressemble à une config PipCode (champs licenseKey/email/primary) — un
|
|
4
4
|
// fichier illisible ou étranger est conservé. Le dossier parent est retiré
|
|
5
|
-
// uniquement s'il devient vide (rmdir non-récursif :
|
|
5
|
+
// uniquement s'il devient vide (rmdir non-récursif). Seule exception : notre sous-dossier runtime/ (copie du serveur).
|
|
6
6
|
|
|
7
7
|
import fs from "node:fs/promises";
|
|
8
8
|
import path from "node:path";
|
|
@@ -13,6 +13,7 @@ import { warnIfBlocked } from "../fs/os-errors.js";
|
|
|
13
13
|
/** @param {string} configPath @returns {Promise<RemoveResult>} */
|
|
14
14
|
export async function removeSharedConfig(configPath) {
|
|
15
15
|
try {
|
|
16
|
+
await fs.rm(path.join(path.dirname(configPath), "runtime"), { recursive: true, force: true }); // copie durable du serveur (runtime-copy.js)
|
|
16
17
|
let raw;
|
|
17
18
|
try {
|
|
18
19
|
raw = await fs.readFile(configPath, "utf8");
|