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 +1 -24
- package/generators/ai-enhancer/index.ts +4 -2
- package/generators/django-app/index.ts +5 -1
- package/generators/django-channel/index.ts +5 -1
- package/generators/django-form/index.ts +5 -1
- package/generators/django-view/index.ts +3 -1
- package/generators/utils/filesystem.ts +44 -6
- package/generators/wagtail-admin/index.ts +5 -1
- package/generators/wagtail-block/index.ts +4 -1
- package/generators/wagtail-page/actions/model.ts +5 -1
- package/generators/wagtail-page/actions/orderable.ts +5 -1
- package/generators/wagtail-page/actions/page.ts +5 -1
- package/generators/wagtail-page/actions/snippet.ts +3 -1
- package/package.json +1 -1
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
|
-
|
|
112
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
30
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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');
|