@freesyntax/notch-cli 0.5.17 → 0.5.20

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 (44) hide show
  1. package/dist/apply-patch-D5PDUXUC.js +14 -0
  2. package/dist/{auth-S3FIB42I.js → auth-JQX6MHJG.js} +0 -1
  3. package/dist/builtins/archimedes.toml +18 -0
  4. package/dist/builtins/awaiter.toml +18 -0
  5. package/dist/builtins/euclid.toml +18 -0
  6. package/dist/builtins/hypatia.toml +18 -0
  7. package/dist/builtins/kepler.toml +18 -0
  8. package/dist/builtins/plato.toml +18 -0
  9. package/dist/builtins/ptolemy.toml +18 -0
  10. package/dist/builtins/pythagoras.toml +18 -0
  11. package/dist/chunk-3QUV4JEX.js +162 -0
  12. package/dist/chunk-6CZCFY6H.js +98 -0
  13. package/dist/chunk-6U3ZAGYA.js +38 -0
  14. package/dist/chunk-C4CPDDMN.js +246 -0
  15. package/dist/chunk-CQMAVWLJ.js +134 -0
  16. package/dist/chunk-FAULT7VE.js +139 -0
  17. package/dist/chunk-FFB7GK3Y.js +72 -0
  18. package/dist/chunk-GBZGR6ID.js +174 -0
  19. package/dist/chunk-KZAS754V.js +118 -0
  20. package/dist/chunk-O3WZW7GS.js +35 -0
  21. package/dist/chunk-TH6GKC7E.js +315 -0
  22. package/dist/chunk-UR4XL6OM.js +104 -0
  23. package/dist/chunk-W4FAGQFL.js +171 -0
  24. package/dist/chunk-YAYPQTOU.js +53 -0
  25. package/dist/chunk-YBYF7L4A.js +2607 -0
  26. package/dist/{compression-LPFNGAV6.js → compression-UTB2Y4BB.js} +0 -1
  27. package/dist/edit-JEFEK43H.js +6 -0
  28. package/dist/git-5T5TSQTX.js +6 -0
  29. package/dist/github-DWRGWX6U.js +6 -0
  30. package/dist/glob-BI3P4C7Q.js +6 -0
  31. package/dist/grep-VZ3I5GNW.js +6 -0
  32. package/dist/index.js +4398 -3447
  33. package/dist/lsp-UPY6I3L7.js +6 -0
  34. package/dist/notebook-FXJBTSPA.js +6 -0
  35. package/dist/plugins-OG2P75K5.js +6 -0
  36. package/dist/read-OVJG2XKW.js +6 -0
  37. package/dist/server-W7FRCVRZ.js +1477 -0
  38. package/dist/shell-4X545EVN.js +6 -0
  39. package/dist/task-OS3E5F3X.js +10 -0
  40. package/dist/tools-Q7CDHB4K.js +30 -0
  41. package/dist/web-fetch-KNIV3Z3W.js +6 -0
  42. package/dist/write-NNHLOTYK.js +6 -0
  43. package/package.json +5 -4
  44. package/dist/chunk-3RG5ZIWI.js +0 -10
@@ -0,0 +1,104 @@
1
+ // src/tools/task.ts
2
+ import { z } from "zod";
3
+ import chalk from "chalk";
4
+ var tasks = [];
5
+ var nextId = 1;
6
+ var parameters = z.object({
7
+ action: z.enum(["create", "update", "list", "get"]).describe("Action: create (new task), update (change status/subject), list (show all), get (show one)"),
8
+ subject: z.string().optional().describe("Task title \u2014 for create action"),
9
+ description: z.string().optional().describe("Task details \u2014 for create action"),
10
+ task_id: z.number().int().positive().optional().describe("Task ID \u2014 for update/get actions"),
11
+ status: z.enum(["pending", "in_progress", "completed", "failed"]).optional().describe("New status \u2014 for update action")
12
+ });
13
+ function formatTask(t) {
14
+ const icons = {
15
+ pending: "\u25CB",
16
+ in_progress: "\u25D0",
17
+ completed: "\u25CF",
18
+ failed: "\u2717"
19
+ };
20
+ const colors = {
21
+ pending: chalk.gray,
22
+ in_progress: chalk.yellow,
23
+ completed: chalk.green,
24
+ failed: chalk.red
25
+ };
26
+ return `${colors[t.status](icons[t.status])} #${t.id} ${colors[t.status](t.subject)} [${t.status}]`;
27
+ }
28
+ function formatTaskList() {
29
+ if (tasks.length === 0) return "No tasks.";
30
+ return tasks.map(formatTask).join("\n");
31
+ }
32
+ var taskTool = {
33
+ name: "task",
34
+ description: "Manage tasks within the current session. Use this to break complex work into tracked steps. Actions: create (new task), update (change status), list (show all tasks), get (show one task). Mark tasks as in_progress when starting and completed when done.",
35
+ parameters,
36
+ async execute(params, _ctx) {
37
+ switch (params.action) {
38
+ case "create": {
39
+ if (!params.subject) {
40
+ return { content: "subject is required for create action.", isError: true };
41
+ }
42
+ const task = {
43
+ id: nextId++,
44
+ subject: params.subject,
45
+ description: params.description,
46
+ status: "pending",
47
+ createdAt: Date.now(),
48
+ updatedAt: Date.now()
49
+ };
50
+ tasks.push(task);
51
+ console.log(chalk.gray(` ${formatTask(task)}`));
52
+ return { content: `Task #${task.id} created: ${task.subject}` };
53
+ }
54
+ case "update": {
55
+ if (params.task_id === void 0) {
56
+ return { content: "task_id is required for update action.", isError: true };
57
+ }
58
+ const task = tasks.find((t) => t.id === params.task_id);
59
+ if (!task) {
60
+ return { content: `Task #${params.task_id} not found.`, isError: true };
61
+ }
62
+ if (params.status) task.status = params.status;
63
+ if (params.subject) task.subject = params.subject;
64
+ task.updatedAt = Date.now();
65
+ console.log(chalk.gray(` ${formatTask(task)}`));
66
+ return { content: `Task #${task.id} updated: ${task.subject} [${task.status}]` };
67
+ }
68
+ case "list": {
69
+ const output = formatTaskList();
70
+ return { content: output };
71
+ }
72
+ case "get": {
73
+ if (params.task_id === void 0) {
74
+ return { content: "task_id is required for get action.", isError: true };
75
+ }
76
+ const task = tasks.find((t) => t.id === params.task_id);
77
+ if (!task) {
78
+ return { content: `Task #${params.task_id} not found.`, isError: true };
79
+ }
80
+ const details = [
81
+ formatTask(task),
82
+ task.description ? ` ${task.description}` : "",
83
+ ` Created: ${new Date(task.createdAt).toLocaleTimeString()}`,
84
+ ` Updated: ${new Date(task.updatedAt).toLocaleTimeString()}`
85
+ ].filter(Boolean).join("\n");
86
+ return { content: details };
87
+ }
88
+ default:
89
+ return { content: `Unknown action: ${params.action}`, isError: true };
90
+ }
91
+ }
92
+ };
93
+ function getAllTasks() {
94
+ return [...tasks];
95
+ }
96
+ function formatTasksDisplay() {
97
+ return formatTaskList();
98
+ }
99
+
100
+ export {
101
+ taskTool,
102
+ getAllTasks,
103
+ formatTasksDisplay
104
+ };
@@ -0,0 +1,171 @@
1
+ // src/tools/shell.ts
2
+ import { execFile, exec } from "child_process";
3
+ import { promisify } from "util";
4
+ import path from "path";
5
+ import { z } from "zod";
6
+ var execFileAsync = promisify(execFile);
7
+ var execAsync = promisify(exec);
8
+ var BLOCKED_PATTERNS = [
9
+ /rm\s+-rf\s+\/(?!\S)/,
10
+ // rm -rf /
11
+ /mkfs\./,
12
+ // format filesystem
13
+ /dd\s+if=.*of=\/dev/,
14
+ // raw disk write
15
+ /:\(\)\s*\{.*:\|:.*\}/,
16
+ // fork bomb
17
+ /chmod\s+-R\s+777\s+\//,
18
+ // recursive chmod on root
19
+ /curl\s.*\|\s*(?:ba)?sh/,
20
+ // curl | sh (remote code execution)
21
+ /wget\s.*\|\s*(?:ba)?sh/,
22
+ // wget | sh
23
+ />\s*\/dev\/sd[a-z]/,
24
+ // overwrite disk device
25
+ /shutdown|reboot|init\s+[06]/,
26
+ // system shutdown/reboot
27
+ /rm\s+-rf\s+~\//
28
+ // rm -rf ~/
29
+ ];
30
+ var DESTRUCTIVE_PATTERNS = [
31
+ /rm\s+-rf/,
32
+ /rm\s+-r\s/,
33
+ /git\s+push\s+--force(?!\s+--with-lease)/,
34
+ /git\s+reset\s+--hard/,
35
+ /git\s+clean\s+-f/,
36
+ /git\s+checkout\s+--\s*\./,
37
+ /DROP\s+(TABLE|DATABASE)/i,
38
+ /TRUNCATE/i,
39
+ />\s*\/dev\/sd/,
40
+ /docker\s+(rm|rmi|system\s+prune)/,
41
+ /kubectl\s+delete/,
42
+ /npm\s+unpublish/
43
+ ];
44
+ var BLOCKED_ENV_PATTERNS = [
45
+ /\bLD_PRELOAD=/,
46
+ /\bLD_LIBRARY_PATH=/,
47
+ /\bDYLD_INSERT_LIBRARIES=/,
48
+ /\bPATH=\//,
49
+ // Setting PATH to absolute (could shadow binaries)
50
+ /\bHOME=\//,
51
+ /\bSHELL=/
52
+ ];
53
+ var MAX_OUTPUT = 5e4;
54
+ var DEFAULT_TIMEOUT = 3e4;
55
+ var MAX_TIMEOUT = 6e5;
56
+ var parameters = z.object({
57
+ command: z.string().describe("Shell command to execute"),
58
+ timeout: z.number().optional().describe("Timeout in ms (default 30s, max 10m)")
59
+ });
60
+ function validateCommand(command, cwd) {
61
+ for (const pattern of BLOCKED_PATTERNS) {
62
+ if (pattern.test(command)) {
63
+ return `Blocked: this command is too dangerous to execute.`;
64
+ }
65
+ }
66
+ for (const pattern of BLOCKED_ENV_PATTERNS) {
67
+ if (pattern.test(command)) {
68
+ return `Blocked: command attempts to override a protected environment variable.`;
69
+ }
70
+ }
71
+ const pipeSegments = command.split(/\s*\|\s*/);
72
+ for (const segment of pipeSegments) {
73
+ for (const pattern of BLOCKED_PATTERNS) {
74
+ if (pattern.test(segment.trim())) {
75
+ return `Blocked: a pipe segment contains a dangerous command.`;
76
+ }
77
+ }
78
+ }
79
+ const subCommands = [
80
+ ...command.matchAll(/\$\(([^)]+)\)/g),
81
+ ...command.matchAll(/`([^`]+)`/g)
82
+ ];
83
+ for (const match2 of subCommands) {
84
+ for (const pattern of BLOCKED_PATTERNS) {
85
+ if (pattern.test(match2[1])) {
86
+ return `Blocked: command substitution contains a dangerous command.`;
87
+ }
88
+ }
89
+ }
90
+ const fileOpRegex = /(?:^|\s)(?:>|>>|cat|cp|mv|ln|tee|tar|zip|scp|rsync|chmod|chown|rm)\s+(\/(?!tmp\b|dev\/null\b)[^\s]+)/g;
91
+ let match;
92
+ while ((match = fileOpRegex.exec(command)) !== null) {
93
+ const targetPath = path.normalize(match[1]);
94
+ if (!targetPath.startsWith(cwd) && !targetPath.startsWith("/tmp")) {
95
+ return `Blocked: command targets path outside project root: ${targetPath}`;
96
+ }
97
+ }
98
+ if (/(?:^|\s)(?:\.\.\/){3,}/.test(command)) {
99
+ return "Blocked: deep path traversal detected.";
100
+ }
101
+ return null;
102
+ }
103
+ function isDestructive(command) {
104
+ const segments = [command, ...command.split(/\s*\|\s*/)];
105
+ for (const segment of segments) {
106
+ for (const pattern of DESTRUCTIVE_PATTERNS) {
107
+ if (pattern.test(segment)) return true;
108
+ }
109
+ }
110
+ return false;
111
+ }
112
+ var shellTool = {
113
+ name: "shell",
114
+ description: "Execute a shell command in the project directory. Dangerous commands (rm -rf, DROP TABLE, git push --force) require confirmation. Some destructive system commands are blocked entirely.",
115
+ parameters,
116
+ async execute(params, ctx) {
117
+ const { command } = params;
118
+ const maxTimeout = ctx.shellTimeout ?? MAX_TIMEOUT;
119
+ const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, maxTimeout);
120
+ const validationError = validateCommand(command, ctx.cwd);
121
+ if (validationError) {
122
+ return { content: validationError, isError: true };
123
+ }
124
+ if (ctx.requireConfirm && isDestructive(command)) {
125
+ const confirmed = await ctx.confirm(
126
+ `\u26A0 Destructive command: ${command}
127
+ Proceed?`
128
+ );
129
+ if (!confirmed) {
130
+ return { content: "Command cancelled by user.", isError: true };
131
+ }
132
+ }
133
+ try {
134
+ const { stdout, stderr } = await execAsync(command, {
135
+ cwd: ctx.cwd,
136
+ encoding: "utf-8",
137
+ timeout,
138
+ maxBuffer: 10 * 1024 * 1024,
139
+ env: { ...process.env, FORCE_COLOR: "0" }
140
+ });
141
+ const combined = [stdout, stderr].filter(Boolean).join("\n");
142
+ const trimmed = combined.length > MAX_OUTPUT ? combined.slice(0, MAX_OUTPUT) + `
143
+ ... (truncated, ${combined.length} chars total)` : combined;
144
+ return { content: trimmed || "(no output)" };
145
+ } catch (err) {
146
+ const e = err;
147
+ const stderr = e.stderr ?? "";
148
+ const stdout = e.stdout ?? "";
149
+ const combined = [stdout, stderr].filter(Boolean).join("\n");
150
+ const trimmed = combined.length > MAX_OUTPUT ? combined.slice(0, MAX_OUTPUT) + "\n... (truncated)" : combined;
151
+ if (e.killed && e.signal === "SIGTERM") {
152
+ return {
153
+ content: `Command timed out after ${(timeout / 1e3).toFixed(0)}s: ${command}
154
+
155
+ Partial output:
156
+ ${trimmed || "(none)"}`,
157
+ isError: true
158
+ };
159
+ }
160
+ return {
161
+ content: `Command failed (exit ${e.status ?? e.code ?? "unknown"}):
162
+ ${trimmed || e.message || "Unknown error"}`,
163
+ isError: true
164
+ };
165
+ }
166
+ }
167
+ };
168
+
169
+ export {
170
+ shellTool
171
+ };
@@ -0,0 +1,53 @@
1
+ // src/tools/edit.ts
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { z } from "zod";
5
+ var parameters = z.object({
6
+ path: z.string().describe("Relative or absolute path to the file"),
7
+ old_string: z.string().describe("Exact string to find and replace (must be unique in file)"),
8
+ new_string: z.string().describe("Replacement string"),
9
+ replace_all: z.boolean().optional().default(false).describe("Replace all occurrences")
10
+ });
11
+ var editTool = {
12
+ name: "edit",
13
+ description: "Perform exact string replacement in a file. old_string must match exactly and be unique unless replace_all is true. Use for surgical edits.",
14
+ parameters,
15
+ async execute(params, ctx) {
16
+ const filePath = path.isAbsolute(params.path) ? params.path : path.resolve(ctx.cwd, params.path);
17
+ try {
18
+ const content = await fs.readFile(filePath, "utf-8");
19
+ if (!content.includes(params.old_string)) {
20
+ return {
21
+ content: `old_string not found in ${filePath}. Make sure it matches exactly (including whitespace and indentation).`,
22
+ isError: true
23
+ };
24
+ }
25
+ if (!params.replace_all) {
26
+ const firstIdx = content.indexOf(params.old_string);
27
+ const secondIdx = content.indexOf(params.old_string, firstIdx + 1);
28
+ if (secondIdx !== -1) {
29
+ return {
30
+ content: `old_string appears multiple times in ${filePath}. Provide more surrounding context to make it unique, or set replace_all: true.`,
31
+ isError: true
32
+ };
33
+ }
34
+ }
35
+ const newContent = params.replace_all ? content.replaceAll(params.old_string, params.new_string) : content.replace(params.old_string, params.new_string);
36
+ await fs.writeFile(filePath, newContent, "utf-8");
37
+ const oldLines = params.old_string.split("\n").length;
38
+ const newLines = params.new_string.split("\n").length;
39
+ return {
40
+ content: `Edited ${filePath}: replaced ${oldLines} line(s) with ${newLines} line(s)`
41
+ };
42
+ } catch (err) {
43
+ if (err.code === "ENOENT") {
44
+ return { content: `File not found: ${filePath}`, isError: true };
45
+ }
46
+ return { content: `Error editing ${filePath}: ${err.message}`, isError: true };
47
+ }
48
+ }
49
+ };
50
+
51
+ export {
52
+ editTool
53
+ };