kalo-cli 0.1.2 → 0.1.3

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/kalo.ts CHANGED
@@ -5,36 +5,13 @@ import minimist from "minimist";
5
5
  import { Plop, run } from "plop";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { loadConfig } from "../generators/utils/config";
8
+ import { findProjectRoot } from "../generators/utils/filesystem";
8
9
 
9
10
  const args = process.argv.slice(2);
10
11
  const argv = minimist(args);
11
12
 
12
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
14
 
14
- /**
15
- * Recherche le répertoire racine du projet en remontant à partir d'un dossier donné.
16
- */
17
- function findProjectRoot(startDir: string): string {
18
- let currentDir = startDir;
19
- while (currentDir !== path.parse(currentDir).root) {
20
- const packageJsonPath = path.join(currentDir, 'package.json');
21
- if (fs.existsSync(packageJsonPath)) {
22
- try {
23
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
24
- if (pkg.name !== 'kalo-cli' || currentDir.includes('node_modules')) {
25
- if (!currentDir.includes('node_modules')) {
26
- return currentDir;
27
- }
28
- } else {
29
- return currentDir;
30
- }
31
- } catch (e) {}
32
- }
33
- currentDir = path.dirname(currentDir);
34
- }
35
- return startDir;
36
- }
37
-
38
15
  const projectRoot = findProjectRoot(process.cwd());
39
16
  const config = await loadConfig();
40
17
 
@@ -4,6 +4,7 @@ import { generateWithModel } from '../utils/ai/common';
4
4
  import { injectMarkers, applyGeneratedCode } from '../utils/code-manipulation';
5
5
  import { Glob } from "bun";
6
6
  import { searchChoices } from '../utils/search';
7
+ import { findProjectRoot } from '../utils/filesystem';
7
8
  import { AI_PROVIDER_TYPES, AI_TEMP_TYPES, BACK_VALUE, EXIT_VALUE } from '../constants';
8
9
  import keywordConfig from './keywords.json';
9
10
 
@@ -108,8 +109,9 @@ export const aiEnhancerGenerator: PlopGeneratorConfig = {
108
109
  source: async (answers, input) => {
109
110
  const glob = new Glob("**/*.py");
110
111
  const files: string[] = [];
111
- // Scans the current directory
112
- for await (const file of glob.scan(".")) {
112
+ const rootDir = findProjectRoot();
113
+ // Scans the project root
114
+ for await (const file of glob.scan(rootDir)) {
113
115
  // Filter for likely python model files or snippets
114
116
  if (file.endsWith('.py') && (file.includes("models") || file.includes("snippet"))) {
115
117
  files.push(file);
@@ -1,4 +1,6 @@
1
1
  import { PlopGeneratorConfig } from 'plop';
2
+ import * as path from 'path';
3
+ import { findProjectRoot } from '../utils/filesystem';
2
4
 
3
5
  /**
4
6
  * Generator configuration for creating a new Django Application.
@@ -22,7 +24,9 @@ export const djangoAppGenerator: PlopGeneratorConfig = {
22
24
  },
23
25
  ],
24
26
  actions: (data: any) => {
25
- const appDir = data.config?.appDir || 'app';
27
+ const rootDir = findProjectRoot();
28
+ const appDirName = data.config?.appDir || 'app';
29
+ const appDir = path.join(rootDir, appDirName);
26
30
  return [
27
31
  {
28
32
  type: 'add',
@@ -1,5 +1,7 @@
1
1
  import { PlopGeneratorConfig } from 'plop';
2
+ import * as path from 'path';
2
3
  import { ensureSuffix, createAppendActions } from '../utils/plop-actions';
4
+ import { findProjectRoot } from '../utils/filesystem';
3
5
  import { CHANNEL_TYPES } from '../constants';
4
6
  import { searchChoices } from '../utils/search';
5
7
 
@@ -41,7 +43,9 @@ export const djangoChannelGenerator: PlopGeneratorConfig = {
41
43
  ],
42
44
  actions: (data: any) => {
43
45
  const actions = [];
44
- const appDir = data.config?.appDir || 'app';
46
+ const rootDir = findProjectRoot();
47
+ const appDirName = data.config?.appDir || 'app';
48
+ const appDir = path.join(rootDir, appDirName);
45
49
  const appPath = `${appDir}/${data.app}`;
46
50
  const isAsync = data.type === 'async';
47
51
  data.isAsync = isAsync;
@@ -1,5 +1,7 @@
1
1
  import { PlopGeneratorConfig } from 'plop';
2
+ import * as path from 'path';
2
3
  import { ensureSuffix, createAppendActions } from '../utils/plop-actions';
4
+ import { findProjectRoot } from '../utils/filesystem';
3
5
  import { FORM_TYPES } from '../constants';
4
6
  import { searchChoices } from '../utils/search';
5
7
 
@@ -40,7 +42,9 @@ export const djangoFormGenerator: PlopGeneratorConfig = {
40
42
  ],
41
43
  actions: (data: any) => {
42
44
  const actions = [];
43
- const appDir = data.config?.appDir || 'app';
45
+ const rootDir = findProjectRoot();
46
+ const appDirName = data.config?.appDir || 'app';
47
+ const appDir = path.join(rootDir, appDirName);
44
48
  const appPath = `${appDir}/${data.app}`;
45
49
  const isModelForm = data.type === 'model_form';
46
50
 
@@ -36,7 +36,9 @@ export const djangoViewGenerator: PlopGeneratorConfig = {
36
36
  ],
37
37
  actions: (data: any) => {
38
38
  const actions = [];
39
- const appDir = data.config?.appDir || 'app';
39
+ const rootDir = findProjectRoot();
40
+ const appDirName = data.config?.appDir || 'app';
41
+ const appDir = path.join(rootDir, appDirName);
40
42
  const appPath = `${appDir}/${data.app}`;
41
43
  const isCBV = data.type !== 'fbv';
42
44
 
@@ -3,7 +3,8 @@ import * as path from 'path';
3
3
 
4
4
  /**
5
5
  * Recherche le répertoire racine du projet en remontant à partir d'un dossier donné.
6
- * Cherche la présence d'un fichier package.json qui n'est pas celui du package kalo-cli lui-même.
6
+ * Cherche la présence d'un fichier package.json valide (avec name et version).
7
+ * Vérifie également les permissions d'écriture.
7
8
  *
8
9
  * @param startDir - Le dossier de départ pour la recherche.
9
10
  * @returns Le chemin absolu vers la racine du projet.
@@ -16,18 +17,50 @@ export const findProjectRoot = (startDir: string = process.cwd()): string => {
16
17
  if (fs.existsSync(packageJsonPath)) {
17
18
  try {
18
19
  const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
20
+
21
+ // Validation basique du package.json
22
+ if (!pkg.name || !pkg.version) {
23
+ // Package.json invalide, on continue
24
+ currentDir = path.dirname(currentDir);
25
+ continue;
26
+ }
27
+
19
28
  // Si on trouve un package.json qui n'est pas celui de kalo-cli, c'est probablement la racine du projet utilisateur
20
29
  // Ou si on est dans un projet qui n'a pas encore de kalo-cli installé mais qui a un package.json
21
30
  if (pkg.name !== 'kalo-cli' || currentDir.includes('node_modules')) {
22
31
  // Si on est dans node_modules, on doit continuer à monter car on a trouvé le package.json de kalo-cli
32
+ // SAUF si le dossier courant n'est PAS dans node_modules (ex: projet utilisateur nommé 'node_modules' - improbable mais possible)
33
+ // La logique ici : Si le chemin CONTIENT node_modules, c'est suspect, on veut sortir de node_modules.
34
+ // MAIS si on a trouvé un package.json valide à un niveau, il faut vérifier si c'est celui de notre dépendance ou du projet racine.
35
+
36
+ // Cas simple : On est dans .../mon-projet/node_modules/kalo-cli
37
+ // currentDir = .../mon-projet/node_modules/kalo-cli -> pkg.name = kalo-cli.
38
+ // La condition (pkg.name !== 'kalo-cli') est fausse. -> else -> return currentDir (Mode dev local)
39
+ // ATTENTION: La logique originale retournait currentDir si pkg.name === 'kalo-cli' (mode dev).
40
+
41
+ // Nouvelle logique plus stricte :
23
42
  if (currentDir.includes('node_modules')) {
24
- // On continue de monter
43
+ // On est à l'intérieur d'un node_modules, ce n'est probablement pas la racine du projet utilisateur
44
+ // On continue de remonter
25
45
  } else {
26
- return currentDir;
46
+ // Vérification des permissions d'écriture
47
+ try {
48
+ fs.accessSync(currentDir, fs.constants.W_OK);
49
+ return currentDir;
50
+ } catch (e) {
51
+ console.warn(`[Kalo] Attention: Le répertoire détecté ${currentDir} n'est pas accessible en écriture.`);
52
+ // On continue quand même ? Ou on retourne avec un warning ?
53
+ // Pour l'instant on retourne, l'erreur surviendra à l'écriture.
54
+ return currentDir;
55
+ }
27
56
  }
28
57
  } else {
29
- // C'est le package.json de kalo-cli en mode développement local
30
- return currentDir;
58
+ // C'est le package.json de kalo-cli (pkg.name === 'kalo-cli')
59
+ // Si on n'est pas dans node_modules, c'est qu'on développe kalo-cli lui-même
60
+ if (!currentDir.includes('node_modules')) {
61
+ return currentDir;
62
+ }
63
+ // Sinon, c'est qu'on est dans node_modules/kalo-cli, donc on continue
31
64
  }
32
65
  } catch (e) {
33
66
  // En cas d'erreur de lecture, on continue de monter
@@ -36,7 +69,12 @@ export const findProjectRoot = (startDir: string = process.cwd()): string => {
36
69
  currentDir = path.dirname(currentDir);
37
70
  }
38
71
 
39
- return startDir; // Fallback sur le dossier de départ
72
+ // Fallback: Si on n'a rien trouvé, on retourne le dossier de départ
73
+ // Mais on prévient l'utilisateur
74
+ if (startDir.includes('node_modules')) {
75
+ console.warn("[Kalo] Attention: Impossible de trouver la racine du projet hors de node_modules.");
76
+ }
77
+ return startDir;
40
78
  };
41
79
 
42
80
  /**
@@ -1,5 +1,7 @@
1
1
  import { PlopGeneratorConfig } from 'plop';
2
+ import * as path from 'path';
2
3
  import { ensureSuffix } from '../utils/plop-actions';
4
+ import { findProjectRoot } from '../utils/filesystem';
3
5
  import { ADMIN_EXT_TYPES } from '../constants';
4
6
  import { searchChoices } from '../utils/search';
5
7
 
@@ -35,7 +37,9 @@ export const wagtailAdminGenerator: PlopGeneratorConfig = {
35
37
  ],
36
38
  actions: (data: any) => {
37
39
  const actions = [];
38
- const appDir = data.config?.appDir || 'app';
40
+ const rootDir = findProjectRoot();
41
+ const appDirName = data.config?.appDir || 'app';
42
+ const appDir = path.join(rootDir, appDirName);
39
43
  const appPath = `${appDir}/${data.app}`;
40
44
  const isView = data.type === 'view';
41
45
 
@@ -2,6 +2,7 @@ import { PlopGeneratorConfig } from 'plop';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import { ensureSuffix, createAppendActions } from '../utils/plop-actions';
5
+ import { findProjectRoot } from '../utils/filesystem';
5
6
 
6
7
  /**
7
8
  * Generator configuration for Wagtail StreamField Blocks.
@@ -29,7 +30,9 @@ export const wagtailBlockGenerator: PlopGeneratorConfig = {
29
30
  ],
30
31
  actions: (data: any) => {
31
32
  const actions = [];
32
- const appDir = data.config?.appDir || 'app';
33
+ const rootDir = findProjectRoot();
34
+ const appDirName = data.config?.appDir || 'app';
35
+ const appDir = path.join(rootDir, appDirName);
33
36
 
34
37
  // Ensure suffix
35
38
  data.name = ensureSuffix(data.name, 'Block');
@@ -1,6 +1,8 @@
1
1
 
2
2
  import { ActionType } from 'plop';
3
+ import * as path from 'path';
3
4
  import { createAppendActions } from '../../utils/plop-actions';
5
+ import { findProjectRoot } from '../../utils/filesystem';
4
6
 
5
7
  /**
6
8
  * Generates Plop actions for creating a standard Django model.
@@ -9,7 +11,9 @@ import { createAppendActions } from '../../utils/plop-actions';
9
11
  * @returns {ActionType[]} An array of Plop actions to create/update model files.
10
12
  */
11
13
  export const getModelActions = (data: any): ActionType[] => {
12
- const appDir = data.config?.appDir || 'app';
14
+ const rootDir = findProjectRoot();
15
+ const appDirName = data.config?.appDir || 'app';
16
+ const appDir = path.join(rootDir, appDirName);
13
17
  const appPath = `${appDir}/${data.app}`;
14
18
 
15
19
  return createAppendActions({
@@ -1,6 +1,8 @@
1
1
 
2
2
  import { ActionType } from 'plop';
3
+ import * as path from 'path';
3
4
  import { ensureSuffix, createAppendActions } from '../../utils/plop-actions';
5
+ import { findProjectRoot } from '../../utils/filesystem';
4
6
 
5
7
  /**
6
8
  * Generates Plop actions for creating a Wagtail Orderable model.
@@ -10,7 +12,9 @@ import { ensureSuffix, createAppendActions } from '../../utils/plop-actions';
10
12
  * @returns {ActionType[]} An array of Plop actions to create/update orderable files.
11
13
  */
12
14
  export const getOrderableActions = (data: any): ActionType[] => {
13
- const appDir = data.config?.appDir || 'app';
15
+ const rootDir = findProjectRoot();
16
+ const appDirName = data.config?.appDir || 'app';
17
+ const appDir = path.join(rootDir, appDirName);
14
18
  const appPath = `${appDir}/${data.app}`;
15
19
 
16
20
  data.name = ensureSuffix(data.name, 'Orderable');
@@ -1,6 +1,8 @@
1
1
 
2
2
  import { ActionType } from 'plop';
3
+ import * as path from 'path';
3
4
  import { createAppendActions } from '../../utils/plop-actions';
5
+ import { findProjectRoot } from '../../utils/filesystem';
4
6
 
5
7
  /**
6
8
  * Generates Plop actions for creating a pair of Wagtail Pages (Index + Detail).
@@ -11,7 +13,9 @@ import { createAppendActions } from '../../utils/plop-actions';
11
13
  */
12
14
  export const getPageActions = (data: any): ActionType[] => {
13
15
  const actions: ActionType[] = [];
14
- const appDir = data.config?.appDir || 'app';
16
+ const rootDir = findProjectRoot();
17
+ const appDirName = data.config?.appDir || 'app';
18
+ const appDir = path.join(rootDir, appDirName);
15
19
  const appPath = `${appDir}/${data.app}`;
16
20
 
17
21
  // Clean base name: Remove 'Page' if present to avoid BlogPagePage
@@ -8,7 +8,9 @@ import { createAppendActions, ensureSuffix } from '../../utils/plop-actions';
8
8
  * @returns {ActionType[]} An array of Plop actions to create snippet files and tests.
9
9
  */
10
10
  export const getSnippetActions = (data: any): ActionType[] => {
11
- const appDir = data.config?.appDir || 'app';
11
+ const rootDir = findProjectRoot();
12
+ const appDirName = data.config?.appDir || 'app';
13
+ const appDir = path.join(rootDir, appDirName);
12
14
  const appPath = `${appDir}/${data.app}`;
13
15
 
14
16
  data.name = ensureSuffix(data.name, 'Snippet');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kalo-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Générateur de code structuré et uniforme pour Django et Wagtail",
5
5
  "bin": {
6
6
  "kalo": "./bin/kalo.ts"