@zhanngning/hecode 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 ADDED
@@ -0,0 +1,125 @@
1
+ # Hecode
2
+
3
+ Your AI Coding Assistant CLI.
4
+
5
+ ## Features
6
+
7
+ - **Multi-Model Support**: OpenAI, Anthropic, MiMo, Ollama, and any OpenAI-compatible API
8
+ - **Tool System**: File read/write/edit, bash execution, glob/grep search
9
+ - **Skill System**: Loadable domain skills (coding, data analysis, finance, etc.)
10
+ - **Memory System**: Session, project, and global memory with search
11
+ - **Interactive REPL**: Streaming output, slash commands, tool status display
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install -g hecode
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Interactive mode
23
+ hecode
24
+
25
+ # Single-shot mode
26
+ hecode "fix the bug in src/app.ts"
27
+
28
+ # Use a specific model
29
+ hecode --model claude:sonnet "explain this code"
30
+
31
+ # Use a specific skill
32
+ hecode --skill coding "implement a sorting algorithm"
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ Edit `~/.hecode/config.json`:
38
+
39
+ ```json
40
+ {
41
+ "defaultModel": "openai:gpt-4o",
42
+ "models": {
43
+ "openai": { "apiKey": "sk-...", "baseUrl": "https://api.openai.com/v1" },
44
+ "claude": { "apiKey": "sk-ant-..." },
45
+ "mimo": { "apiKey": "...", "baseUrl": "https://api.mimo.xiaomi.com" },
46
+ "ollama": { "baseUrl": "http://localhost:11434" }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Supported Models
52
+
53
+ | Provider | Models | Config Key |
54
+ |----------|--------|------------|
55
+ | OpenAI | GPT-4o, GPT-4.1, o3, o4-mini | `openai` |
56
+ | Anthropic | Claude Sonnet 4, Claude Opus 4 | `claude` / `anthropic` |
57
+ | MiMo | MiMo series | `mimo` |
58
+ | Ollama | Llama, Qwen, DeepSeek, etc. | `ollama` |
59
+ | OpenAI Compatible | Any compatible API | `openai` + custom `baseUrl` |
60
+
61
+ ## Built-in Tools
62
+
63
+ | Tool | Description |
64
+ |------|-------------|
65
+ | `read_file` | Read file content with offset/limit |
66
+ | `write_file` | Write/create files |
67
+ | `edit_file` | Precise string replacement |
68
+ | `bash` | Execute shell commands |
69
+ | `glob` | File pattern matching |
70
+ | `grep` | Content regex search |
71
+
72
+ ## REPL Commands
73
+
74
+ | Command | Description |
75
+ |---------|-------------|
76
+ | `/help` | Show help |
77
+ | `/clear` | Clear conversation |
78
+ | `/history` | Show message count |
79
+ | `/save` | Save session |
80
+ | `/session` | Show session ID |
81
+ | `/exit` | Exit Hecode |
82
+
83
+ ## Skill System
84
+
85
+ Create custom skills in `skills/<name>/SKILL.md`:
86
+
87
+ ```markdown
88
+ # My Skill
89
+
90
+ trigger: keyword1, keyword2
91
+
92
+ Instructions for this skill...
93
+ ```
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ git clone <repo-url>
99
+ cd hecode
100
+ npm install
101
+ npm run dev # Run in dev mode
102
+ npm test # Run tests
103
+ npm run build # Build for production
104
+ npm run lint # Type check
105
+ ```
106
+
107
+ ## Project Structure
108
+
109
+ ```
110
+ hecode/
111
+ ├── src/
112
+ │ ├── core/ # Core engine (orchestrator, types)
113
+ │ ├── tools/ # Built-in tools
114
+ │ ├── models/ # Multi-model providers
115
+ │ ├── memory/ # Session/project/global memory
116
+ │ ├── skills/ # Skill loader
117
+ │ └── cli/ # CLI entry, REPL, commands
118
+ ├── skills/ # Built-in skill definitions
119
+ ├── tests/ # Unit tests
120
+ └── dist/ # Build output
121
+ ```
122
+
123
+ ## License
124
+
125
+ MIT
@@ -0,0 +1,365 @@
1
+ // src/tools/read_file.ts
2
+ import { readFile } from "fs/promises";
3
+ var readFileTool = {
4
+ name: "read_file",
5
+ description: "Read file content. Supports offset and limit for large files.",
6
+ parameters: {
7
+ type: "object",
8
+ properties: {
9
+ file_path: { type: "string", description: "Absolute path to the file" },
10
+ offset: { type: "number", description: "Line number to start from (1-indexed)" },
11
+ limit: { type: "number", description: "Max lines to read (default 2000)" }
12
+ },
13
+ required: ["file_path"]
14
+ },
15
+ async execute(params) {
16
+ try {
17
+ const content = await readFile(params.file_path, "utf-8");
18
+ const lines = content.split("\n");
19
+ const offset = params.offset || 1;
20
+ const limit = params.limit || 2e3;
21
+ const sliced = lines.slice(offset - 1, offset - 1 + limit);
22
+ const numbered = sliced.map((line, i) => `${offset + i}: ${line}`).join("\n");
23
+ return { output: numbered };
24
+ } catch (e) {
25
+ return { output: "", error: e.message };
26
+ }
27
+ }
28
+ };
29
+
30
+ // src/tools/write_file.ts
31
+ import { writeFile, mkdir } from "fs/promises";
32
+ import { dirname } from "path";
33
+ var writeFileTool = {
34
+ name: "write_file",
35
+ description: "Write content to a file. Creates parent directories if needed.",
36
+ parameters: {
37
+ type: "object",
38
+ properties: {
39
+ file_path: { type: "string", description: "Absolute path to the file" },
40
+ content: { type: "string", description: "Content to write" }
41
+ },
42
+ required: ["file_path", "content"]
43
+ },
44
+ async execute(params) {
45
+ try {
46
+ await mkdir(dirname(params.file_path), { recursive: true });
47
+ await writeFile(params.file_path, params.content, "utf-8");
48
+ return { output: `File written: ${params.file_path}` };
49
+ } catch (e) {
50
+ return { output: "", error: e.message };
51
+ }
52
+ }
53
+ };
54
+
55
+ // src/tools/edit_file.ts
56
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
57
+ var editFileTool = {
58
+ name: "edit_file",
59
+ description: "Replace exact string match in a file. Fails if old_string not found or matches multiple times.",
60
+ parameters: {
61
+ type: "object",
62
+ properties: {
63
+ file_path: { type: "string", description: "Absolute path to the file" },
64
+ old_string: { type: "string", description: "Exact string to replace" },
65
+ new_string: { type: "string", description: "Replacement string" },
66
+ replace_all: { type: "boolean", description: "Replace all occurrences (default false)" }
67
+ },
68
+ required: ["file_path", "old_string", "new_string"]
69
+ },
70
+ async execute(params) {
71
+ try {
72
+ const content = await readFile2(params.file_path, "utf-8");
73
+ const oldStr = params.old_string;
74
+ const newStr = params.new_string;
75
+ const replaceAll = params.replace_all;
76
+ if (!content.includes(oldStr)) {
77
+ return { output: "", error: `old_string not found in ${params.file_path}` };
78
+ }
79
+ let result;
80
+ if (replaceAll) {
81
+ result = content.replaceAll(oldStr, newStr);
82
+ } else {
83
+ const count = content.split(oldStr).length - 1;
84
+ if (count > 1) {
85
+ return {
86
+ output: "",
87
+ error: `Found ${count} matches for old_string. Provide more context or set replace_all=true.`
88
+ };
89
+ }
90
+ result = content.replace(oldStr, newStr);
91
+ }
92
+ await writeFile2(params.file_path, result, "utf-8");
93
+ return { output: `Edited: ${params.file_path}` };
94
+ } catch (e) {
95
+ return { output: "", error: e.message };
96
+ }
97
+ }
98
+ };
99
+
100
+ // src/tools/bash.ts
101
+ import { exec } from "child_process";
102
+ var bashTool = {
103
+ name: "bash",
104
+ description: "Execute a shell command. Returns stdout and stderr.",
105
+ parameters: {
106
+ type: "object",
107
+ properties: {
108
+ command: { type: "string", description: "The command to execute" },
109
+ timeout: { type: "number", description: "Timeout in ms (default 120000)" },
110
+ workdir: { type: "string", description: "Working directory" }
111
+ },
112
+ required: ["command"]
113
+ },
114
+ async execute(params) {
115
+ return new Promise((resolve) => {
116
+ const timeout = params.timeout || 12e4;
117
+ exec(
118
+ params.command,
119
+ {
120
+ timeout,
121
+ cwd: params.workdir || process.cwd(),
122
+ encoding: "utf-8"
123
+ },
124
+ (error, stdout, stderr) => {
125
+ if (error && error.killed) {
126
+ resolve({
127
+ output: stdout ?? "",
128
+ error: `Command timed out after ${timeout}ms`
129
+ });
130
+ } else if (error && !stdout && !stderr) {
131
+ resolve({ output: "", error: error.message });
132
+ } else {
133
+ resolve({ output: [stdout, stderr].filter(Boolean).join("\n").trim() });
134
+ }
135
+ }
136
+ );
137
+ });
138
+ }
139
+ };
140
+
141
+ // src/tools/glob.ts
142
+ import { glob } from "fs/promises";
143
+ var globTool = {
144
+ name: "glob",
145
+ description: "Find files matching a glob pattern.",
146
+ parameters: {
147
+ type: "object",
148
+ properties: {
149
+ pattern: {
150
+ type: "string",
151
+ description: "Glob pattern (e.g. '**/*.ts', 'src/**/*.test.*')"
152
+ },
153
+ path: { type: "string", description: "Directory to search in (default: cwd)" }
154
+ },
155
+ required: ["pattern"]
156
+ },
157
+ async execute(params) {
158
+ try {
159
+ const files = [];
160
+ for await (const f of glob(params.pattern, {
161
+ cwd: params.path || process.cwd()
162
+ })) {
163
+ files.push(f);
164
+ }
165
+ files.sort();
166
+ return { output: files.join("\n") || "No files found" };
167
+ } catch (e) {
168
+ return { output: "", error: e.message };
169
+ }
170
+ }
171
+ };
172
+
173
+ // src/tools/grep.ts
174
+ import { readFile as readFile3, readdir } from "fs/promises";
175
+ import { join } from "path";
176
+ var grepTool = {
177
+ name: "grep",
178
+ description: "Search file contents using regex. Returns file paths and matching line numbers.",
179
+ parameters: {
180
+ type: "object",
181
+ properties: {
182
+ pattern: { type: "string", description: "Regex pattern to search for" },
183
+ path: { type: "string", description: "Directory to search in (default: cwd)" },
184
+ include: { type: "string", description: "File pattern to include (e.g. '*.ts')" }
185
+ },
186
+ required: ["pattern"]
187
+ },
188
+ async execute(params) {
189
+ try {
190
+ const regex = new RegExp(params.pattern, "gi");
191
+ const rootDir = params.path || process.cwd();
192
+ const includePattern = params.include;
193
+ const results = [];
194
+ async function searchDir(dir, depth) {
195
+ if (depth > 10 || results.length >= 200) return;
196
+ const entries = await readdir(dir, { withFileTypes: true });
197
+ for (const entry of entries) {
198
+ if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
199
+ const fullPath = join(dir, entry.name);
200
+ if (entry.isDirectory()) {
201
+ await searchDir(fullPath, depth + 1);
202
+ } else if (entry.isFile()) {
203
+ if (includePattern && !matchGlob(entry.name, includePattern)) continue;
204
+ try {
205
+ const content = await readFile3(fullPath, "utf-8");
206
+ const lines = content.split("\n");
207
+ for (let i = 0; i < lines.length; i++) {
208
+ if (regex.test(lines[i])) {
209
+ results.push(`${fullPath}:${i + 1}: ${lines[i].trim()}`);
210
+ if (results.length >= 200) return;
211
+ }
212
+ regex.lastIndex = 0;
213
+ }
214
+ } catch {
215
+ }
216
+ }
217
+ }
218
+ }
219
+ await searchDir(rootDir, 0);
220
+ return { output: results.join("\n") || "No matches found" };
221
+ } catch (e) {
222
+ return { output: "", error: e.message };
223
+ }
224
+ }
225
+ };
226
+ function matchGlob(filename, pattern) {
227
+ const regexStr = "^" + pattern.replace(/\*/g, ".*").replace(/\?/g, ".") + "$";
228
+ return new RegExp(regexStr, "i").test(filename);
229
+ }
230
+
231
+ // src/tools/index.ts
232
+ var builtinTools = [
233
+ readFileTool,
234
+ writeFileTool,
235
+ editFileTool,
236
+ bashTool,
237
+ globTool,
238
+ grepTool
239
+ ];
240
+
241
+ // src/core/orchestrator.ts
242
+ var Orchestrator = class {
243
+ messages = [];
244
+ tools;
245
+ model;
246
+ systemPrompt;
247
+ maxIterations;
248
+ callbacks;
249
+ constructor(opts) {
250
+ this.model = opts.model;
251
+ this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
252
+ if (opts.skillInstructions) {
253
+ this.systemPrompt += "\n\n" + opts.skillInstructions;
254
+ }
255
+ this.tools = opts.tools ?? builtinTools;
256
+ this.maxIterations = opts.maxIterations ?? 20;
257
+ this.callbacks = {
258
+ onToken: opts.onToken,
259
+ onToolStart: opts.onToolStart,
260
+ onToolEnd: opts.onToolEnd
261
+ };
262
+ if (this.systemPrompt) {
263
+ this.messages.push({ role: "system", content: this.systemPrompt });
264
+ }
265
+ }
266
+ async run(userMessage) {
267
+ this.messages.push({ role: "user", content: userMessage });
268
+ for (let i = 0; i < this.maxIterations; i++) {
269
+ const response = await this.model.chat(this.messages, this.tools);
270
+ if (response.content) {
271
+ this.messages.push({
272
+ role: "assistant",
273
+ content: response.content,
274
+ tool_calls: response.tool_calls
275
+ });
276
+ }
277
+ if (!response.tool_calls?.length) {
278
+ return response.content;
279
+ }
280
+ for (const tc of response.tool_calls) {
281
+ this.callbacks.onToolStart?.(
282
+ tc.function.name,
283
+ JSON.parse(tc.function.arguments)
284
+ );
285
+ const result = await this.executeTool(tc);
286
+ this.callbacks.onToolEnd?.(tc.function.name, result);
287
+ this.messages.push({
288
+ role: "tool",
289
+ content: result.error ? `Error: ${result.error}` : result.output,
290
+ tool_call_id: tc.id
291
+ });
292
+ }
293
+ }
294
+ return "Max iterations reached.";
295
+ }
296
+ async *runStream(userMessage) {
297
+ this.messages.push({ role: "user", content: userMessage });
298
+ for (let i = 0; i < this.maxIterations; i++) {
299
+ let fullContent = "";
300
+ let toolCalls = [];
301
+ for await (const chunk of this.model.stream(this.messages, this.tools)) {
302
+ if (chunk.content) {
303
+ fullContent += chunk.content;
304
+ yield chunk.content;
305
+ }
306
+ if (chunk.tool_calls) {
307
+ toolCalls = chunk.tool_calls;
308
+ }
309
+ }
310
+ if (!toolCalls.length) {
311
+ this.messages.push({ role: "assistant", content: fullContent });
312
+ return;
313
+ }
314
+ this.messages.push({
315
+ role: "assistant",
316
+ content: fullContent,
317
+ tool_calls: toolCalls
318
+ });
319
+ for (const tc of toolCalls) {
320
+ this.callbacks.onToolStart?.(
321
+ tc.function.name,
322
+ JSON.parse(tc.function.arguments)
323
+ );
324
+ const result = await this.executeTool(tc);
325
+ this.callbacks.onToolEnd?.(tc.function.name, result);
326
+ this.messages.push({
327
+ role: "tool",
328
+ content: result.error ? `Error: ${result.error}` : result.output,
329
+ tool_call_id: tc.id
330
+ });
331
+ }
332
+ }
333
+ }
334
+ async executeTool(tc) {
335
+ const tool = this.tools.find((t) => t.name === tc.function.name);
336
+ if (!tool) return { output: "", error: `Unknown tool: ${tc.function.name}` };
337
+ try {
338
+ const params = JSON.parse(tc.function.arguments);
339
+ return await tool.execute(params);
340
+ } catch (e) {
341
+ return { output: "", error: e.message };
342
+ }
343
+ }
344
+ getMessages() {
345
+ return [...this.messages];
346
+ }
347
+ clearMessages() {
348
+ this.messages = [];
349
+ if (this.systemPrompt) {
350
+ this.messages.push({ role: "system", content: this.systemPrompt });
351
+ }
352
+ }
353
+ };
354
+ var DEFAULT_SYSTEM_PROMPT = `You are Hecode, an AI coding assistant. You help users with software engineering tasks using the tools available to you.
355
+
356
+ Key principles:
357
+ - Be concise and direct
358
+ - Use tools to read/write files, execute commands, and search code
359
+ - Verify your work by running tests or checks when possible
360
+ - Follow existing code conventions in the project`;
361
+
362
+ export {
363
+ Orchestrator
364
+ };
365
+ //# sourceMappingURL=chunk-ECQ3AREB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/read_file.ts","../src/tools/write_file.ts","../src/tools/edit_file.ts","../src/tools/bash.ts","../src/tools/glob.ts","../src/tools/grep.ts","../src/tools/index.ts","../src/core/orchestrator.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const readFileTool: Tool = {\n name: \"read_file\",\n description: \"Read file content. Supports offset and limit for large files.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n offset: { type: \"number\", description: \"Line number to start from (1-indexed)\" },\n limit: { type: \"number\", description: \"Max lines to read (default 2000)\" },\n },\n required: [\"file_path\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const lines = content.split(\"\\n\");\n const offset = (params.offset as number) || 1;\n const limit = (params.limit as number) || 2000;\n const sliced = lines.slice(offset - 1, offset - 1 + limit);\n const numbered = sliced.map((line, i) => `${offset + i}: ${line}`).join(\"\\n\");\n return { output: numbered };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const writeFileTool: Tool = {\n name: \"write_file\",\n description: \"Write content to a file. Creates parent directories if needed.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n content: { type: \"string\", description: \"Content to write\" },\n },\n required: [\"file_path\", \"content\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n await mkdir(dirname(params.file_path as string), { recursive: true });\n await writeFile(params.file_path as string, params.content as string, \"utf-8\");\n return { output: `File written: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const editFileTool: Tool = {\n name: \"edit_file\",\n description:\n \"Replace exact string match in a file. Fails if old_string not found or matches multiple times.\",\n parameters: {\n type: \"object\",\n properties: {\n file_path: { type: \"string\", description: \"Absolute path to the file\" },\n old_string: { type: \"string\", description: \"Exact string to replace\" },\n new_string: { type: \"string\", description: \"Replacement string\" },\n replace_all: { type: \"boolean\", description: \"Replace all occurrences (default false)\" },\n },\n required: [\"file_path\", \"old_string\", \"new_string\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const content = await readFile(params.file_path as string, \"utf-8\");\n const oldStr = params.old_string as string;\n const newStr = params.new_string as string;\n const replaceAll = params.replace_all as boolean;\n\n if (!content.includes(oldStr)) {\n return { output: \"\", error: `old_string not found in ${params.file_path}` };\n }\n\n let result: string;\n if (replaceAll) {\n result = content.replaceAll(oldStr, newStr);\n } else {\n const count = content.split(oldStr).length - 1;\n if (count > 1) {\n return {\n output: \"\",\n error: `Found ${count} matches for old_string. Provide more context or set replace_all=true.`,\n };\n }\n result = content.replace(oldStr, newStr);\n }\n\n await writeFile(params.file_path as string, result, \"utf-8\");\n return { output: `Edited: ${params.file_path}` };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { exec } from \"node:child_process\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const bashTool: Tool = {\n name: \"bash\",\n description: \"Execute a shell command. Returns stdout and stderr.\",\n parameters: {\n type: \"object\",\n properties: {\n command: { type: \"string\", description: \"The command to execute\" },\n timeout: { type: \"number\", description: \"Timeout in ms (default 120000)\" },\n workdir: { type: \"string\", description: \"Working directory\" },\n },\n required: [\"command\"],\n },\n async execute(params): Promise<ToolResult> {\n return new Promise((resolve) => {\n const timeout = (params.timeout as number) || 120_000;\n exec(\n params.command as string,\n {\n timeout,\n cwd: (params.workdir as string) || process.cwd(),\n encoding: \"utf-8\",\n },\n (error, stdout, stderr) => {\n if (error && error.killed) {\n resolve({\n output: stdout ?? \"\",\n error: `Command timed out after ${timeout}ms`,\n });\n } else if (error && !stdout && !stderr) {\n resolve({ output: \"\", error: error.message });\n } else {\n resolve({ output: [stdout, stderr].filter(Boolean).join(\"\\n\").trim() });\n }\n },\n );\n });\n },\n};\n","import { glob } from \"node:fs/promises\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const globTool: Tool = {\n name: \"glob\",\n description: \"Find files matching a glob pattern.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Glob pattern (e.g. '**/*.ts', 'src/**/*.test.*')\",\n },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const files: string[] = [];\n for await (const f of glob(params.pattern as string, {\n cwd: (params.path as string) || process.cwd(),\n })) {\n files.push(f);\n }\n files.sort();\n return { output: files.join(\"\\n\") || \"No files found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { Tool, ToolResult } from \"../core/types.js\";\n\nexport const grepTool: Tool = {\n name: \"grep\",\n description:\n \"Search file contents using regex. Returns file paths and matching line numbers.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\", description: \"Regex pattern to search for\" },\n path: { type: \"string\", description: \"Directory to search in (default: cwd)\" },\n include: { type: \"string\", description: \"File pattern to include (e.g. '*.ts')\" },\n },\n required: [\"pattern\"],\n },\n async execute(params): Promise<ToolResult> {\n try {\n const regex = new RegExp(params.pattern as string, \"gi\");\n const rootDir = (params.path as string) || process.cwd();\n const includePattern = params.include as string | undefined;\n const results: string[] = [];\n\n async function searchDir(dir: string, depth: number) {\n if (depth > 10 || results.length >= 200) return;\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await searchDir(fullPath, depth + 1);\n } else if (entry.isFile()) {\n if (includePattern && !matchGlob(entry.name, includePattern)) continue;\n try {\n const content = await readFile(fullPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i]!)) {\n results.push(`${fullPath}:${i + 1}: ${lines[i]!.trim()}`);\n if (results.length >= 200) return;\n }\n regex.lastIndex = 0;\n }\n } catch {\n /* skip binary/unreadable files */\n }\n }\n }\n }\n\n await searchDir(rootDir, 0);\n return { output: results.join(\"\\n\") || \"No matches found\" };\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n },\n};\n\nfunction matchGlob(filename: string, pattern: string): boolean {\n const regexStr = \"^\" + pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\") + \"$\";\n return new RegExp(regexStr, \"i\").test(filename);\n}\n","import type { Tool } from \"../core/types.js\";\nimport { readFileTool } from \"./read_file.js\";\nimport { writeFileTool } from \"./write_file.js\";\nimport { editFileTool } from \"./edit_file.js\";\nimport { bashTool } from \"./bash.js\";\nimport { globTool } from \"./glob.js\";\nimport { grepTool } from \"./grep.js\";\n\nexport const builtinTools: Tool[] = [\n readFileTool,\n writeFileTool,\n editFileTool,\n bashTool,\n globTool,\n grepTool,\n];\n\nexport function getToolsByNames(names: string[]): Tool[] {\n return builtinTools.filter((t) => names.includes(t.name));\n}\n\nexport { readFileTool } from \"./read_file.js\";\nexport { writeFileTool } from \"./write_file.js\";\nexport { editFileTool } from \"./edit_file.js\";\nexport { bashTool } from \"./bash.js\";\nexport { globTool } from \"./glob.js\";\nexport { grepTool } from \"./grep.js\";\n","import type { ModelProvider, Message, Tool, ToolCall, ToolResult } from \"./types.js\";\nimport { builtinTools } from \"../tools/index.js\";\n\nexport interface OrchestratorOptions {\n model: ModelProvider;\n systemPrompt?: string;\n skillInstructions?: string;\n tools?: Tool[];\n maxIterations?: number;\n onToken?: (token: string) => void;\n onToolStart?: (name: string, params: Record<string, unknown>) => void;\n onToolEnd?: (name: string, result: ToolResult) => void;\n}\n\nexport class Orchestrator {\n private messages: Message[] = [];\n private tools: Tool[];\n private model: ModelProvider;\n private systemPrompt: string;\n private maxIterations: number;\n private callbacks: Pick<\n OrchestratorOptions,\n \"onToken\" | \"onToolStart\" | \"onToolEnd\"\n >;\n\n constructor(opts: OrchestratorOptions) {\n this.model = opts.model;\n this.systemPrompt = opts.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n if (opts.skillInstructions) {\n this.systemPrompt += \"\\n\\n\" + opts.skillInstructions;\n }\n this.tools = opts.tools ?? builtinTools;\n this.maxIterations = opts.maxIterations ?? 20;\n this.callbacks = {\n onToken: opts.onToken,\n onToolStart: opts.onToolStart,\n onToolEnd: opts.onToolEnd,\n };\n\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n\n async run(userMessage: string): Promise<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n const response = await this.model.chat(this.messages, this.tools);\n\n if (response.content) {\n this.messages.push({\n role: \"assistant\",\n content: response.content,\n tool_calls: response.tool_calls,\n });\n }\n\n if (!response.tool_calls?.length) {\n return response.content;\n }\n\n for (const tc of response.tool_calls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n\n return \"Max iterations reached.\";\n }\n\n async *runStream(userMessage: string): AsyncIterable<string> {\n this.messages.push({ role: \"user\", content: userMessage });\n\n for (let i = 0; i < this.maxIterations; i++) {\n let fullContent = \"\";\n let toolCalls: ToolCall[] = [];\n\n for await (const chunk of this.model.stream(this.messages, this.tools)) {\n if (chunk.content) {\n fullContent += chunk.content;\n yield chunk.content;\n }\n if (chunk.tool_calls) {\n toolCalls = chunk.tool_calls;\n }\n }\n\n if (!toolCalls.length) {\n this.messages.push({ role: \"assistant\", content: fullContent });\n return;\n }\n\n this.messages.push({\n role: \"assistant\",\n content: fullContent,\n tool_calls: toolCalls,\n });\n\n for (const tc of toolCalls) {\n this.callbacks.onToolStart?.(\n tc.function.name,\n JSON.parse(tc.function.arguments),\n );\n const result = await this.executeTool(tc);\n this.callbacks.onToolEnd?.(tc.function.name, result);\n this.messages.push({\n role: \"tool\",\n content: result.error ? `Error: ${result.error}` : result.output,\n tool_call_id: tc.id,\n });\n }\n }\n }\n\n private async executeTool(tc: ToolCall): Promise<ToolResult> {\n const tool = this.tools.find((t) => t.name === tc.function.name);\n if (!tool) return { output: \"\", error: `Unknown tool: ${tc.function.name}` };\n try {\n const params = JSON.parse(tc.function.arguments);\n return await tool.execute(params);\n } catch (e: any) {\n return { output: \"\", error: e.message };\n }\n }\n\n getMessages(): Message[] {\n return [...this.messages];\n }\n\n clearMessages(): void {\n this.messages = [];\n if (this.systemPrompt) {\n this.messages.push({ role: \"system\", content: this.systemPrompt });\n }\n }\n}\n\nconst DEFAULT_SYSTEM_PROMPT = `You are Hecode, an AI coding assistant. You help users with software engineering tasks using the tools available to you.\n\nKey principles:\n- Be concise and direct\n- Use tools to read/write files, execute commands, and search code\n- Verify your work by running tests or checks when possible\n- Follow existing code conventions in the project`;\n"],"mappings":"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","names":["readFile","writeFile","readFile"]}
package/dist/index.js ADDED
@@ -0,0 +1,505 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Orchestrator
4
+ } from "./chunk-ECQ3AREB.js";
5
+
6
+ // src/cli/commands.ts
7
+ import { Command } from "commander";
8
+
9
+ // src/cli/config.ts
10
+ import { readFile, mkdir, writeFile } from "fs/promises";
11
+ import { join } from "path";
12
+ import { homedir } from "os";
13
+ var CONFIG_DIR = join(homedir(), ".hecode");
14
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
15
+ async function loadConfig() {
16
+ try {
17
+ const raw = await readFile(CONFIG_FILE, "utf-8");
18
+ return JSON.parse(raw);
19
+ } catch {
20
+ return { defaultModel: "openai:gpt-4o", models: {} };
21
+ }
22
+ }
23
+
24
+ // src/models/openai.ts
25
+ import OpenAI from "openai";
26
+ var OpenAIProvider = class {
27
+ name = "openai";
28
+ client;
29
+ model;
30
+ constructor(config) {
31
+ this.client = new OpenAI({
32
+ apiKey: config.apiKey ?? process.env.OPENAI_API_KEY,
33
+ baseURL: config.baseUrl
34
+ });
35
+ this.model = config.model ?? "gpt-4o";
36
+ }
37
+ async chat(messages, tools) {
38
+ const params = {
39
+ model: this.model,
40
+ messages: this.convertMessages(messages),
41
+ ...tools?.length && { tools: this.convertTools(tools) }
42
+ };
43
+ const completion = await this.client.chat.completions.create(params);
44
+ const choice = completion.choices[0];
45
+ return {
46
+ content: choice.message.content ?? "",
47
+ tool_calls: choice.message.tool_calls?.filter((tc) => tc.type === "function").map((tc) => ({
48
+ id: tc.id,
49
+ type: "function",
50
+ function: { name: tc.function.name, arguments: tc.function.arguments }
51
+ })),
52
+ usage: completion.usage ? { prompt: completion.usage.prompt_tokens, completion: completion.usage.completion_tokens } : void 0
53
+ };
54
+ }
55
+ async *stream(messages, tools) {
56
+ const stream = await this.client.chat.completions.create({
57
+ model: this.model,
58
+ messages: this.convertMessages(messages),
59
+ stream: true,
60
+ ...tools?.length && { tools: this.convertTools(tools) }
61
+ });
62
+ for await (const chunk of stream) {
63
+ const delta = chunk.choices[0]?.delta;
64
+ if (!delta) continue;
65
+ yield {
66
+ content: delta.content ?? void 0,
67
+ tool_calls: delta.tool_calls?.map((tc) => ({
68
+ id: tc.id ?? "",
69
+ type: "function",
70
+ function: { name: tc.function?.name ?? "", arguments: tc.function?.arguments ?? "" }
71
+ })),
72
+ done: chunk.choices[0]?.finish_reason != null
73
+ };
74
+ }
75
+ }
76
+ convertMessages(messages) {
77
+ return messages.map((m) => {
78
+ if (m.role === "tool") {
79
+ return { role: "tool", content: m.content, tool_call_id: m.tool_call_id };
80
+ }
81
+ if (m.role === "assistant" && m.tool_calls?.length) {
82
+ return {
83
+ role: "assistant",
84
+ content: m.content,
85
+ tool_calls: m.tool_calls.map((tc) => ({
86
+ id: tc.id,
87
+ type: "function",
88
+ function: tc.function
89
+ }))
90
+ };
91
+ }
92
+ return { role: m.role, content: m.content };
93
+ });
94
+ }
95
+ convertTools(tools) {
96
+ return tools.map((t) => ({
97
+ type: "function",
98
+ function: { name: t.name, description: t.description, parameters: t.parameters }
99
+ }));
100
+ }
101
+ };
102
+
103
+ // src/models/anthropic.ts
104
+ import Anthropic from "@anthropic-ai/sdk";
105
+ var AnthropicProvider = class {
106
+ name = "anthropic";
107
+ client;
108
+ model;
109
+ constructor(config) {
110
+ this.client = new Anthropic({ apiKey: config.apiKey ?? process.env.ANTHROPIC_API_KEY });
111
+ this.model = config.model ?? "claude-sonnet-4-20250514";
112
+ }
113
+ async chat(messages, tools) {
114
+ const system = messages.find((m) => m.role === "system")?.content ?? "";
115
+ const convMessages = messages.filter((m) => m.role !== "system");
116
+ const params = {
117
+ model: this.model,
118
+ max_tokens: 8192,
119
+ system,
120
+ messages: this.convertMessages(convMessages),
121
+ ...tools?.length && { tools: this.convertTools(tools) }
122
+ };
123
+ const msg = await this.client.messages.create(params);
124
+ const textBlock = msg.content.find((b) => b.type === "text");
125
+ const toolBlocks = msg.content.filter((b) => b.type === "tool_use");
126
+ return {
127
+ content: textBlock?.text ?? "",
128
+ tool_calls: toolBlocks.map((tb) => ({
129
+ id: tb.id,
130
+ type: "function",
131
+ function: { name: tb.name, arguments: JSON.stringify(tb.input) }
132
+ })),
133
+ usage: { prompt: msg.usage.input_tokens, completion: msg.usage.output_tokens }
134
+ };
135
+ }
136
+ async *stream(messages, tools) {
137
+ const system = messages.find((m) => m.role === "system")?.content ?? "";
138
+ const convMessages = messages.filter((m) => m.role !== "system");
139
+ const stream = this.client.messages.stream({
140
+ model: this.model,
141
+ max_tokens: 8192,
142
+ system,
143
+ messages: this.convertMessages(convMessages),
144
+ ...tools?.length && { tools: this.convertTools(tools) }
145
+ });
146
+ for await (const event of stream) {
147
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
148
+ yield { content: event.delta.text, done: false };
149
+ }
150
+ }
151
+ yield { content: void 0, done: true };
152
+ }
153
+ convertMessages(messages) {
154
+ return messages.map((m) => ({
155
+ role: m.role === "assistant" ? "assistant" : "user",
156
+ content: m.content
157
+ }));
158
+ }
159
+ convertTools(tools) {
160
+ return tools.map((t) => ({
161
+ name: t.name,
162
+ description: t.description,
163
+ input_schema: t.parameters
164
+ }));
165
+ }
166
+ };
167
+
168
+ // src/models/ollama.ts
169
+ var OllamaProvider = class {
170
+ name = "ollama";
171
+ baseUrl;
172
+ model;
173
+ constructor(config) {
174
+ this.baseUrl = config.baseUrl ?? "http://localhost:11434";
175
+ this.model = config.model ?? "llama3.1";
176
+ }
177
+ async chat(messages, tools) {
178
+ const res = await fetch(`${this.baseUrl}/api/chat`, {
179
+ method: "POST",
180
+ headers: { "Content-Type": "application/json" },
181
+ body: JSON.stringify({
182
+ model: this.model,
183
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
184
+ stream: false,
185
+ ...tools?.length && { tools: this.convertTools(tools) }
186
+ })
187
+ });
188
+ const data = await res.json();
189
+ return {
190
+ content: data.message?.content ?? "",
191
+ tool_calls: data.message?.tool_calls?.map((tc, i) => ({
192
+ id: `call_${i}`,
193
+ type: "function",
194
+ function: {
195
+ name: tc.function?.name ?? "",
196
+ arguments: JSON.stringify(tc.function?.arguments ?? {})
197
+ }
198
+ }))
199
+ };
200
+ }
201
+ async *stream(messages, tools) {
202
+ const res = await fetch(`${this.baseUrl}/api/chat`, {
203
+ method: "POST",
204
+ headers: { "Content-Type": "application/json" },
205
+ body: JSON.stringify({
206
+ model: this.model,
207
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
208
+ stream: true,
209
+ ...tools?.length && { tools: this.convertTools(tools) }
210
+ })
211
+ });
212
+ const reader = res.body.getReader();
213
+ const decoder = new TextDecoder();
214
+ let buffer = "";
215
+ while (true) {
216
+ const { done, value } = await reader.read();
217
+ if (done) break;
218
+ buffer += decoder.decode(value, { stream: true });
219
+ const lines = buffer.split("\n");
220
+ buffer = lines.pop();
221
+ for (const line of lines) {
222
+ if (!line.trim()) continue;
223
+ const data = JSON.parse(line);
224
+ yield {
225
+ content: data.message?.content ?? void 0,
226
+ done: data.done ?? false
227
+ };
228
+ }
229
+ }
230
+ yield { done: true };
231
+ }
232
+ convertTools(tools) {
233
+ return tools.map((t) => ({
234
+ type: "function",
235
+ function: {
236
+ name: t.name,
237
+ description: t.description,
238
+ parameters: t.parameters
239
+ }
240
+ }));
241
+ }
242
+ };
243
+
244
+ // src/models/factory.ts
245
+ var registry = /* @__PURE__ */ new Map();
246
+ registry.set("openai", (c) => new OpenAIProvider(c));
247
+ registry.set("claude", (c) => new AnthropicProvider(c));
248
+ registry.set("anthropic", (c) => new AnthropicProvider(c));
249
+ registry.set("ollama", (c) => new OllamaProvider(c));
250
+ function createProvider(name, config) {
251
+ const factory = registry.get(name);
252
+ if (!factory)
253
+ throw new Error(
254
+ `Unknown model provider: ${name}. Available: ${[...registry.keys()].join(", ")}`
255
+ );
256
+ return factory(config);
257
+ }
258
+ function parseModelString(modelStr) {
259
+ const [provider, ...rest] = modelStr.split(":");
260
+ return { provider, model: rest.join(":") || "" };
261
+ }
262
+
263
+ // src/cli/repl.ts
264
+ import * as readline from "readline";
265
+ import chalk from "chalk";
266
+ import { join as join4 } from "path";
267
+
268
+ // src/memory/session.ts
269
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
270
+ import { join as join2 } from "path";
271
+ import { homedir as homedir2 } from "os";
272
+ import { randomUUID } from "crypto";
273
+ var SESSIONS_DIR = join2(homedir2(), ".hecode", "sessions");
274
+ var SessionMemory = class {
275
+ sessionDir;
276
+ constructor(sessionId) {
277
+ const id = sessionId ?? randomUUID().slice(0, 12);
278
+ this.sessionDir = join2(SESSIONS_DIR, id);
279
+ }
280
+ get sessionId() {
281
+ return this.sessionDir.split(/[\\/]/).pop();
282
+ }
283
+ async save(messages) {
284
+ await mkdir2(this.sessionDir, { recursive: true });
285
+ const session = {
286
+ id: this.sessionId,
287
+ messages,
288
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
289
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
290
+ };
291
+ await writeFile2(
292
+ join2(this.sessionDir, "session.json"),
293
+ JSON.stringify(session, null, 2)
294
+ );
295
+ }
296
+ async load() {
297
+ try {
298
+ const raw = await readFile2(
299
+ join2(this.sessionDir, "session.json"),
300
+ "utf-8"
301
+ );
302
+ const session = JSON.parse(raw);
303
+ return session.messages;
304
+ } catch {
305
+ return [];
306
+ }
307
+ }
308
+ async saveCheckpoint(data) {
309
+ await mkdir2(this.sessionDir, { recursive: true });
310
+ await writeFile2(
311
+ join2(this.sessionDir, "checkpoint.md"),
312
+ JSON.stringify(data, null, 2)
313
+ );
314
+ }
315
+ async saveNote(content) {
316
+ await mkdir2(this.sessionDir, { recursive: true });
317
+ const notePath = join2(this.sessionDir, "notes.md");
318
+ let existing = "";
319
+ try {
320
+ existing = await readFile2(notePath, "utf-8");
321
+ } catch {
322
+ }
323
+ await writeFile2(notePath, existing + "\n\n" + content);
324
+ }
325
+ };
326
+
327
+ // src/skills/loader.ts
328
+ import { readFile as readFile3, readdir } from "fs/promises";
329
+ import { join as join3 } from "path";
330
+ async function loadSkills(skillsDir) {
331
+ const skills = [];
332
+ try {
333
+ const entries = await readdir(skillsDir, { withFileTypes: true });
334
+ for (const entry of entries) {
335
+ if (!entry.isDirectory()) continue;
336
+ const skillPath = join3(skillsDir, entry.name, "SKILL.md");
337
+ try {
338
+ const content = await readFile3(skillPath, "utf-8");
339
+ const skill = parseSkill(entry.name, content);
340
+ if (skill) skills.push(skill);
341
+ } catch {
342
+ }
343
+ }
344
+ } catch {
345
+ }
346
+ return skills;
347
+ }
348
+ function parseSkill(name, content) {
349
+ const descMatch = content.match(/^#\s+(.+)$/m);
350
+ const triggerMatch = content.match(/trigger:\s*(.+)/i);
351
+ if (!descMatch) return null;
352
+ return {
353
+ name,
354
+ description: descMatch[1] ?? name,
355
+ trigger: triggerMatch?.[1] ?? "",
356
+ instructions: content
357
+ };
358
+ }
359
+ function matchSkill(skills, userMessage) {
360
+ const lower = userMessage.toLowerCase();
361
+ for (const skill of skills) {
362
+ if (skill.trigger) {
363
+ const triggers = skill.trigger.split(",").map((t) => t.trim().toLowerCase());
364
+ for (const t of triggers) {
365
+ if (lower.includes(t)) return skill;
366
+ }
367
+ }
368
+ }
369
+ return null;
370
+ }
371
+
372
+ // src/cli/repl.ts
373
+ async function startREPL(model, opts) {
374
+ const session = new SessionMemory();
375
+ const skillsDir = join4(process.cwd(), "skills");
376
+ const skills = await loadSkills(skillsDir);
377
+ let skillInstructions;
378
+ if (opts?.skillName) {
379
+ const skill = skills.find((s) => s.name === opts.skillName);
380
+ if (skill) skillInstructions = skill.instructions;
381
+ }
382
+ const orchestrator = new Orchestrator({
383
+ model,
384
+ skillInstructions,
385
+ onToolStart: (name) => console.log(chalk.yellow(` \u2699 ${name}...`)),
386
+ onToolEnd: (_name, result) => {
387
+ if (result.error) console.log(chalk.red(` \u2717 ${_name}: ${result.error}`));
388
+ else console.log(chalk.green(` \u2713 ${_name}`));
389
+ }
390
+ });
391
+ const rl = readline.createInterface({
392
+ input: process.stdin,
393
+ output: process.stdout,
394
+ prompt: chalk.cyan("hecode> ")
395
+ });
396
+ console.log(chalk.bold("Hecode v0.1.0 \u2014 Your AI Coding Assistant"));
397
+ console.log(chalk.gray(`Session: ${session.sessionId}`));
398
+ if (skills.length) {
399
+ console.log(chalk.gray(`Skills loaded: ${skills.map((s) => s.name).join(", ")}`));
400
+ }
401
+ console.log(chalk.gray("Type /help for commands, Ctrl+C to exit\n"));
402
+ rl.prompt();
403
+ rl.on("line", async (line) => {
404
+ const input = line.trim();
405
+ if (!input) {
406
+ rl.prompt();
407
+ return;
408
+ }
409
+ if (input.startsWith("/")) {
410
+ handleCommand(input, orchestrator, session);
411
+ rl.prompt();
412
+ return;
413
+ }
414
+ if (!skillInstructions) {
415
+ const matched = matchSkill(skills, input);
416
+ if (matched) {
417
+ console.log(chalk.gray(` [skill: ${matched.name}]`));
418
+ }
419
+ }
420
+ try {
421
+ process.stdout.write(chalk.white("\n"));
422
+ for await (const token of orchestrator.runStream(input)) {
423
+ process.stdout.write(token);
424
+ }
425
+ process.stdout.write("\n\n");
426
+ await session.save(orchestrator.getMessages());
427
+ } catch (e) {
428
+ console.log(chalk.red(`
429
+ Error: ${e.message}
430
+ `));
431
+ }
432
+ rl.prompt();
433
+ });
434
+ rl.on("close", () => {
435
+ console.log(chalk.gray("\nGoodbye!"));
436
+ process.exit(0);
437
+ });
438
+ }
439
+ function handleCommand(input, orchestrator, session) {
440
+ const cmd = input.split(" ")[0];
441
+ switch (cmd) {
442
+ case "/help":
443
+ console.log(
444
+ chalk.cyan(`
445
+ /help \u2014 Show this help
446
+ /clear \u2014 Clear conversation
447
+ /history \u2014 Show message count
448
+ /save \u2014 Save session manually
449
+ /session \u2014 Show session ID
450
+ /exit \u2014 Exit Hecode
451
+ `)
452
+ );
453
+ break;
454
+ case "/clear":
455
+ orchestrator.clearMessages();
456
+ console.log(chalk.gray("Conversation cleared."));
457
+ break;
458
+ case "/history":
459
+ console.log(chalk.gray(`Messages: ${orchestrator.getMessages().length}`));
460
+ break;
461
+ case "/save":
462
+ session.save(orchestrator.getMessages()).then(() => {
463
+ console.log(chalk.gray("Session saved."));
464
+ });
465
+ break;
466
+ case "/session":
467
+ console.log(chalk.gray(`Session ID: ${session.sessionId}`));
468
+ break;
469
+ case "/exit":
470
+ process.exit(0);
471
+ default:
472
+ console.log(chalk.red(`Unknown command: ${cmd}`));
473
+ }
474
+ }
475
+
476
+ // src/cli/commands.ts
477
+ function createProgram() {
478
+ const program2 = new Command();
479
+ program2.name("hecode").description("Hecode \u2014 Your AI Coding Assistant CLI").version("0.1.0").option("-m, --model <model>", "Model to use (e.g. openai:gpt-4o, claude:sonnet)").option("-s, --skill <skill>", "Skill to activate").argument("[prompt...]", "Single-shot prompt (non-interactive)").action(async (prompt, opts) => {
480
+ const config = await loadConfig();
481
+ const modelStr = opts.model ?? config.defaultModel;
482
+ const { provider, model } = parseModelString(modelStr);
483
+ const modelConfig = config.models[provider] ?? {};
484
+ if (model) modelConfig.model = model;
485
+ const modelProvider = createProvider(provider, modelConfig);
486
+ if (prompt.length) {
487
+ const { Orchestrator: Orchestrator2 } = await import("./orchestrator-VEQUC74P.js");
488
+ const orch = new Orchestrator2({ model: modelProvider });
489
+ const result = await orch.run(prompt.join(" "));
490
+ console.log(result);
491
+ } else {
492
+ await startREPL(modelProvider, { skillName: opts.skill });
493
+ }
494
+ });
495
+ program2.command("config").description("Show or edit configuration").action(async () => {
496
+ const config = await loadConfig();
497
+ console.log(JSON.stringify(config, null, 2));
498
+ });
499
+ return program2;
500
+ }
501
+
502
+ // src/index.ts
503
+ var program = createProgram();
504
+ program.parse();
505
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands.ts","../src/cli/config.ts","../src/models/openai.ts","../src/models/anthropic.ts","../src/models/ollama.ts","../src/models/factory.ts","../src/cli/repl.ts","../src/memory/session.ts","../src/skills/loader.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { loadConfig } from \"./config.js\";\nimport { createProvider, parseModelString } from \"../models/factory.js\";\nimport { startREPL } from \"./repl.js\";\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name(\"hecode\")\n .description(\"Hecode — Your AI Coding Assistant CLI\")\n .version(\"0.1.0\")\n .option(\"-m, --model <model>\", \"Model to use (e.g. openai:gpt-4o, claude:sonnet)\")\n .option(\"-s, --skill <skill>\", \"Skill to activate\")\n .argument(\"[prompt...]\", \"Single-shot prompt (non-interactive)\")\n .action(async (prompt: string[], opts: { model?: string; skill?: string }) => {\n const config = await loadConfig();\n const modelStr = opts.model ?? config.defaultModel;\n const { provider, model } = parseModelString(modelStr);\n const modelConfig = config.models[provider] ?? {};\n if (model) modelConfig.model = model;\n const modelProvider = createProvider(provider, modelConfig as Record<string, unknown>);\n\n if (prompt.length) {\n const { Orchestrator } = await import(\"../core/orchestrator.js\");\n const orch = new Orchestrator({ model: modelProvider });\n const result = await orch.run(prompt.join(\" \"));\n console.log(result);\n } else {\n await startREPL(modelProvider, { skillName: opts.skill });\n }\n });\n\n program\n .command(\"config\")\n .description(\"Show or edit configuration\")\n .action(async () => {\n const config = await loadConfig();\n console.log(JSON.stringify(config, null, 2));\n });\n\n return program;\n}\n","import { readFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { Config } from \"../core/types.js\";\n\nconst CONFIG_DIR = join(homedir(), \".hecode\");\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\n\nexport async function loadConfig(): Promise<Config> {\n try {\n const raw = await readFile(CONFIG_FILE, \"utf-8\");\n return JSON.parse(raw);\n } catch {\n return { defaultModel: \"openai:gpt-4o\", models: {} };\n }\n}\n\nexport async function saveConfig(config: Config): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), \"utf-8\");\n}\n","import OpenAI from \"openai\";\nimport type { ModelProvider, Message, Tool, Response, Chunk } from \"../core/types.js\";\n\nexport class OpenAIProvider implements ModelProvider {\n name = \"openai\";\n private client: OpenAI;\n private model: string;\n\n constructor(config: { apiKey?: string; baseUrl?: string; model?: string }) {\n this.client = new OpenAI({\n apiKey: config.apiKey ?? process.env.OPENAI_API_KEY,\n baseURL: config.baseUrl,\n });\n this.model = config.model ?? \"gpt-4o\";\n }\n\n async chat(messages: Message[], tools?: Tool[]): Promise<Response> {\n const params: OpenAI.ChatCompletionCreateParams = {\n model: this.model,\n messages: this.convertMessages(messages),\n ...(tools?.length && { tools: this.convertTools(tools) }),\n };\n const completion = await this.client.chat.completions.create(params);\n const choice = completion.choices[0]!;\n return {\n content: choice.message.content ?? \"\",\n tool_calls: choice.message.tool_calls\n ?.filter((tc) => tc.type === \"function\")\n .map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: { name: tc.function.name, arguments: tc.function.arguments },\n })),\n usage: completion.usage\n ? { prompt: completion.usage.prompt_tokens, completion: completion.usage.completion_tokens }\n : undefined,\n };\n }\n\n async *stream(messages: Message[], tools?: Tool[]): AsyncIterable<Chunk> {\n const stream = await this.client.chat.completions.create({\n model: this.model,\n messages: this.convertMessages(messages),\n stream: true,\n ...(tools?.length && { tools: this.convertTools(tools) }),\n });\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n if (!delta) continue;\n yield {\n content: delta.content ?? undefined,\n tool_calls: delta.tool_calls?.map((tc) => ({\n id: tc.id ?? \"\",\n type: \"function\" as const,\n function: { name: tc.function?.name ?? \"\", arguments: tc.function?.arguments ?? \"\" },\n })),\n done: chunk.choices[0]?.finish_reason != null,\n };\n }\n }\n\n private convertMessages(messages: Message[]): OpenAI.ChatCompletionMessageParam[] {\n return messages.map((m) => {\n if (m.role === \"tool\") {\n return { role: \"tool\" as const, content: m.content, tool_call_id: m.tool_call_id! };\n }\n if (m.role === \"assistant\" && m.tool_calls?.length) {\n return {\n role: \"assistant\" as const,\n content: m.content,\n tool_calls: m.tool_calls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: tc.function,\n })),\n };\n }\n return { role: m.role as \"system\" | \"user\" | \"assistant\", content: m.content };\n });\n }\n\n private convertTools(tools: Tool[]): OpenAI.ChatCompletionTool[] {\n return tools.map((t) => ({\n type: \"function\" as const,\n function: { name: t.name, description: t.description, parameters: t.parameters },\n }));\n }\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { ModelProvider, Message, Tool, Response, Chunk } from \"../core/types.js\";\n\nexport class AnthropicProvider implements ModelProvider {\n name = \"anthropic\";\n private client: Anthropic;\n private model: string;\n\n constructor(config: { apiKey?: string; model?: string }) {\n this.client = new Anthropic({ apiKey: config.apiKey ?? process.env.ANTHROPIC_API_KEY });\n this.model = config.model ?? \"claude-sonnet-4-20250514\";\n }\n\n async chat(messages: Message[], tools?: Tool[]): Promise<Response> {\n const system = messages.find((m) => m.role === \"system\")?.content ?? \"\";\n const convMessages = messages.filter((m) => m.role !== \"system\");\n const params: Anthropic.MessageCreateParams = {\n model: this.model,\n max_tokens: 8192,\n system,\n messages: this.convertMessages(convMessages),\n ...(tools?.length && { tools: this.convertTools(tools) }),\n };\n const msg = await this.client.messages.create(params);\n const textBlock = msg.content.find((b) => b.type === \"text\");\n const toolBlocks = msg.content.filter((b) => b.type === \"tool_use\");\n return {\n content: textBlock?.text ?? \"\",\n tool_calls: toolBlocks.map((tb) => ({\n id: tb.id,\n type: \"function\" as const,\n function: { name: tb.name, arguments: JSON.stringify(tb.input) },\n })),\n usage: { prompt: msg.usage.input_tokens, completion: msg.usage.output_tokens },\n };\n }\n\n async *stream(messages: Message[], tools?: Tool[]): AsyncIterable<Chunk> {\n const system = messages.find((m) => m.role === \"system\")?.content ?? \"\";\n const convMessages = messages.filter((m) => m.role !== \"system\");\n const stream = this.client.messages.stream({\n model: this.model,\n max_tokens: 8192,\n system,\n messages: this.convertMessages(convMessages),\n ...(tools?.length && { tools: this.convertTools(tools) }),\n });\n for await (const event of stream) {\n if (event.type === \"content_block_delta\" && event.delta.type === \"text_delta\") {\n yield { content: event.delta.text, done: false };\n }\n }\n yield { content: undefined, done: true };\n }\n\n private convertMessages(messages: Message[]): Anthropic.MessageParam[] {\n return messages.map((m) => ({\n role: m.role === \"assistant\" ? \"assistant\" : \"user\",\n content: m.content,\n }));\n }\n\n private convertTools(tools: Tool[]): Anthropic.Tool[] {\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.parameters as Anthropic.Tool[\"input_schema\"],\n }));\n }\n}\n","import type { ModelProvider, Message, Tool, Response, Chunk } from \"../core/types.js\";\n\nexport class OllamaProvider implements ModelProvider {\n name = \"ollama\";\n private baseUrl: string;\n private model: string;\n\n constructor(config: { baseUrl?: string; model?: string }) {\n this.baseUrl = config.baseUrl ?? \"http://localhost:11434\";\n this.model = config.model ?? \"llama3.1\";\n }\n\n async chat(messages: Message[], tools?: Tool[]): Promise<Response> {\n const res = await fetch(`${this.baseUrl}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\n stream: false,\n ...(tools?.length && { tools: this.convertTools(tools) }),\n }),\n });\n const data = (await res.json()) as any;\n return {\n content: data.message?.content ?? \"\",\n tool_calls: data.message?.tool_calls?.map((tc: any, i: number) => ({\n id: `call_${i}`,\n type: \"function\" as const,\n function: {\n name: tc.function?.name ?? \"\",\n arguments: JSON.stringify(tc.function?.arguments ?? {}),\n },\n })),\n };\n }\n\n async *stream(messages: Message[], tools?: Tool[]): AsyncIterable<Chunk> {\n const res = await fetch(`${this.baseUrl}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n messages: messages.map((m) => ({ role: m.role, content: m.content })),\n stream: true,\n ...(tools?.length && { tools: this.convertTools(tools) }),\n }),\n });\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop()!;\n for (const line of lines) {\n if (!line.trim()) continue;\n const data = JSON.parse(line);\n yield {\n content: data.message?.content ?? undefined,\n done: data.done ?? false,\n };\n }\n }\n yield { done: true };\n }\n\n private convertTools(tools: Tool[]) {\n return tools.map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n },\n }));\n }\n}\n","import type { ModelProvider } from \"../core/types.js\";\nimport { OpenAIProvider } from \"./openai.js\";\nimport { AnthropicProvider } from \"./anthropic.js\";\nimport { OllamaProvider } from \"./ollama.js\";\n\ntype ProviderFactory = (config: Record<string, unknown>) => ModelProvider;\n\nconst registry = new Map<string, ProviderFactory>();\n\nregistry.set(\"openai\", (c) => new OpenAIProvider(c as any));\nregistry.set(\"claude\", (c) => new AnthropicProvider(c as any));\nregistry.set(\"anthropic\", (c) => new AnthropicProvider(c as any));\nregistry.set(\"ollama\", (c) => new OllamaProvider(c as any));\n\nexport function registerProvider(name: string, factory: ProviderFactory) {\n registry.set(name, factory);\n}\n\nexport function createProvider(name: string, config: Record<string, unknown>): ModelProvider {\n const factory = registry.get(name);\n if (!factory)\n throw new Error(\n `Unknown model provider: ${name}. Available: ${[...registry.keys()].join(\", \")}`,\n );\n return factory(config);\n}\n\nexport function parseModelString(modelStr: string): { provider: string; model: string } {\n const [provider, ...rest] = modelStr.split(\":\");\n return { provider: provider!, model: rest.join(\":\") || \"\" };\n}\n","import * as readline from \"node:readline\";\nimport chalk from \"chalk\";\nimport { join } from \"node:path\";\nimport { Orchestrator } from \"../core/orchestrator.js\";\nimport { SessionMemory } from \"../memory/session.js\";\nimport { loadSkills, matchSkill } from \"../skills/loader.js\";\nimport type { ModelProvider, ToolResult } from \"../core/types.js\";\n\nexport async function startREPL(\n model: ModelProvider,\n opts?: { skillName?: string },\n): Promise<void> {\n const session = new SessionMemory();\n const skillsDir = join(process.cwd(), \"skills\");\n const skills = await loadSkills(skillsDir);\n\n let skillInstructions: string | undefined;\n if (opts?.skillName) {\n const skill = skills.find((s) => s.name === opts.skillName);\n if (skill) skillInstructions = skill.instructions;\n }\n\n const orchestrator = new Orchestrator({\n model,\n skillInstructions,\n onToolStart: (name) => console.log(chalk.yellow(` ⚙ ${name}...`)),\n onToolEnd: (_name, result: ToolResult) => {\n if (result.error) console.log(chalk.red(` ✗ ${_name}: ${result.error}`));\n else console.log(chalk.green(` ✓ ${_name}`));\n },\n });\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: chalk.cyan(\"hecode> \"),\n });\n\n console.log(chalk.bold(\"Hecode v0.1.0 — Your AI Coding Assistant\"));\n console.log(chalk.gray(`Session: ${session.sessionId}`));\n if (skills.length) {\n console.log(chalk.gray(`Skills loaded: ${skills.map((s) => s.name).join(\", \")}`));\n }\n console.log(chalk.gray(\"Type /help for commands, Ctrl+C to exit\\n\"));\n rl.prompt();\n\n rl.on(\"line\", async (line) => {\n const input = line.trim();\n if (!input) {\n rl.prompt();\n return;\n }\n\n if (input.startsWith(\"/\")) {\n handleCommand(input, orchestrator, session);\n rl.prompt();\n return;\n }\n\n // Auto-match skill if not already set\n if (!skillInstructions) {\n const matched = matchSkill(skills, input);\n if (matched) {\n console.log(chalk.gray(` [skill: ${matched.name}]`));\n }\n }\n\n try {\n process.stdout.write(chalk.white(\"\\n\"));\n for await (const token of orchestrator.runStream(input)) {\n process.stdout.write(token);\n }\n process.stdout.write(\"\\n\\n\");\n\n // Auto-save session after each exchange\n await session.save(orchestrator.getMessages());\n } catch (e: any) {\n console.log(chalk.red(`\\nError: ${e.message}\\n`));\n }\n\n rl.prompt();\n });\n\n rl.on(\"close\", () => {\n console.log(chalk.gray(\"\\nGoodbye!\"));\n process.exit(0);\n });\n}\n\nfunction handleCommand(\n input: string,\n orchestrator: Orchestrator,\n session: SessionMemory,\n): void {\n const cmd = input.split(\" \")[0];\n switch (cmd) {\n case \"/help\":\n console.log(\n chalk.cyan(`\n /help — Show this help\n /clear — Clear conversation\n /history — Show message count\n /save — Save session manually\n /session — Show session ID\n /exit — Exit Hecode\n `),\n );\n break;\n case \"/clear\":\n orchestrator.clearMessages();\n console.log(chalk.gray(\"Conversation cleared.\"));\n break;\n case \"/history\":\n console.log(chalk.gray(`Messages: ${orchestrator.getMessages().length}`));\n break;\n case \"/save\":\n session.save(orchestrator.getMessages()).then(() => {\n console.log(chalk.gray(\"Session saved.\"));\n });\n break;\n case \"/session\":\n console.log(chalk.gray(`Session ID: ${session.sessionId}`));\n break;\n case \"/exit\":\n process.exit(0);\n default:\n console.log(chalk.red(`Unknown command: ${cmd}`));\n }\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { randomUUID } from \"node:crypto\";\nimport type { Message } from \"../core/types.js\";\n\nconst SESSIONS_DIR = join(homedir(), \".hecode\", \"sessions\");\n\nexport interface Session {\n id: string;\n messages: Message[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport class SessionMemory {\n private sessionDir: string;\n\n constructor(sessionId?: string) {\n const id = sessionId ?? randomUUID().slice(0, 12);\n this.sessionDir = join(SESSIONS_DIR, id);\n }\n\n get sessionId(): string {\n return this.sessionDir.split(/[\\\\/]/).pop()!;\n }\n\n async save(messages: Message[]): Promise<void> {\n await mkdir(this.sessionDir, { recursive: true });\n const session: Session = {\n id: this.sessionId,\n messages,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n await writeFile(\n join(this.sessionDir, \"session.json\"),\n JSON.stringify(session, null, 2),\n );\n }\n\n async load(): Promise<Message[]> {\n try {\n const raw = await readFile(\n join(this.sessionDir, \"session.json\"),\n \"utf-8\",\n );\n const session: Session = JSON.parse(raw);\n return session.messages;\n } catch {\n return [];\n }\n }\n\n async saveCheckpoint(data: Record<string, unknown>): Promise<void> {\n await mkdir(this.sessionDir, { recursive: true });\n await writeFile(\n join(this.sessionDir, \"checkpoint.md\"),\n JSON.stringify(data, null, 2),\n );\n }\n\n async saveNote(content: string): Promise<void> {\n await mkdir(this.sessionDir, { recursive: true });\n const notePath = join(this.sessionDir, \"notes.md\");\n let existing = \"\";\n try {\n existing = await readFile(notePath, \"utf-8\");\n } catch {}\n await writeFile(notePath, existing + \"\\n\\n\" + content);\n }\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface Skill {\n name: string;\n description: string;\n trigger: string;\n instructions: string;\n tools?: string[];\n}\n\nexport async function loadSkills(skillsDir: string): Promise<Skill[]> {\n const skills: Skill[] = [];\n try {\n const entries = await readdir(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillPath = join(skillsDir, entry.name, \"SKILL.md\");\n try {\n const content = await readFile(skillPath, \"utf-8\");\n const skill = parseSkill(entry.name, content);\n if (skill) skills.push(skill);\n } catch {\n /* no SKILL.md, skip */\n }\n }\n } catch {\n /* skills dir doesn't exist */\n }\n return skills;\n}\n\nfunction parseSkill(name: string, content: string): Skill | null {\n const descMatch = content.match(/^#\\s+(.+)$/m);\n const triggerMatch = content.match(/trigger:\\s*(.+)/i);\n if (!descMatch) return null;\n\n return {\n name,\n description: descMatch[1] ?? name,\n trigger: triggerMatch?.[1] ?? \"\",\n instructions: content,\n };\n}\n\nexport function matchSkill(skills: Skill[], userMessage: string): Skill | null {\n const lower = userMessage.toLowerCase();\n for (const skill of skills) {\n if (skill.trigger) {\n const triggers = skill.trigger.split(\",\").map((t) => t.trim().toLowerCase());\n for (const t of triggers) {\n if (lower.includes(t)) return skill;\n }\n }\n }\n return null;\n}\n","#!/usr/bin/env node\nimport { createProgram } from \"./cli/commands.js\";\n\nconst program = createProgram();\nprogram.parse();\n"],"mappings":"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","names":["join","readFile","writeFile","mkdir","join","homedir","readFile","join","join","program","Orchestrator"]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ Orchestrator
3
+ } from "./chunk-ECQ3AREB.js";
4
+ export {
5
+ Orchestrator
6
+ };
7
+ //# sourceMappingURL=orchestrator-VEQUC74P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@zhanngning/hecode",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "hecode": "./dist/index.js"
7
+ },
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup",
14
+ "dev": "tsx src/index.ts",
15
+ "test": "vitest run",
16
+ "lint": "tsc --noEmit"
17
+ },
18
+ "engines": {
19
+ "node": ">=20.0.0"
20
+ },
21
+ "license": "MIT",
22
+ "devDependencies": {
23
+ "@types/node": "^24.0.0",
24
+ "tsup": "^8.5.0",
25
+ "tsx": "^4.20.0",
26
+ "typescript": "^5.8.0",
27
+ "vitest": "^3.2.0"
28
+ },
29
+ "dependencies": {
30
+ "@anthropic-ai/sdk": "^0.106.0",
31
+ "chalk": "^5.6.2",
32
+ "commander": "^15.0.0",
33
+ "openai": "^6.45.0"
34
+ }
35
+ }