johankit 0.1.5 → 0.4.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/README.md +26 -58
- package/dist/cli/commands/sync.js +37 -57
- package/dist/core/validation.js +6 -18
- package/dist/core/write.js +9 -7
- package/dist/src/cli/commands/copy.js +11 -0
- package/dist/src/cli/commands/paste.js +120 -0
- package/dist/src/cli/commands/prompt.js +54 -0
- package/dist/src/cli/commands/sync.js +173 -0
- package/dist/src/core/clipboard.js +64 -0
- package/dist/src/core/config.js +39 -0
- package/dist/{core → src/core}/diff.js +9 -12
- package/dist/src/core/scan.js +70 -0
- package/dist/src/core/schema.js +18 -0
- package/dist/src/core/validation.js +11 -0
- package/dist/src/core/write.js +24 -0
- package/dist/src/index.js +34 -0
- package/dist/src/tests/cleanCodeBlock.test.js +23 -0
- package/dist/src/tests/scan.test.js +35 -0
- package/dist/src/tests/schema.test.js +22 -0
- package/dist/src/utils/cleanCodeBlock.js +21 -0
- package/dist/types.js +1 -0
- package/johankit.yml +6 -0
- package/package.json +20 -10
- package/src/cli/commands/copy.ts +6 -19
- package/src/cli/commands/paste.ts +70 -31
- package/src/cli/commands/prompt.ts +24 -64
- package/src/cli/commands/sync.ts +121 -73
- package/src/core/clipboard.ts +46 -80
- package/src/core/config.ts +20 -32
- package/src/core/diff.ts +10 -21
- package/src/core/scan.ts +43 -40
- package/src/core/schema.ts +17 -34
- package/src/core/validation.ts +8 -27
- package/src/core/write.ts +11 -17
- package/src/index.ts +38 -77
- package/src/types.ts +4 -50
- package/src/utils/cleanCodeBlock.ts +17 -8
- package/tsconfig.json +14 -6
- package/Readme.md +0 -56
- package/dist/cli/commands/copy.js +0 -21
- package/dist/cli/commands/paste.js +0 -48
- package/dist/cli/commands/prompt.js +0 -88
- package/dist/cli/commands/three.js +0 -106
- package/dist/cli/commands/tree.js +0 -106
- package/dist/core/clipboard.js +0 -88
- package/dist/core/config.js +0 -51
- package/dist/core/scan.js +0 -66
- package/dist/core/schema.js +0 -40
- package/dist/index.js +0 -72
- package/dist/services/JohankitService.js +0 -59
- package/dist/utils/cleanCodeBlock.js +0 -12
- package/dist/utils/createAsciiTree.js +0 -46
- package/johankit.yaml +0 -2
- package/src/cli/commands/tree.ts +0 -119
- package/src/services/JohankitService.ts +0 -70
- package/src/utils/createAsciiTree.ts +0 -53
- package/types.ts +0 -11
- /package/dist/{core → src/core}/git.js +0 -0
- /package/{types.js → dist/src/types.js} +0 -0
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prompt = prompt;
|
|
4
|
-
// src/cli/commands/prompt.ts
|
|
5
|
-
const scan_1 = require("../../core/scan");
|
|
6
|
-
const clipboard_1 = require("../../core/clipboard");
|
|
7
|
-
async function prompt(dir, userPrompt, diff = false) {
|
|
8
|
-
const snapshot = (0, scan_1.scanDir)(dir);
|
|
9
|
-
const llmExamples = [
|
|
10
|
-
{
|
|
11
|
-
type: 'FileSnapshot',
|
|
12
|
-
example: [
|
|
13
|
-
{
|
|
14
|
-
path: 'src/example.ts',
|
|
15
|
-
content: 'export const x = 42;'
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
type: 'DiffPatch',
|
|
21
|
-
example: [
|
|
22
|
-
{
|
|
23
|
-
type: 'modify',
|
|
24
|
-
path: 'src/example.ts',
|
|
25
|
-
content: 'export const x = 43;'
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
type: 'create',
|
|
29
|
-
path: 'src/newFile.ts',
|
|
30
|
-
content: 'export const newFile = true;'
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
type: 'delete',
|
|
34
|
-
path: 'src/oldFile.ts'
|
|
35
|
-
}
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
];
|
|
39
|
-
const template = `
|
|
40
|
-
You are an AI software engineer.
|
|
41
|
-
|
|
42
|
-
You will receive a JSON array representing a snapshot of a codebase.
|
|
43
|
-
Each item has the following structure:
|
|
44
|
-
{
|
|
45
|
-
"path": "relative/path/to/file.ext",
|
|
46
|
-
"content": "full file content"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
SNAPSHOT
|
|
52
|
-
${JSON.stringify(snapshot, null, 2)}
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
YOUR TASK
|
|
57
|
-
Propose changes according to the user request.
|
|
58
|
-
|
|
59
|
-
Return ONLY a JSON array of ${diff ? 'DiffPatch' : 'FileSnapshot'}.
|
|
60
|
-
|
|
61
|
-
PATCH FORMAT (STRICT)
|
|
62
|
-
{
|
|
63
|
-
\"path\": \"relative/path/to/file.ext\",
|
|
64
|
-
\"content\": \"FULL updated file content (omit for delete)\"
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
EXAMPLE RESPONSE FROM LLM:
|
|
68
|
-
${JSON.stringify(diff ? llmExamples.find(e => e.type === 'DiffPatch')?.example : llmExamples.find(e => e.type === 'FileSnapshot')?.example, null, 2)}
|
|
69
|
-
|
|
70
|
-
IMPORTANT RULES
|
|
71
|
-
- Do NOT return explanations
|
|
72
|
-
- Do NOT return markdown
|
|
73
|
-
- Return ONLY valid JSON inside the \"\`\`\`\"
|
|
74
|
-
- Always return within a Markdown Code Block.
|
|
75
|
-
|
|
76
|
-
USER REQUEST
|
|
77
|
-
${userPrompt}
|
|
78
|
-
`;
|
|
79
|
-
try {
|
|
80
|
-
await (0, clipboard_1.copyToClipboard)(template.trim());
|
|
81
|
-
process.stdout.write(template.trim());
|
|
82
|
-
process.stdout.write("\n\n✔ Prompt + Snapshot + Example copied to clipboard\n");
|
|
83
|
-
}
|
|
84
|
-
catch (e) {
|
|
85
|
-
process.stdout.write(template.trim());
|
|
86
|
-
process.stderr.write("\n✖ Failed to copy to clipboard (output only)\n");
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.tree = void 0;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const ts_morph_1 = require("ts-morph");
|
|
9
|
-
/**
|
|
10
|
-
* Heurística simples para classificar arquivos
|
|
11
|
-
*/
|
|
12
|
-
function detectFileKind(filePath, exportsCount) {
|
|
13
|
-
if (filePath.includes("/cli/"))
|
|
14
|
-
return "cli";
|
|
15
|
-
if (filePath.endsWith("index.ts") || filePath.endsWith("main.ts"))
|
|
16
|
-
return "entry";
|
|
17
|
-
if (exportsCount === 0)
|
|
18
|
-
return "util";
|
|
19
|
-
if (exportsCount > 3)
|
|
20
|
-
return "domain";
|
|
21
|
-
return "unknown";
|
|
22
|
-
}
|
|
23
|
-
async function tree(dir) {
|
|
24
|
-
const project = new ts_morph_1.Project({});
|
|
25
|
-
project.addSourceFilesAtPaths([
|
|
26
|
-
`${dir}/**/*.{ts,tsx,js,jsx}`,
|
|
27
|
-
`!${dir}/**/node_modules/**/*`,
|
|
28
|
-
`!${dir}/**/dist/**/*`,
|
|
29
|
-
]);
|
|
30
|
-
const tree = [];
|
|
31
|
-
for (const file of project.getSourceFiles()) {
|
|
32
|
-
const absolutePath = file.getFilePath();
|
|
33
|
-
const filePath = path_1.default.relative(dir, absolutePath);
|
|
34
|
-
if (filePath.includes("node_modules") || filePath.includes("/dist/")) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
/* ---------------- IMPORTS ---------------- */
|
|
38
|
-
const imports = file
|
|
39
|
-
.getImportDeclarations()
|
|
40
|
-
.map(i => i.getModuleSpecifierValue());
|
|
41
|
-
/* ---------------- CLASSES ---------------- */
|
|
42
|
-
const classes = file.getClasses().map(cls => ({
|
|
43
|
-
name: cls.getName() || "<anonymous>",
|
|
44
|
-
methods: cls.getMethods().map(m => ({
|
|
45
|
-
name: m.getName(),
|
|
46
|
-
params: m.getParameters().map(p => p.getName()),
|
|
47
|
-
returnType: safeType(() => m.getReturnType().getText()),
|
|
48
|
-
scope: "class",
|
|
49
|
-
}))
|
|
50
|
-
}));
|
|
51
|
-
/* ---------------- FUNCTIONS ---------------- */
|
|
52
|
-
const functions = file.getFunctions().map(fn => ({
|
|
53
|
-
name: fn.getName() || "<anonymous>",
|
|
54
|
-
params: fn.getParameters().map(p => p.getName()),
|
|
55
|
-
returnType: safeType(() => fn.getReturnType().getText()),
|
|
56
|
-
scope: "global",
|
|
57
|
-
}));
|
|
58
|
-
/* ---------------- VARIABLES ---------------- */
|
|
59
|
-
const variables = file.getVariableDeclarations().map(v => ({
|
|
60
|
-
name: v.getName(),
|
|
61
|
-
type: safeType(() => v.getType().getText()),
|
|
62
|
-
scope: v.getParent() instanceof ts_morph_1.SourceFile ? "global" : "local",
|
|
63
|
-
}));
|
|
64
|
-
/* ---------------- EXPORTS ---------------- */
|
|
65
|
-
const exports = [];
|
|
66
|
-
let mainExport;
|
|
67
|
-
file.getExportedDeclarations().forEach((decls, name) => {
|
|
68
|
-
decls.forEach(d => {
|
|
69
|
-
let kind = "unknown";
|
|
70
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.ClassDeclaration)
|
|
71
|
-
kind = "class";
|
|
72
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.FunctionDeclaration)
|
|
73
|
-
kind = "function";
|
|
74
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.VariableDeclaration)
|
|
75
|
-
kind = "variable";
|
|
76
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.TypeAliasDeclaration)
|
|
77
|
-
kind = "type";
|
|
78
|
-
exports.push({ name, kind });
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
if (exports.length === 1) {
|
|
82
|
-
mainExport = exports[0].name;
|
|
83
|
-
}
|
|
84
|
-
const kind = detectFileKind(filePath, exports.length);
|
|
85
|
-
tree.push({
|
|
86
|
-
path: filePath,
|
|
87
|
-
kind,
|
|
88
|
-
imports,
|
|
89
|
-
classes,
|
|
90
|
-
functions,
|
|
91
|
-
variables,
|
|
92
|
-
exports,
|
|
93
|
-
mainExport,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
return tree;
|
|
97
|
-
}
|
|
98
|
-
exports.tree = tree;
|
|
99
|
-
function safeType(fn) {
|
|
100
|
-
try {
|
|
101
|
-
return fn();
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return "unknown";
|
|
105
|
-
}
|
|
106
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.tree = tree;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const ts_morph_1 = require("ts-morph");
|
|
9
|
-
/**
|
|
10
|
-
* Heurística simples para classificar arquivos
|
|
11
|
-
*/
|
|
12
|
-
function detectFileKind(filePath, exportsCount) {
|
|
13
|
-
if (filePath.includes("/cli/"))
|
|
14
|
-
return "cli";
|
|
15
|
-
if (filePath.endsWith("index.ts") || filePath.endsWith("main.ts"))
|
|
16
|
-
return "entry";
|
|
17
|
-
if (exportsCount === 0)
|
|
18
|
-
return "util";
|
|
19
|
-
if (exportsCount > 3)
|
|
20
|
-
return "domain";
|
|
21
|
-
return "unknown";
|
|
22
|
-
}
|
|
23
|
-
async function tree(dir) {
|
|
24
|
-
const project = new ts_morph_1.Project({});
|
|
25
|
-
project.addSourceFilesAtPaths([
|
|
26
|
-
`${dir}/**/*.{ts,tsx,js,jsx}`,
|
|
27
|
-
`!${dir}/**/node_modules/**/*`,
|
|
28
|
-
`!${dir}/**/dist/**/*`,
|
|
29
|
-
]);
|
|
30
|
-
const tree = [];
|
|
31
|
-
for (const file of project.getSourceFiles()) {
|
|
32
|
-
const absolutePath = file.getFilePath();
|
|
33
|
-
const filePath = path_1.default.relative(dir, absolutePath);
|
|
34
|
-
console.log(filePath);
|
|
35
|
-
if (filePath.includes("node_modules") || filePath.includes("/dist/")) {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
/* ---------------- IMPORTS ---------------- */
|
|
39
|
-
const imports = file
|
|
40
|
-
.getImportDeclarations()
|
|
41
|
-
.map(i => i.getModuleSpecifierValue());
|
|
42
|
-
/* ---------------- CLASSES ---------------- */
|
|
43
|
-
const classes = file.getClasses().map(cls => ({
|
|
44
|
-
name: cls.getName() || "<anonymous>",
|
|
45
|
-
methods: cls.getMethods().map(m => ({
|
|
46
|
-
name: m.getName(),
|
|
47
|
-
params: m.getParameters().map(p => p.getName()),
|
|
48
|
-
returnType: safeType(() => m.getReturnType().getText()),
|
|
49
|
-
scope: "class",
|
|
50
|
-
}))
|
|
51
|
-
}));
|
|
52
|
-
/* ---------------- FUNCTIONS ---------------- */
|
|
53
|
-
const functions = file.getFunctions().map(fn => ({
|
|
54
|
-
name: fn.getName() || "<anonymous>",
|
|
55
|
-
params: fn.getParameters().map(p => p.getName()),
|
|
56
|
-
returnType: safeType(() => fn.getReturnType().getText()),
|
|
57
|
-
scope: "global",
|
|
58
|
-
}));
|
|
59
|
-
/* ---------------- VARIABLES ---------------- */
|
|
60
|
-
const variables = file.getVariableDeclarations().map(v => ({
|
|
61
|
-
name: v.getName(),
|
|
62
|
-
type: safeType(() => v.getType().getText()),
|
|
63
|
-
scope: v.getParent() instanceof ts_morph_1.SourceFile ? "global" : "local",
|
|
64
|
-
}));
|
|
65
|
-
/* ---------------- EXPORTS ---------------- */
|
|
66
|
-
const exports = [];
|
|
67
|
-
let mainExport;
|
|
68
|
-
file.getExportedDeclarations().forEach((decls, name) => {
|
|
69
|
-
decls.forEach(d => {
|
|
70
|
-
let kind = "unknown";
|
|
71
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.ClassDeclaration)
|
|
72
|
-
kind = "class";
|
|
73
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.FunctionDeclaration)
|
|
74
|
-
kind = "function";
|
|
75
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.VariableDeclaration)
|
|
76
|
-
kind = "variable";
|
|
77
|
-
if (d.getKind() === ts_morph_1.SyntaxKind.TypeAliasDeclaration)
|
|
78
|
-
kind = "type";
|
|
79
|
-
exports.push({ name, kind });
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
if (exports.length === 1) {
|
|
83
|
-
mainExport = exports[0].name;
|
|
84
|
-
}
|
|
85
|
-
const kind = detectFileKind(filePath, exports.length);
|
|
86
|
-
tree.push({
|
|
87
|
-
path: filePath,
|
|
88
|
-
kind,
|
|
89
|
-
imports,
|
|
90
|
-
classes,
|
|
91
|
-
functions,
|
|
92
|
-
variables,
|
|
93
|
-
exports,
|
|
94
|
-
mainExport,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return tree;
|
|
98
|
-
}
|
|
99
|
-
function safeType(fn) {
|
|
100
|
-
try {
|
|
101
|
-
return fn();
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
return "unknown";
|
|
105
|
-
}
|
|
106
|
-
}
|
package/dist/core/clipboard.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.copyToClipboard = copyToClipboard;
|
|
4
|
-
exports.readClipboard = readClipboard;
|
|
5
|
-
// src/core/clipboard.ts
|
|
6
|
-
const child_process_1 = require("child_process");
|
|
7
|
-
let memoryClipboard = "";
|
|
8
|
-
function copyToClipboard(text) {
|
|
9
|
-
return new Promise((resolve, reject) => {
|
|
10
|
-
let command = "xclip";
|
|
11
|
-
let args = ["-selection", "clipboard"];
|
|
12
|
-
if (process.platform === "darwin") {
|
|
13
|
-
command = "pbcopy";
|
|
14
|
-
args = [];
|
|
15
|
-
}
|
|
16
|
-
else if (process.platform === "win32") {
|
|
17
|
-
command = "clip";
|
|
18
|
-
args = [];
|
|
19
|
-
}
|
|
20
|
-
const child = (0, child_process_1.spawn)(command, args, {
|
|
21
|
-
stdio: ["pipe", "ignore", "ignore"]
|
|
22
|
-
});
|
|
23
|
-
let resolved = false;
|
|
24
|
-
child.on("error", (err) => {
|
|
25
|
-
memoryClipboard = text;
|
|
26
|
-
resolved = true;
|
|
27
|
-
resolve();
|
|
28
|
-
});
|
|
29
|
-
child.stdin.on("error", (err) => {
|
|
30
|
-
if (err.code === "EPIPE") {
|
|
31
|
-
resolved = true;
|
|
32
|
-
resolve();
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
memoryClipboard = text;
|
|
36
|
-
if (!resolved)
|
|
37
|
-
resolve();
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
child.stdin.write(text);
|
|
41
|
-
child.stdin.end();
|
|
42
|
-
child.on("close", () => {
|
|
43
|
-
if (!resolved)
|
|
44
|
-
resolve();
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function readClipboard() {
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
let command;
|
|
51
|
-
let args = [];
|
|
52
|
-
if (process.platform === "darwin") {
|
|
53
|
-
command = "pbpaste";
|
|
54
|
-
}
|
|
55
|
-
else if (process.platform === "win32") {
|
|
56
|
-
command = "powershell";
|
|
57
|
-
args = ["-Command", "Get-Clipboard"];
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
command = "xclip";
|
|
61
|
-
args = ["-selection", "clipboard", "-o"];
|
|
62
|
-
}
|
|
63
|
-
const child = (0, child_process_1.spawn)(command, args, {
|
|
64
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
65
|
-
});
|
|
66
|
-
let data = "";
|
|
67
|
-
let error = "";
|
|
68
|
-
let fallback = false;
|
|
69
|
-
child.stdout.on("data", chunk => {
|
|
70
|
-
data += chunk.toString();
|
|
71
|
-
});
|
|
72
|
-
child.stderr.on("data", chunk => {
|
|
73
|
-
error += chunk.toString();
|
|
74
|
-
});
|
|
75
|
-
child.on("error", () => {
|
|
76
|
-
fallback = true;
|
|
77
|
-
resolve(memoryClipboard);
|
|
78
|
-
});
|
|
79
|
-
child.on("close", code => {
|
|
80
|
-
if (code !== 0 || fallback) {
|
|
81
|
-
resolve(memoryClipboard);
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
resolve(data);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
package/dist/core/config.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadConfig = loadConfig;
|
|
7
|
-
// src/core/config.ts
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const fs_1 = require("fs");
|
|
10
|
-
const js_yaml_1 = require("js-yaml");
|
|
11
|
-
const CONFIG_FILENAME = "johankit.yaml";
|
|
12
|
-
const DEFAULT_IGNORE = [
|
|
13
|
-
".git",
|
|
14
|
-
"node_modules",
|
|
15
|
-
"dist",
|
|
16
|
-
"build",
|
|
17
|
-
"coverage",
|
|
18
|
-
"tmp",
|
|
19
|
-
"temp",
|
|
20
|
-
];
|
|
21
|
-
/**
|
|
22
|
-
* Tenta carregar as configurações do arquivo johankit.yaml na basePath.
|
|
23
|
-
* Retorna um objeto Config com defaults se o arquivo não for encontrado.
|
|
24
|
-
* @param basePath O diretório base para procurar o arquivo de configuração.
|
|
25
|
-
* @returns O objeto de configuração.
|
|
26
|
-
*/
|
|
27
|
-
function loadConfig(basePath) {
|
|
28
|
-
const configPath = path_1.default.join(basePath, CONFIG_FILENAME);
|
|
29
|
-
try {
|
|
30
|
-
const content = (0, fs_1.readFileSync)(configPath, "utf8");
|
|
31
|
-
const loadedConfig = (0, js_yaml_1.load)(content);
|
|
32
|
-
return {
|
|
33
|
-
ignore: [
|
|
34
|
-
...DEFAULT_IGNORE,
|
|
35
|
-
...(loadedConfig.ignore || []),
|
|
36
|
-
],
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
if (error instanceof Error && error.code === "ENOENT") {
|
|
41
|
-
// Arquivo não encontrado, retorna configuração padrão
|
|
42
|
-
return {
|
|
43
|
-
ignore: DEFAULT_IGNORE,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
console.warn(`[johankit] Aviso: Falha ao carregar ${CONFIG_FILENAME}. Usando defaults.`, error);
|
|
47
|
-
return {
|
|
48
|
-
ignore: DEFAULT_IGNORE,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
package/dist/core/scan.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.scanDir = scanDir;
|
|
7
|
-
// src/core/scan.ts
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
function scanDir(basePath, options = {}) {
|
|
11
|
-
const result = [];
|
|
12
|
-
const base = path_1.default.resolve(basePath);
|
|
13
|
-
const exts = options.extensions?.map(e => e.startsWith(".") ? e : `.${e}`);
|
|
14
|
-
// Default ignores
|
|
15
|
-
const ignoreSet = new Set([
|
|
16
|
-
"node_modules", ".git", "dist", "build", ".DS_Store", "coverage", ".env", "yarn.lock",
|
|
17
|
-
]);
|
|
18
|
-
// Read .gitignore if exists
|
|
19
|
-
const gitignorePath = path_1.default.join(base, ".gitignore");
|
|
20
|
-
if (fs_1.default.existsSync(gitignorePath)) {
|
|
21
|
-
try {
|
|
22
|
-
const lines = fs_1.default.readFileSync(gitignorePath, "utf8").split("\n");
|
|
23
|
-
for (const line of lines) {
|
|
24
|
-
const trimmed = line.trim();
|
|
25
|
-
if (trimmed && !trimmed.startsWith("#")) {
|
|
26
|
-
ignoreSet.add(trimmed.replace(/^\//, "").replace(/\/$/, ""));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
catch (e) {
|
|
31
|
-
// ignore read errors
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
function shouldIgnore(name) {
|
|
35
|
-
if (ignoreSet.has(name))
|
|
36
|
-
return true;
|
|
37
|
-
for (const pattern of ignoreSet) {
|
|
38
|
-
if (pattern.startsWith("*") && name.endsWith(pattern.slice(1)))
|
|
39
|
-
return true;
|
|
40
|
-
if (name.startsWith(pattern + "/"))
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
function loop(currentPath) {
|
|
46
|
-
const entries = fs_1.default.readdirSync(currentPath, { withFileTypes: true });
|
|
47
|
-
for (const entry of entries) {
|
|
48
|
-
if (shouldIgnore(entry.name))
|
|
49
|
-
continue;
|
|
50
|
-
const fullPath = path_1.default.join(currentPath, entry.name);
|
|
51
|
-
if (entry.isDirectory()) {
|
|
52
|
-
loop(fullPath);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
if (exts && !exts.includes(path_1.default.extname(entry.name)))
|
|
56
|
-
continue;
|
|
57
|
-
result.push({
|
|
58
|
-
path: path_1.default.relative(base, fullPath).replace(/\\/g, "/"),
|
|
59
|
-
content: fs_1.default.readFileSync(fullPath, "utf8"),
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
loop(base);
|
|
65
|
-
return result;
|
|
66
|
-
}
|
package/dist/core/schema.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validatePatches = validatePatches;
|
|
4
|
-
/**
|
|
5
|
-
* Valida se um objeto se parece com um Patch de DiffPatch válido.
|
|
6
|
-
* Não faz validação completa de esquema (JSON Schema), mas verifica a estrutura básica.
|
|
7
|
-
*/
|
|
8
|
-
function isValidPatch(patch) {
|
|
9
|
-
if (typeof patch !== "object" || patch === null)
|
|
10
|
-
return false;
|
|
11
|
-
if (typeof patch.path !== "string" || patch.path.length === 0)
|
|
12
|
-
return false;
|
|
13
|
-
const validTypes = ["modify", "create", "delete"];
|
|
14
|
-
if (!validTypes.includes(patch.type))
|
|
15
|
-
return false;
|
|
16
|
-
if (patch.type === "delete") {
|
|
17
|
-
return patch.content === undefined;
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
return typeof patch.content === "string";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Valida um array de patches de diff (DiffPatch[]).
|
|
25
|
-
* @param patches O array a ser validado.
|
|
26
|
-
* @returns O array de patches se for válido.
|
|
27
|
-
* @throws Um erro se a validação falhar.
|
|
28
|
-
*/
|
|
29
|
-
function validatePatches(patches) {
|
|
30
|
-
if (!Array.isArray(patches)) {
|
|
31
|
-
throw new Error("O patch deve ser um array JSON válido");
|
|
32
|
-
}
|
|
33
|
-
for (const [index, patch] of patches.entries()) {
|
|
34
|
-
if (!isValidPatch(patch)) {
|
|
35
|
-
throw new Error(`Patch inválido no índice ${index}: ${JSON.stringify(patch, null, 2)}.\nEsperado: { type: 'modify'|'create'|'delete', path: string, content?: string }`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// Assume que o array validado está no formato correto de DiffPatch[]
|
|
39
|
-
return patches;
|
|
40
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.JohankitService = void 0;
|
|
5
|
-
const JohankitService_1 = require("./services/JohankitService");
|
|
6
|
-
Object.defineProperty(exports, "JohankitService", { enumerable: true, get: function () { return JohankitService_1.JohankitService; } });
|
|
7
|
-
const [, , command, ...args] = process.argv;
|
|
8
|
-
const service = new JohankitService_1.JohankitService();
|
|
9
|
-
async function main() {
|
|
10
|
-
try {
|
|
11
|
-
switch (command) {
|
|
12
|
-
case "copy": {
|
|
13
|
-
const dir = args[0] ?? ".";
|
|
14
|
-
await service.copy(dir);
|
|
15
|
-
break;
|
|
16
|
-
}
|
|
17
|
-
case "paste": {
|
|
18
|
-
const dir = args[0] ?? ".";
|
|
19
|
-
await service.paste(dir);
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
case "prompt": {
|
|
23
|
-
const dir = args[0] ?? ".";
|
|
24
|
-
const diff = args.includes("--diff");
|
|
25
|
-
const userPrompt = args.filter(a => a !== "--diff").slice(1).join(" ");
|
|
26
|
-
await service.prompt(dir, userPrompt, diff);
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
case "sync": {
|
|
30
|
-
const dir = args[0] ?? ".";
|
|
31
|
-
await service.sync(dir);
|
|
32
|
-
break;
|
|
33
|
-
}
|
|
34
|
-
case "tree": {
|
|
35
|
-
const dir = args[0] ?? ".";
|
|
36
|
-
const output = await service.tree(dir);
|
|
37
|
-
console.log(output);
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
default:
|
|
41
|
-
showHelp();
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
if (error instanceof Error) {
|
|
47
|
-
console.error("Error:", error.message);
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
console.error("Unexpected error:", error);
|
|
51
|
-
}
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function showHelp() {
|
|
56
|
-
console.log(`
|
|
57
|
-
Usage:
|
|
58
|
-
johankit copy <dir>
|
|
59
|
-
johankit paste <dir>
|
|
60
|
-
johankit prompt <dir> "<user request>" [--diff]
|
|
61
|
-
johankit sync <dir>
|
|
62
|
-
johankit tree <dir>
|
|
63
|
-
|
|
64
|
-
Examples:
|
|
65
|
-
johankit copy src
|
|
66
|
-
johankit paste src
|
|
67
|
-
johankit prompt src "refactor to async/await"
|
|
68
|
-
johankit sync src
|
|
69
|
-
johankit tree src
|
|
70
|
-
`);
|
|
71
|
-
}
|
|
72
|
-
main();
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.JohankitService = void 0;
|
|
7
|
-
const createAsciiTree_1 = __importDefault(require("../utils/createAsciiTree"));
|
|
8
|
-
const copy_1 = require("../cli/commands/copy");
|
|
9
|
-
const paste_1 = require("../cli/commands/paste");
|
|
10
|
-
const prompt_1 = require("../cli/commands/prompt");
|
|
11
|
-
const tree_1 = require("../cli/commands/tree");
|
|
12
|
-
const scan_1 = require("../core/scan");
|
|
13
|
-
const diff_1 = require("../core/diff");
|
|
14
|
-
const validation_1 = require("../core/validation");
|
|
15
|
-
const write_1 = require("../core/write");
|
|
16
|
-
class JohankitService {
|
|
17
|
-
constructor(options = {}) {
|
|
18
|
-
this.isolated = options.isolated ?? false;
|
|
19
|
-
}
|
|
20
|
-
setInput(input) {
|
|
21
|
-
this.internalInput = input;
|
|
22
|
-
}
|
|
23
|
-
async copy(dir = ".") {
|
|
24
|
-
return (0, copy_1.copy)(dir);
|
|
25
|
-
}
|
|
26
|
-
async paste(dir = ".") {
|
|
27
|
-
return (0, paste_1.paste)(dir);
|
|
28
|
-
}
|
|
29
|
-
async prompt(dir, userPrompt, diff = false) {
|
|
30
|
-
if (!userPrompt) {
|
|
31
|
-
throw new Error("Missing user prompt");
|
|
32
|
-
}
|
|
33
|
-
return (0, prompt_1.prompt)(dir, userPrompt, diff);
|
|
34
|
-
}
|
|
35
|
-
async sync(dir = ".", diff = false) {
|
|
36
|
-
const snapshotBefore = (0, scan_1.scanDir)(dir);
|
|
37
|
-
const input = this.isolated ? this.internalInput : undefined;
|
|
38
|
-
if (!this.isolated && input === undefined) {
|
|
39
|
-
throw new Error("sync() without isolation must be used via CLI (stdin)");
|
|
40
|
-
}
|
|
41
|
-
if (!input) {
|
|
42
|
-
throw new Error("No input provided for isolated sync");
|
|
43
|
-
}
|
|
44
|
-
if (diff) {
|
|
45
|
-
const validated = (0, validation_1.validatePatches)(input);
|
|
46
|
-
(0, diff_1.applyDiff)(dir, validated);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
(0, write_1.writeFiles)(dir, input, true);
|
|
50
|
-
}
|
|
51
|
-
const snapshotAfter = (0, scan_1.scanDir)(dir);
|
|
52
|
-
return { before: snapshotBefore, after: snapshotAfter };
|
|
53
|
-
}
|
|
54
|
-
async tree(dir = ".") {
|
|
55
|
-
const _tree = await (0, tree_1.tree)(dir);
|
|
56
|
-
return (0, createAsciiTree_1.default)(_tree);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.JohankitService = JohankitService;
|