@neikyun/ciel 5.2.9 → 5.2.11

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/ciel.js CHANGED
@@ -1,23 +1,35 @@
1
1
  #!/usr/bin/env node
2
2
  // Ciel CLI — bootstrap entry point
3
- // Vérifie si l'initialisation est nécessaire, sinon lance la CLI normalement.
4
- // Solution de secours quand le postinstall npm ne s'exécute pas.
3
+ // Vérifie si l'initialisation est nécessaire et détecte les nouvelles plateformes.
5
4
 
6
5
  const { existsSync, mkdirSync, writeFileSync, readFileSync, copyFileSync, readdirSync, chmodSync, unlinkSync } = require("fs");
7
- const { join, dirname } = require("path");
8
- const { execSync } = require("child_process");
6
+ const { join, delimiter } = require("path");
9
7
 
10
8
  const PKG_DIR = join(__dirname, "..");
11
9
  const PKG = JSON.parse(readFileSync(join(PKG_DIR, "package.json"), "utf-8"));
12
10
  const CIEL_VERSION = PKG.version || "0.0.0";
13
11
  const ASSETS = join(PKG_DIR, "assets");
14
-
15
- // Vérifier si une (ré)initialisation est nécessaire
16
12
  const targetDir = process.env.INIT_CWD || process.cwd();
17
13
  const memPath = join(targetDir, ".ciel", "memory.json");
18
- const storedVersion = (() => { try { return JSON.parse(readFileSync(memPath, "utf-8")).cielVersion; } catch { return null; } })();
19
- const needsInit = !existsSync(memPath) || storedVersion !== CIEL_VERSION;
20
14
 
15
+ const c = (code, s) => process.stderr.isTTY ? `\x1b[${code}m${s}\x1b[0m` : s;
16
+ const green = (s) => c(32, s);
17
+ const cyan = (s) => c(36, s);
18
+
19
+ // Cherche un exécutable dans le PATH (fiable cross-platform, pas besoin de shell)
20
+ function searchPath(name) {
21
+ const pathExt = (process.env.PATHEXT || "").split(";");
22
+ if (!pathExt[0]) pathExt.push("", ".exe", ".cmd", ".bat", ".com");
23
+ const pathDirs = (process.env.PATH || "").split(delimiter);
24
+ for (const dir of pathDirs) {
25
+ for (const ext of pathExt) {
26
+ if (existsSync(join(dir, name + ext))) return true;
27
+ }
28
+ }
29
+ return false;
30
+ }
31
+
32
+ // ---- Helpers ----
21
33
  function copyDir(src, dest) {
22
34
  if (!existsSync(src)) return 0;
23
35
  let count = 0;
@@ -30,7 +42,7 @@ function copyDir(src, dest) {
30
42
  return count;
31
43
  }
32
44
 
33
- function patchConfig(targetDir, assets) {
45
+ function patchOpencodeJson(targetDir) {
34
46
  const cfgPath = join(targetDir, "opencode.json");
35
47
  if (!existsSync(cfgPath)) return false;
36
48
  try {
@@ -45,84 +57,102 @@ function patchConfig(targetDir, assets) {
45
57
  } catch { return false; }
46
58
  }
47
59
 
48
- function runInit(targetDir, assets) {
60
+ // ---- Détection des plateformes ----
61
+ function detectPlatforms() {
62
+ const platforms = [];
63
+ const hasOC = existsSync(join(targetDir, "opencode.json")) || existsSync(join(targetDir, ".opencode"));
64
+ const hasClaude = existsSync(join(targetDir, ".claude/settings.json")) || existsSync(join(targetDir, ".claude"));
65
+
66
+ // Détection CLI
67
+ const hasOC_CLI = searchPath("opencode");
68
+ const hasClaude_CLI = searchPath("claude");
69
+
70
+ if (hasOC || hasOC_CLI) platforms.push("OpenCode");
71
+ if (hasClaude || hasClaude_CLI) platforms.push("Claude Code");
72
+ return platforms;
73
+ }
74
+
75
+ // ---- Installer une plateforme ----
76
+ function installOpenCode() {
77
+ let total = 0;
78
+ // Nettoyer ancien plugin curl
79
+ const old = join(targetDir, ".opencode/plugins/ciel.ts");
80
+ if (existsSync(old)) { try { unlinkSync(old); } catch {} }
81
+ total += copyDir(join(ASSETS, "platforms/opencode/.opencode/agents"), join(targetDir, ".opencode/agents"));
82
+ total += copyDir(join(ASSETS, "platforms/opencode/.opencode/commands"), join(targetDir, ".opencode/commands"));
83
+ if (existsSync(join(ASSETS, "platforms/opencode/AGENTS.md"))) {
84
+ copyFileSync(join(ASSETS, "platforms/opencode/AGENTS.md"), join(targetDir, "AGENTS.md"));
85
+ total++;
86
+ }
87
+ if (patchOpencodeJson(targetDir)) total++;
88
+ return total;
89
+ }
90
+
91
+ function installClaude() {
49
92
  let total = 0;
93
+ total += copyDir(join(ASSETS, ".claude/agents"), join(targetDir, ".claude/agents"));
94
+ total += copyDir(join(ASSETS, ".claude/hooks"), join(targetDir, ".claude/hooks"));
95
+ total += copyDir(join(ASSETS, "commands"), join(targetDir, ".claude/commands"));
96
+ if (existsSync(join(ASSETS, ".claude/settings.json"))) {
97
+ copyFileSync(join(ASSETS, ".claude/settings.json"), join(targetDir, ".claude/settings.json"));
98
+ }
99
+ if (existsSync(join(ASSETS, "CLAUDE.md"))) {
100
+ copyFileSync(join(ASSETS, "CLAUDE.md"), join(targetDir, "CLAUDE.md"));
101
+ }
102
+ return total;
103
+ }
50
104
 
51
- // .ciel/ state
105
+ function ensureCielState() {
52
106
  mkdirSync(join(targetDir, ".ciel"), { recursive: true });
53
107
  if (!existsSync(join(targetDir, ".ciel/map.json")))
54
108
  writeFileSync(join(targetDir, ".ciel/map.json"), JSON.stringify({ modules: [], lastUpdated: "" }), "utf-8");
55
109
  if (!existsSync(join(targetDir, ".ciel/parking.md")))
56
110
  writeFileSync(join(targetDir, ".ciel/parking.md"), "# Ciel Parking Lot\n\n", "utf-8");
111
+ writeFileSync(memPath, JSON.stringify({ cielVersion: CIEL_VERSION, lastUpdated: new Date().toISOString() }, null, 2), "utf-8");
112
+ }
57
113
 
58
- // OpenCode files
59
- if (existsSync(join(targetDir, "opencode.json")) || existsSync(join(targetDir, ".opencode"))) {
60
- // Clean old curl plugin
61
- const old = join(targetDir, ".opencode/plugins/ciel.ts");
62
- if (existsSync(old)) { try { unlinkSync(old); } catch {} }
63
- // Copy agents
64
- total += copyDir(join(assets, "platforms/opencode/.opencode/agents"), join(targetDir, ".opencode/agents"));
65
- // Copy commands
66
- total += copyDir(join(assets, "platforms/opencode/.opencode/commands"), join(targetDir, ".opencode/commands"));
67
- // Copy AGENTS.md
68
- if (existsSync(join(assets, "platforms/opencode/AGENTS.md"))) {
69
- copyFileSync(join(assets, "platforms/opencode/AGENTS.md"), join(targetDir, "AGENTS.md"));
70
- total++;
71
- }
72
- if (patchConfig(targetDir, assets)) total++;
73
- console.error(` ${green("✓")} OpenCode: ${total} fichiers`);
74
- }
114
+ // ===== MAIN BOOT =====
115
+ const args = process.argv.slice(2);
116
+ const isHelp = args.includes("--help") || args.includes("-h");
117
+ const isVersion = args.includes("--version") || args.includes("-v");
118
+
119
+ if (!isHelp && !isVersion && ASSETS && existsSync(join(ASSETS, "platforms/opencode/.opencode/agents/ciel.md"))) {
120
+ try {
121
+ const storedVersion = (() => { try { return JSON.parse(readFileSync(memPath, "utf-8")).cielVersion; } catch { return null; } })();
122
+ const needsInit = !storedVersion || storedVersion !== CIEL_VERSION;
75
123
 
76
- // Claude Code files
77
- if (existsSync(join(targetDir, ".claude/settings.json")) || existsSync(join(targetDir, ".claude"))) {
78
- total += copyDir(join(assets, ".claude/agents"), join(targetDir, ".claude/agents"));
79
- total += copyDir(join(assets, ".claude/hooks"), join(targetDir, ".claude/hooks"));
80
- total += copyDir(join(assets, "commands"), join(targetDir, ".claude/commands"));
81
- if (existsSync(join(assets, ".claude/settings.json"))) {
82
- copyFileSync(join(assets, ".claude/settings.json"), join(targetDir, ".claude/settings.json"));
124
+ // Toujours détecter les plateformes
125
+ const platforms = detectPlatforms();
126
+
127
+ // Créer les configs si CLI détectée mais pas de fichiers
128
+ if (platforms.includes("OpenCode") && !existsSync(join(targetDir, "opencode.json"))) {
129
+ writeFileSync(join(targetDir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json", plugin: ["@neikyun/ciel"] }, null, 2) + "\n", "utf-8");
83
130
  }
84
- if (existsSync(join(assets, "CLAUDE.md"))) {
85
- copyFileSync(join(assets, "CLAUDE.md"), join(targetDir, "CLAUDE.md"));
131
+ if (platforms.includes("Claude Code") && !existsSync(join(targetDir, ".claude/settings.json"))) {
132
+ mkdirSync(join(targetDir, ".claude"), { recursive: true });
133
+ writeFileSync(join(targetDir, ".claude/settings.json"), "{}\n", "utf-8");
86
134
  }
87
- console.error(` ${green("✓")} Claude Code: ${total} fichiers`);
88
- }
89
135
 
90
- // Save version
91
- writeFileSync(memPath, JSON.stringify({ cielVersion: CIEL_VERSION, lastUpdated: new Date().toISOString() }, null, 2), "utf-8");
92
- return total;
93
- }
136
+ // Vérifier ce qui manque pour chaque plateforme détectée
137
+ const opencodeFilesExist = existsSync(join(targetDir, ".opencode/agents/ciel.md"));
138
+ const claudeFilesExist = existsSync(join(targetDir, ".claude/hooks/check-test-first.sh"));
94
139
 
95
- const c = (code, s) => process.stderr.isTTY ? `\x1b[${code}m${s}\x1b[0m` : s;
96
- const green = (s) => c(32, s);
97
- const cyan = (s) => c(36, s);
140
+ if (needsInit || (platforms.includes("OpenCode") && !opencodeFilesExist) || (platforms.includes("Claude Code") && !claudeFilesExist)) {
141
+ let n = 0;
142
+ console.error(`\n ⚡ Ciel v${CIEL_VERSION} Configuration...`);
143
+ ensureCielState();
98
144
 
99
- if (needsInit) {
100
- const args = process.argv.slice(2);
101
- if (!args.includes("--help") && !args.includes("-h") && !args.includes("--version") && !args.includes("-v")) {
102
- try {
103
- const hasOC = existsSync(join(targetDir, "opencode.json")) || existsSync(join(targetDir, ".opencode"));
104
- const hasClaude = existsSync(join(targetDir, ".claude/settings.json")) || existsSync(join(targetDir, ".claude"));
105
- const hasOC_CLI = (() => { try { return execSync("opencode --version 2>&1", { stdio: "pipe", timeout: 3000 }).toString().length > 0; } catch { return false; } })();
106
- const hasClaude_CLI = (() => { try { return execSync("claude --version 2>&1", { stdio: "pipe", timeout: 3000 }).toString().length > 0; } catch { return false; } })();
107
-
108
- // Créer les configs si CLI détectée mais pas de fichier
109
- if (hasOC_CLI && !hasOC) {
110
- writeFileSync(join(targetDir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json", plugin: ["@neikyun/ciel"] }, null, 2) + "\n", "utf-8");
111
- }
112
- if (hasClaude_CLI && !hasClaude) {
113
- mkdirSync(join(targetDir, ".claude"), { recursive: true });
114
- writeFileSync(join(targetDir, ".claude/settings.json"), "{}\n", "utf-8");
145
+ if (platforms.includes("OpenCode") && (!opencodeFilesExist || needsInit)) {
146
+ n += installOpenCode();
147
+ console.error(` ${green("")} OpenCode: agents + commands`);
115
148
  }
116
-
117
- if (hasOC || hasClaude || hasOC_CLI || hasClaude_CLI) {
118
- if (existsSync(ASSETS) && existsSync(join(ASSETS, "platforms/opencode/.opencode/agents/ciel.md"))) {
119
- console.error(`\n ⚡ Ciel v${CIEL_VERSION} — Premier lancement, initialisation...`);
120
- const n = runInit(targetDir, ASSETS);
121
- console.error(` ${green("✓")} Ciel v${CIEL_VERSION} configuré (${n} fichiers)\n`);
122
- }
149
+ if (platforms.includes("Claude Code") && (!claudeFilesExist || needsInit)) {
150
+ n += installClaude();
151
+ console.error(` ${green("✓")} Claude Code: agents + hooks + commands`);
123
152
  }
124
- } catch {}
125
- }
153
+ console.error(` ${green("✓")} Ciel v${CIEL_VERSION} prêt !\n`);
154
+ }
155
+ } catch {}
126
156
  }
127
157
 
128
158
  // Lancer la CLI normalement
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neikyun/ciel",
3
- "version": "5.2.9",
3
+ "version": "5.2.11",
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",
@@ -34,11 +34,16 @@ function resolveAssets() {
34
34
  }
35
35
 
36
36
  function detectCLI(name) {
37
- try {
38
- const { execSync } = require("child_process");
39
- const r = execSync(name + " --version 2>&1", { stdio: "pipe", timeout: 3000, encoding: "utf8" });
40
- return r.length > 0 && !r.includes("not found");
41
- } catch { return false; }
37
+ // Cherche l'exécutable dans le PATH directement (fiable cross-platform)
38
+ const pathExt = process.env.PATHEXT ? process.env.PATHEXT.split(";") : ["", ".exe", ".cmd", ".bat", ".com"];
39
+ const pathDirs = (process.env.PATH || "").split(require("path").delimiter);
40
+ for (const dir of pathDirs) {
41
+ for (const ext of pathExt) {
42
+ const fullPath = require("path").join(dir, name + ext);
43
+ if (existsSync(fullPath)) return true;
44
+ }
45
+ }
46
+ return false;
42
47
  }
43
48
 
44
49
  // ---- Installation ----