novahiz 0.11.5 → 0.11.7

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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.11.7] - 2026-10-23
9
+
10
+ ### Fixed
11
+
12
+ - **MCP Novahiz ne fonctionnent pas sur Linux** - OpenCode (en mode GUI/Desktop) ne
13
+ n'hérite pas du PATH du shell, donc `node` seul ne se résolvait pas pour les MCP
14
+ locaux (`novahiz-core`, `novahiz-gate`, `novahiz-docs`, `novahiz-search`,
15
+ `novahiz-scheduler`, `novahiz-scan`). L'installateur utilise maintenant le chemin
16
+ absolu de `node` (`process.execPath`) et propage le `PATH` de l'installateur via
17
+ `environment` à chaque MCP. Le MCP `dart` est omis si le Dart SDK n'est pas
18
+ présent (`which dart` / `where dart`).
19
+
20
+ ## [0.11.6] - 2026-10-23
21
+
22
+ ### Fixed
23
+
24
+ - **Installer spawnSync arguments** - `spawnSync(...cmd, opts)` spread the
25
+ command array into separate positional arguments, causing
26
+ `ERR_INVALID_ARG_TYPE` on the options object during the catalog sync step
27
+ of `novahiz setup`. All 5 call sites now use
28
+ `spawnSync(cmd[0], cmd.slice(1), opts)`.
29
+
8
30
  ## [0.11.5] - 2026-10-23
9
31
 
10
32
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  17 catégories, 94 skills, 13 gate rules, 8 MCP providers — tout déterministe, tout local, tout JSON.
6
6
 
7
- > **Version 0.11.4** — `npm install -g novahiz` pose le CLI, et le premier `novahiz` lancé termine l'installation (core puis extras). `CHANGELOG.md` et `scripts/` sont dans le tarball.
7
+ > **Version 0.11.6** — `npm install -g novahiz` pose le CLI, et le premier `novahiz` lancé termine l'installation (core puis extras). `CHANGELOG.md` et `scripts/` sont dans le tarball.
8
8
 
9
9
  ```
10
10
  ┌──────────────────────────────────────────────────────────────────────────┐
@@ -43,8 +43,48 @@
43
43
 
44
44
  ### Option 1 — npm (recommandé)
45
45
 
46
+ #### Linux
47
+
48
+ Sur Linux, `/usr/local/lib/node_modules` appartient à `root`. Pour éviter d'utiliser `sudo` avec npm, configurez un préfixe dans votre dossier personnel :
49
+
50
+ ```bash
51
+ mkdir -p ~/.npm-global
52
+ npm config set prefix '~/.npm-global'
53
+ echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
54
+ source ~/.bashrc
55
+ npm install -g novahiz
56
+ novahiz setup
57
+ novahiz doctor
58
+ ```
59
+
60
+ Si vous préférez conserver l'installation système (nécessite `sudo`) :
61
+
62
+ ```bash
63
+ sudo npm install -g novahiz
64
+ sudo novahiz setup
65
+ ```
66
+
67
+ #### Windows
68
+
69
+ Sur Windows, aucune configuration préalable n'est nécessaire :
70
+
71
+ ```bash
72
+ npm install -g novahiz
73
+ novahiz setup
74
+ novahiz doctor
75
+ ```
76
+
77
+ #### macOS
78
+
79
+ Sur macOS, aucune configuration particulière n'est nécessaire en général. Si vous obtenez une erreur de permissions sur `/usr/local/lib/node_modules`, utilisez la même méthode que sous Linux :
80
+
46
81
  ```bash
82
+ mkdir -p ~/.npm-global
83
+ npm config set prefix '~/.npm-global'
84
+ echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
85
+ source ~/.zshrc
47
86
  npm install -g novahiz
87
+ novahiz setup
48
88
  novahiz doctor
49
89
  ```
50
90
 
@@ -505,7 +505,7 @@ async function main() {
505
505
  const cmd = cliSpawnArgs(home, "sync");
506
506
  if (cmd) {
507
507
  note("Building catalog (sync)");
508
- const result = spawnSync(...cmd, {
508
+ const result = spawnSync(cmd[0], cmd.slice(1), {
509
509
  encoding: "utf8",
510
510
  env: { ...process.env, NOVAHIZ_HOME: home }
511
511
  });
@@ -534,7 +534,8 @@ async function main() {
534
534
  ? providersChoice
535
535
  : Boolean(flags["install-providers"]) || config?.providers?.autoInstall !== false;
536
536
  note("Checking dependencies");
537
- const check = spawnSync(...cliSpawnArgs(home, "deps"), {
537
+ const checkArgs = cliSpawnArgs(home, "deps");
538
+ const check = spawnSync(checkArgs[0], checkArgs.slice(1), {
538
539
  encoding: "utf8",
539
540
  env: { ...process.env, NOVAHIZ_HOME: home }
540
541
  });
@@ -548,7 +549,8 @@ async function main() {
548
549
  note(autoInstall
549
550
  ? "Installing dependencies and providers (toolchain, MCP, skills, commands)"
550
551
  : "Installing core system dependencies (toolchain: python, uv — npm health)");
551
- const result = spawnSync(...cliSpawnArgs(home, ...args), {
552
+ const installArgs = cliSpawnArgs(home, ...args);
553
+ const result = spawnSync(installArgs[0], installArgs.slice(1), {
552
554
  encoding: "utf8",
553
555
  env: { ...process.env, NOVAHIZ_HOME: home }
554
556
  });
@@ -744,6 +746,97 @@ async function main() {
744
746
  const agentsSkillsDir = join(homedir(), ".agents", "skills");
745
747
  const agentsSkillsDirLegacy = join(homedir(), ".config", ".agents", "skills");
746
748
 
749
+ // Le chemin absolu de node est essentiel : OpenCode (notamment en
750
+ // mode GUI/Desktop sur Linux) ne hérite pas du PATH du shell, donc
751
+ // `node` seul ne se résout pas. On utilise donc le chemin absolu du
752
+ // node qui lance l'installateur.
753
+ const nodeBin = process.execPath;
754
+ // On propage le PATH de l'installateur aux MCP locaux pour que `node`,
755
+ // `npx`, `dart` etc. soient trouvables même sans héritage du shell.
756
+ const mcpEnv = { PATH: process.env.PATH };
757
+
758
+ // Détermine si le Dart SDK est présent (nécessaire pour le MCP dart).
759
+ let hasDart = false;
760
+ try {
761
+ const dartCheck = spawnSync(
762
+ process.platform === "win32" ? "where" : "which",
763
+ ["dart"],
764
+ { encoding: "utf8", stdio: "pipe" }
765
+ );
766
+ hasDart = dartCheck.status === 0;
767
+ } catch {
768
+ // dart introuvable, le MCP dart sera omis
769
+ }
770
+
771
+ const mcp = {
772
+ "novahiz-docs": {
773
+ "type": "local",
774
+ "command": [nodeBin, join(home, "mcp", "novahiz-docs", "index.mjs")],
775
+ "environment": mcpEnv,
776
+ "enabled": true
777
+ },
778
+ "novahiz-search": {
779
+ "type": "local",
780
+ "command": [nodeBin, join(home, "mcp", "lodestone", "index.mjs")],
781
+ "timeout": 120000,
782
+ "environment": mcpEnv,
783
+ "enabled": true
784
+ },
785
+ // `novahiz-scheduler` is the local scheduler (mcp/clepsydre, zero npm
786
+ // dependency): it ships ready to run, no setup step.
787
+ "novahiz-scheduler": {
788
+ "type": "local",
789
+ "command": [nodeBin, join(home, "mcp", "clepsydre", "index.mjs")],
790
+ "timeout": 120000,
791
+ "environment": mcpEnv,
792
+ "enabled": true
793
+ },
794
+ "playwright": {
795
+ "type": "local",
796
+ // See playwrightBrowserFlag() in lib.mjs for the platform rule.
797
+ "command": ["npx", "-y", "@playwright/mcp@0.0.82", playwrightBrowserFlag()],
798
+ "environment": mcpEnv,
799
+ "enabled": true
800
+ },
801
+ // Trio runtime (audit 2026-10-08) : novahiz_classify (27 outils dont
802
+ // la classification du pipeline), novahiz_gate (la porte que le skill
803
+ // novahiz-gate appelle) et scan (argus). Le transform du plugin les
804
+ // inscrit aussi, mais un transform arrive apres la resolution MCP ne
805
+ // lie jamais les serveurs — en config statique la connexion est
806
+ // garantie des l'installation. Le plugin voit editor.get(id) deja
807
+ // present et les saute : aucun doublon. timeout 120s = cold start
808
+ // argus (audit 2026-09-25 P2).
809
+ "novahiz-core": {
810
+ "type": "local",
811
+ "command": [nodeBin, join(home, "mcp", "novahiz-tools", "index.mjs")],
812
+ "timeout": 120000,
813
+ "environment": mcpEnv,
814
+ "enabled": true
815
+ },
816
+ "novahiz-gate": {
817
+ "type": "local",
818
+ "command": [nodeBin, join(home, "mcp", "novahiz-gate", "index.mjs")],
819
+ "timeout": 120000,
820
+ "environment": mcpEnv,
821
+ "enabled": true
822
+ },
823
+ "novahiz-scan": {
824
+ "type": "local",
825
+ "command": [nodeBin, join(home, "mcp", "argus", "src", "cli.mjs")],
826
+ "timeout": 120000,
827
+ "environment": mcpEnv,
828
+ "enabled": true
829
+ }
830
+ };
831
+ if (hasDart) {
832
+ mcp["dart"] = {
833
+ "type": "local",
834
+ "command": ["dart", "mcp-server"],
835
+ "environment": mcpEnv,
836
+ "enabled": true
837
+ };
838
+ }
839
+
747
840
  const openCodeConfig = {
748
841
  "$schema": "https://opencode.ai/config.json",
749
842
  // T3: sans ce champ, adapters/opencode/instructions.md n'est lu par
@@ -758,64 +851,7 @@ async function main() {
758
851
  // (typescript-language-server, etc.) peuvent manquer — des entrees
759
852
  // mortes = exactement le probleme qu'on veut jamais livrer.
760
853
  "lsp": true,
761
- "mcp": {
762
- "novahiz-docs": {
763
- "type": "local",
764
- "command": ["node", join(home, "mcp", "novahiz-docs", "index.mjs")],
765
- "enabled": true
766
- },
767
- "novahiz-search": {
768
- "type": "local",
769
- "command": ["node", join(home, "mcp", "lodestone", "index.mjs")],
770
- "timeout": 120000,
771
- "enabled": true
772
- },
773
- // `novahiz-scheduler` is the local scheduler (mcp/clepsydre, zero npm
774
- // dependency): it ships ready to run, no setup step.
775
- "novahiz-scheduler": {
776
- "type": "local",
777
- "command": ["node", join(home, "mcp", "clepsydre", "index.mjs")],
778
- "timeout": 120000,
779
- "enabled": true
780
- },
781
- "playwright": {
782
- "type": "local",
783
- // See playwrightBrowserFlag() in lib.mjs for the platform rule.
784
- "command": ["npx", "-y", "@playwright/mcp@0.0.82", playwrightBrowserFlag()],
785
- "enabled": true
786
- },
787
- "dart": {
788
- "type": "local",
789
- "command": ["dart", "mcp-server"],
790
- "enabled": true
791
- },
792
- // Trio runtime (audit 2026-10-08) : novahiz_classify (27 outils dont
793
- // la classification du pipeline), novahiz_gate (la porte que le skill
794
- // novahiz-gate appelle) et scan (argus). Le transform du plugin les
795
- // inscrit aussi, mais un transform arrive apres la resolution MCP ne
796
- // lie jamais les serveurs — en config statique la connexion est
797
- // garantie des l'installation. Le plugin voit editor.get(id) deja
798
- // present et les saute : aucun doublon. timeout 120s = cold start
799
- // argus (audit 2026-09-25 P2).
800
- "novahiz-core": {
801
- "type": "local",
802
- "command": ["node", join(home, "mcp", "novahiz-tools", "index.mjs")],
803
- "timeout": 120000,
804
- "enabled": true
805
- },
806
- "novahiz-gate": {
807
- "type": "local",
808
- "command": ["node", join(home, "mcp", "novahiz-gate", "index.mjs")],
809
- "timeout": 120000,
810
- "enabled": true
811
- },
812
- "novahiz-scan": {
813
- "type": "local",
814
- "command": ["node", join(home, "mcp", "argus", "src", "cli.mjs")],
815
- "timeout": 120000,
816
- "enabled": true
817
- }
818
- },
854
+ "mcp": mcp,
819
855
  "skills": {
820
856
  "paths": [skillsDir]
821
857
  },
@@ -861,7 +897,7 @@ async function main() {
861
897
  const vaultCmd = cliSpawnArgs(home, "second-memory", "init");
862
898
  if (vaultCmd) {
863
899
  note("Creating the second-memory vault (structure + Obsidian plugins, ~10 downloads)...");
864
- const vault = spawnSync(...vaultCmd, {
900
+ const vault = spawnSync(vaultCmd[0], vaultCmd.slice(1), {
865
901
  encoding: "utf8",
866
902
  timeout: 180000,
867
903
  env: { ...process.env, NOVAHIZ_HOME: home }
@@ -949,7 +985,7 @@ async function main() {
949
985
  const cleanupCmd = cliSpawnArgs(home, "sync");
950
986
  if (cleanupCmd) {
951
987
  note("Rebuilding catalog after cleanup (sync)");
952
- const rebuild = spawnSync(...cleanupCmd, {
988
+ const rebuild = spawnSync(cleanupCmd[0], cleanupCmd.slice(1), {
953
989
  encoding: "utf8",
954
990
  env: { ...process.env, NOVAHIZ_HOME: home }
955
991
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "novahiz",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "Enforce AI agent skills before every file edit: prompt classifier, skill catalog, and pre-edit gate.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",