@freesyntax/notch-cli 0.5.17 → 0.5.19
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/dist/apply-patch-EBZ5VLO7.js +15 -0
- package/dist/chunk-3QUV4JEX.js +162 -0
- package/dist/chunk-6CZCFY6H.js +98 -0
- package/dist/chunk-6U3ZAGYA.js +38 -0
- package/dist/chunk-75K7DQVI.js +630 -0
- package/dist/chunk-C4CPDDMN.js +246 -0
- package/dist/chunk-CQMAVWLJ.js +134 -0
- package/dist/chunk-FAULT7VE.js +139 -0
- package/dist/chunk-FFB7GK3Y.js +72 -0
- package/dist/chunk-GBZGR6ID.js +174 -0
- package/dist/chunk-KZAS754V.js +118 -0
- package/dist/chunk-O3WZW7GS.js +35 -0
- package/dist/chunk-TH6GKC7E.js +315 -0
- package/dist/chunk-UR4XL6OM.js +104 -0
- package/dist/chunk-W4FAGQFL.js +171 -0
- package/dist/chunk-YAYPQTOU.js +53 -0
- package/dist/edit-FXWXOFAF.js +7 -0
- package/dist/git-XVWI2BT7.js +7 -0
- package/dist/github-DOZ2MVQE.js +7 -0
- package/dist/glob-XSBN4MDB.js +7 -0
- package/dist/grep-2A42QPWM.js +7 -0
- package/dist/index.js +1691 -3152
- package/dist/lsp-WUEGBQ3F.js +7 -0
- package/dist/notebook-5U6PAF6M.js +7 -0
- package/dist/plugins-GJIUZCJ5.js +7 -0
- package/dist/read-LY2VGCZY.js +7 -0
- package/dist/server-4JRQH3DT.js +1479 -0
- package/dist/shell-RGXMLRLH.js +7 -0
- package/dist/task-VIJ3N5EB.js +11 -0
- package/dist/tools-XKVTMNR5.js +31 -0
- package/dist/web-fetch-XOH5PUCP.js +7 -0
- package/dist/write-DOLDW7HM.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PatchApplyError,
|
|
3
|
+
PatchParseError,
|
|
4
|
+
applyHunk,
|
|
5
|
+
applyPatchTool,
|
|
6
|
+
parsePatch
|
|
7
|
+
} from "./chunk-C4CPDDMN.js";
|
|
8
|
+
import "./chunk-3RG5ZIWI.js";
|
|
9
|
+
export {
|
|
10
|
+
PatchApplyError,
|
|
11
|
+
PatchParseError,
|
|
12
|
+
applyHunk,
|
|
13
|
+
applyPatchTool,
|
|
14
|
+
parsePatch
|
|
15
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/plugins/discovery.ts
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
async function discoverPlugins(projectRoot) {
|
|
6
|
+
const globalDir = path.join(os.homedir(), ".notch", "plugins");
|
|
7
|
+
const projectDir = path.join(projectRoot, ".notch", "plugins");
|
|
8
|
+
const plugins = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const plugin of await scanDirectory(globalDir)) {
|
|
10
|
+
plugins.set(plugin.name, plugin);
|
|
11
|
+
}
|
|
12
|
+
for (const plugin of await scanDirectory(projectDir)) {
|
|
13
|
+
plugins.set(plugin.name, plugin);
|
|
14
|
+
}
|
|
15
|
+
return [...plugins.values()];
|
|
16
|
+
}
|
|
17
|
+
async function scanDirectory(dir) {
|
|
18
|
+
const results = [];
|
|
19
|
+
try {
|
|
20
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
if (!entry.isDirectory()) continue;
|
|
23
|
+
const pluginDir = path.join(dir, entry.name);
|
|
24
|
+
const pkgPath = path.join(pluginDir, "package.json");
|
|
25
|
+
try {
|
|
26
|
+
const raw = await fs.readFile(pkgPath, "utf-8");
|
|
27
|
+
const pkg = JSON.parse(raw);
|
|
28
|
+
if (pkg["notch-plugin"] && pkg.name) {
|
|
29
|
+
results.push({
|
|
30
|
+
name: pkg.name,
|
|
31
|
+
version: pkg.version ?? "0.0.0",
|
|
32
|
+
description: pkg.description ?? "",
|
|
33
|
+
path: pluginDir,
|
|
34
|
+
manifest: pkg["notch-plugin"]
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/plugins/loader.ts
|
|
46
|
+
import path2 from "path";
|
|
47
|
+
import { pathToFileURL } from "url";
|
|
48
|
+
|
|
49
|
+
// src/commands/registry.ts
|
|
50
|
+
var registry = /* @__PURE__ */ new Map();
|
|
51
|
+
function registerCommand(name, handler) {
|
|
52
|
+
registry.set(name, handler);
|
|
53
|
+
}
|
|
54
|
+
async function dispatchCommand(input, ctx) {
|
|
55
|
+
for (const [name, handler] of registry) {
|
|
56
|
+
if (input === name || input.startsWith(name + " ")) {
|
|
57
|
+
const args = input.slice(name.length).trim();
|
|
58
|
+
await handler(args, ctx);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/plugins/loader.ts
|
|
66
|
+
async function loadPlugin(discovered, projectRoot, log) {
|
|
67
|
+
const entryPath = path2.resolve(discovered.path, discovered.manifest.main);
|
|
68
|
+
const tools = [];
|
|
69
|
+
const hooks = [];
|
|
70
|
+
const ctx = {
|
|
71
|
+
cwd: projectRoot,
|
|
72
|
+
log,
|
|
73
|
+
registerTool(tool) {
|
|
74
|
+
tools.push(tool);
|
|
75
|
+
},
|
|
76
|
+
registerCommand(name, handler) {
|
|
77
|
+
registerCommand(name, handler);
|
|
78
|
+
},
|
|
79
|
+
registerHook(hook) {
|
|
80
|
+
hooks.push(hook);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
try {
|
|
84
|
+
const moduleUrl = pathToFileURL(entryPath).href;
|
|
85
|
+
const mod = await import(moduleUrl);
|
|
86
|
+
const plugin = mod.default ?? mod;
|
|
87
|
+
if (typeof plugin.activate !== "function") {
|
|
88
|
+
log(`Plugin ${discovered.name}: no activate() function \u2014 skipping`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
await plugin.activate(ctx);
|
|
92
|
+
return {
|
|
93
|
+
name: discovered.name,
|
|
94
|
+
version: discovered.version,
|
|
95
|
+
description: discovered.description,
|
|
96
|
+
path: discovered.path,
|
|
97
|
+
instance: plugin,
|
|
98
|
+
tools,
|
|
99
|
+
hooks
|
|
100
|
+
};
|
|
101
|
+
} catch (err) {
|
|
102
|
+
log(`Plugin ${discovered.name} failed to load: ${err.message}`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/plugins/index.ts
|
|
108
|
+
var PluginManager = class {
|
|
109
|
+
plugins = [];
|
|
110
|
+
initialized = false;
|
|
111
|
+
/**
|
|
112
|
+
* Discover and load all plugins. Call once at startup.
|
|
113
|
+
*/
|
|
114
|
+
async init(projectRoot, log) {
|
|
115
|
+
if (this.initialized) return this.plugins.length;
|
|
116
|
+
const discovered = await discoverPlugins(projectRoot);
|
|
117
|
+
if (discovered.length === 0) {
|
|
118
|
+
this.initialized = true;
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
for (const d of discovered) {
|
|
122
|
+
const loaded = await loadPlugin(d, projectRoot, log);
|
|
123
|
+
if (loaded) {
|
|
124
|
+
this.plugins.push(loaded);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
this.initialized = true;
|
|
128
|
+
return this.plugins.length;
|
|
129
|
+
}
|
|
130
|
+
/** All tools registered by plugins */
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
132
|
+
getTools() {
|
|
133
|
+
return this.plugins.flatMap((p) => p.tools);
|
|
134
|
+
}
|
|
135
|
+
/** All hooks registered by plugins */
|
|
136
|
+
getHooks() {
|
|
137
|
+
return this.plugins.flatMap((p) => p.hooks);
|
|
138
|
+
}
|
|
139
|
+
/** List all loaded plugins */
|
|
140
|
+
list() {
|
|
141
|
+
return [...this.plugins];
|
|
142
|
+
}
|
|
143
|
+
/** Shut down all plugins gracefully */
|
|
144
|
+
async shutdown() {
|
|
145
|
+
for (const p of this.plugins) {
|
|
146
|
+
try {
|
|
147
|
+
await p.instance.deactivate?.();
|
|
148
|
+
} catch (err) {
|
|
149
|
+
console.warn(` Plugin ${p.name} deactivation failed: ${err.message}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
this.plugins = [];
|
|
153
|
+
this.initialized = false;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var pluginManager = new PluginManager();
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
registerCommand,
|
|
160
|
+
dispatchCommand,
|
|
161
|
+
pluginManager
|
|
162
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/tools/grep.ts
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var parameters = z.object({
|
|
7
|
+
pattern: z.string().describe("Regex pattern to search for"),
|
|
8
|
+
path: z.string().optional().describe("File or directory to search (defaults to project root)"),
|
|
9
|
+
glob: z.string().optional().describe('Glob filter, e.g. "*.ts" or "**/*.tsx"'),
|
|
10
|
+
context: z.number().optional().default(0).describe("Lines of context around each match"),
|
|
11
|
+
max_results: z.number().optional().default(50).describe("Maximum number of matches to return")
|
|
12
|
+
});
|
|
13
|
+
var grepTool = {
|
|
14
|
+
name: "grep",
|
|
15
|
+
description: "Search file contents by regex pattern. Returns matching lines with file paths and line numbers. Supports glob filtering and context lines.",
|
|
16
|
+
parameters,
|
|
17
|
+
async execute(params, ctx) {
|
|
18
|
+
const searchPath = params.path ? path.isAbsolute(params.path) ? params.path : path.resolve(ctx.cwd, params.path) : ctx.cwd;
|
|
19
|
+
try {
|
|
20
|
+
const rgArgs = [
|
|
21
|
+
"rg",
|
|
22
|
+
"--no-heading",
|
|
23
|
+
"--line-number",
|
|
24
|
+
"--color=never",
|
|
25
|
+
`--max-count=${params.max_results}`,
|
|
26
|
+
params.context ? `-C ${params.context}` : "",
|
|
27
|
+
params.glob ? `--glob "${params.glob}"` : "",
|
|
28
|
+
"--",
|
|
29
|
+
JSON.stringify(params.pattern),
|
|
30
|
+
searchPath
|
|
31
|
+
].filter(Boolean).join(" ");
|
|
32
|
+
const output = execSync(rgArgs, {
|
|
33
|
+
cwd: ctx.cwd,
|
|
34
|
+
encoding: "utf-8",
|
|
35
|
+
timeout: 15e3,
|
|
36
|
+
maxBuffer: 5 * 1024 * 1024
|
|
37
|
+
});
|
|
38
|
+
return { content: output || "(no matches)" };
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const regex = new RegExp(params.pattern, "g");
|
|
43
|
+
const results = [];
|
|
44
|
+
async function searchDir(dir) {
|
|
45
|
+
if (results.length >= (params.max_results ?? 50)) return;
|
|
46
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
if (results.length >= (params.max_results ?? 50)) return;
|
|
49
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
50
|
+
const full = path.join(dir, entry.name);
|
|
51
|
+
if (entry.isDirectory()) {
|
|
52
|
+
await searchDir(full);
|
|
53
|
+
} else if (entry.isFile()) {
|
|
54
|
+
if (params.glob) {
|
|
55
|
+
const ext = params.glob.replace(/^\*+\.?/, "");
|
|
56
|
+
if (ext && !entry.name.endsWith(ext)) continue;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const content = await fs.readFile(full, "utf-8");
|
|
60
|
+
const lines = content.split("\n");
|
|
61
|
+
for (let i = 0; i < lines.length; i++) {
|
|
62
|
+
if (regex.test(lines[i])) {
|
|
63
|
+
const rel = path.relative(ctx.cwd, full);
|
|
64
|
+
results.push(`${rel}:${i + 1}:${lines[i]}`);
|
|
65
|
+
regex.lastIndex = 0;
|
|
66
|
+
if (results.length >= (params.max_results ?? 50)) return;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const stat = await fs.stat(searchPath);
|
|
75
|
+
if (stat.isFile()) {
|
|
76
|
+
const content = await fs.readFile(searchPath, "utf-8");
|
|
77
|
+
const lines = content.split("\n");
|
|
78
|
+
const rel = path.relative(ctx.cwd, searchPath);
|
|
79
|
+
for (let i = 0; i < lines.length; i++) {
|
|
80
|
+
if (regex.test(lines[i])) {
|
|
81
|
+
results.push(`${rel}:${i + 1}:${lines[i]}`);
|
|
82
|
+
regex.lastIndex = 0;
|
|
83
|
+
if (results.length >= (params.max_results ?? 50)) break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
await searchDir(searchPath);
|
|
88
|
+
}
|
|
89
|
+
return { content: results.join("\n") || "(no matches)" };
|
|
90
|
+
} catch (err) {
|
|
91
|
+
return { content: `Search error: ${err.message}`, isError: true };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
grepTool
|
|
98
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/tools/glob.ts
|
|
2
|
+
import { glob as globFn } from "glob";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
var parameters = z.object({
|
|
6
|
+
pattern: z.string().describe('Glob pattern, e.g. "**/*.ts" or "src/**/*.tsx"'),
|
|
7
|
+
path: z.string().optional().describe("Directory to search (defaults to project root)")
|
|
8
|
+
});
|
|
9
|
+
var globTool = {
|
|
10
|
+
name: "glob",
|
|
11
|
+
description: "Find files matching a glob pattern. Returns relative paths sorted by modification time. Ignores node_modules and .git by default.",
|
|
12
|
+
parameters,
|
|
13
|
+
async execute(params, ctx) {
|
|
14
|
+
const searchDir = params.path ? path.isAbsolute(params.path) ? params.path : path.resolve(ctx.cwd, params.path) : ctx.cwd;
|
|
15
|
+
try {
|
|
16
|
+
const matches = await globFn(params.pattern, {
|
|
17
|
+
cwd: searchDir,
|
|
18
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**"],
|
|
19
|
+
nodir: true,
|
|
20
|
+
dot: false
|
|
21
|
+
});
|
|
22
|
+
if (matches.length === 0) {
|
|
23
|
+
return { content: `No files matching "${params.pattern}" in ${path.relative(ctx.cwd, searchDir) || "."}` };
|
|
24
|
+
}
|
|
25
|
+
const relative = matches.map((m) => path.relative(ctx.cwd, path.resolve(searchDir, m)));
|
|
26
|
+
return {
|
|
27
|
+
content: `Found ${relative.length} file(s):
|
|
28
|
+
${relative.join("\n")}`
|
|
29
|
+
};
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return { content: `Glob error: ${err.message}`, isError: true };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
globTool
|
|
38
|
+
};
|