@neikyun/ciel 5.2.0 → 5.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neikyun/ciel",
3
- "version": "5.2.0",
3
+ "version": "5.2.2",
4
4
  "description": "Ciel — Deep-reasoning pipeline for LLM-assisted development. OpenCode plugin + multi-platform CLI (OpenCode, Claude Code, more).",
5
5
  "main": "./dist/plugin/index.js",
6
6
  "types": "./dist/plugin/index.d.ts",
@@ -1,234 +1,155 @@
1
1
  #!/usr/bin/env node
2
- // Ciel postinstall — auto-configure après npm install / npm update
2
+ // Ciel postinstall — s'exécute après npm install / npm update
3
3
  //
4
- // S'exécute automatiquement après `npm install @neikyun/ciel`.
5
- // Détecte OpenCode / Claude Code, configure tout, gère les mises à jour.
6
- //
7
- // Comportement :
8
- // - Première install → propose et configure
9
- // - npm update (nouvelle version) → détecte et propose la mise à jour
10
- // - npm install (même version) → skip silencieux
11
- // - Désactivable : CI=true npm install @neikyun/ciel
12
- // npm install @neikyun/ciel --ignore-scripts
13
-
14
- const { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, chmodSync, unlinkSync } = require("fs");
4
+ // Toujours visible. Détecte les plateformes, configure, ou guide l'utilisateur.
5
+ // Désactivable avec CI=true ou --ignore-scripts
6
+
7
+ const { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, chmodSync, unlinkSync, readdirSync } = require("fs");
15
8
  const { join, dirname } = require("path");
16
9
 
17
10
  // ---- Version ----
18
- const PKG_PATH = join(__dirname, "..", "package.json");
19
- const PKG = existsSync(PKG_PATH) ? JSON.parse(readFileSync(PKG_PATH, "utf-8")) : {};
11
+ const PKG = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
20
12
  const CIEL_VERSION = PKG.version || "0.0.0";
21
13
 
22
- // ---- Colors ----
23
- const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
24
- const green = (s) => `\x1b[32m${s}\x1b[0m`;
25
- const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
26
- const bold = (s) => `\x1b[1m${s}\x1b[0m`;
14
+ // ---- Couleurs ----
15
+ const c = (code, s) => process.stdout.isTTY ? `\x1b[${code}m${s}\x1b[0m` : s;
16
+ const cyan = (s) => c(36, s);
17
+ const green = (s) => c(32, s);
18
+ const yellow = (s) => c(33, s);
19
+ const bold = (s) => c(1, s);
27
20
 
28
- // ---- Helpers ----
29
- function detectPlatform(targetDir) {
21
+ // ---- Détection de plateforme ----
22
+ function detectPlatforms(targetDir) {
30
23
  const platforms = [];
31
- if (existsSync(join(targetDir, "opencode.json")) || existsSync(join(targetDir, ".opencode")))
32
- platforms.push("opencode");
33
- if (existsSync(join(targetDir, ".claude/settings.json")) || existsSync(join(targetDir, ".claude")))
34
- platforms.push("claude");
24
+ if (existsSync(join(targetDir, "opencode.json")) || existsSync(join(targetDir, ".opencode"))) platforms.push("OpenCode");
25
+ if (existsSync(join(targetDir, ".claude/settings.json")) || existsSync(join(targetDir, ".claude"))) platforms.push("Claude Code");
35
26
  return platforms;
36
27
  }
37
28
 
38
- function resolveAssetsDir() {
39
- const candidates = [
40
- join(__dirname, "..", "assets"),
41
- join(__dirname, "..", "..", "assets"),
42
- ];
43
- for (const dir of candidates) {
44
- if (dir && existsSync(join(dir, "platforms/opencode/.opencode/agents/ciel.md")))
45
- return dir;
29
+ function resolveAssets() {
30
+ for (const dir of [join(__dirname, "..", "assets"), join(__dirname, "..", "..", "assets")]) {
31
+ if (existsSync(join(dir, "platforms/opencode/.opencode/agents/ciel.md"))) return dir;
46
32
  }
47
33
  return null;
48
34
  }
49
35
 
36
+ // ---- Installation ----
50
37
  function copyDir(src, dest) {
51
38
  if (!existsSync(src)) return 0;
52
- const { readdirSync } = require("fs");
53
39
  let count = 0;
54
40
  mkdirSync(dest, { recursive: true });
55
41
  for (const entry of readdirSync(src, { withFileTypes: true })) {
56
- const s = join(src, entry.name);
57
- const d = join(dest, entry.name);
58
- if (entry.isDirectory()) {
59
- count += copyDir(s, d);
60
- } else {
61
- copyFileSync(s, d);
62
- if (s.endsWith(".sh")) try { chmodSync(d, 0o755); } catch {}
63
- count++;
64
- }
42
+ const s = join(src, entry.name), d = join(dest, entry.name);
43
+ if (entry.isDirectory()) count += copyDir(s, d);
44
+ else { copyFileSync(s, d); if (s.endsWith(".sh")) try { chmodSync(d, 0o755); } catch {} count++; }
65
45
  }
66
46
  return count;
67
47
  }
68
48
 
69
- function patchOpencodeJson(targetDir) {
70
- const configPath = join(targetDir, "opencode.json");
71
- if (!existsSync(configPath)) return false;
72
- try {
73
- const raw = readFileSync(configPath, "utf-8");
74
- const config = JSON.parse(raw);
75
- let changed = false;
76
-
77
- // Remove old local plugin reference (curl install)
78
- if (config.plugin) {
79
- const filtered = config.plugin.filter((p) => p !== "./.opencode/plugins/ciel.ts");
80
- if (filtered.length !== config.plugin.length) changed = true;
81
- config.plugin = filtered;
82
- }
83
-
84
- // Add new npm plugin reference
85
- if (!config.plugin) config.plugin = [];
86
- if (!config.plugin.includes("@neikyun/ciel")) {
87
- config.plugin.push("@neikyun/ciel");
88
- changed = true;
89
- }
90
-
91
- // Add instructions
92
- if (!config.instructions) config.instructions = [];
93
- if (!config.instructions.includes("AGENTS.md")) {
94
- config.instructions.push("AGENTS.md");
95
- changed = true;
96
- }
97
-
98
- if (changed) {
99
- writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
100
- }
101
- return changed;
102
- } catch {
103
- return false;
104
- }
105
- }
106
-
107
- function installForPlatform(targetDir, assetsDir, platform) {
49
+ function installOpenCode(targetDir, assets) {
108
50
  let count = 0;
109
- if (platform === "opencode") {
110
- // Clean old curl files
111
- const oldPlugin = join(targetDir, ".opencode/plugins/ciel.ts");
112
- if (existsSync(oldPlugin)) {
113
- try { unlinkSync(oldPlugin); count++; } catch {}
114
- }
115
-
116
- // Copy fresh agents
117
- count += copyDir(
118
- join(assetsDir, "platforms/opencode/.opencode/agents"),
119
- join(targetDir, ".opencode/agents")
120
- );
121
- // Copy fresh commands
122
- count += copyDir(
123
- join(assetsDir, "platforms/opencode/.opencode/commands"),
124
- join(targetDir, ".opencode/commands")
125
- );
126
- // Copy AGENTS.md
127
- const agentsMdSrc = join(assetsDir, "platforms/opencode/AGENTS.md");
128
- if (existsSync(agentsMdSrc)) {
129
- copyFileSync(agentsMdSrc, join(targetDir, "AGENTS.md"));
130
- count++;
131
- }
132
- // Patch config
133
- if (patchOpencodeJson(targetDir)) count++;
134
- return count;
51
+ // Nettoyer ancien plugin curl
52
+ const old = join(targetDir, ".opencode/plugins/ciel.ts");
53
+ if (existsSync(old)) { try { unlinkSync(old); count++; } catch {} }
54
+ // Copier agents
55
+ count += copyDir(join(assets, "platforms/opencode/.opencode/agents"), join(targetDir, ".opencode/agents"));
56
+ // Copier commandes
57
+ count += copyDir(join(assets, "platforms/opencode/.opencode/commands"), join(targetDir, ".opencode/commands"));
58
+ // Copier AGENTS.md
59
+ if (existsSync(join(assets, "platforms/opencode/AGENTS.md"))) {
60
+ copyFileSync(join(assets, "platforms/opencode/AGENTS.md"), join(targetDir, "AGENTS.md"));
61
+ count++;
135
62
  }
136
-
137
- if (platform === "claude") {
138
- count += copyDir(join(assetsDir, ".claude/agents"), join(targetDir, ".claude/agents"));
139
- count += copyDir(join(assetsDir, ".claude/hooks"), join(targetDir, ".claude/hooks"));
140
- const settingsSrc = join(assetsDir, ".claude/settings.json");
141
- if (existsSync(settingsSrc)) {
142
- copyFileSync(settingsSrc, join(targetDir, ".claude/settings.json"));
143
- count++;
144
- }
145
- const claudeMdSrc = join(assetsDir, "CLAUDE.md");
146
- if (existsSync(claudeMdSrc)) {
147
- copyFileSync(claudeMdSrc, join(targetDir, "CLAUDE.md"));
63
+ // Patcher opencode.json
64
+ try {
65
+ const cfgPath = join(targetDir, "opencode.json");
66
+ if (existsSync(cfgPath)) {
67
+ let cfg = JSON.parse(readFileSync(cfgPath, "utf-8"));
68
+ if (!cfg.plugin) cfg.plugin = [];
69
+ // Remplacer ancienne ref locale par npm
70
+ cfg.plugin = cfg.plugin.filter(p => p !== "./.opencode/plugins/ciel.ts");
71
+ if (!cfg.plugin.includes("@neikyun/ciel")) cfg.plugin.push("@neikyun/ciel");
72
+ if (!cfg.instructions) cfg.instructions = [];
73
+ if (!cfg.instructions.includes("AGENTS.md")) cfg.instructions.push("AGENTS.md");
74
+ writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
148
75
  count++;
149
76
  }
150
- return count;
151
- }
152
- return 0;
153
- }
154
-
155
- function readMemory(targetDir) {
156
- const memPath = join(targetDir, ".ciel/memory.json");
157
- try {
158
- return JSON.parse(readFileSync(memPath, "utf-8"));
159
- } catch {
160
- return {};
161
- }
77
+ } catch {}
78
+ return count;
162
79
  }
163
80
 
164
- function writeMemory(targetDir, data) {
165
- const memPath = join(targetDir, ".ciel/memory.json");
166
- mkdirSync(join(targetDir, ".ciel"), { recursive: true });
167
- writeFileSync(memPath, JSON.stringify(data, null, 2), "utf-8");
81
+ function installClaude(targetDir, assets) {
82
+ let count = 0;
83
+ count += copyDir(join(assets, ".claude/agents"), join(targetDir, ".claude/agents"));
84
+ count += copyDir(join(assets, ".claude/hooks"), join(targetDir, ".claude/hooks"));
85
+ const settings = join(assets, ".claude/settings.json");
86
+ if (existsSync(settings)) { copyFileSync(settings, join(targetDir, ".claude/settings.json")); count++; }
87
+ const claudeMd = join(assets, "CLAUDE.md");
88
+ if (existsSync(claudeMd)) { copyFileSync(claudeMd, join(targetDir, "CLAUDE.md")); count++; }
89
+ return count;
168
90
  }
169
91
 
170
- // ===== MAIN =====
92
+ // ---- MAIN ----
171
93
  async function main() {
172
- // Skip in CI
173
94
  if (process.env.CI || process.env.NO_CIEL_POSTINSTALL) return;
174
95
 
175
- const targetDir = process.cwd();
176
- const platforms = detectPlatform(targetDir);
177
- if (platforms.length === 0) return; // Not a Ciel-compatible project
178
-
179
- const assetsDir = resolveAssetsDir();
180
- if (!assetsDir) return; // No templates bundled
96
+ // INIT_CWD = répertoire où l'utilisateur a lancé npm install
97
+ // (npm lance les lifecycle scripts dans node_modules/<pkg>/, pas dans le projet)
98
+ const targetDir = process.env.INIT_CWD || process.cwd();
99
+ const platforms = detectPlatforms(targetDir);
100
+ const assetsDir = resolveAssets();
181
101
 
182
- // Check installed version vs current version
183
- const memory = readMemory(targetDir);
184
- const installedVersion = memory.cielVersion || null;
185
- const isUpdate = installedVersion && installedVersion !== CIEL_VERSION;
186
- const isFirstInstall = !installedVersion;
102
+ // Toujours afficher le message Ciel
103
+ console.log(`\n ${bold("✦ Ciel v" + CIEL_VERSION)}`);
187
104
 
188
- if (!isFirstInstall && !isUpdate) return; // Same version → skip
105
+ if (!assetsDir) {
106
+ console.log(` ${yellow("~")} Templates non trouvés (package corrompu ?)\n`);
107
+ return;
108
+ }
189
109
 
190
- // Show banner
191
- const action = isUpdate ? "mise à jour" : "configuration";
192
- console.log(`\n ${bold("✦ Ciel v" + CIEL_VERSION)} ${action} pour ${cyan(platforms.join(" + "))}`);
110
+ if (platforms.length === 0) {
111
+ console.log(` ${yellow("~")} Aucune plateforme détectée.`);
112
+ console.log(` Ajoutez ${cyan("opencode.json")} ou créez ${cyan(".claude/")} puis relancez npm install.`);
113
+ console.log(` Ou utilisez ${green("npx ciel init")} pour configurer manuellement.\n`);
114
+ return;
115
+ }
193
116
 
194
- // Prompt (skip if non-interactive)
195
- let answer = "y";
117
+ // Demander confirmation (sauter si non-TTY)
118
+ let ok = true;
196
119
  if (process.stdin.isTTY) {
197
120
  try {
198
121
  const readline = require("readline");
199
122
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
200
- answer = await new Promise((resolve) => {
201
- rl.question(` ${yellow("?")} ${isUpdate ? "Mettre à jour" : "Configurer"} Ciel ? ${green("(Y/n)")} `, (a) => {
202
- rl.close();
203
- resolve(a.trim().toLowerCase() || "y");
204
- });
205
- });
206
- } catch {
207
- answer = "y";
208
- }
123
+ ok = await new Promise(r => rl.question(` ${yellow("?")} Configurer Ciel pour ${cyan(platforms.join(" + "))} ? ${green("(Y/n)")} `, a => { rl.close(); r(a.trim().toLowerCase() !== "n"); }));
124
+ } catch { ok = true; }
209
125
  }
210
126
 
211
- if (answer !== "y" && answer !== "yes") {
127
+ if (!ok) {
212
128
  console.log(` ${cyan("→")} Annulé.\n`);
213
129
  return;
214
130
  }
215
131
 
216
- // ---- Execute ----
132
+ // Créer .ciel/
133
+ mkdirSync(join(targetDir, ".ciel"), { recursive: true });
134
+ if (!existsSync(join(targetDir, ".ciel/map.json")))
135
+ writeFileSync(join(targetDir, ".ciel/map.json"), JSON.stringify({ modules: [], lastUpdated: "" }), "utf-8");
136
+ if (!existsSync(join(targetDir, ".ciel/parking.md")))
137
+ writeFileSync(join(targetDir, ".ciel/parking.md"), "# Ciel Parking Lot\n\n", "utf-8");
138
+
139
+ // Installer
217
140
  let total = 0;
218
141
  for (const p of platforms) {
219
- const n = installForPlatform(targetDir, assetsDir, p);
142
+ const n = p === "OpenCode" ? installOpenCode(targetDir, assetsDir) : installClaude(targetDir, assetsDir);
220
143
  total += n;
221
144
  console.log(` ${green("✓")} ${p}: ${n} fichiers`);
222
145
  }
223
146
 
224
- // Store version
225
- writeMemory(targetDir, { ...memory, cielVersion: CIEL_VERSION, lastUpdated: new Date().toISOString() });
147
+ // Sauvegarder version
148
+ writeFileSync(join(targetDir, ".ciel/memory.json"), JSON.stringify({ cielVersion: CIEL_VERSION, lastUpdated: new Date().toISOString() }, null, 2), "utf-8");
226
149
 
227
- console.log(`\n ${green("✓")} Ciel v${CIEL_VERSION} ${isUpdate ? "mis à jour" : "prêt"} !`);
228
- if (platforms.includes("opencode"))
229
- console.log(` → OpenCode: plugin "${cyan("@neikyun/ciel")}" dans opencode.json`);
230
- if (platforms.includes("claude"))
231
- console.log(` → Claude Code: redémarrez ${cyan("claude .")}`);
150
+ console.log(`\n ${green("✓")} Ciel v${CIEL_VERSION} installé !`);
151
+ if (platforms.includes("OpenCode")) console.log(` → plugin ${cyan("@neikyun/ciel")} ajouté à opencode.json`);
152
+ if (platforms.includes("Claude Code")) console.log(` → redémarrez ${cyan("claude .")}`);
232
153
  console.log();
233
154
  }
234
155