codeshark-cli 0.1.1 → 0.1.4

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.
@@ -9,12 +9,19 @@ function exec(cmd, args, timeoutMs) {
9
9
  const child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
10
10
  let stdout = "";
11
11
  let stderr = "";
12
- child.stdout.on("data", (d) => (stdout += d));
13
- child.stderr.on("data", (d) => (stderr += d));
12
+ let truncated = false;
13
+ child.stdout.setEncoding("utf8");
14
+ child.stderr.setEncoding("utf8");
15
+ child.stdout.on("data", (d) => {
16
+ if (stdout.length + d.length > 30_000)
17
+ truncated = true;
18
+ stdout += d.slice(0, Math.max(0, 30_000 - stdout.length));
19
+ });
20
+ child.stderr.on("data", (d) => { stderr += d.slice(0, Math.max(0, 1000 - stderr.length)); });
14
21
  const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
15
22
  child.on("close", (code) => {
16
23
  clearTimeout(timer);
17
- resolvePromise({ code, stdout, stderr });
24
+ resolvePromise({ code, stdout: stdout + (truncated ? "\n[Search output truncated; narrow the pattern.]" : ""), stderr });
18
25
  });
19
26
  child.on("error", () => {
20
27
  clearTimeout(timer);
@@ -32,10 +39,10 @@ function parseFlags(flags) {
32
39
  }
33
40
  /** Dependency-free fallback when ripgrep isn't installed. */
34
41
  function jsSearch(root, pattern, flags) {
35
- const { caseInsensitive, filesOnly, context } = parseFlags(flags);
42
+ const { caseInsensitive, filesOnly, context, word } = parseFlags(flags);
36
43
  let rx;
37
44
  try {
38
- rx = new RegExp(pattern, caseInsensitive ? "i" : "");
45
+ rx = new RegExp(word ? "\\b(?:" + pattern + ")\\b" : pattern, caseInsensitive ? "i" : "");
39
46
  }
40
47
  catch {
41
48
  return `Invalid regex: ${pattern}`;
@@ -67,6 +74,8 @@ function jsSearch(root, pattern, flags) {
67
74
  continue;
68
75
  let text;
69
76
  try {
77
+ if (statSync(full).size > 10 * 1024 * 1024)
78
+ continue;
70
79
  text = readFileSync(full, "utf8");
71
80
  }
72
81
  catch {
@@ -81,7 +90,7 @@ function jsSearch(root, pattern, flags) {
81
90
  results.push(rel);
82
91
  continue;
83
92
  }
84
- for (let i = 0; i < lines.length; i++) {
93
+ for (let i = 0; i < lines.length && results.length < MAX_RESULTS; i++) {
85
94
  const line = lines[i];
86
95
  if (!rx.test(line))
87
96
  continue;
@@ -102,6 +111,7 @@ function jsSearch(root, pattern, flags) {
102
111
  }
103
112
  export const codeSearchTool = {
104
113
  name: "code_search",
114
+ readOnly: true,
105
115
  description: "Search file contents with a regular expression (ripgrep if installed, a built-in fallback otherwise). Returns up to 200 matches with line numbers. Flags: -i case-insensitive, -l files only, -w whole word, -C n context lines.",
106
116
  inputSchema: {
107
117
  type: "object",
@@ -136,6 +146,7 @@ export const codeSearchTool = {
136
146
  ...(/-l/.test(flags) ? ["-l"] : []),
137
147
  ...(/-w/.test(flags) ? ["-w"] : []),
138
148
  ...(/-C\s*(\d+)/.test(flags) ? ["-C", /-C\s*(\d+)/.exec(flags)[1]] : []),
149
+ "--",
139
150
  pattern,
140
151
  cwd,
141
152
  ];
@@ -68,35 +68,67 @@ export const runCommandTool = {
68
68
  if (!command)
69
69
  return "No command provided.";
70
70
  const cwd = args.cwd ? resolveProjectPath(String(args.cwd), ctx.cwd) : ctx.cwd;
71
- const timeoutMs = args.timeoutMs ? Math.max(1000, Number(args.timeoutMs)) : DEFAULT_TIMEOUT_MS;
71
+ const timeoutMs = args.timeoutMs ? Math.min(300_000, Math.max(1000, Number(args.timeoutMs))) : DEFAULT_TIMEOUT_MS;
72
72
  const danger = isDangerousCommand(command);
73
73
  if (danger && !process.env.CODESHARK_ALLOW_DANGEROUS) {
74
74
  throw new Error(`Blocked: "${command}" matches the danger pattern "${danger}". CodeShark refuses destructive commands by default (set CODESHARK_ALLOW_DANGEROUS=1 to override).`);
75
75
  }
76
76
  const shell = pickShell();
77
- return new Promise((resolvePromise) => {
78
- const child = spawn(shell.cmd, shell.args(command), { cwd, stdio: ["ignore", "pipe", "pipe"] });
77
+ ctx.signal?.throwIfAborted();
78
+ return new Promise((resolvePromise, reject) => {
79
+ const child = spawn(shell.cmd, shell.args(command), { cwd, stdio: ["ignore", "pipe", "pipe"], windowsHide: true, detached: process.platform !== "win32" });
79
80
  let stdout = "";
80
81
  let stderr = "";
81
82
  let timedOut = false;
82
- child.stdout.on("data", (d) => (stdout += d));
83
- child.stderr.on("data", (d) => (stderr += d));
83
+ let stdoutChars = 0;
84
+ let stderrChars = 0;
85
+ child.stdout.setEncoding("utf8");
86
+ child.stderr.setEncoding("utf8");
87
+ child.stdout.on("data", (d) => { stdoutChars += d.length; stdout += d.slice(0, Math.max(0, MAX_OUTPUT_CHARS - stdout.length)); });
88
+ child.stderr.on("data", (d) => { stderrChars += d.length; stderr += d.slice(0, Math.max(0, MAX_OUTPUT_CHARS - stderr.length)); });
89
+ const stop = () => {
90
+ if (!child.pid)
91
+ return;
92
+ if (process.platform === "win32") {
93
+ const killer = spawn("taskkill", ["/pid", String(child.pid), "/t", "/f"], { windowsHide: true, stdio: "ignore" });
94
+ killer.on("error", () => child.kill());
95
+ }
96
+ else {
97
+ try {
98
+ process.kill(-child.pid, "SIGKILL");
99
+ }
100
+ catch {
101
+ child.kill("SIGKILL");
102
+ }
103
+ }
104
+ };
105
+ ctx.signal?.addEventListener("abort", stop, { once: true });
84
106
  const timer = setTimeout(() => {
85
107
  timedOut = true;
86
- child.kill("SIGKILL");
108
+ stop();
87
109
  }, timeoutMs);
88
110
  child.on("close", (code) => {
89
111
  clearTimeout(timer);
112
+ ctx.signal?.removeEventListener("abort", stop);
90
113
  const parts = [`$ ${command}`, `exit code: ${timedOut ? `timed out after ${timeoutMs}ms` : code}`];
91
114
  if (stdout.trim())
92
115
  parts.push(`stdout:\n${truncate(stdout).trimEnd()}`);
93
116
  if (stderr.trim())
94
117
  parts.push(`stderr:\n${truncate(stderr).trimEnd()}`);
95
- resolvePromise(parts.join("\n"));
118
+ if (stdoutChars > stdout.length || stderrChars > stderr.length)
119
+ parts.push("[Output truncated; use a narrower command.]");
120
+ const result = parts.join("\n");
121
+ if (ctx.signal?.aborted)
122
+ reject(ctx.signal.reason);
123
+ else if (timedOut || code !== 0)
124
+ reject(new Error(result));
125
+ else
126
+ resolvePromise(result);
96
127
  });
97
128
  child.on("error", (e) => {
98
129
  clearTimeout(timer);
99
- resolvePromise(`Failed to spawn shell: ${e.message}`);
130
+ ctx.signal?.removeEventListener("abort", stop);
131
+ reject(new Error(`Failed to spawn shell: ${e.message}`));
100
132
  });
101
133
  });
102
134
  },
package/dist/update.js ADDED
@@ -0,0 +1,43 @@
1
+ import { exec } from "node:child_process";
2
+ function npmCommand() {
3
+ return process.platform === "win32" ? "npm.cmd" : "npm";
4
+ }
5
+ function versionParts(version) {
6
+ return version
7
+ .replace(/^v/, "")
8
+ .split(".")
9
+ .slice(0, 3)
10
+ .map((part) => Number.parseInt(part, 10) || 0);
11
+ }
12
+ export function isNewerVersion(current, latest) {
13
+ const a = versionParts(current);
14
+ const b = versionParts(latest);
15
+ for (let i = 0; i < 3; i++) {
16
+ if ((b[i] ?? 0) !== (a[i] ?? 0))
17
+ return (b[i] ?? 0) > (a[i] ?? 0);
18
+ }
19
+ return false;
20
+ }
21
+ export function latestPublishedVersion() {
22
+ return new Promise((resolve) => {
23
+ exec(`${npmCommand()} view codeshark-cli version --json`, { timeout: 5000, windowsHide: true }, (error, stdout) => {
24
+ if (error) {
25
+ resolve(null);
26
+ return;
27
+ }
28
+ const version = stdout.trim().replace(/^\"|\"$/g, "");
29
+ resolve(/^\d+\.\d+\.\d+$/.test(version) ? version : null);
30
+ });
31
+ });
32
+ }
33
+ export async function installLatestVersion() {
34
+ await new Promise((resolve, reject) => {
35
+ exec(`${npmCommand()} install --global codeshark-cli@latest`, { timeout: 120_000, windowsHide: true }, (error, stdout, stderr) => {
36
+ if (error) {
37
+ reject(new Error((stderr || stdout || error.message).trim()));
38
+ return;
39
+ }
40
+ resolve();
41
+ });
42
+ });
43
+ }
package/package.json CHANGED
@@ -1,25 +1,26 @@
1
1
  {
2
2
  "name": "codeshark-cli",
3
- "version": "0.1.1",
4
- "description": "An open-source terminal coding agent with a pixel-shark mascot. Five frontier models, zero setup, no API keys required.",
3
+ "version": "0.1.4",
4
+ "description": "An open-source terminal coding agent. Eight model choices, project tools, and approval before every tool action.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "codeshark": "./dist/index.js"
7
+ "codeshark": "dist/index.js"
8
8
  },
9
9
  "main": "dist/index.js",
10
10
  "files": [
11
11
  "dist",
12
12
  "README.md",
13
13
  "TERMS.md",
14
+ "PRIVACY.md",
14
15
  "LICENSE"
15
16
  ],
16
17
  "repository": {
17
18
  "type": "git",
18
- "url": "https://github.com/codeshark/codeshark.git"
19
+ "url": "git+https://github.com/ajashratripathi-crypto/codeshark-cli.git"
19
20
  },
20
- "homepage": "https://github.com/codeshark/codeshark",
21
+ "homepage": "https://github.com/ajashratripathi-crypto/codeshark-cli#readme",
21
22
  "bugs": {
22
- "url": "https://github.com/codeshark/codeshark/issues"
23
+ "url": "https://github.com/ajashratripathi-crypto/codeshark-cli/issues"
23
24
  },
24
25
  "publishConfig": {
25
26
  "access": "public"
@@ -41,7 +42,6 @@
41
42
  "ai",
42
43
  "agent",
43
44
  "coding-agent",
44
- "unorouter",
45
45
  "terminal",
46
46
  "llm"
47
47
  ],
@@ -51,4 +51,4 @@
51
51
  "@types/node": "^22.10.2",
52
52
  "typescript": "^5.7.2"
53
53
  }
54
- }
54
+ }