@thejeetsingh/kalcode 2.0.0 → 2.2.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.
Files changed (125) hide show
  1. package/README.md +0 -4
  2. package/dist/bin/kalcode.d.ts +2 -0
  3. package/dist/bin/kalcode.js +12 -0
  4. package/dist/bin/kalcode.js.map +1 -0
  5. package/dist/src/agent/context.d.ts +6 -0
  6. package/dist/src/agent/context.js +60 -0
  7. package/dist/src/agent/context.js.map +1 -0
  8. package/dist/src/agent/history.d.ts +8 -0
  9. package/dist/src/agent/history.js +59 -0
  10. package/dist/src/agent/history.js.map +1 -0
  11. package/dist/src/agent/loop.d.ts +6 -0
  12. package/dist/src/agent/loop.js +235 -0
  13. package/dist/src/agent/loop.js.map +1 -0
  14. package/dist/src/agent/memory.d.ts +2 -0
  15. package/dist/src/agent/memory.js +27 -0
  16. package/dist/src/agent/memory.js.map +1 -0
  17. package/dist/src/agent/permissions.d.ts +5 -0
  18. package/dist/src/agent/permissions.js +66 -0
  19. package/dist/src/agent/permissions.js.map +1 -0
  20. package/dist/src/agent/text-tool-parser.d.ts +2 -0
  21. package/dist/src/agent/text-tool-parser.js +68 -0
  22. package/dist/src/agent/text-tool-parser.js.map +1 -0
  23. package/dist/src/api/client.d.ts +2 -0
  24. package/dist/src/api/client.js +86 -0
  25. package/dist/src/api/client.js.map +1 -0
  26. package/dist/src/api/stream-parser.d.ts +2 -0
  27. package/dist/src/api/stream-parser.js +97 -0
  28. package/dist/src/api/stream-parser.js.map +1 -0
  29. package/dist/src/config.d.ts +7 -0
  30. package/dist/src/config.js +52 -0
  31. package/dist/src/config.js.map +1 -0
  32. package/dist/src/constants.d.ts +25 -0
  33. package/{src/constants.ts → dist/src/constants.js} +17 -19
  34. package/dist/src/constants.js.map +1 -0
  35. package/dist/src/git/git.d.ts +15 -0
  36. package/dist/src/git/git.js +73 -0
  37. package/dist/src/git/git.js.map +1 -0
  38. package/dist/src/index.d.ts +1 -0
  39. package/dist/src/index.js +415 -0
  40. package/dist/src/index.js.map +1 -0
  41. package/dist/src/proxy/server.d.ts +1 -0
  42. package/dist/src/proxy/server.js +92 -0
  43. package/dist/src/proxy/server.js.map +1 -0
  44. package/dist/src/tools/edit-file.d.ts +2 -0
  45. package/dist/src/tools/edit-file.js +88 -0
  46. package/dist/src/tools/edit-file.js.map +1 -0
  47. package/dist/src/tools/glob-tool.d.ts +2 -0
  48. package/dist/src/tools/glob-tool.js +52 -0
  49. package/dist/src/tools/glob-tool.js.map +1 -0
  50. package/dist/src/tools/grep.d.ts +2 -0
  51. package/dist/src/tools/grep.js +93 -0
  52. package/dist/src/tools/grep.js.map +1 -0
  53. package/dist/src/tools/list-directory.d.ts +2 -0
  54. package/dist/src/tools/list-directory.js +90 -0
  55. package/dist/src/tools/list-directory.js.map +1 -0
  56. package/dist/src/tools/read-file.d.ts +2 -0
  57. package/dist/src/tools/read-file.js +64 -0
  58. package/dist/src/tools/read-file.js.map +1 -0
  59. package/dist/src/tools/registry.d.ts +4 -0
  60. package/dist/src/tools/registry.js +32 -0
  61. package/dist/src/tools/registry.js.map +1 -0
  62. package/dist/src/tools/run-command.d.ts +2 -0
  63. package/dist/src/tools/run-command.js +98 -0
  64. package/dist/src/tools/run-command.js.map +1 -0
  65. package/dist/src/tools/write-file.d.ts +2 -0
  66. package/dist/src/tools/write-file.js +39 -0
  67. package/dist/src/tools/write-file.js.map +1 -0
  68. package/dist/src/types.d.ts +61 -0
  69. package/dist/src/types.js +2 -0
  70. package/dist/src/types.js.map +1 -0
  71. package/dist/src/ui/input.d.ts +5 -0
  72. package/dist/src/ui/input.js +52 -0
  73. package/dist/src/ui/input.js.map +1 -0
  74. package/dist/src/ui/model-picker.d.ts +7 -0
  75. package/dist/src/ui/model-picker.js +70 -0
  76. package/dist/src/ui/model-picker.js.map +1 -0
  77. package/dist/src/ui/skills-picker.d.ts +2 -0
  78. package/dist/src/ui/skills-picker.js +95 -0
  79. package/dist/src/ui/skills-picker.js.map +1 -0
  80. package/dist/src/ui/skills.d.ts +14 -0
  81. package/dist/src/ui/skills.js +137 -0
  82. package/dist/src/ui/skills.js.map +1 -0
  83. package/dist/src/ui/spinner.d.ts +5 -0
  84. package/dist/src/ui/spinner.js +49 -0
  85. package/dist/src/ui/spinner.js.map +1 -0
  86. package/dist/src/ui/stream-renderer.d.ts +2 -0
  87. package/dist/src/ui/stream-renderer.js +66 -0
  88. package/dist/src/ui/stream-renderer.js.map +1 -0
  89. package/dist/src/ui/terminal.d.ts +24 -0
  90. package/dist/src/ui/terminal.js +272 -0
  91. package/dist/src/ui/terminal.js.map +1 -0
  92. package/package.json +16 -16
  93. package/api/health.ts +0 -10
  94. package/api/v1/chat/completions.ts +0 -59
  95. package/bin/kalcode.ts +0 -14
  96. package/src/agent/context.ts +0 -62
  97. package/src/agent/history.ts +0 -70
  98. package/src/agent/loop.ts +0 -282
  99. package/src/agent/memory.ts +0 -26
  100. package/src/agent/permissions.ts +0 -84
  101. package/src/agent/text-tool-parser.ts +0 -71
  102. package/src/api/client.ts +0 -110
  103. package/src/api/stream-parser.ts +0 -109
  104. package/src/config.ts +0 -61
  105. package/src/git/git.ts +0 -86
  106. package/src/index.ts +0 -403
  107. package/src/proxy/server.ts +0 -128
  108. package/src/tools/edit-file.ts +0 -97
  109. package/src/tools/glob-tool.ts +0 -59
  110. package/src/tools/grep.ts +0 -96
  111. package/src/tools/list-directory.ts +0 -101
  112. package/src/tools/read-file.ts +0 -71
  113. package/src/tools/registry.ts +0 -41
  114. package/src/tools/run-command.ts +0 -99
  115. package/src/tools/write-file.ts +0 -42
  116. package/src/types.ts +0 -68
  117. package/src/ui/input.ts +0 -60
  118. package/src/ui/model-picker.ts +0 -92
  119. package/src/ui/skills-picker.ts +0 -113
  120. package/src/ui/skills.ts +0 -152
  121. package/src/ui/spinner.ts +0 -56
  122. package/src/ui/stream-renderer.ts +0 -69
  123. package/src/ui/terminal.ts +0 -337
  124. package/tsconfig.json +0 -15
  125. package/vercel.json +0 -12
package/src/ui/input.ts DELETED
@@ -1,60 +0,0 @@
1
- import * as readline from "readline";
2
- import chalk from "chalk";
3
-
4
- export interface InputController {
5
- prompt: () => Promise<string>;
6
- close: () => void;
7
- }
8
-
9
- export function createInput(slashCommands: string[] = []): InputController {
10
- let rl: readline.Interface | null = null;
11
- const commands = Array.from(new Set(slashCommands.map((c) => c.trim()).filter(Boolean))).sort();
12
-
13
- function completer(line: string): [string[], string] {
14
- if (!line.startsWith("/")) return [[], line];
15
- const hits = commands.filter((c) => c.startsWith(line.toLowerCase()));
16
- // If user just typed "/" show all slash commands like a command menu seed.
17
- if (line === "/") return [commands, line];
18
- return [hits.length > 0 ? hits : commands, line];
19
- }
20
-
21
- function ensureRL(): readline.Interface {
22
- if (process.stdin.isRaw) {
23
- process.stdin.setRawMode(false);
24
- }
25
- process.stdin.resume();
26
-
27
- if (rl) return rl;
28
-
29
- rl = readline.createInterface({
30
- input: process.stdin,
31
- output: process.stdout,
32
- historySize: 200,
33
- completer,
34
- });
35
- rl.on("close", () => {
36
- rl = null;
37
- });
38
- return rl;
39
- }
40
-
41
- // Claude Code uses ❯ as the prompt
42
- const promptStr = chalk.bold.cyan("❯ ");
43
-
44
- return {
45
- prompt(): Promise<string> {
46
- return new Promise((resolve) => {
47
- const iface = ensureRL();
48
- iface.question(promptStr, (answer) => {
49
- resolve(answer.trim());
50
- });
51
- });
52
- },
53
- close() {
54
- if (rl) {
55
- rl.close();
56
- rl = null;
57
- }
58
- },
59
- };
60
- }
@@ -1,92 +0,0 @@
1
- import chalk from "chalk";
2
-
3
- interface ModelOption {
4
- id: string;
5
- name: string;
6
- params: string;
7
- }
8
-
9
- export function pickModel(
10
- models: ModelOption[],
11
- currentModelId: string,
12
- ): Promise<string | null> {
13
- return new Promise((resolve) => {
14
- const startIndex = models.findIndex((m) => m.id === currentModelId);
15
- let cursor = startIndex >= 0 ? startIndex : 0;
16
-
17
- const stdin = process.stdin;
18
- const wasRaw = stdin.isRaw;
19
- stdin.setRawMode(true);
20
- stdin.resume();
21
-
22
- const totalLines = models.length + 4;
23
- let firstDraw = true;
24
-
25
- function render() {
26
- if (!firstDraw) {
27
- process.stdout.write(`\x1b[${totalLines}A`);
28
- }
29
- firstDraw = false;
30
- draw();
31
- }
32
-
33
- function draw() {
34
- console.log("");
35
- console.log(
36
- chalk.bold(" Select model") +
37
- chalk.dim(" ↑↓ navigate · enter select · esc cancel"),
38
- );
39
- console.log("");
40
- for (let i = 0; i < models.length; i++) {
41
- const m = models[i]!;
42
- const isActive = m.id === currentModelId;
43
- const isCursor = i === cursor;
44
-
45
- const pointer = isCursor ? chalk.cyan("❯") : " ";
46
- const marker = isActive ? chalk.green("●") : chalk.dim("○");
47
- const name = isCursor ? chalk.bold.white(m.name) : chalk.dim(m.name);
48
- const params = chalk.dim(`(${m.params})`);
49
- console.log(` ${pointer} ${marker} ${name} ${params}`);
50
- }
51
- console.log("");
52
- }
53
-
54
- function cleanup() {
55
- stdin.removeListener("data", onKey);
56
- stdin.setRawMode(wasRaw ?? false);
57
- }
58
-
59
- function onKey(data: Buffer) {
60
- const key = data.toString();
61
-
62
- if (key === "\x1b" || key === "q") {
63
- cleanup();
64
- resolve(null);
65
- return;
66
- }
67
-
68
- if (key === "\r" || key === "\n") {
69
- cleanup();
70
- resolve(models[cursor]!.id);
71
- return;
72
- }
73
-
74
- if (key === "\x03") {
75
- cleanup();
76
- resolve(null);
77
- return;
78
- }
79
-
80
- if (key === "\x1b[A" || key === "k") {
81
- cursor = cursor > 0 ? cursor - 1 : models.length - 1;
82
- render();
83
- } else if (key === "\x1b[B" || key === "j") {
84
- cursor = cursor < models.length - 1 ? cursor + 1 : 0;
85
- render();
86
- }
87
- }
88
-
89
- stdin.on("data", onKey);
90
- render();
91
- });
92
- }
@@ -1,113 +0,0 @@
1
- import chalk from "chalk";
2
- import type { Skill } from "./skills.js";
3
- import { searchSkills } from "./skills.js";
4
-
5
- export function pickSkill(initialQuery = ""): Promise<Skill | null> {
6
- return new Promise((resolve) => {
7
- const stdin = process.stdin;
8
- const wasRaw = stdin.isRaw;
9
- stdin.setRawMode(true);
10
- stdin.resume();
11
-
12
- let query = initialQuery;
13
- let cursor = 0;
14
- let firstDraw = true;
15
- let linesRendered = 0;
16
-
17
- function filtered(): Skill[] {
18
- return searchSkills(query).slice(0, 8);
19
- }
20
-
21
- function render() {
22
- if (!firstDraw && linesRendered > 0) {
23
- process.stdout.write(`\x1b[${linesRendered}A`);
24
- }
25
- firstDraw = false;
26
-
27
- const list = filtered();
28
- const lines: string[] = [];
29
-
30
- lines.push("");
31
- lines.push(
32
- chalk.bold(" Command palette") +
33
- chalk.dim(" type to filter · ↑↓ navigate · enter select · esc cancel"),
34
- );
35
- lines.push(` ${chalk.cyan("❯")} ${query}${chalk.dim("│")}`);
36
- lines.push("");
37
-
38
- if (list.length === 0) {
39
- lines.push(chalk.dim(" No matching skills"));
40
- } else {
41
- if (cursor >= list.length) cursor = list.length - 1;
42
- if (cursor < 0) cursor = 0;
43
- for (let i = 0; i < list.length; i++) {
44
- const skill = list[i]!;
45
- const pointer = i === cursor ? chalk.cyan("❯") : " ";
46
- const title =
47
- i === cursor ? chalk.bold.white(skill.displayName) : chalk.dim(skill.displayName);
48
- const command = chalk.dim(skill.command);
49
- lines.push(` ${pointer} ${title} ${command}`);
50
- }
51
- }
52
- lines.push("");
53
-
54
- process.stdout.write(lines.map((line) => `${line}\x1b[2K`).join("\n"));
55
- linesRendered = lines.length;
56
- }
57
-
58
- function cleanup() {
59
- stdin.removeListener("data", onKey);
60
- stdin.setRawMode(wasRaw ?? false);
61
- }
62
-
63
- function finish(selection: Skill | null) {
64
- cleanup();
65
- resolve(selection);
66
- }
67
-
68
- function onKey(data: Buffer) {
69
- const key = data.toString();
70
- const list = filtered();
71
-
72
- if (key === "\x1b" || key === "\x03") {
73
- finish(null);
74
- return;
75
- }
76
-
77
- if (key === "\r" || key === "\n") {
78
- finish(list[cursor] || null);
79
- return;
80
- }
81
-
82
- if (key === "\x1b[A") {
83
- cursor = cursor > 0 ? cursor - 1 : Math.max(0, list.length - 1);
84
- render();
85
- return;
86
- }
87
-
88
- if (key === "\x1b[B") {
89
- cursor = cursor < list.length - 1 ? cursor + 1 : 0;
90
- render();
91
- return;
92
- }
93
-
94
- if (key === "\x7f") {
95
- if (query.length > 0) {
96
- query = query.slice(0, -1);
97
- cursor = 0;
98
- render();
99
- }
100
- return;
101
- }
102
-
103
- if (key.length === 1 && key >= " " && key <= "~") {
104
- query += key;
105
- cursor = 0;
106
- render();
107
- }
108
- }
109
-
110
- stdin.on("data", onKey);
111
- render();
112
- });
113
- }
package/src/ui/skills.ts DELETED
@@ -1,152 +0,0 @@
1
- import chalk from "chalk";
2
-
3
- export interface Skill {
4
- id: string;
5
- displayName: string;
6
- description: string;
7
- command: string;
8
- contextTags: string[];
9
- keybinding?: string;
10
- inputSchema?: Record<string, unknown>;
11
- outputSchema?: Record<string, unknown>;
12
- ui?: Record<string, unknown>;
13
- }
14
-
15
- const SKILLS: Skill[] = [
16
- {
17
- id: "help",
18
- displayName: "Show help",
19
- description: "Display all available REPL commands.",
20
- command: "/help",
21
- contextTags: ["global"],
22
- keybinding: "h",
23
- },
24
- {
25
- id: "switch_model",
26
- displayName: "Switch model",
27
- description: "Open model picker and set active model.",
28
- command: "/model",
29
- contextTags: ["global"],
30
- keybinding: "m",
31
- },
32
- {
33
- id: "list_context_files",
34
- displayName: "List context files",
35
- description: "Show files currently pinned into agent context.",
36
- command: "/files",
37
- contextTags: ["project_loaded"],
38
- keybinding: "f",
39
- },
40
- {
41
- id: "add_context_file",
42
- displayName: "Add context file",
43
- description: "Add a file to context memory for the session.",
44
- command: "/add <file>",
45
- contextTags: ["project_loaded", "code_view"],
46
- },
47
- {
48
- id: "drop_context_file",
49
- displayName: "Drop context file",
50
- description: "Remove a file from context memory.",
51
- command: "/drop <file>",
52
- contextTags: ["project_loaded", "code_view"],
53
- },
54
- {
55
- id: "show_git_status",
56
- displayName: "Git status",
57
- description: "Show changed files and branch status.",
58
- command: "/status",
59
- contextTags: ["git_repo"],
60
- keybinding: "s",
61
- },
62
- {
63
- id: "show_git_diff",
64
- displayName: "Git diff summary",
65
- description: "Show uncommitted changes summary.",
66
- command: "/diff",
67
- contextTags: ["git_repo"],
68
- keybinding: "d",
69
- },
70
- {
71
- id: "git_commit",
72
- displayName: "Commit changes",
73
- description: "Commit staged and unstaged changes.",
74
- command: "/commit <message>",
75
- contextTags: ["git_repo"],
76
- },
77
- {
78
- id: "toggle_read_only",
79
- displayName: "Toggle read-only mode",
80
- description: "Prevent write tools from being used by the agent.",
81
- command: "/ask",
82
- contextTags: ["global"],
83
- keybinding: "r",
84
- },
85
- {
86
- id: "toggle_auto_accept",
87
- displayName: "Toggle auto-accept",
88
- description: "Auto-approve write and command tool actions.",
89
- command: "/auto",
90
- contextTags: ["global"],
91
- keybinding: "a",
92
- },
93
- {
94
- id: "retry_last",
95
- displayName: "Retry last request",
96
- description: "Retry the most recent user prompt.",
97
- command: "/retry",
98
- contextTags: ["chat"],
99
- keybinding: "y",
100
- },
101
- ];
102
-
103
- export function getSkills(): Skill[] {
104
- return SKILLS.slice();
105
- }
106
-
107
- export function searchSkills(query: string): Skill[] {
108
- const q = query.trim().toLowerCase();
109
- if (!q) return getSkills();
110
-
111
- return getSkills()
112
- .map((skill) => ({ skill, score: scoreSkill(skill, q) }))
113
- .filter((entry) => entry.score > 0)
114
- .sort((a, b) => b.score - a.score || a.skill.displayName.localeCompare(b.skill.displayName))
115
- .map((entry) => entry.skill);
116
- }
117
-
118
- export function renderSkillsList(skills: Skill[], query = ""): void {
119
- const q = query.trim();
120
- console.log("");
121
- console.log(chalk.bold(" Skills") + (q ? chalk.dim(` — "${q}"`) : ""));
122
- console.log("");
123
- if (skills.length === 0) {
124
- console.log(chalk.dim(" No matching skills"));
125
- console.log("");
126
- return;
127
- }
128
-
129
- for (const skill of skills) {
130
- const kb = skill.keybinding ? chalk.dim(` [${skill.keybinding}]`) : "";
131
- console.log(` ${chalk.cyan("●")} ${chalk.bold(skill.displayName)}${kb}`);
132
- console.log(` ${chalk.dim(skill.description)}`);
133
- console.log(` ${chalk.dim(skill.command)}`);
134
- }
135
- console.log("");
136
- }
137
-
138
- function scoreSkill(skill: Skill, q: string): number {
139
- const haystack = [
140
- skill.id,
141
- skill.displayName,
142
- skill.description,
143
- skill.command,
144
- ...skill.contextTags,
145
- skill.keybinding || "",
146
- ].join(" ").toLowerCase();
147
-
148
- if (!haystack.includes(q)) return 0;
149
- if (skill.id === q || skill.command === q || skill.displayName.toLowerCase() === q) return 100;
150
- if (skill.command.startsWith(q) || skill.displayName.toLowerCase().startsWith(q)) return 80;
151
- return 50;
152
- }
package/src/ui/spinner.ts DELETED
@@ -1,56 +0,0 @@
1
- import chalk from "chalk";
2
-
3
- // Braille spinner — matches Claude Code's spinner aesthetic
4
- const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
5
- let interval: ReturnType<typeof setInterval> | null = null;
6
- let frameIdx = 0;
7
- let currentText = "";
8
- let startTime = 0;
9
-
10
- export function startSpinner(text: string): void {
11
- stopSpinner();
12
- currentText = text;
13
- startTime = Date.now();
14
- frameIdx = 0;
15
- render();
16
- interval = setInterval(() => {
17
- frameIdx = (frameIdx + 1) % frames.length;
18
- render();
19
- }, 80);
20
- }
21
-
22
- export function stopSpinner(): void {
23
- if (interval) {
24
- clearInterval(interval);
25
- interval = null;
26
- process.stdout.write("\r\x1b[2K");
27
- }
28
- }
29
-
30
- export function updateSpinner(text: string): void {
31
- currentText = text;
32
- if (interval) render();
33
- }
34
-
35
- export function succeedSpinner(_text: string): void {
36
- stopSpinner();
37
- }
38
-
39
- export function failSpinner(_text: string): void {
40
- stopSpinner();
41
- }
42
-
43
- function render(): void {
44
- const frame = chalk.cyan(frames[frameIdx]!);
45
- const elapsed = formatElapsed();
46
- process.stdout.write(
47
- `\r\x1b[2K ${frame} ${chalk.dim(currentText)} ${chalk.dim(elapsed)}`,
48
- );
49
- }
50
-
51
- function formatElapsed(): string {
52
- const ms = Date.now() - startTime;
53
- if (ms < 1000) return "";
54
- const sec = (ms / 1000).toFixed(1);
55
- return `${sec}s`;
56
- }
@@ -1,69 +0,0 @@
1
- let hasOutput = false;
2
- let lineStarted = false;
3
- let currentLine = "";
4
- let inThinkBlock = false;
5
- let buffer = "";
6
-
7
- export function writeStreamToken(token: string): void {
8
- buffer += token;
9
-
10
- // Filter out <think>...</think> blocks (some models emit these)
11
- while (true) {
12
- if (inThinkBlock) {
13
- const closeIdx = buffer.indexOf("</think>");
14
- if (closeIdx === -1) {
15
- // Still inside think block, consume everything
16
- buffer = "";
17
- return;
18
- }
19
- // Skip past closing tag
20
- buffer = buffer.slice(closeIdx + 8);
21
- inThinkBlock = false;
22
- continue;
23
- }
24
-
25
- const openIdx = buffer.indexOf("<think>");
26
- if (openIdx === -1) break;
27
-
28
- // Output everything before <think>
29
- const before = buffer.slice(0, openIdx);
30
- if (before) emitText(before);
31
-
32
- buffer = buffer.slice(openIdx + 7);
33
- inThinkBlock = true;
34
- }
35
-
36
- // Output remaining buffer
37
- if (buffer) {
38
- emitText(buffer);
39
- buffer = "";
40
- }
41
- }
42
-
43
- function emitText(text: string): void {
44
- const parts = text.split("\n");
45
- for (let i = 0; i < parts.length; i++) {
46
- if (i > 0) {
47
- process.stdout.write("\n");
48
- lineStarted = false;
49
- currentLine = "";
50
- }
51
- const seg = parts[i]!;
52
- if (seg.length === 0 && i > 0) continue;
53
- if (!lineStarted) lineStarted = true;
54
- process.stdout.write(seg);
55
- currentLine += seg;
56
- }
57
- hasOutput = true;
58
- }
59
-
60
- export function finishStream(): void {
61
- if (hasOutput) {
62
- process.stdout.write("\n");
63
- }
64
- hasOutput = false;
65
- lineStarted = false;
66
- currentLine = "";
67
- inThinkBlock = false;
68
- buffer = "";
69
- }