mkctx 1.0.2 → 2.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/LICENSE +21 -0
- package/README.md +242 -176
- package/bin/mkctx.js +462 -0
- package/favicon.svg +5 -0
- package/package.json +57 -49
- package/cleanup.js +0 -28
- package/install.js +0 -185
- package/main.go +0 -210
package/install.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { execSync } = require("child_process");
|
|
4
|
-
|
|
5
|
-
function install() {
|
|
6
|
-
const isWindows = process.platform === "win32";
|
|
7
|
-
const binaryName = isWindows ? "mkctx.exe" : "mkctx";
|
|
8
|
-
const sourceBinary = isWindows ? "mkctx.exe" : "mkctx";
|
|
9
|
-
const sourcePath = path.join(__dirname, sourceBinary);
|
|
10
|
-
|
|
11
|
-
// Rename the binary if necessary (from mkctx to mkctx.exe on Windows)
|
|
12
|
-
if (isWindows && fs.existsSync("mkctx") && !fs.existsSync("mkctx.exe")) {
|
|
13
|
-
fs.renameSync("mkctx", "mkctx.exe");
|
|
14
|
-
console.log("✅ Binary renamed for Windows: mkctx -> mkctx.exe");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Check if the binary exists
|
|
18
|
-
if (!fs.existsSync(sourcePath)) {
|
|
19
|
-
console.log("❌ Compiled binary not found at:", sourcePath);
|
|
20
|
-
console.log("📋 Files in directory:");
|
|
21
|
-
try {
|
|
22
|
-
const files = fs.readdirSync(__dirname);
|
|
23
|
-
files.forEach((file) => console.log(" -", file));
|
|
24
|
-
} catch (e) {
|
|
25
|
-
console.log(" Could not read directory");
|
|
26
|
-
}
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
// Method 1: Use npm to get the global bin directory
|
|
32
|
-
let npmGlobalBin;
|
|
33
|
-
try {
|
|
34
|
-
npmGlobalBin = execSync("npm bin -g").toString().trim();
|
|
35
|
-
} catch (error) {
|
|
36
|
-
// Alternative method to get global bin directory
|
|
37
|
-
npmGlobalBin = execSync("npm root -g").toString().trim();
|
|
38
|
-
npmGlobalBin = path.join(npmGlobalBin, ".bin");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const installPath = path.join(npmGlobalBin, binaryName);
|
|
42
|
-
|
|
43
|
-
console.log(`📦 Installing mkctx at: ${installPath}`);
|
|
44
|
-
|
|
45
|
-
// Ensure the directory exists
|
|
46
|
-
if (!fs.existsSync(npmGlobalBin)) {
|
|
47
|
-
fs.mkdirSync(npmGlobalBin, { recursive: true });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Copy the binary
|
|
51
|
-
fs.copyFileSync(sourcePath, installPath);
|
|
52
|
-
|
|
53
|
-
// Set execution permissions (Unix only)
|
|
54
|
-
if (!isWindows) {
|
|
55
|
-
fs.chmodSync(installPath, 0o755);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
console.log("✅ mkctx installed successfully via npm");
|
|
59
|
-
|
|
60
|
-
// Create a .cmd wrapper for Windows
|
|
61
|
-
if (isWindows) {
|
|
62
|
-
createWindowsWrapper(npmGlobalBin);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return;
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.log(
|
|
68
|
-
"⚠️ npm method failed, trying alternative method...",
|
|
69
|
-
error.message
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Alternative method: Search common PATH directories
|
|
74
|
-
const alternativePaths = getAlternativePaths();
|
|
75
|
-
|
|
76
|
-
for (const altPath of alternativePaths) {
|
|
77
|
-
try {
|
|
78
|
-
if (fs.existsSync(altPath)) {
|
|
79
|
-
const altInstallPath = path.join(altPath, binaryName);
|
|
80
|
-
console.log(`🔄 Trying to install at: ${altInstallPath}`);
|
|
81
|
-
|
|
82
|
-
fs.copyFileSync(sourcePath, altInstallPath);
|
|
83
|
-
|
|
84
|
-
// Set execution permissions (Unix only)
|
|
85
|
-
if (!isWindows) {
|
|
86
|
-
fs.chmodSync(altInstallPath, 0o755);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Create Windows wrapper if needed
|
|
90
|
-
if (isWindows) {
|
|
91
|
-
createWindowsWrapper(altPath);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
console.log(`✅ mkctx installed at: ${altInstallPath}`);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
} catch (e) {
|
|
98
|
-
console.log(` ❌ Installation failed at ${altPath}: ${e.message}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// If we get here, all methods failed
|
|
103
|
-
console.log("❌ Could not install automatically");
|
|
104
|
-
console.log("📋 Manual installation required:");
|
|
105
|
-
console.log(` 1. Copy the file '${sourcePath}' to a folder in your PATH`);
|
|
106
|
-
console.log(` 2. Make sure the file has execution permissions`);
|
|
107
|
-
|
|
108
|
-
// Show current PATH to help the user
|
|
109
|
-
console.log("\n📁 Your PATH includes these folders:");
|
|
110
|
-
const pathDirs = process.env.PATH
|
|
111
|
-
? process.env.PATH.split(path.delimiter)
|
|
112
|
-
: [];
|
|
113
|
-
pathDirs.forEach((dir) => console.log(" -", dir));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function createWindowsWrapper(installDir) {
|
|
117
|
-
const wrapperPath = path.join(installDir, "mkctx.cmd");
|
|
118
|
-
const wrapperContent = `@echo off
|
|
119
|
-
"${path.join(installDir, "mkctx.exe")}" %*
|
|
120
|
-
`;
|
|
121
|
-
fs.writeFileSync(wrapperPath, wrapperContent);
|
|
122
|
-
console.log(`✅ Created Windows wrapper: ${wrapperPath}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function getAlternativePaths() {
|
|
126
|
-
const paths = [];
|
|
127
|
-
const isWindows = process.platform === "win32";
|
|
128
|
-
|
|
129
|
-
if (isWindows) {
|
|
130
|
-
// Windows paths
|
|
131
|
-
if (process.env.APPDATA) {
|
|
132
|
-
paths.push(path.join(process.env.APPDATA, "npm"));
|
|
133
|
-
}
|
|
134
|
-
if (process.env.LOCALAPPDATA) {
|
|
135
|
-
paths.push(
|
|
136
|
-
path.join(process.env.LOCALAPPDATA, "Microsoft", "WindowsApps")
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
if (process.env.ProgramFiles) {
|
|
140
|
-
paths.push(path.join(process.env.ProgramFiles, "nodejs"));
|
|
141
|
-
}
|
|
142
|
-
// Common Node.js installation paths
|
|
143
|
-
paths.push("C:\\Program Files\\nodejs");
|
|
144
|
-
paths.push("C:\\Program Files (x86)\\nodejs");
|
|
145
|
-
|
|
146
|
-
// User's local bin
|
|
147
|
-
if (process.env.USERPROFILE) {
|
|
148
|
-
paths.push(
|
|
149
|
-
path.join(process.env.USERPROFILE, "AppData", "Roaming", "npm")
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
153
|
-
// Unix/Linux/macOS paths
|
|
154
|
-
paths.push("/usr/local/bin");
|
|
155
|
-
paths.push("/usr/bin");
|
|
156
|
-
paths.push("/opt/local/bin");
|
|
157
|
-
|
|
158
|
-
// User bin directory
|
|
159
|
-
if (process.env.HOME) {
|
|
160
|
-
paths.push(path.join(process.env.HOME, "bin"));
|
|
161
|
-
paths.push(path.join(process.env.HOME, ".local", "bin"));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Common directories on macOS
|
|
165
|
-
if (process.platform === "darwin") {
|
|
166
|
-
paths.push("/opt/homebrew/bin");
|
|
167
|
-
paths.push("/usr/local/opt/bin");
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return paths.filter((p) => p !== null && p !== undefined);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Handle uncaught errors
|
|
175
|
-
process.on("uncaughtException", (error) => {
|
|
176
|
-
console.log("❌ Installation failed:", error.message);
|
|
177
|
-
process.exit(1);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
process.on("unhandledRejection", (reason, promise) => {
|
|
181
|
-
console.log("❌ Unhandled rejection at:", promise, "reason:", reason);
|
|
182
|
-
process.exit(1);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
install();
|
package/main.go
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"fmt"
|
|
6
|
-
"os"
|
|
7
|
-
"path/filepath"
|
|
8
|
-
"strings"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
type Config struct {
|
|
12
|
-
Src string `json:"src"`
|
|
13
|
-
Ignore string `json:"ignore"`
|
|
14
|
-
Output string `json:"output"`
|
|
15
|
-
FirstComment string `json:"first_comment"`
|
|
16
|
-
LastComment string `json:"last_comment"`
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
func main() {
|
|
20
|
-
if len(os.Args) > 1 && os.Args[1] == "config" {
|
|
21
|
-
createConfig()
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
generateContext()
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
func createConfig() {
|
|
28
|
-
config := Config{
|
|
29
|
-
Src: "./src",
|
|
30
|
-
Ignore: "*.log, temp/, node_modules/, .git/",
|
|
31
|
-
Output: "./mkctx",
|
|
32
|
-
FirstComment: "/* Project Context */",
|
|
33
|
-
LastComment: "/* End of Context */",
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
configJSON, _ := json.MarshalIndent(config, "", " ")
|
|
37
|
-
|
|
38
|
-
// Create mkctx directory if it doesn't exist
|
|
39
|
-
_ = os.MkdirAll("mkctx", 0755)
|
|
40
|
-
|
|
41
|
-
// Write configuration file
|
|
42
|
-
_ = os.WriteFile("mkctx.config.json", configJSON, 0644)
|
|
43
|
-
|
|
44
|
-
// Update .gitignore
|
|
45
|
-
updateGitignore()
|
|
46
|
-
|
|
47
|
-
fmt.Println("✅ Configuration created:")
|
|
48
|
-
fmt.Println(" - mkctx.config.json")
|
|
49
|
-
fmt.Println(" - mkctx/ folder")
|
|
50
|
-
fmt.Println(" - Entry in .gitignore")
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
func updateGitignore() {
|
|
54
|
-
gitignorePath := ".gitignore"
|
|
55
|
-
content, err := os.ReadFile(gitignorePath)
|
|
56
|
-
gitignoreExists := err == nil
|
|
57
|
-
|
|
58
|
-
var newContent string
|
|
59
|
-
if gitignoreExists {
|
|
60
|
-
newContent = string(content)
|
|
61
|
-
if !strings.Contains(newContent, "mkctx/") {
|
|
62
|
-
newContent += "\n# mkctx - generated context\nmkctx/\n"
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
newContent = "# mkctx - generated context\nmkctx/\n"
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
_ = os.WriteFile(gitignorePath, []byte(newContent), 0644)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
func generateContext() {
|
|
72
|
-
config := loadConfig()
|
|
73
|
-
files := getFiles(config)
|
|
74
|
-
content := buildContent(files, config)
|
|
75
|
-
|
|
76
|
-
outputPath := config.Output
|
|
77
|
-
if outputPath == "" {
|
|
78
|
-
outputPath = "."
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Ensure output directory exists
|
|
82
|
-
_ = os.MkdirAll(outputPath, 0755)
|
|
83
|
-
|
|
84
|
-
outputFile := filepath.Join(outputPath, "context.md")
|
|
85
|
-
err := os.WriteFile(outputFile, []byte(content), 0644)
|
|
86
|
-
if err != nil {
|
|
87
|
-
fmt.Printf("❌ Error creating file: %v\n", err)
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
fmt.Printf("✅ Context generated at: %s\n", outputFile)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
func loadConfig() Config {
|
|
94
|
-
var config Config
|
|
95
|
-
file, err := os.ReadFile("mkctx.config.json")
|
|
96
|
-
if err != nil {
|
|
97
|
-
return getDefaultConfig()
|
|
98
|
-
}
|
|
99
|
-
json.Unmarshal(file, &config)
|
|
100
|
-
|
|
101
|
-
// Validate and complete configuration
|
|
102
|
-
if config.Src == "" {
|
|
103
|
-
config.Src = "."
|
|
104
|
-
}
|
|
105
|
-
if config.Output == "" {
|
|
106
|
-
config.Output = "."
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return config
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
func getDefaultConfig() Config {
|
|
113
|
-
return Config{
|
|
114
|
-
Src: ".",
|
|
115
|
-
Output: ".",
|
|
116
|
-
FirstComment: "/* Project Context */",
|
|
117
|
-
LastComment: "/* End of Context */",
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
func getFiles(config Config) []string {
|
|
122
|
-
var files []string
|
|
123
|
-
|
|
124
|
-
srcPath := config.Src
|
|
125
|
-
if srcPath == "" {
|
|
126
|
-
srcPath = "."
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error {
|
|
130
|
-
if err != nil || shouldIgnore(path, config) || info.IsDir() {
|
|
131
|
-
return nil
|
|
132
|
-
}
|
|
133
|
-
files = append(files, path)
|
|
134
|
-
return nil
|
|
135
|
-
})
|
|
136
|
-
return files
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
func shouldIgnore(path string, config Config) bool {
|
|
140
|
-
// Ignore system files
|
|
141
|
-
if strings.Contains(path, ".git") ||
|
|
142
|
-
strings.Contains(path, ".DS_Store") ||
|
|
143
|
-
strings.Contains(path, "Thumbs.db") {
|
|
144
|
-
return true
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Ignore based on configuration
|
|
148
|
-
if config.Ignore != "" {
|
|
149
|
-
ignorePatterns := strings.Split(config.Ignore, ",")
|
|
150
|
-
for _, pattern := range ignorePatterns {
|
|
151
|
-
pattern = strings.TrimSpace(pattern)
|
|
152
|
-
if pattern == "" {
|
|
153
|
-
continue
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Simple pattern with wildcard
|
|
157
|
-
if strings.Contains(pattern, "*") {
|
|
158
|
-
if matched, _ := filepath.Match(pattern, filepath.Base(path)); matched {
|
|
159
|
-
return true
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Entire directory
|
|
164
|
-
if strings.HasSuffix(pattern, "/") {
|
|
165
|
-
dir := strings.TrimSuffix(pattern, "/")
|
|
166
|
-
if strings.Contains(path, dir) {
|
|
167
|
-
return true
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Exact match
|
|
172
|
-
if strings.Contains(path, pattern) {
|
|
173
|
-
return true
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return false
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
func buildContent(files []string, config Config) string {
|
|
182
|
-
var content strings.Builder
|
|
183
|
-
|
|
184
|
-
if config.FirstComment != "" {
|
|
185
|
-
content.WriteString(config.FirstComment + "\n\n")
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
for _, file := range files {
|
|
189
|
-
fileContent, err := os.ReadFile(file)
|
|
190
|
-
if err != nil {
|
|
191
|
-
continue
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
ext := filepath.Ext(file)
|
|
195
|
-
lang := "text"
|
|
196
|
-
if ext != "" {
|
|
197
|
-
lang = ext[1:] // Remove the dot
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
content.WriteString("```" + lang + "\n")
|
|
201
|
-
content.WriteString("// " + file + "\n")
|
|
202
|
-
content.WriteString(string(fileContent))
|
|
203
|
-
content.WriteString("\n```\n\n")
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if config.LastComment != "" {
|
|
207
|
-
content.WriteString(config.LastComment)
|
|
208
|
-
}
|
|
209
|
-
return content.String()
|
|
210
|
-
}
|