johankit 0.1.5 → 1.0.0
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 +45 -62
- 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 +128 -0
- package/dist/src/cli/commands/prompt.js +54 -0
- package/dist/src/cli/commands/sync.js +166 -0
- package/dist/src/core/clipboard.js +64 -0
- package/dist/src/core/config.js +41 -0
- package/dist/{core → src/core}/diff.js +9 -12
- package/dist/src/core/scan.js +75 -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 +39 -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 +13 -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 +79 -31
- package/src/cli/commands/prompt.ts +24 -64
- package/src/cli/commands/sync.ts +112 -71
- package/src/core/clipboard.ts +46 -80
- package/src/core/config.ts +22 -32
- package/src/core/diff.ts +10 -21
- package/src/core/scan.ts +52 -43
- 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 +43 -77
- package/src/tests/cleanCodeBlock.test.ts +21 -0
- package/src/tests/scan.test.ts +33 -0
- package/src/tests/schema.test.ts +24 -0
- package/src/types.ts +4 -50
- package/src/utils/cleanCodeBlock.ts +12 -12
- 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
package/README.md
CHANGED
|
@@ -1,89 +1,81 @@
|
|
|
1
1
|
# JohanKit
|
|
2
2
|
|
|
3
|
-
**JohanKit** is a developer-friendly CLI
|
|
3
|
+
**JohanKit** is a developer-friendly CLI for capturing, restoring, and applying codebase snapshots — perfect for vibe-coding with AI.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Why JohanKit?
|
|
10
|
-
|
|
11
|
-
JohanKit is a “kit for developers,” crafted to streamline coding sessions, prototype features quickly, and integrate seamlessly with AI-assisted refactoring or review tools.
|
|
12
|
-
|
|
13
|
-
---
|
|
5
|
+
Lightweight, fast, platform-agnostic.
|
|
14
6
|
|
|
15
7
|
## Features
|
|
16
8
|
|
|
17
9
|
### copy
|
|
18
|
-
|
|
19
|
-
Take a snapshot of files in a directory and copy it to your clipboard as JSON.
|
|
10
|
+
Capture directory snapshot as JSON array to clipboard.
|
|
20
11
|
|
|
21
12
|
```bash
|
|
22
|
-
johankit copy
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* `dir`: Directory to scan (default: current)
|
|
26
|
-
* `exts`: Comma-separated list of extensions (e.g., `ts,js`)
|
|
13
|
+
johankit copy [dir] [exts]
|
|
14
|
+
```
|
|
27
15
|
|
|
28
|
-
|
|
16
|
+
**Example:**
|
|
17
|
+
```bash
|
|
18
|
+
johankit copy src ts,tsx,js,jsx
|
|
19
|
+
```
|
|
29
20
|
|
|
30
21
|
### paste
|
|
31
|
-
|
|
32
|
-
Restore files from a JSON snapshot stored in your clipboard.
|
|
22
|
+
Apply patches from JSON clipboard content.
|
|
33
23
|
|
|
34
24
|
```bash
|
|
35
|
-
johankit paste
|
|
25
|
+
johankit paste [dir] [--run] [--diff] [--dry-run] [-y]
|
|
36
26
|
```
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
**Examples:**
|
|
29
|
+
```bash
|
|
30
|
+
johankit paste src --dry-run # Preview only
|
|
31
|
+
johankit paste src --diff # Interactive diff review
|
|
32
|
+
johankit paste src --run -y # Auto-apply + run commands
|
|
33
|
+
```
|
|
41
34
|
|
|
42
35
|
### prompt
|
|
43
|
-
|
|
44
|
-
Generate a ready-to-use AI prompt including a snapshot of your codebase.
|
|
36
|
+
Generate AI-ready prompt with snapshot + your request.
|
|
45
37
|
|
|
46
38
|
```bash
|
|
47
|
-
johankit prompt
|
|
39
|
+
johankit prompt [dir] "<request>"
|
|
48
40
|
```
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
**Example:**
|
|
43
|
+
```bash
|
|
44
|
+
johankit prompt src "Add Zod validation to all API routes"
|
|
45
|
+
```
|
|
54
46
|
|
|
55
47
|
### sync
|
|
56
|
-
|
|
57
|
-
Apply JSON patches to your codebase and update the clipboard with the new snapshot.
|
|
48
|
+
Iterative AI workflow: snapshot → paste patch → new snapshot.
|
|
58
49
|
|
|
59
50
|
```bash
|
|
60
|
-
johankit sync
|
|
51
|
+
johankit sync [dir] [--run] [--diff] [--dry-run] [--watch] [--auto]
|
|
61
52
|
```
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
**Examples:**
|
|
55
|
+
```bash
|
|
56
|
+
johankit sync src --auto # Watch clipboard + auto-apply
|
|
57
|
+
johankit sync src --diff --run # Interactive + execute commands
|
|
58
|
+
```
|
|
66
59
|
|
|
67
|
-
##
|
|
60
|
+
## Quick Workflow Example
|
|
68
61
|
|
|
69
62
|
```bash
|
|
70
|
-
#
|
|
71
|
-
johankit
|
|
63
|
+
# 1. Generate prompt
|
|
64
|
+
johankit prompt src "Refactor auth middleware to use JWT"
|
|
72
65
|
|
|
73
|
-
#
|
|
74
|
-
johankit prompt src "Convert all callbacks to async/await"
|
|
66
|
+
# 2. Paste into LLM → copy JSON patch back to clipboard
|
|
75
67
|
|
|
76
|
-
# Apply
|
|
77
|
-
johankit
|
|
68
|
+
# 3. Apply with review
|
|
69
|
+
johankit paste src --diff
|
|
78
70
|
```
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
## Configuration
|
|
72
|
+
Or fast loop:
|
|
73
|
+
```bash
|
|
74
|
+
johankit sync src --auto
|
|
75
|
+
```
|
|
85
76
|
|
|
86
|
-
|
|
77
|
+
## Config
|
|
78
|
+
Create `johankit.yml` in project root:
|
|
87
79
|
|
|
88
80
|
```yaml
|
|
89
81
|
ignore:
|
|
@@ -92,19 +84,10 @@ ignore:
|
|
|
92
84
|
- .git
|
|
93
85
|
```
|
|
94
86
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
## Requirements
|
|
87
|
+
Also respects `.gitignore`.
|
|
100
88
|
|
|
101
|
-
|
|
102
|
-
* Clipboard-compatible OS (`xclip`, `pbcopy`, or `clip` on Windows)
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Installation
|
|
89
|
+
## Install
|
|
107
90
|
|
|
108
91
|
```bash
|
|
109
92
|
npm install -g johankit
|
|
110
|
-
```
|
|
93
|
+
```
|
|
@@ -1,80 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.sync = sync;
|
|
4
7
|
// src/cli/commands/sync.ts
|
|
5
8
|
const scan_1 = require("../../core/scan");
|
|
9
|
+
const schema_1 = require("../../core/schema");
|
|
6
10
|
const diff_1 = require("../../core/diff");
|
|
7
11
|
const clipboard_1 = require("../../core/clipboard");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
12
|
+
const child_process_1 = require("child_process");
|
|
13
|
+
const cleanCodeBlock_1 = __importDefault(require("../../utils/cleanCodeBlock"));
|
|
14
|
+
const readline_1 = __importDefault(require("readline"));
|
|
15
|
+
async function confirm(msg) {
|
|
16
|
+
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
17
|
+
return new Promise(resolve => {
|
|
18
|
+
rl.question(`${msg} (y/N): `, (ans) => {
|
|
19
|
+
rl.close();
|
|
20
|
+
resolve(ans.toLowerCase() === 'y');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async function sync(dir, runAll = false) {
|
|
25
|
+
const autoAccept = process.argv.includes("-y");
|
|
11
26
|
try {
|
|
12
27
|
const snapshotBefore = (0, scan_1.scanDir)(dir);
|
|
13
28
|
const template = `
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
You will receive a JSON array representing a snapshot of a codebase.
|
|
17
|
-
Each item has the following structure:
|
|
18
|
-
|
|
19
|
-
\`\`\`json
|
|
20
|
-
{
|
|
21
|
-
"path": "relative/path/to/file.ext",
|
|
22
|
-
"content": "full file content"
|
|
23
|
-
}
|
|
24
|
-
\`\`\`
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
SNAPSHOT
|
|
29
|
+
// ... (template mantido) ...
|
|
29
30
|
${JSON.stringify(snapshotBefore, null, 2)}
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
YOUR TASK
|
|
34
|
-
Propose changes according to the user request.
|
|
35
|
-
|
|
36
|
-
Return ONLY a JSON array of ${diff ? 'DiffPatch' : 'FileSnapshot'}.
|
|
37
|
-
|
|
38
|
-
PATCH FORMAT (STRICT)
|
|
39
|
-
{
|
|
40
|
-
\"path\": \"relative/path/to/file.ext\",
|
|
41
|
-
\"content\": \"FULL updated file content (omit for delete)\"
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
IMPORTANT RULES
|
|
45
|
-
- Do NOT return explanations
|
|
46
|
-
- Do NOT return markdown
|
|
47
|
-
- Return ONLY valid JSON
|
|
48
|
-
|
|
49
|
-
USER REQUEST
|
|
50
|
-
<Replace this with the user request>
|
|
51
31
|
`;
|
|
52
32
|
await (0, clipboard_1.copyToClipboard)(template.trim());
|
|
53
|
-
process.stdout.write("✔ Prompt with snapshot copied to clipboard
|
|
33
|
+
process.stdout.write("✔ Prompt with snapshot copied to clipboard. Paste the response here and press Enter (Ctrl+D to finish):\n");
|
|
54
34
|
const input = await readStdin();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
35
|
+
const { cleaned } = (0, cleanCodeBlock_1.default)(input);
|
|
36
|
+
const patches = (0, schema_1.validatePatches)(JSON.parse(cleaned));
|
|
37
|
+
for (const patch of patches) {
|
|
38
|
+
if (patch.type === 'console' && patch.command) {
|
|
39
|
+
if (runAll) {
|
|
40
|
+
const shouldRun = autoAccept || await confirm(`> Execute: ${patch.command}`);
|
|
41
|
+
if (shouldRun)
|
|
42
|
+
(0, child_process_1.execSync)(patch.command, { stdio: 'inherit', cwd: dir });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log(`> Skipped command: ${patch.command} (use --run)`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (patch.path) {
|
|
49
|
+
(0, diff_1.applyDiff)(dir, [patch]);
|
|
50
|
+
}
|
|
68
51
|
}
|
|
69
52
|
const snapshotAfter = (0, scan_1.scanDir)(dir);
|
|
70
53
|
await (0, clipboard_1.copyToClipboard)(JSON.stringify(snapshotAfter, null, 2));
|
|
71
54
|
process.stdout.write("✔ Sync applied and new snapshot copied to clipboard\n");
|
|
72
55
|
}
|
|
73
56
|
catch (error) {
|
|
74
|
-
process.stderr.write(
|
|
75
|
-
if (error instanceof Error) {
|
|
76
|
-
process.stderr.write(`${error.message}\n`);
|
|
77
|
-
}
|
|
57
|
+
process.stderr.write(`✖ Sync failed: ${error.message}\n`);
|
|
78
58
|
process.exit(1);
|
|
79
59
|
}
|
|
80
60
|
}
|
package/dist/core/validation.js
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validatePatches = validatePatches;
|
|
4
|
+
// src/core/validation.ts
|
|
5
|
+
const schema_1 = require("./schema");
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use validatePatches from core/schema instead.
|
|
8
|
+
*/
|
|
4
9
|
function validatePatches(json) {
|
|
5
|
-
|
|
6
|
-
throw new Error("Validation Error: Input is not a JSON array.");
|
|
7
|
-
}
|
|
8
|
-
return json.map((item, index) => {
|
|
9
|
-
if (typeof item !== "object" || item === null) {
|
|
10
|
-
throw new Error(`Validation Error: Item at index ${index} is not an object.`);
|
|
11
|
-
}
|
|
12
|
-
if (!["modify", "create", "delete"].includes(item.type)) {
|
|
13
|
-
throw new Error(`Validation Error: Invalid type '${item.type}' at index ${index}.`);
|
|
14
|
-
}
|
|
15
|
-
if (typeof item.path !== "string" || !item.path.trim()) {
|
|
16
|
-
throw new Error(`Validation Error: Invalid or missing path at index ${index}.`);
|
|
17
|
-
}
|
|
18
|
-
if (item.type !== "delete" && typeof item.content !== "string") {
|
|
19
|
-
throw new Error(`Validation Error: Missing content for '${item.type}' at index ${index}.`);
|
|
20
|
-
}
|
|
21
|
-
return item;
|
|
22
|
-
});
|
|
10
|
+
return (0, schema_1.validatePatches)(json);
|
|
23
11
|
}
|
package/dist/core/write.js
CHANGED
|
@@ -8,16 +8,18 @@ exports.writeFiles = writeFiles;
|
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const git_1 = require("./git");
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use applyDiff from core/diff for more flexibility (supports deletes and console commands).
|
|
13
|
+
*/
|
|
11
14
|
function writeFiles(basePath, files, commit = true) {
|
|
12
|
-
if (commit) {
|
|
13
|
-
(0, git_1.ensureGitCommit)("johankit: before
|
|
15
|
+
if (commit && files.length > 0) {
|
|
16
|
+
(0, git_1.ensureGitCommit)("johankit: before write");
|
|
14
17
|
}
|
|
15
18
|
for (const file of files) {
|
|
19
|
+
if (!file.path)
|
|
20
|
+
continue;
|
|
16
21
|
const fullPath = path_1.default.join(basePath, file.path);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
20
|
-
}
|
|
21
|
-
fs_1.default.writeFileSync(fullPath, file.content, "utf8");
|
|
22
|
+
fs_1.default.mkdirSync(path_1.default.dirname(fullPath), { recursive: true });
|
|
23
|
+
fs_1.default.writeFileSync(fullPath, file.content || "", "utf8");
|
|
22
24
|
}
|
|
23
25
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.copy = copy;
|
|
4
|
+
const scan_1 = require("../../core/scan");
|
|
5
|
+
const clipboard_1 = require("../../core/clipboard");
|
|
6
|
+
async function copy(dir, extensions) {
|
|
7
|
+
const snapshot = (0, scan_1.scanDir)(dir, { extensions });
|
|
8
|
+
const clipboardJSON = JSON.stringify(snapshot);
|
|
9
|
+
await (0, clipboard_1.copyToClipboard)(clipboardJSON);
|
|
10
|
+
process.stdout.write(`✔ Snapshot de ${dir} copiado (${(clipboardJSON.length / 1024).toFixed(2)} KB)\n`);
|
|
11
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.paste = paste;
|
|
40
|
+
// src/cli/commands/paste.ts
|
|
41
|
+
const diff_1 = require("../../core/diff");
|
|
42
|
+
const clipboard_1 = require("../../core/clipboard");
|
|
43
|
+
const schema_1 = require("../../core/schema");
|
|
44
|
+
const cleanCodeBlock_1 = __importDefault(require("../../utils/cleanCodeBlock"));
|
|
45
|
+
const child_process_1 = require("child_process");
|
|
46
|
+
const readline_1 = __importDefault(require("readline"));
|
|
47
|
+
const fs_1 = __importDefault(require("fs"));
|
|
48
|
+
const path_1 = __importDefault(require("path"));
|
|
49
|
+
const diff = __importStar(require("diff"));
|
|
50
|
+
require("colors");
|
|
51
|
+
async function confirm(msg) {
|
|
52
|
+
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
53
|
+
return new Promise(resolve => {
|
|
54
|
+
rl.question(`${msg} (y/N): `, (ans) => {
|
|
55
|
+
rl.close();
|
|
56
|
+
resolve(ans.toLowerCase() === 'y');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function showDiff(filename, oldContent, newContent) {
|
|
61
|
+
console.log(`\n--- DIFF FOR: ${filename.bold} ---`);
|
|
62
|
+
// Otimização: Usar diffLines apenas se o conteúdo for diferente para evitar processamento inútil
|
|
63
|
+
if (oldContent === newContent) {
|
|
64
|
+
console.log("No changes detected.".gray);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const patches = diff.diffLines(oldContent, newContent);
|
|
68
|
+
patches.forEach((part) => {
|
|
69
|
+
const color = part.added ? 'green' : part.removed ? 'red' : 'gray';
|
|
70
|
+
const prefix = part.added ? '+' : part.removed ? '-' : ' ';
|
|
71
|
+
const value = part.value.endsWith('\n') ? part.value : part.value + '\n';
|
|
72
|
+
process.stdout.write((value.split('\n').map(line => line ? `${prefix}${line}` : '').join('\n'))[color]);
|
|
73
|
+
});
|
|
74
|
+
console.log('\n-----------------------');
|
|
75
|
+
}
|
|
76
|
+
async function paste(dir, runAll = false, dryRun = false, interactiveDiff = false) {
|
|
77
|
+
const autoAccept = process.argv.includes("-y");
|
|
78
|
+
try {
|
|
79
|
+
const content = await (0, clipboard_1.readClipboard)();
|
|
80
|
+
if (!content)
|
|
81
|
+
throw new Error("Clipboard empty");
|
|
82
|
+
const { cleaned } = (0, cleanCodeBlock_1.default)(content);
|
|
83
|
+
const items = (0, schema_1.validatePatches)(JSON.parse(cleaned));
|
|
84
|
+
if (dryRun)
|
|
85
|
+
process.stdout.write("--- DRY RUN MODE ---\n");
|
|
86
|
+
// Otimização: Agrupar patches de arquivos para aplicar de uma vez se não for interativo
|
|
87
|
+
const filePatches = [];
|
|
88
|
+
for (const item of items) {
|
|
89
|
+
if (item.type === 'console' && item.command) {
|
|
90
|
+
if (dryRun) {
|
|
91
|
+
process.stdout.write(`[DRY-RUN] Would execute: ${item.command}\n`);
|
|
92
|
+
}
|
|
93
|
+
else if (runAll) {
|
|
94
|
+
if (autoAccept || await confirm(`> Execute: ${item.command}`)) {
|
|
95
|
+
(0, child_process_1.execSync)(item.command, { stdio: 'inherit', cwd: dir });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (item.path) {
|
|
100
|
+
if (interactiveDiff && item.content !== null) {
|
|
101
|
+
const fullPath = path_1.default.join(dir, item.path);
|
|
102
|
+
const oldContent = fs_1.default.existsSync(fullPath) ? fs_1.default.readFileSync(fullPath, 'utf8') : "";
|
|
103
|
+
showDiff(item.path, oldContent, item.content || "");
|
|
104
|
+
if (await confirm(`Apply changes to ${item.path}?`)) {
|
|
105
|
+
(0, diff_1.applyDiff)(dir, [item]);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.log(`Skipped: ${item.path}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (dryRun) {
|
|
112
|
+
process.stdout.write(`[DRY-RUN] Would ${item.content === null ? 'Delete' : 'Write'}: ${item.path}\n`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
filePatches.push(item);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (filePatches.length > 0) {
|
|
120
|
+
(0, diff_1.applyDiff)(dir, filePatches);
|
|
121
|
+
}
|
|
122
|
+
process.stdout.write("✔ Operation completed\n");
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
process.stderr.write(`✘ Failed: ${error.message}\n`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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) {
|
|
8
|
+
const snapshot = (0, scan_1.scanDir)(dir);
|
|
9
|
+
const template = `
|
|
10
|
+
You are an AI software engineer.
|
|
11
|
+
Your goal is to help the user with their codebase using a specific JSON patch format.
|
|
12
|
+
|
|
13
|
+
Maintain 100% of previous functionality for full compatibility.
|
|
14
|
+
Always submit the complete code; never use comments.
|
|
15
|
+
Use "git add {files} && git commit -m {message}" after each change via the console.
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### CAPABILITIES
|
|
19
|
+
1. **File Updates**: You can create, update, or delete files.
|
|
20
|
+
2. **Console Commands**: You can execute shell commands (e.g., npm install, mkdir, rm, vitest).
|
|
21
|
+
|
|
22
|
+
### RESPONSE FORMAT
|
|
23
|
+
Return ONLY a JSON array. No conversational text. No explanations.
|
|
24
|
+
Wrap the JSON in a markdown code block: \`\`\`json [your_array] \`\`\`
|
|
25
|
+
|
|
26
|
+
### PATCH TYPES
|
|
27
|
+
- **File Patch**: { "path": "src/file.ts", "content": "full code" }
|
|
28
|
+
- **Delete File**: { "path": "src/old-file.ts", "content": null }
|
|
29
|
+
- **Console**: { "type": "console", "command": "npm install lodash" }
|
|
30
|
+
|
|
31
|
+
### STRATEGY
|
|
32
|
+
If the user request requires a new library, include the "npm install" command in the array before the file updates.
|
|
33
|
+
If the user wants to refactor and ensure it works, you can include a command to run tests.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
SNAPSHOT
|
|
38
|
+
${JSON.stringify(snapshot, null, 2)}
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
USER REQUEST
|
|
43
|
+
${userPrompt}
|
|
44
|
+
`;
|
|
45
|
+
try {
|
|
46
|
+
await (0, clipboard_1.copyToClipboard)(template.trim());
|
|
47
|
+
process.stdout.write(template.trim());
|
|
48
|
+
process.stdout.write("\n\n✔ Prompt + Snapshot copied to clipboard\n");
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
process.stdout.write(template.trim());
|
|
52
|
+
process.stderr.write("\n✖ Failed to copy to clipboard (output only)\n");
|
|
53
|
+
}
|
|
54
|
+
}
|