crack-code 0.1.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 +15 -0
- package/bun.lock +79 -0
- package/package.json +26 -0
- package/src/agent.ts +104 -0
- package/src/config.ts +410 -0
- package/src/index.ts +329 -0
- package/src/logo/crack-code.ts +13 -0
- package/src/permissions/index.ts +127 -0
- package/src/providers/anthropic.ts +22 -0
- package/src/providers/google.ts +26 -0
- package/src/providers/ollama.ts +33 -0
- package/src/providers/openai.ts +25 -0
- package/src/providers/types.ts +4 -0
- package/src/providers.ts +39 -0
- package/src/repl.ts +284 -0
- package/src/tools/file-read.ts +77 -0
- package/src/tools/file-write.ts +42 -0
- package/src/tools/glob.ts +84 -0
- package/src/tools/registry.ts +63 -0
- package/src/tools/shell.ts +70 -0
- package/src/ui/renderer.ts +208 -0
- package/tsconfig.json +29 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const C = {
|
|
2
|
+
reset: "\x1b[0m",
|
|
3
|
+
bold: "\x1b[1m",
|
|
4
|
+
dim: "\x1b[2m",
|
|
5
|
+
italic: "\x1b[3m",
|
|
6
|
+
under: "\x1b[4m",
|
|
7
|
+
|
|
8
|
+
red: "\x1b[31m",
|
|
9
|
+
green: "\x1b[32m",
|
|
10
|
+
yellow: "\x1b[33m",
|
|
11
|
+
blue: "\x1b[34m",
|
|
12
|
+
magenta: "\x1b[35m",
|
|
13
|
+
cyan: "\x1b[36m",
|
|
14
|
+
white: "\x1b[37m",
|
|
15
|
+
gray: "\x1b[90m",
|
|
16
|
+
|
|
17
|
+
bgRed: "\x1b[41m",
|
|
18
|
+
bgYellow: "\x1b[43m",
|
|
19
|
+
bgCyan: "\x1b[46m",
|
|
20
|
+
bgGray: "\x1b[100m",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
type Severity = "CRITICAL" | "HIGH" | "MEDIUM" | "LOW" | "INFO";
|
|
24
|
+
|
|
25
|
+
const SEVERITY_STYLE: Record<Severity, { badge: string; color: string }> = {
|
|
26
|
+
CRITICAL: {
|
|
27
|
+
badge: `${C.bold}${C.bgRed}${C.white} CRITICAL ${C.reset}`,
|
|
28
|
+
color: C.red,
|
|
29
|
+
},
|
|
30
|
+
HIGH: {
|
|
31
|
+
badge: `${C.bold}${C.bgYellow}${C.white} HIGH ${C.reset}`,
|
|
32
|
+
color: C.yellow,
|
|
33
|
+
},
|
|
34
|
+
MEDIUM: {
|
|
35
|
+
badge: `${C.bold}${C.bgCyan}${C.white} MEDIUM ${C.reset}`,
|
|
36
|
+
color: C.cyan,
|
|
37
|
+
},
|
|
38
|
+
LOW: {
|
|
39
|
+
badge: `${C.bold}${C.bgGray}${C.white} LOW ${C.reset}`,
|
|
40
|
+
color: C.gray,
|
|
41
|
+
},
|
|
42
|
+
INFO: { badge: `${C.dim} INFO ${C.reset}`, color: C.gray },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// --- Core Output ---
|
|
46
|
+
|
|
47
|
+
export function streamText(chunk: string): void {
|
|
48
|
+
process.stdout.write(chunk);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function newline(): void {
|
|
52
|
+
process.stdout.write("\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function clearLine(): void {
|
|
56
|
+
process.stdout.write("\r\x1b[K");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// --- Tool Calls ---
|
|
60
|
+
|
|
61
|
+
export function toolStart(name: string, args?: unknown): void {
|
|
62
|
+
const summary = args ? truncate(formatArgs(name, args), 100) : "";
|
|
63
|
+
process.stdout.write(
|
|
64
|
+
`\n${C.gray}╭─ ${C.cyan}${C.bold}${name}${C.reset}${summary ? ` ${C.gray}${summary}` : ""}${C.reset}\n`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function toolEnd(name: string, result: string): void {
|
|
69
|
+
const lines = result.split("\n");
|
|
70
|
+
const maxPreview = 6;
|
|
71
|
+
const preview = lines.slice(0, maxPreview);
|
|
72
|
+
|
|
73
|
+
for (const line of preview) {
|
|
74
|
+
process.stdout.write(`${C.gray}│${C.reset} ${line}\n`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (lines.length > maxPreview) {
|
|
78
|
+
process.stdout.write(
|
|
79
|
+
`${C.gray}│ ... ${lines.length - maxPreview} more lines${C.reset}\n`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.stdout.write(`${C.gray}╰─ done${C.reset}\n\n`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function toolBlocked(name: string, reason: string): void {
|
|
87
|
+
process.stdout.write(`\n${C.gray}╭─ ${C.red}${name}${C.reset}\n`);
|
|
88
|
+
process.stdout.write(`${C.gray}│${C.reset} ${C.red}⛔ ${reason}${C.reset}\n`);
|
|
89
|
+
process.stdout.write(`${C.gray}╰─${C.reset}\n\n`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- Severity ---
|
|
93
|
+
|
|
94
|
+
export function severity(level: string): void {
|
|
95
|
+
const key = level.toUpperCase() as Severity;
|
|
96
|
+
const style = SEVERITY_STYLE[key];
|
|
97
|
+
if (style) {
|
|
98
|
+
process.stdout.write(`${style.badge} `);
|
|
99
|
+
} else {
|
|
100
|
+
process.stdout.write(`${C.dim}[${level}]${C.reset} `);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// --- Spinner ---
|
|
105
|
+
|
|
106
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
107
|
+
|
|
108
|
+
export interface SpinnerHandle {
|
|
109
|
+
update: (text: string) => void;
|
|
110
|
+
stop: () => void;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function spinner(text: string): SpinnerHandle {
|
|
114
|
+
let i = 0;
|
|
115
|
+
let current = text;
|
|
116
|
+
|
|
117
|
+
const id = setInterval(() => {
|
|
118
|
+
const frame = SPINNER_FRAMES[i++ % SPINNER_FRAMES.length];
|
|
119
|
+
process.stdout.write(
|
|
120
|
+
`\r\x1b[K${C.cyan}${frame}${C.reset} ${C.gray}${current}${C.reset}`,
|
|
121
|
+
);
|
|
122
|
+
}, 80);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
update(newText: string) {
|
|
126
|
+
current = newText;
|
|
127
|
+
},
|
|
128
|
+
stop() {
|
|
129
|
+
clearInterval(id);
|
|
130
|
+
process.stdout.write("\r\x1b[K");
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- Prompts ---
|
|
136
|
+
|
|
137
|
+
export function userPrompt(): void {
|
|
138
|
+
process.stdout.write(`\n${C.bold}${C.blue}❯${C.reset} `);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function permissionPrompt(name: string, summary: string): void {
|
|
142
|
+
process.stdout.write(
|
|
143
|
+
`\n${C.yellow}⚠ Allow ${C.bold}${name}${C.reset}${C.yellow}?${C.reset}\n`,
|
|
144
|
+
);
|
|
145
|
+
process.stdout.write(`${C.gray} ${summary}${C.reset}\n`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- Status ---
|
|
149
|
+
|
|
150
|
+
export function info(msg: string): void {
|
|
151
|
+
console.log(`${C.gray}${msg}${C.reset}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function success(msg: string): void {
|
|
155
|
+
console.log(`${C.green}✓ ${msg}${C.reset}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function warn(msg: string): void {
|
|
159
|
+
console.log(`${C.yellow}⚠ ${msg}${C.reset}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function error(msg: string): void {
|
|
163
|
+
console.error(`${C.red}✗ ${msg}${C.reset}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function dim(msg: string): void {
|
|
167
|
+
console.log(`${C.gray}${msg}${C.reset}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// --- Banner ---
|
|
171
|
+
|
|
172
|
+
export function banner(model: string, mode: string): void {
|
|
173
|
+
console.log();
|
|
174
|
+
console.log(`${C.bold}${C.cyan}Crack Code${C.reset}`);
|
|
175
|
+
console.log(`${C.gray} Model: ${C.white}${model}${C.reset}`);
|
|
176
|
+
console.log(
|
|
177
|
+
`${C.gray} Mode: ${mode === "read-only" ? `${C.green}read-only` : `${C.yellow}edits enabled`}${C.reset}`,
|
|
178
|
+
);
|
|
179
|
+
console.log(
|
|
180
|
+
`${C.gray} Type ${C.white}/help${C.gray} for commands, ${C.white}/exit${C.gray} to quit${C.reset}`,
|
|
181
|
+
);
|
|
182
|
+
console.log();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// --- Helpers ---
|
|
186
|
+
|
|
187
|
+
function truncate(s: string, max: number): string {
|
|
188
|
+
return s.length > max ? s.slice(0, max) + "…" : s;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function formatArgs(toolName: string, args: unknown): string {
|
|
192
|
+
if (typeof args !== "object" || args === null) return "";
|
|
193
|
+
|
|
194
|
+
const a = args as Record<string, unknown>;
|
|
195
|
+
|
|
196
|
+
switch (toolName) {
|
|
197
|
+
case "read_file":
|
|
198
|
+
return String(a.path ?? "");
|
|
199
|
+
case "write_file":
|
|
200
|
+
return String(a.path ?? "");
|
|
201
|
+
case "run_command":
|
|
202
|
+
return `$ ${String(a.command ?? "")}`;
|
|
203
|
+
case "list_files":
|
|
204
|
+
return String(a.pattern ?? "");
|
|
205
|
+
default:
|
|
206
|
+
return truncate(JSON.stringify(args), 100);
|
|
207
|
+
}
|
|
208
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|