johankit 0.1.3 → 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 +38 -59
- package/dist/core/validation.js +7 -20
- package/dist/core/write.js +10 -9
- 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 +10 -14
- package/dist/{core → src/core}/git.js +1 -2
- 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 -5
- package/Readme.md +0 -56
- package/dist/cli/commands/copy.js +0 -29
- package/dist/cli/commands/paste.js +0 -49
- package/dist/cli/commands/prompt.js +0 -89
- package/dist/cli/commands/three.js +0 -106
- package/dist/cli/commands/tree.js +0 -107
- package/dist/core/clipboard.js +0 -89
- package/dist/core/config.js +0 -52
- package/dist/core/scan.js +0 -67
- package/dist/core/schema.js +0 -41
- 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/{types.js → dist/src/types.js} +0 -0
package/README.md
CHANGED
|
@@ -2,109 +2,77 @@
|
|
|
2
2
|
|
|
3
3
|
**JohanKit** is a developer-friendly CLI designed to supercharge your **vibe-coding** flow. It helps you capture, restore, and manipulate snapshots of your codebase, making it effortless to experiment, refactor, and collaborate—without locking you into a specific framework or workflow.
|
|
4
4
|
|
|
5
|
-
Think of it as your personal **code snapshot toolkit**: lightweight, fast, and agnostic.
|
|
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.
|
|
5
|
+
Think of it as your personal **code snapshot toolkit**: lightweight, fast, and platform-agnostic.
|
|
12
6
|
|
|
13
7
|
---
|
|
14
8
|
|
|
15
9
|
## Features
|
|
16
10
|
|
|
17
|
-
### copy
|
|
18
|
-
|
|
19
|
-
Take a snapshot of files in a directory and copy it to your clipboard as JSON.
|
|
20
|
-
|
|
11
|
+
### 📸 copy
|
|
12
|
+
Take a snapshot of files in a directory and copy it to your clipboard as a JSON array.
|
|
21
13
|
```bash
|
|
22
14
|
johankit copy <dir> [exts]
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
```
|
|
25
16
|
* `dir`: Directory to scan (default: current)
|
|
26
17
|
* `exts`: Comma-separated list of extensions (e.g., `ts,js`)
|
|
27
18
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
### paste
|
|
31
|
-
|
|
32
|
-
Restore files from a JSON snapshot stored in your clipboard.
|
|
33
|
-
|
|
19
|
+
### 📋 paste
|
|
20
|
+
Restore files or apply patches from a JSON snapshot stored in your clipboard.
|
|
34
21
|
```bash
|
|
35
|
-
johankit paste
|
|
22
|
+
johankit paste [dir] [--run] [--diff] [--dry-run]
|
|
36
23
|
```
|
|
24
|
+
* `--run`: Execute console commands included in the patch.
|
|
25
|
+
* `--diff`: Interactive mode. Shows a line-by-line diff and asks for confirmation before applying changes to each file.
|
|
26
|
+
* `--dry-run`: Preview changes without modifying any files.
|
|
27
|
+
* `-y`: Auto-accept all prompts.
|
|
37
28
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
### prompt
|
|
43
|
-
|
|
44
|
-
Generate a ready-to-use AI prompt including a snapshot of your codebase.
|
|
45
|
-
|
|
29
|
+
### 🤖 prompt
|
|
30
|
+
Generate a ready-to-use AI prompt containing your codebase snapshot and your instructions.
|
|
46
31
|
```bash
|
|
47
32
|
johankit prompt <dir> "<user request>"
|
|
48
33
|
```
|
|
34
|
+
* `dir`: Directory to include in the context.
|
|
35
|
+
* `<user request>`: Instructions for the AI to perform on the codebase.
|
|
49
36
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
### sync
|
|
56
|
-
|
|
57
|
-
Apply JSON patches to your codebase and update the clipboard with the new snapshot.
|
|
58
|
-
|
|
37
|
+
### 🔄 sync
|
|
38
|
+
Two-way synchronization: copies the current snapshot, waits for your AI-generated patch input via terminal (Ctrl+D to finish), applies it, and copies the updated snapshot back to the clipboard.
|
|
59
39
|
```bash
|
|
60
|
-
johankit sync
|
|
40
|
+
johankit sync [dir] [--run] [--dry-run]
|
|
61
41
|
```
|
|
62
42
|
|
|
63
|
-
* `dir`: Target directory (default: current)
|
|
64
|
-
|
|
65
43
|
---
|
|
66
44
|
|
|
67
45
|
## Example Workflow
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
johankit
|
|
72
|
-
|
|
73
|
-
# Ask AI to refactor your codebase
|
|
74
|
-
johankit prompt src "Convert all callbacks to async/await"
|
|
75
|
-
|
|
76
|
-
# Apply AI-suggested changes and update snapshot
|
|
77
|
-
johankit sync src
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
With just a few commands, JohanKit lets you **capture ideas, experiment safely, and sync changes instantly**.
|
|
47
|
+
1. **Prepare Context**: `johankit prompt src "Add input validation to all API routes"`
|
|
48
|
+
2. **Get AI Response**: Copy the JSON patch array generated by your favorite LLM.
|
|
49
|
+
3. **Review & Apply**: `johankit paste --diff`
|
|
81
50
|
|
|
82
51
|
---
|
|
83
52
|
|
|
84
53
|
## Configuration
|
|
85
54
|
|
|
86
|
-
|
|
55
|
+
Customize ignored patterns by creating a `johankit.yaml` or `johankit.yml` in your project root:
|
|
87
56
|
|
|
88
57
|
```yaml
|
|
89
58
|
ignore:
|
|
90
59
|
- dist
|
|
91
60
|
- node_modules
|
|
92
61
|
- .git
|
|
62
|
+
- custom-build-folder
|
|
93
63
|
```
|
|
94
64
|
|
|
95
|
-
|
|
65
|
+
JohanKit also automatically respects patterns found in your `.gitignore` file.
|
|
96
66
|
|
|
97
67
|
---
|
|
98
68
|
|
|
99
69
|
## Requirements
|
|
100
70
|
|
|
101
71
|
* Node.js >= 14
|
|
102
|
-
* Clipboard-compatible OS (`
|
|
103
|
-
|
|
104
|
-
---
|
|
72
|
+
* Clipboard-compatible OS (`pbcopy`, `xclip`, or Windows `clip`)
|
|
105
73
|
|
|
106
74
|
## Installation
|
|
107
75
|
|
|
108
76
|
```bash
|
|
109
77
|
npm install -g johankit
|
|
110
|
-
```
|
|
78
|
+
```
|
|
@@ -1,84 +1,63 @@
|
|
|
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
|
-
exports.sync =
|
|
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
|
}
|
|
81
|
-
exports.sync = sync;
|
|
82
61
|
function readStdin() {
|
|
83
62
|
return new Promise(resolve => {
|
|
84
63
|
let data = "";
|
package/dist/core/validation.js
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validatePatches =
|
|
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
|
}
|
|
24
|
-
exports.validatePatches = validatePatches;
|
package/dist/core/write.js
CHANGED
|
@@ -3,22 +3,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writeFiles =
|
|
6
|
+
exports.writeFiles = writeFiles;
|
|
7
7
|
// src/core/write.ts
|
|
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
|
}
|
|
24
|
-
exports.writeFiles = writeFiles;
|
|
@@ -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,120 @@
|
|
|
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
|
+
const patches = diff.diffLines(oldContent, newContent);
|
|
63
|
+
patches.forEach((part) => {
|
|
64
|
+
const color = part.added ? 'green' : part.removed ? 'red' : 'gray';
|
|
65
|
+
const prefix = part.added ? '+' : part.removed ? '-' : ' ';
|
|
66
|
+
const value = part.value.endsWith('\n') ? part.value : part.value + '\n';
|
|
67
|
+
process.stdout.write((value.split('\n').map((line) => line ? `${prefix}${line}` : '').join('\n'))[color]);
|
|
68
|
+
});
|
|
69
|
+
console.log('\n-----------------------');
|
|
70
|
+
}
|
|
71
|
+
async function paste(dir, runAll = false, dryRun = false, interactiveDiff = false) {
|
|
72
|
+
const autoAccept = process.argv.includes("-y");
|
|
73
|
+
try {
|
|
74
|
+
const content = await (0, clipboard_1.readClipboard)();
|
|
75
|
+
if (!content)
|
|
76
|
+
throw new Error("Clipboard empty");
|
|
77
|
+
const { cleaned } = (0, cleanCodeBlock_1.default)(content);
|
|
78
|
+
const items = (0, schema_1.validatePatches)(JSON.parse(cleaned));
|
|
79
|
+
if (dryRun)
|
|
80
|
+
process.stdout.write("--- DRY RUN MODE ---\n");
|
|
81
|
+
for (const item of items) {
|
|
82
|
+
if (item.type === 'console' && item.command) {
|
|
83
|
+
if (dryRun) {
|
|
84
|
+
process.stdout.write(`[DRY-RUN] Would execute: ${item.command}\n`);
|
|
85
|
+
}
|
|
86
|
+
else if (runAll) {
|
|
87
|
+
if (autoAccept || await confirm(`> Execute: ${item.command}`)) {
|
|
88
|
+
(0, child_process_1.execSync)(item.command, { stdio: 'inherit', cwd: dir });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (item.path) {
|
|
93
|
+
const fullPath = path_1.default.join(dir, item.path);
|
|
94
|
+
const exists = fs_1.default.existsSync(fullPath);
|
|
95
|
+
const oldContent = exists ? fs_1.default.readFileSync(fullPath, 'utf8') : "";
|
|
96
|
+
const newContent = item.content || "";
|
|
97
|
+
if (interactiveDiff && item.content !== null) {
|
|
98
|
+
showDiff(item.path, oldContent, newContent);
|
|
99
|
+
if (await confirm(`Apply changes to ${item.path}?`)) {
|
|
100
|
+
(0, diff_1.applyDiff)(dir, [item]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log(`Skipped: ${item.path}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (dryRun) {
|
|
107
|
+
process.stdout.write(`[DRY-RUN] Would ${item.content === null ? 'Delete' : 'Write'}: ${item.path}\n`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
(0, diff_1.applyDiff)(dir, [item]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
process.stdout.write("√ Operation completed\n");
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
process.stderr.write(`× Failed: ${error.message}\n`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -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
|
+
}
|