@morphllm/gitmorph-sdk 0.2.1 → 0.3.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 +429 -0
- package/dist/ai/index.d.ts +48 -0
- package/dist/ai/index.js +25 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/anthropic/index.d.ts +85 -0
- package/dist/anthropic/index.js +64 -0
- package/dist/anthropic/index.js.map +1 -0
- package/dist/chunk-A3AOZFPE.js +474 -0
- package/dist/chunk-A3AOZFPE.js.map +1 -0
- package/dist/chunk-FXEX72CO.js +43 -0
- package/dist/chunk-FXEX72CO.js.map +1 -0
- package/dist/chunk-JXXUBMF6.js +61 -0
- package/dist/chunk-JXXUBMF6.js.map +1 -0
- package/dist/chunk-QT3Y4ZIS.js +547 -0
- package/dist/chunk-QT3Y4ZIS.js.map +1 -0
- package/dist/{types.d.ts → client-B_I_0i1T.d.ts} +69 -37
- package/dist/index.d.ts +21 -5
- package/dist/index.js +3 -547
- package/dist/index.js.map +1 -0
- package/dist/instructions-BE0g1eFs.d.ts +284 -0
- package/dist/mcp/bin.d.ts +1 -0
- package/dist/mcp/bin.js +21 -0
- package/dist/mcp/bin.js.map +1 -0
- package/dist/mcp/index.d.ts +29 -0
- package/dist/mcp/index.js +5 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/openai/index.d.ts +60 -0
- package/dist/openai/index.js +75 -0
- package/dist/openai/index.js.map +1 -0
- package/package.json +56 -8
- package/dist/api.d.ts +0 -10
- package/dist/api.d.ts.map +0 -1
- package/dist/client.d.ts +0 -13
- package/dist/client.d.ts.map +0 -1
- package/dist/config.d.ts +0 -8
- package/dist/config.d.ts.map +0 -1
- package/dist/errors.d.ts +0 -18
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/mirror.d.ts +0 -6
- package/dist/mirror.d.ts.map +0 -1
- package/dist/repo.d.ts +0 -28
- package/dist/repo.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -5
- package/dist/utils.d.ts.map +0 -1
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// src/tools/schemas.ts
|
|
4
|
+
var REPO_SLUG = /^[^/\s]+\/[^/\s]+$/;
|
|
5
|
+
var repoField = z.string().regex(REPO_SLUG, "Expected 'owner/name', e.g. 'facebook/react'").describe("Repository in 'owner/name' form, e.g. 'facebook/react'.");
|
|
6
|
+
var refField = z.string().optional().describe(
|
|
7
|
+
"Branch name, tag, or commit SHA. Defaults to the repository's default branch."
|
|
8
|
+
);
|
|
9
|
+
var gmReadFileSchema = z.object({
|
|
10
|
+
path: z.string().min(1).describe("File path relative to the repository root, e.g. 'src/index.ts'."),
|
|
11
|
+
ref: refField,
|
|
12
|
+
startLine: z.number().int().min(1).optional().describe(
|
|
13
|
+
"1-indexed start line (inclusive). Requires endLine. Omit both to read the whole file."
|
|
14
|
+
),
|
|
15
|
+
endLine: z.number().int().min(1).optional().describe("1-indexed end line (inclusive). Requires startLine.")
|
|
16
|
+
});
|
|
17
|
+
var gmReadFileDescription = `
|
|
18
|
+
Read a single file from a Git repository. Returns the file's text content and
|
|
19
|
+
total line count. When startLine and endLine are both provided, returns only
|
|
20
|
+
that line range (1-indexed, inclusive on both ends).
|
|
21
|
+
|
|
22
|
+
Use this when: you already know the exact file path you want to inspect \u2014
|
|
23
|
+
typically after gm_grep or gm_glob has pointed you at it. Prefer a line range
|
|
24
|
+
over reading the whole file for anything over ~200 lines.
|
|
25
|
+
|
|
26
|
+
Do not use this when: you don't yet know the file path \u2014 use gm_glob to find
|
|
27
|
+
files by name or gm_grep to find files by content first. For multiple files
|
|
28
|
+
at once, prefer gm_read_files.
|
|
29
|
+
|
|
30
|
+
Example: read lines 1-50 of package.json on the main branch:
|
|
31
|
+
{ path: "package.json", startLine: 1, endLine: 50 }
|
|
32
|
+
`.trim();
|
|
33
|
+
var gmReadFilesSchema = z.object({
|
|
34
|
+
paths: z.array(z.string().min(1)).min(1).max(50).describe("List of file paths to read, relative to the repository root."),
|
|
35
|
+
ref: refField
|
|
36
|
+
});
|
|
37
|
+
var gmReadFilesDescription = `
|
|
38
|
+
Read multiple files from a Git repository in a single call. Returns an array
|
|
39
|
+
of file contents in the same order as the input paths; missing files come
|
|
40
|
+
back as null.
|
|
41
|
+
|
|
42
|
+
Use this when: you have several known file paths to inspect together (e.g.
|
|
43
|
+
package.json + tsconfig.json + README.md). Much faster than calling
|
|
44
|
+
gm_read_file repeatedly \u2014 one round trip instead of N.
|
|
45
|
+
|
|
46
|
+
Do not use this when: you only need one file (use gm_read_file), when you
|
|
47
|
+
don't know the paths yet (use gm_glob or gm_grep first), or when files are
|
|
48
|
+
large \u2014 this tool returns whole files, not line ranges.
|
|
49
|
+
|
|
50
|
+
Example: read three config files at once:
|
|
51
|
+
{ paths: ["package.json", "tsconfig.json", ".eslintrc.json"] }
|
|
52
|
+
`.trim();
|
|
53
|
+
var gmGrepSchema = z.object({
|
|
54
|
+
pattern: z.string().min(1).describe(
|
|
55
|
+
"Search pattern. Supports regex; also works as a plain substring. Case-insensitive by default."
|
|
56
|
+
),
|
|
57
|
+
language: z.string().optional().describe(
|
|
58
|
+
"Restrict results to files of this language (e.g. 'TypeScript', 'Python', 'Go')."
|
|
59
|
+
),
|
|
60
|
+
caseSensitive: z.boolean().optional().describe("Make the pattern case-sensitive. Default: false."),
|
|
61
|
+
maxMatches: z.number().int().min(1).max(50).optional().describe("Maximum matches to return (1-50). Default: 20."),
|
|
62
|
+
page: z.number().int().min(1).optional().describe("Page number for pagination (1-indexed).")
|
|
63
|
+
});
|
|
64
|
+
var gmGrepDescription = `
|
|
65
|
+
Search file contents within a single repository using regex or keyword.
|
|
66
|
+
Returns matching lines with file paths and line numbers. Runs on a
|
|
67
|
+
pre-indexed server-side mirror \u2014 no cloning, sub-second on large repos.
|
|
68
|
+
|
|
69
|
+
Use this when: you know roughly what text you're looking for and want to
|
|
70
|
+
find where in the codebase it lives \u2014 function names, config keys, error
|
|
71
|
+
strings, imports, comments, regex patterns.
|
|
72
|
+
|
|
73
|
+
Do not use this when: you don't yet know which repo to search (use
|
|
74
|
+
gm_grep_all instead), when you want to enumerate files by name or extension
|
|
75
|
+
(use gm_glob), or when you already have a specific file path (use
|
|
76
|
+
gm_read_file).
|
|
77
|
+
|
|
78
|
+
Example: find every React hook definition in facebook/react:
|
|
79
|
+
{ pattern: "^export function use[A-Z]", language: "TypeScript" }
|
|
80
|
+
`.trim();
|
|
81
|
+
var gmGlobSchema = z.object({
|
|
82
|
+
patterns: z.array(z.string().min(1)).min(1).max(20).describe(
|
|
83
|
+
"Doublestar glob patterns. Use '**/*.ts' for recursive, '!**/*.test.ts' to exclude. Multiple patterns are OR-ed."
|
|
84
|
+
),
|
|
85
|
+
ref: refField,
|
|
86
|
+
prefix: z.string().optional().describe("Optional directory prefix to narrow the search, e.g. 'src/'."),
|
|
87
|
+
limit: z.number().int().min(1).max(5e3).optional().describe("Maximum results (default 1000, max 5000).")
|
|
88
|
+
});
|
|
89
|
+
var gmGlobDescription = `
|
|
90
|
+
Find files in a repository by path pattern using doublestar globs. Returns
|
|
91
|
+
matching paths (and sizes) \u2014 contents are not included. Fast, uses the
|
|
92
|
+
cached repo tree.
|
|
93
|
+
|
|
94
|
+
Use this when: you want to enumerate files by name, extension, or directory
|
|
95
|
+
structure \u2014 'all TypeScript files', 'every test file under packages/',
|
|
96
|
+
'config files at the repo root'.
|
|
97
|
+
|
|
98
|
+
Do not use this when: you want to search file contents (use gm_grep), when
|
|
99
|
+
you already know the exact paths (go straight to gm_read_file or
|
|
100
|
+
gm_read_files), or when you want directory-only listing (use gm_list_dir).
|
|
101
|
+
|
|
102
|
+
Example: all TypeScript source files excluding tests:
|
|
103
|
+
{ patterns: ["src/**/*.ts", "!**/*.test.ts", "!**/*.d.ts"] }
|
|
104
|
+
`.trim();
|
|
105
|
+
var gmListDirSchema = z.object({
|
|
106
|
+
path: z.string().optional().describe("Directory path to list, e.g. 'src'. Omit for the repo root."),
|
|
107
|
+
ref: refField,
|
|
108
|
+
recursive: z.boolean().optional().describe(
|
|
109
|
+
"Walk subdirectories recursively. Default: false. Be careful \u2014 recursive listings on large repos can be huge."
|
|
110
|
+
)
|
|
111
|
+
});
|
|
112
|
+
var gmListDirDescription = `
|
|
113
|
+
List the entries (files and subdirectories) in a directory. Returns each
|
|
114
|
+
entry's path, type ('file' or 'dir'), and size.
|
|
115
|
+
|
|
116
|
+
Use this when: you want to see the immediate structure of a directory, or
|
|
117
|
+
check which top-level files exist before diving in.
|
|
118
|
+
|
|
119
|
+
Do not use this when: you want to find files by pattern (use gm_glob \u2014 much
|
|
120
|
+
more efficient for filtering), when recursive listing would return thousands
|
|
121
|
+
of entries (use gm_glob with a prefix instead), or when you want file
|
|
122
|
+
contents (use gm_read_file).
|
|
123
|
+
|
|
124
|
+
Example: list the top level of the src directory:
|
|
125
|
+
{ path: "src", recursive: false }
|
|
126
|
+
`.trim();
|
|
127
|
+
var gmListBranchesSchema = z.object({
|
|
128
|
+
page: z.number().int().min(1).optional().describe("Page number (1-indexed)."),
|
|
129
|
+
limit: z.number().int().min(1).max(100).optional().describe("Results per page (default 50, max 100).")
|
|
130
|
+
});
|
|
131
|
+
var gmListBranchesDescription = `
|
|
132
|
+
List branches in a repository with the latest commit on each. Useful for
|
|
133
|
+
discovering active development branches, release branches, or the default
|
|
134
|
+
branch.
|
|
135
|
+
|
|
136
|
+
Use this when: you need to know which branches exist, to pick the right
|
|
137
|
+
branch for a subsequent read, or to find a release branch like 'v18' or
|
|
138
|
+
'release/2024-q1'.
|
|
139
|
+
|
|
140
|
+
Do not use this when: you just need the default branch \u2014 the SDK defaults
|
|
141
|
+
to it automatically. Don't use to list commits (use gm_list_commits).
|
|
142
|
+
|
|
143
|
+
Example: page through the first 50 branches:
|
|
144
|
+
{ page: 1, limit: 50 }
|
|
145
|
+
`.trim();
|
|
146
|
+
var gmListCommitsSchema = z.object({
|
|
147
|
+
sha: z.string().optional().describe(
|
|
148
|
+
"Branch name or commit SHA to list commits from. Defaults to the repo's default branch."
|
|
149
|
+
),
|
|
150
|
+
path: z.string().optional().describe(
|
|
151
|
+
"Only include commits that touch this file or directory path."
|
|
152
|
+
),
|
|
153
|
+
since: z.string().optional().describe("ISO 8601 date \u2014 only commits after this date."),
|
|
154
|
+
until: z.string().optional().describe("ISO 8601 date \u2014 only commits before this date."),
|
|
155
|
+
page: z.number().int().min(1).optional().describe("Page number (1-indexed)."),
|
|
156
|
+
limit: z.number().int().min(1).max(100).optional().describe("Results per page (default 50, max 100).")
|
|
157
|
+
});
|
|
158
|
+
var gmListCommitsDescription = `
|
|
159
|
+
List commits in a repository, optionally filtered by branch, file path, or
|
|
160
|
+
date range. Returns SHA, message, author, and parent refs for each commit.
|
|
161
|
+
|
|
162
|
+
Use this when: you want to answer 'what changed', 'when was X introduced',
|
|
163
|
+
'who last touched this file', or to walk history for a specific subtree.
|
|
164
|
+
|
|
165
|
+
Do not use this when: you want the diff of a specific commit (not supported
|
|
166
|
+
in this tool set \u2014 read files at two refs to compare), or when you want
|
|
167
|
+
branch metadata (use gm_list_branches).
|
|
168
|
+
|
|
169
|
+
Example: commits that touched src/hooks in the last 30 days:
|
|
170
|
+
{ path: "src/hooks", since: "2025-10-01T00:00:00Z", limit: 20 }
|
|
171
|
+
`.trim();
|
|
172
|
+
var gmGrepAllSchema = z.object({
|
|
173
|
+
pattern: z.string().min(1).describe(
|
|
174
|
+
"Search pattern. Regex or plain substring. Case-insensitive by default."
|
|
175
|
+
),
|
|
176
|
+
language: z.string().optional().describe("Restrict to files of this language."),
|
|
177
|
+
sortByStars: z.boolean().optional().describe(
|
|
178
|
+
"Sort results so matches from more-starred repos come first. Default: false."
|
|
179
|
+
),
|
|
180
|
+
limit: z.number().int().min(1).max(50).optional().describe("Maximum results (default 20, max 50).")
|
|
181
|
+
});
|
|
182
|
+
var gmGrepAllDescription = `
|
|
183
|
+
Search code across ALL mirrored repositories at once. Returns matches
|
|
184
|
+
grouped by repo and file. Slower than single-repo gm_grep but essential
|
|
185
|
+
when you don't yet know where code lives.
|
|
186
|
+
|
|
187
|
+
Use this when: you're looking for a pattern across the ecosystem \u2014 'who
|
|
188
|
+
else uses this function', 'which repos call this API', 'find all examples
|
|
189
|
+
of X'. Also the right tool when the user asks a question without naming a
|
|
190
|
+
repo.
|
|
191
|
+
|
|
192
|
+
Do not use this when: you already know which repo to search (use gm_grep \u2014
|
|
193
|
+
much faster and scoped). Don't use to find files by name (use gm_glob on a
|
|
194
|
+
specific repo).
|
|
195
|
+
|
|
196
|
+
Example: find every repo that uses the 'fastApply' identifier:
|
|
197
|
+
{ pattern: "fastApply", language: "TypeScript", sortByStars: true, limit: 10 }
|
|
198
|
+
`.trim();
|
|
199
|
+
var gmGetRepoInfoSchema = z.object({
|
|
200
|
+
repo: repoField
|
|
201
|
+
});
|
|
202
|
+
var gmGetRepoInfoDescription = `
|
|
203
|
+
Fetch metadata for a repository: default branch, stars, language, size,
|
|
204
|
+
description, open issues, last update. No file contents are returned.
|
|
205
|
+
|
|
206
|
+
Use this when: you need the default branch name, want to know how popular
|
|
207
|
+
or active a repo is, or need basic description/language info to orient
|
|
208
|
+
yourself before exploring.
|
|
209
|
+
|
|
210
|
+
Do not use this when: you want to read files or search code \u2014 this is
|
|
211
|
+
metadata only.
|
|
212
|
+
|
|
213
|
+
Example: get metadata for facebook/react:
|
|
214
|
+
{ repo: "facebook/react" }
|
|
215
|
+
`.trim();
|
|
216
|
+
var gmMirrorSchema = z.object({
|
|
217
|
+
source: z.string().min(1).describe(
|
|
218
|
+
"Source URL or slug \u2014 'owner/repo' (GitHub default) or full URL like 'https://gitlab.com/org/repo'."
|
|
219
|
+
),
|
|
220
|
+
repoName: z.string().optional().describe("Override the destination repository name."),
|
|
221
|
+
private: z.boolean().optional().describe("Mark the mirrored repo as private. Default: false."),
|
|
222
|
+
issues: z.boolean().optional().describe("Mirror issues. Default: false."),
|
|
223
|
+
pullRequests: z.boolean().optional().describe("Mirror pull requests. Default: false."),
|
|
224
|
+
releases: z.boolean().optional().describe("Mirror releases. Default: false.")
|
|
225
|
+
});
|
|
226
|
+
var gmMirrorDescription = `
|
|
227
|
+
Mirror a repository from GitHub/GitLab/Gitea into GitMorph so subsequent
|
|
228
|
+
read/grep/glob calls work against it. This triggers a server-side clone
|
|
229
|
+
that can take seconds to minutes for large repos.
|
|
230
|
+
|
|
231
|
+
Use this when: the user asks for a repo that isn't yet mirrored and you
|
|
232
|
+
explicitly need to fetch it first. This tool is disabled by default \u2014
|
|
233
|
+
callers opt in via includeMirror.
|
|
234
|
+
|
|
235
|
+
Do not use this when: the repo is already available via gm_grep_all or
|
|
236
|
+
gm_get_repo_info, or when you're speculating \u2014 mirroring is a write-ish
|
|
237
|
+
operation with real cost. Only use when the user has explicitly asked.
|
|
238
|
+
|
|
239
|
+
Example: mirror facebook/react from GitHub:
|
|
240
|
+
{ source: "facebook/react" }
|
|
241
|
+
`.trim();
|
|
242
|
+
|
|
243
|
+
// src/tools/registry.ts
|
|
244
|
+
var GITMORPH_TOOLS = [
|
|
245
|
+
{
|
|
246
|
+
name: "gm_read_file",
|
|
247
|
+
description: gmReadFileDescription,
|
|
248
|
+
schema: gmReadFileSchema,
|
|
249
|
+
repoScoped: true,
|
|
250
|
+
execute: async ({ getRepo }, input) => {
|
|
251
|
+
const repo = getRepo(input.repo);
|
|
252
|
+
const hasRange = input.startLine !== void 0 && input.endLine !== void 0;
|
|
253
|
+
return repo.readFile(input.path, {
|
|
254
|
+
ref: input.ref,
|
|
255
|
+
lines: hasRange ? [{ start: input.startLine, end: input.endLine }] : void 0
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "gm_read_files",
|
|
261
|
+
description: gmReadFilesDescription,
|
|
262
|
+
schema: gmReadFilesSchema,
|
|
263
|
+
repoScoped: true,
|
|
264
|
+
execute: async ({ getRepo }, input) => {
|
|
265
|
+
const repo = getRepo(input.repo);
|
|
266
|
+
return repo.getFileContents(input.paths, { ref: input.ref });
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: "gm_grep",
|
|
271
|
+
description: gmGrepDescription,
|
|
272
|
+
schema: gmGrepSchema,
|
|
273
|
+
repoScoped: true,
|
|
274
|
+
execute: async ({ getRepo }, input) => {
|
|
275
|
+
const repo = getRepo(input.repo);
|
|
276
|
+
return repo.grep({
|
|
277
|
+
pattern: input.pattern,
|
|
278
|
+
language: input.language,
|
|
279
|
+
caseSensitive: input.caseSensitive,
|
|
280
|
+
maxMatches: input.maxMatches,
|
|
281
|
+
page: input.page
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "gm_glob",
|
|
287
|
+
description: gmGlobDescription,
|
|
288
|
+
schema: gmGlobSchema,
|
|
289
|
+
repoScoped: true,
|
|
290
|
+
execute: async ({ getRepo }, input) => {
|
|
291
|
+
const repo = getRepo(input.repo);
|
|
292
|
+
return repo.glob({
|
|
293
|
+
patterns: [...input.patterns],
|
|
294
|
+
ref: input.ref,
|
|
295
|
+
prefix: input.prefix,
|
|
296
|
+
limit: input.limit
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: "gm_list_dir",
|
|
302
|
+
description: gmListDirDescription,
|
|
303
|
+
schema: gmListDirSchema,
|
|
304
|
+
repoScoped: true,
|
|
305
|
+
execute: async ({ getRepo }, input) => {
|
|
306
|
+
const repo = getRepo(input.repo);
|
|
307
|
+
return repo.listDir({
|
|
308
|
+
path: input.path,
|
|
309
|
+
ref: input.ref,
|
|
310
|
+
recursive: input.recursive
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: "gm_list_branches",
|
|
316
|
+
description: gmListBranchesDescription,
|
|
317
|
+
schema: gmListBranchesSchema,
|
|
318
|
+
repoScoped: true,
|
|
319
|
+
execute: async ({ getRepo }, input) => {
|
|
320
|
+
const repo = getRepo(input.repo);
|
|
321
|
+
return repo.listBranches({ page: input.page, limit: input.limit });
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "gm_list_commits",
|
|
326
|
+
description: gmListCommitsDescription,
|
|
327
|
+
schema: gmListCommitsSchema,
|
|
328
|
+
repoScoped: true,
|
|
329
|
+
execute: async ({ getRepo }, input) => {
|
|
330
|
+
const repo = getRepo(input.repo);
|
|
331
|
+
return repo.listCommits({
|
|
332
|
+
sha: input.sha,
|
|
333
|
+
path: input.path,
|
|
334
|
+
since: input.since,
|
|
335
|
+
until: input.until,
|
|
336
|
+
page: input.page,
|
|
337
|
+
limit: input.limit
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "gm_grep_all",
|
|
343
|
+
description: gmGrepAllDescription,
|
|
344
|
+
schema: gmGrepAllSchema,
|
|
345
|
+
repoScoped: false,
|
|
346
|
+
execute: async ({ gm }, input) => gm.grepAll({
|
|
347
|
+
pattern: input.pattern,
|
|
348
|
+
language: input.language,
|
|
349
|
+
sortByStars: input.sortByStars,
|
|
350
|
+
limit: input.limit
|
|
351
|
+
})
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "gm_get_repo_info",
|
|
355
|
+
description: gmGetRepoInfoDescription,
|
|
356
|
+
schema: gmGetRepoInfoSchema,
|
|
357
|
+
repoScoped: false,
|
|
358
|
+
execute: async ({ gm }, input) => gm.getRepositoryInfo(input.repo)
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: "gm_mirror",
|
|
362
|
+
description: gmMirrorDescription,
|
|
363
|
+
schema: gmMirrorSchema,
|
|
364
|
+
repoScoped: false,
|
|
365
|
+
execute: async ({ gm }, input) => {
|
|
366
|
+
const result = await gm.mirror(input.source, {
|
|
367
|
+
repoName: input.repoName,
|
|
368
|
+
private: input.private,
|
|
369
|
+
issues: input.issues,
|
|
370
|
+
pullRequests: input.pullRequests,
|
|
371
|
+
releases: input.releases
|
|
372
|
+
});
|
|
373
|
+
return {
|
|
374
|
+
full_name: result.repository.full_name,
|
|
375
|
+
default_branch: result.repository.default_branch,
|
|
376
|
+
stars_count: result.repository.stars_count,
|
|
377
|
+
language: result.repository.language
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
];
|
|
382
|
+
var DEFAULT_TOOL_NAMES = [
|
|
383
|
+
"gm_read_file",
|
|
384
|
+
"gm_read_files",
|
|
385
|
+
"gm_grep",
|
|
386
|
+
"gm_glob",
|
|
387
|
+
"gm_list_dir",
|
|
388
|
+
"gm_list_branches",
|
|
389
|
+
"gm_list_commits",
|
|
390
|
+
"gm_grep_all",
|
|
391
|
+
"gm_get_repo_info"
|
|
392
|
+
];
|
|
393
|
+
function resolveToolSet(gm, opts = {}, pinnedRepo) {
|
|
394
|
+
if (pinnedRepo !== void 0 && !REPO_SLUG.test(pinnedRepo)) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Invalid pinned repo slug '${pinnedRepo}'. Expected 'owner/name', e.g. 'facebook/react'.`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
const ctx = {
|
|
400
|
+
gm,
|
|
401
|
+
getRepo: (slugFromInput) => {
|
|
402
|
+
const slug = pinnedRepo ?? slugFromInput;
|
|
403
|
+
if (!slug) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
"Missing 'repo' argument. Repo-scoped tools require a repository when not using the pinned variant."
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
return gm.repo(slug);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
const renameMap = opts.rename ?? {};
|
|
412
|
+
const availableNames = new Set(DEFAULT_TOOL_NAMES);
|
|
413
|
+
if (opts.includeMirror) availableNames.add("gm_mirror");
|
|
414
|
+
if (opts.only) {
|
|
415
|
+
const missing = opts.only.filter((n) => !availableNames.has(n));
|
|
416
|
+
if (missing.length > 0) {
|
|
417
|
+
const hint = missing.includes("gm_mirror") ? " (gm_mirror requires includeMirror: true)" : "";
|
|
418
|
+
throw new Error(
|
|
419
|
+
`Unknown or unavailable tool name(s) in 'only': ${missing.join(", ")}${hint}`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const onlySet = opts.only ? new Set(opts.only) : null;
|
|
424
|
+
const excludeSet = opts.exclude ? new Set(opts.exclude) : null;
|
|
425
|
+
const selected = GITMORPH_TOOLS.filter((def) => {
|
|
426
|
+
if (!availableNames.has(def.name)) return false;
|
|
427
|
+
if (onlySet && !onlySet.has(def.name)) return false;
|
|
428
|
+
if (excludeSet && excludeSet.has(def.name)) return false;
|
|
429
|
+
return true;
|
|
430
|
+
});
|
|
431
|
+
const normalized = selected.map((def) => {
|
|
432
|
+
const needsRepoArg = def.repoScoped && pinnedRepo === void 0;
|
|
433
|
+
const schema = needsRepoArg ? injectRepoField(def.schema) : def.schema;
|
|
434
|
+
const displayName = renameMap[def.name] ?? def.name;
|
|
435
|
+
return {
|
|
436
|
+
name: displayName,
|
|
437
|
+
description: def.description,
|
|
438
|
+
schema,
|
|
439
|
+
execute: async (raw) => def.execute(ctx, raw)
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
const seen = /* @__PURE__ */ new Set();
|
|
443
|
+
for (const t of normalized) {
|
|
444
|
+
if (seen.has(t.name)) {
|
|
445
|
+
throw new Error(
|
|
446
|
+
`Duplicate tool name '${t.name}' after rename. Tool names must be unique.`
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
seen.add(t.name);
|
|
450
|
+
}
|
|
451
|
+
return normalized;
|
|
452
|
+
}
|
|
453
|
+
function injectRepoField(schema) {
|
|
454
|
+
if (!(schema instanceof z.ZodObject)) {
|
|
455
|
+
throw new Error("Internal: repo-scoped tool schema must be a ZodObject");
|
|
456
|
+
}
|
|
457
|
+
return z.object({
|
|
458
|
+
repo: z.string().regex(REPO_SLUG, "Expected 'owner/name', e.g. 'facebook/react'").describe("Repository in 'owner/name' form, e.g. 'facebook/react'.")
|
|
459
|
+
}).extend(schema.shape);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// src/tools/instructions.ts
|
|
463
|
+
var GITMORPH_SYSTEM_PROMPT = `
|
|
464
|
+
You have access to GitMorph tools for reading Git repositories without
|
|
465
|
+
cloning. Prefer gm_grep and gm_glob over recursive directory listing.
|
|
466
|
+
Use gm_read_file with startLine and endLine to read specific regions \u2014 do
|
|
467
|
+
not read whole files unless they are small. When you don't yet know which
|
|
468
|
+
repository to search, start with gm_grep_all; once you've found the right
|
|
469
|
+
repo, switch to gm_grep for deeper searches.
|
|
470
|
+
`.trim();
|
|
471
|
+
|
|
472
|
+
export { DEFAULT_TOOL_NAMES, GITMORPH_SYSTEM_PROMPT, resolveToolSet };
|
|
473
|
+
//# sourceMappingURL=chunk-A3AOZFPE.js.map
|
|
474
|
+
//# sourceMappingURL=chunk-A3AOZFPE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/schemas.ts","../src/tools/registry.ts","../src/tools/core.ts","../src/tools/instructions.ts"],"names":["z"],"mappings":"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","file":"chunk-A3AOZFPE.js","sourcesContent":["import { z } from \"zod\";\n\n// ── shared fragments ─────────────────────────────────────────────────────────\n\n/** `owner/name` — GitHub-style repository slug. */\nexport const REPO_SLUG = /^[^/\\s]+\\/[^/\\s]+$/;\n\nconst repoField = z\n .string()\n .regex(REPO_SLUG, \"Expected 'owner/name', e.g. 'facebook/react'\")\n .describe(\"Repository in 'owner/name' form, e.g. 'facebook/react'.\");\n\nconst refField = z\n .string()\n .optional()\n .describe(\n \"Branch name, tag, or commit SHA. Defaults to the repository's default branch.\",\n );\n\n// ── gm_read_file ─────────────────────────────────────────────────────────────\n\nexport const gmReadFileSchema = z.object({\n path: z\n .string()\n .min(1)\n .describe(\"File path relative to the repository root, e.g. 'src/index.ts'.\"),\n ref: refField,\n startLine: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n \"1-indexed start line (inclusive). Requires endLine. Omit both to read the whole file.\",\n ),\n endLine: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\"1-indexed end line (inclusive). Requires startLine.\"),\n});\n\nexport const gmReadFileDescription = `\nRead a single file from a Git repository. Returns the file's text content and\ntotal line count. When startLine and endLine are both provided, returns only\nthat line range (1-indexed, inclusive on both ends).\n\nUse this when: you already know the exact file path you want to inspect —\ntypically after gm_grep or gm_glob has pointed you at it. Prefer a line range\nover reading the whole file for anything over ~200 lines.\n\nDo not use this when: you don't yet know the file path — use gm_glob to find\nfiles by name or gm_grep to find files by content first. For multiple files\nat once, prefer gm_read_files.\n\nExample: read lines 1-50 of package.json on the main branch:\n { path: \"package.json\", startLine: 1, endLine: 50 }\n`.trim();\n\n// ── gm_read_files ────────────────────────────────────────────────────────────\n\nexport const gmReadFilesSchema = z.object({\n paths: z\n .array(z.string().min(1))\n .min(1)\n .max(50)\n .describe(\"List of file paths to read, relative to the repository root.\"),\n ref: refField,\n});\n\nexport const gmReadFilesDescription = `\nRead multiple files from a Git repository in a single call. Returns an array\nof file contents in the same order as the input paths; missing files come\nback as null.\n\nUse this when: you have several known file paths to inspect together (e.g.\npackage.json + tsconfig.json + README.md). Much faster than calling\ngm_read_file repeatedly — one round trip instead of N.\n\nDo not use this when: you only need one file (use gm_read_file), when you\ndon't know the paths yet (use gm_glob or gm_grep first), or when files are\nlarge — this tool returns whole files, not line ranges.\n\nExample: read three config files at once:\n { paths: [\"package.json\", \"tsconfig.json\", \".eslintrc.json\"] }\n`.trim();\n\n// ── gm_grep ──────────────────────────────────────────────────────────────────\n\nexport const gmGrepSchema = z.object({\n pattern: z\n .string()\n .min(1)\n .describe(\n \"Search pattern. Supports regex; also works as a plain substring. Case-insensitive by default.\",\n ),\n language: z\n .string()\n .optional()\n .describe(\n \"Restrict results to files of this language (e.g. 'TypeScript', 'Python', 'Go').\",\n ),\n caseSensitive: z\n .boolean()\n .optional()\n .describe(\"Make the pattern case-sensitive. Default: false.\"),\n maxMatches: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(\"Maximum matches to return (1-50). Default: 20.\"),\n page: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\"Page number for pagination (1-indexed).\"),\n});\n\nexport const gmGrepDescription = `\nSearch file contents within a single repository using regex or keyword.\nReturns matching lines with file paths and line numbers. Runs on a\npre-indexed server-side mirror — no cloning, sub-second on large repos.\n\nUse this when: you know roughly what text you're looking for and want to\nfind where in the codebase it lives — function names, config keys, error\nstrings, imports, comments, regex patterns.\n\nDo not use this when: you don't yet know which repo to search (use\ngm_grep_all instead), when you want to enumerate files by name or extension\n(use gm_glob), or when you already have a specific file path (use\ngm_read_file).\n\nExample: find every React hook definition in facebook/react:\n { pattern: \"^export function use[A-Z]\", language: \"TypeScript\" }\n`.trim();\n\n// ── gm_glob ──────────────────────────────────────────────────────────────────\n\nexport const gmGlobSchema = z.object({\n patterns: z\n .array(z.string().min(1))\n .min(1)\n .max(20)\n .describe(\n \"Doublestar glob patterns. Use '**/*.ts' for recursive, '!**/*.test.ts' to exclude. Multiple patterns are OR-ed.\",\n ),\n ref: refField,\n prefix: z\n .string()\n .optional()\n .describe(\"Optional directory prefix to narrow the search, e.g. 'src/'.\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(5000)\n .optional()\n .describe(\"Maximum results (default 1000, max 5000).\"),\n});\n\nexport const gmGlobDescription = `\nFind files in a repository by path pattern using doublestar globs. Returns\nmatching paths (and sizes) — contents are not included. Fast, uses the\ncached repo tree.\n\nUse this when: you want to enumerate files by name, extension, or directory\nstructure — 'all TypeScript files', 'every test file under packages/',\n'config files at the repo root'.\n\nDo not use this when: you want to search file contents (use gm_grep), when\nyou already know the exact paths (go straight to gm_read_file or\ngm_read_files), or when you want directory-only listing (use gm_list_dir).\n\nExample: all TypeScript source files excluding tests:\n { patterns: [\"src/**/*.ts\", \"!**/*.test.ts\", \"!**/*.d.ts\"] }\n`.trim();\n\n// ── gm_list_dir ──────────────────────────────────────────────────────────────\n\nexport const gmListDirSchema = z.object({\n path: z\n .string()\n .optional()\n .describe(\"Directory path to list, e.g. 'src'. Omit for the repo root.\"),\n ref: refField,\n recursive: z\n .boolean()\n .optional()\n .describe(\n \"Walk subdirectories recursively. Default: false. Be careful — recursive listings on large repos can be huge.\",\n ),\n});\n\nexport const gmListDirDescription = `\nList the entries (files and subdirectories) in a directory. Returns each\nentry's path, type ('file' or 'dir'), and size.\n\nUse this when: you want to see the immediate structure of a directory, or\ncheck which top-level files exist before diving in.\n\nDo not use this when: you want to find files by pattern (use gm_glob — much\nmore efficient for filtering), when recursive listing would return thousands\nof entries (use gm_glob with a prefix instead), or when you want file\ncontents (use gm_read_file).\n\nExample: list the top level of the src directory:\n { path: \"src\", recursive: false }\n`.trim();\n\n// ── gm_list_branches ─────────────────────────────────────────────────────────\n\nexport const gmListBranchesSchema = z.object({\n page: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\"Page number (1-indexed).\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Results per page (default 50, max 100).\"),\n});\n\nexport const gmListBranchesDescription = `\nList branches in a repository with the latest commit on each. Useful for\ndiscovering active development branches, release branches, or the default\nbranch.\n\nUse this when: you need to know which branches exist, to pick the right\nbranch for a subsequent read, or to find a release branch like 'v18' or\n'release/2024-q1'.\n\nDo not use this when: you just need the default branch — the SDK defaults\nto it automatically. Don't use to list commits (use gm_list_commits).\n\nExample: page through the first 50 branches:\n { page: 1, limit: 50 }\n`.trim();\n\n// ── gm_list_commits ──────────────────────────────────────────────────────────\n\nexport const gmListCommitsSchema = z.object({\n sha: z\n .string()\n .optional()\n .describe(\n \"Branch name or commit SHA to list commits from. Defaults to the repo's default branch.\",\n ),\n path: z\n .string()\n .optional()\n .describe(\n \"Only include commits that touch this file or directory path.\",\n ),\n since: z\n .string()\n .optional()\n .describe(\"ISO 8601 date — only commits after this date.\"),\n until: z\n .string()\n .optional()\n .describe(\"ISO 8601 date — only commits before this date.\"),\n page: z.number().int().min(1).optional().describe(\"Page number (1-indexed).\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Results per page (default 50, max 100).\"),\n});\n\nexport const gmListCommitsDescription = `\nList commits in a repository, optionally filtered by branch, file path, or\ndate range. Returns SHA, message, author, and parent refs for each commit.\n\nUse this when: you want to answer 'what changed', 'when was X introduced',\n'who last touched this file', or to walk history for a specific subtree.\n\nDo not use this when: you want the diff of a specific commit (not supported\nin this tool set — read files at two refs to compare), or when you want\nbranch metadata (use gm_list_branches).\n\nExample: commits that touched src/hooks in the last 30 days:\n { path: \"src/hooks\", since: \"2025-10-01T00:00:00Z\", limit: 20 }\n`.trim();\n\n// ── gm_grep_all ──────────────────────────────────────────────────────────────\n\nexport const gmGrepAllSchema = z.object({\n pattern: z\n .string()\n .min(1)\n .describe(\n \"Search pattern. Regex or plain substring. Case-insensitive by default.\",\n ),\n language: z\n .string()\n .optional()\n .describe(\"Restrict to files of this language.\"),\n sortByStars: z\n .boolean()\n .optional()\n .describe(\n \"Sort results so matches from more-starred repos come first. Default: false.\",\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(\"Maximum results (default 20, max 50).\"),\n});\n\nexport const gmGrepAllDescription = `\nSearch code across ALL mirrored repositories at once. Returns matches\ngrouped by repo and file. Slower than single-repo gm_grep but essential\nwhen you don't yet know where code lives.\n\nUse this when: you're looking for a pattern across the ecosystem — 'who\nelse uses this function', 'which repos call this API', 'find all examples\nof X'. Also the right tool when the user asks a question without naming a\nrepo.\n\nDo not use this when: you already know which repo to search (use gm_grep —\nmuch faster and scoped). Don't use to find files by name (use gm_glob on a\nspecific repo).\n\nExample: find every repo that uses the 'fastApply' identifier:\n { pattern: \"fastApply\", language: \"TypeScript\", sortByStars: true, limit: 10 }\n`.trim();\n\n// ── gm_get_repo_info ─────────────────────────────────────────────────────────\n\nexport const gmGetRepoInfoSchema = z.object({\n repo: repoField,\n});\n\nexport const gmGetRepoInfoDescription = `\nFetch metadata for a repository: default branch, stars, language, size,\ndescription, open issues, last update. No file contents are returned.\n\nUse this when: you need the default branch name, want to know how popular\nor active a repo is, or need basic description/language info to orient\nyourself before exploring.\n\nDo not use this when: you want to read files or search code — this is\nmetadata only.\n\nExample: get metadata for facebook/react:\n { repo: \"facebook/react\" }\n`.trim();\n\n// ── gm_mirror (opt-in, not in default set) ───────────────────────────────────\n\nexport const gmMirrorSchema = z.object({\n source: z\n .string()\n .min(1)\n .describe(\n \"Source URL or slug — 'owner/repo' (GitHub default) or full URL like 'https://gitlab.com/org/repo'.\",\n ),\n repoName: z\n .string()\n .optional()\n .describe(\"Override the destination repository name.\"),\n private: z\n .boolean()\n .optional()\n .describe(\"Mark the mirrored repo as private. Default: false.\"),\n issues: z.boolean().optional().describe(\"Mirror issues. Default: false.\"),\n pullRequests: z\n .boolean()\n .optional()\n .describe(\"Mirror pull requests. Default: false.\"),\n releases: z.boolean().optional().describe(\"Mirror releases. Default: false.\"),\n});\n\nexport const gmMirrorDescription = `\nMirror a repository from GitHub/GitLab/Gitea into GitMorph so subsequent\nread/grep/glob calls work against it. This triggers a server-side clone\nthat can take seconds to minutes for large repos.\n\nUse this when: the user asks for a repo that isn't yet mirrored and you\nexplicitly need to fetch it first. This tool is disabled by default —\ncallers opt in via includeMirror.\n\nDo not use this when: the repo is already available via gm_grep_all or\ngm_get_repo_info, or when you're speculating — mirroring is a write-ish\noperation with real cost. Only use when the user has explicitly asked.\n\nExample: mirror facebook/react from GitHub:\n { source: \"facebook/react\" }\n`.trim();\n","import type { z } from \"zod\";\nimport type { GitMorph } from \"../client.js\";\nimport type { GitMorphRepo } from \"../repo.js\";\nimport {\n gmReadFileSchema,\n gmReadFileDescription,\n gmReadFilesSchema,\n gmReadFilesDescription,\n gmGrepSchema,\n gmGrepDescription,\n gmGlobSchema,\n gmGlobDescription,\n gmListDirSchema,\n gmListDirDescription,\n gmListBranchesSchema,\n gmListBranchesDescription,\n gmListCommitsSchema,\n gmListCommitsDescription,\n gmGrepAllSchema,\n gmGrepAllDescription,\n gmGetRepoInfoSchema,\n gmGetRepoInfoDescription,\n gmMirrorSchema,\n gmMirrorDescription,\n} from \"./schemas.js\";\n\n/**\n * Execution context passed to every tool's `execute` function.\n *\n * `getRepo` resolves a `GitMorphRepo` handle. In pinned mode (set via\n * `createGitmorphRepoTools`), it ignores its argument and always returns the\n * pinned repo. In multi-repo mode, it requires the tool's `repo` input field.\n */\nexport interface ToolCtx {\n readonly gm: GitMorph;\n readonly getRepo: (slugFromInput?: string) => GitMorphRepo;\n}\n\n/**\n * One tool in the GitMorph toolkit. The registry is a `readonly ToolDef[]`\n * declared `as const satisfies` so literal names survive inference.\n */\nexport interface ToolDef<S extends z.ZodTypeAny = z.ZodTypeAny> {\n readonly name: string;\n readonly description: string;\n readonly schema: S;\n /**\n * Whether this tool operates on a specific repository.\n * Repo-scoped tools take a `repo` argument in multi-repo mode, which\n * `resolveToolSet` injects automatically. In pinned mode, schemas are\n * left untouched.\n */\n readonly repoScoped: boolean;\n readonly execute: (ctx: ToolCtx, input: z.infer<S>) => Promise<unknown>;\n}\n\n// ── The registry ─────────────────────────────────────────────────────────────\n//\n// Edit this file — and schemas.ts next to it — to add or change a tool.\n// Everything downstream (Vercel AI SDK, Anthropic, OpenAI, MCP) derives from\n// this one array.\n\nexport const GITMORPH_TOOLS = [\n {\n name: \"gm_read_file\",\n description: gmReadFileDescription,\n schema: gmReadFileSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n const hasRange =\n input.startLine !== undefined && input.endLine !== undefined;\n return repo.readFile(input.path, {\n ref: input.ref,\n lines: hasRange\n ? [{ start: input.startLine!, end: input.endLine! }]\n : undefined,\n });\n },\n },\n {\n name: \"gm_read_files\",\n description: gmReadFilesDescription,\n schema: gmReadFilesSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.getFileContents(input.paths, { ref: input.ref });\n },\n },\n {\n name: \"gm_grep\",\n description: gmGrepDescription,\n schema: gmGrepSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.grep({\n pattern: input.pattern,\n language: input.language,\n caseSensitive: input.caseSensitive,\n maxMatches: input.maxMatches,\n page: input.page,\n });\n },\n },\n {\n name: \"gm_glob\",\n description: gmGlobDescription,\n schema: gmGlobSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.glob({\n patterns: [...input.patterns],\n ref: input.ref,\n prefix: input.prefix,\n limit: input.limit,\n });\n },\n },\n {\n name: \"gm_list_dir\",\n description: gmListDirDescription,\n schema: gmListDirSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.listDir({\n path: input.path,\n ref: input.ref,\n recursive: input.recursive,\n });\n },\n },\n {\n name: \"gm_list_branches\",\n description: gmListBranchesDescription,\n schema: gmListBranchesSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.listBranches({ page: input.page, limit: input.limit });\n },\n },\n {\n name: \"gm_list_commits\",\n description: gmListCommitsDescription,\n schema: gmListCommitsSchema,\n repoScoped: true,\n execute: async ({ getRepo }, input) => {\n const repo = getRepo((input as { repo?: string }).repo);\n return repo.listCommits({\n sha: input.sha,\n path: input.path,\n since: input.since,\n until: input.until,\n page: input.page,\n limit: input.limit,\n });\n },\n },\n {\n name: \"gm_grep_all\",\n description: gmGrepAllDescription,\n schema: gmGrepAllSchema,\n repoScoped: false,\n execute: async ({ gm }, input) =>\n gm.grepAll({\n pattern: input.pattern,\n language: input.language,\n sortByStars: input.sortByStars,\n limit: input.limit,\n }),\n },\n {\n name: \"gm_get_repo_info\",\n description: gmGetRepoInfoDescription,\n schema: gmGetRepoInfoSchema,\n repoScoped: false,\n execute: async ({ gm }, input) => gm.getRepositoryInfo(input.repo),\n },\n {\n name: \"gm_mirror\",\n description: gmMirrorDescription,\n schema: gmMirrorSchema,\n repoScoped: false,\n execute: async ({ gm }, input) => {\n const result = await gm.mirror(input.source, {\n repoName: input.repoName,\n private: input.private,\n issues: input.issues,\n pullRequests: input.pullRequests,\n releases: input.releases,\n });\n return {\n full_name: result.repository.full_name,\n default_branch: result.repository.default_branch,\n stars_count: result.repository.stars_count,\n language: result.repository.language,\n };\n },\n },\n] as const satisfies readonly ToolDef[];\n\n/** Union of every built-in tool name. */\nexport type GitmorphToolName = (typeof GITMORPH_TOOLS)[number][\"name\"];\n\n/** Tool names that are included by default (excludes opt-in `gm_mirror`). */\nexport type DefaultGitmorphToolName = Exclude<GitmorphToolName, \"gm_mirror\">;\n\n/** Names of tools included by default — use for filtering. */\nexport const DEFAULT_TOOL_NAMES = [\n \"gm_read_file\",\n \"gm_read_files\",\n \"gm_grep\",\n \"gm_glob\",\n \"gm_list_dir\",\n \"gm_list_branches\",\n \"gm_list_commits\",\n \"gm_grep_all\",\n \"gm_get_repo_info\",\n] as const satisfies readonly DefaultGitmorphToolName[];\n","import { z } from \"zod\";\nimport type { GitMorph } from \"../client.js\";\nimport {\n GITMORPH_TOOLS,\n DEFAULT_TOOL_NAMES,\n type ToolCtx,\n type ToolDef,\n type GitmorphToolName,\n} from \"./registry.js\";\nimport { REPO_SLUG } from \"./schemas.js\";\n\n/**\n * Options accepted by every adapter's `createGitmorphTools` factory.\n *\n * @typeParam Only - Literal tuple of tool names. When passed as a `const`\n * array, the return type of the factory narrows to exactly those tools.\n */\nexport interface CreateToolsOptions<\n Only extends readonly GitmorphToolName[] = readonly GitmorphToolName[],\n> {\n /**\n * Restrict to these tool names. Narrows the factory's return type.\n *\n * @example\n * createGitmorphTools(gm, { only: [\"gm_grep\", \"gm_read_file\"] as const })\n */\n only?: Only;\n /** Remove these tools. Applied after `only`. */\n exclude?: readonly GitmorphToolName[];\n /**\n * Rename tools. Keys are built-in names; values are the new names.\n * Names must be unique after renaming.\n *\n * @example\n * createGitmorphTools(gm, { rename: { gm_grep: \"search_code\" } })\n */\n rename?: Partial<Record<GitmorphToolName, string>>;\n /**\n * Include `gm_mirror` in the tool set. Off by default because mirroring\n * triggers a server-side clone — don't let agents fire it speculatively.\n */\n includeMirror?: boolean;\n /**\n * Maximum serialized bytes per tool result (Anthropic/OpenAI/MCP only).\n * Larger results are replaced with a truncation notice. Default: 262144 (256 KB).\n */\n maxOutputBytes?: number;\n}\n\n/**\n * A tool in its framework-agnostic normalized shape. Adapters map this into\n * Vercel AI SDK `Tool`, Anthropic `Tool`, OpenAI `ChatCompletionTool`, or MCP\n * tool definitions.\n */\nexport interface NormalizedTool {\n readonly name: string;\n readonly description: string;\n /** Zod schema with the `repo` field already injected in multi-repo mode. */\n readonly schema: z.ZodTypeAny;\n readonly execute: (input: unknown) => Promise<unknown>;\n}\n\n/**\n * The heart of the toolkit. Takes the raw registry + user options + optional\n * pinned repo and produces a list of normalized tools ready for any adapter.\n *\n * Order of operations:\n * 1. Filter by `only`\n * 2. Filter by `exclude`\n * 3. Drop `gm_mirror` unless `includeMirror`\n * 4. Wrap repo-scoped schemas with a `repo` field (multi-repo mode only)\n * 5. Apply `rename`\n * 6. Bind each `execute` against the shared `ToolCtx`\n */\nexport function resolveToolSet(\n gm: GitMorph,\n opts: CreateToolsOptions = {},\n pinnedRepo?: string,\n): NormalizedTool[] {\n if (pinnedRepo !== undefined && !REPO_SLUG.test(pinnedRepo)) {\n throw new Error(\n `Invalid pinned repo slug '${pinnedRepo}'. Expected 'owner/name', e.g. 'facebook/react'.`,\n );\n }\n\n const ctx: ToolCtx = {\n gm,\n getRepo: (slugFromInput?: string) => {\n const slug = pinnedRepo ?? slugFromInput;\n if (!slug) {\n throw new Error(\n \"Missing 'repo' argument. Repo-scoped tools require a repository when not using the pinned variant.\",\n );\n }\n return gm.repo(slug);\n },\n };\n\n const renameMap = opts.rename ?? {};\n\n // 1. Start from the full registry and apply the defaults/opt-ins.\n const availableNames = new Set<string>(DEFAULT_TOOL_NAMES);\n if (opts.includeMirror) availableNames.add(\"gm_mirror\");\n\n // 2. Validate `only` up front — typos and gm_mirror-without-opt-in fail loud.\n if (opts.only) {\n const missing = opts.only.filter((n) => !availableNames.has(n));\n if (missing.length > 0) {\n const hint = missing.includes(\"gm_mirror\" as GitmorphToolName)\n ? \" (gm_mirror requires includeMirror: true)\"\n : \"\";\n throw new Error(\n `Unknown or unavailable tool name(s) in 'only': ${missing.join(\", \")}${hint}`,\n );\n }\n }\n\n // 3. Apply the filter chain.\n const onlySet = opts.only ? new Set<string>(opts.only) : null;\n const excludeSet = opts.exclude ? new Set<string>(opts.exclude) : null;\n\n const selected = (GITMORPH_TOOLS as readonly ToolDef[]).filter((def) => {\n if (!availableNames.has(def.name)) return false;\n if (onlySet && !onlySet.has(def.name)) return false;\n if (excludeSet && excludeSet.has(def.name)) return false;\n return true;\n });\n\n const normalized = selected.map((def): NormalizedTool => {\n const needsRepoArg = def.repoScoped && pinnedRepo === undefined;\n const schema = needsRepoArg ? injectRepoField(def.schema) : def.schema;\n const displayName = renameMap[def.name as GitmorphToolName] ?? def.name;\n\n return {\n name: displayName,\n description: def.description,\n schema,\n execute: async (raw: unknown) => def.execute(ctx, raw as never),\n };\n });\n\n // Detect duplicate names after rename.\n const seen = new Set<string>();\n for (const t of normalized) {\n if (seen.has(t.name)) {\n throw new Error(\n `Duplicate tool name '${t.name}' after rename. Tool names must be unique.`,\n );\n }\n seen.add(t.name);\n }\n\n return normalized;\n}\n\n/** Prepend a required `repo` field to a registry schema (which is always a ZodObject). */\nfunction injectRepoField(schema: z.ZodTypeAny): z.ZodTypeAny {\n if (!(schema instanceof z.ZodObject)) {\n throw new Error(\"Internal: repo-scoped tool schema must be a ZodObject\");\n }\n return z\n .object({\n repo: z\n .string()\n .regex(REPO_SLUG, \"Expected 'owner/name', e.g. 'facebook/react'\")\n .describe(\"Repository in 'owner/name' form, e.g. 'facebook/react'.\"),\n })\n .extend(schema.shape);\n}\n","/**\n * Optional system prompt snippet to append to your agent's system message.\n * Gives the model explicit guidance on when to reach for each GitMorph tool.\n *\n * Re-exported from every adapter subpath (`/ai`, `/anthropic`, `/openai`,\n * `/mcp`) so you can import it alongside the tools.\n *\n * @example\n * import { createGitmorphTools, GITMORPH_SYSTEM_PROMPT } from \"@morphllm/gitmorph-sdk/ai\";\n *\n * const result = await generateText({\n * model,\n * system: `You are a code reading assistant.\\n\\n${GITMORPH_SYSTEM_PROMPT}`,\n * tools: createGitmorphTools(gm),\n * prompt: \"Find every useEffect in facebook/react\",\n * });\n */\nexport const GITMORPH_SYSTEM_PROMPT = `\nYou have access to GitMorph tools for reading Git repositories without\ncloning. Prefer gm_grep and gm_glob over recursive directory listing.\nUse gm_read_file with startLine and endLine to read specific regions — do\nnot read whole files unless they are small. When you don't yet know which\nrepository to search, start with gm_grep_all; once you've found the right\nrepo, switch to gm_grep for deeper searches.\n`.trim();\n\n/** Escape hatch for tests / internal use. Same content as above. */\nexport const DEFAULT_INSTRUCTIONS = GITMORPH_SYSTEM_PROMPT;\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
2
|
+
|
|
3
|
+
// src/tools/json-schema.ts
|
|
4
|
+
var cache = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
function toJsonSchema(schema) {
|
|
6
|
+
const hit = cache.get(schema);
|
|
7
|
+
if (hit) return hit;
|
|
8
|
+
const result = zodToJsonSchema(schema, {
|
|
9
|
+
target: "jsonSchema7",
|
|
10
|
+
$refStrategy: "none"
|
|
11
|
+
});
|
|
12
|
+
const { $schema: _schemaMarker, ...clean } = result;
|
|
13
|
+
cache.set(schema, clean);
|
|
14
|
+
return clean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/tools/truncate.ts
|
|
18
|
+
var DEFAULT_MAX_BYTES = 262144;
|
|
19
|
+
function clampOutput(value, maxBytes = DEFAULT_MAX_BYTES) {
|
|
20
|
+
const serialized = typeof value === "string" ? value : safeStringify(value);
|
|
21
|
+
if (serialized.length <= maxBytes) return serialized;
|
|
22
|
+
const previewBudget = Math.floor(maxBytes * 0.8);
|
|
23
|
+
return JSON.stringify({
|
|
24
|
+
truncated: true,
|
|
25
|
+
originalSize: serialized.length,
|
|
26
|
+
preview: serialized.slice(0, previewBudget),
|
|
27
|
+
hint: "Output exceeded the tool result size limit. Narrow the query: use gm_grep with a more specific pattern, gm_read_file with startLine/endLine, or gm_glob with a prefix."
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function safeStringify(value) {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.stringify(value) ?? String(value);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
return JSON.stringify({
|
|
35
|
+
error: "Failed to serialize tool result",
|
|
36
|
+
message: err instanceof Error ? err.message : String(err)
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { clampOutput, toJsonSchema };
|
|
42
|
+
//# sourceMappingURL=chunk-FXEX72CO.js.map
|
|
43
|
+
//# sourceMappingURL=chunk-FXEX72CO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/json-schema.ts","../src/tools/truncate.ts"],"names":[],"mappings":";;;AAWA,IAAM,KAAA,uBAAY,OAAA,EAAwC;AASnD,SAAS,aAAa,MAAA,EAAwC;AACnE,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,MAAM,CAAA;AAC5B,EAAA,IAAI,KAAK,OAAO,GAAA;AAEhB,EAAA,MAAM,MAAA,GAAS,gBAAgB,MAAA,EAAQ;AAAA,IACrC,MAAA,EAAQ,aAAA;AAAA,IACR,YAAA,EAAc;AAAA,GACf,CAAA;AAID,EAAA,MAAM,EAAE,OAAA,EAAS,aAAA,EAAe,GAAG,OAAM,GAAI,MAAA;AAG7C,EAAA,KAAA,CAAM,GAAA,CAAI,QAAQ,KAAK,CAAA;AACvB,EAAA,OAAO,KAAA;AACT;;;ACpCA,IAAM,iBAAA,GAAoB,MAAA;AAYnB,SAAS,WAAA,CACd,KAAA,EACA,QAAA,GAAmB,iBAAA,EACX;AACR,EAAA,MAAM,aACJ,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,cAAc,KAAK,CAAA;AAEzD,EAAA,IAAI,UAAA,CAAW,MAAA,IAAU,QAAA,EAAU,OAAO,UAAA;AAE1C,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,GAAG,CAAA;AAC/C,EAAA,OAAO,KAAK,SAAA,CAAU;AAAA,IACpB,SAAA,EAAW,IAAA;AAAA,IACX,cAAc,UAAA,CAAW,MAAA;AAAA,IACzB,OAAA,EAAS,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,aAAa,CAAA;AAAA,IAC1C,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAEA,SAAS,cAAc,KAAA,EAAwB;AAC7C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,IAAK,OAAO,KAAK,CAAA;AAAA,EAC9C,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO,KAAK,SAAA,CAAU;AAAA,MACpB,KAAA,EAAO,iCAAA;AAAA,MACP,SAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACzD,CAAA;AAAA,EACH;AACF","file":"chunk-FXEX72CO.js","sourcesContent":["import type { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\n\ntype JsonSchemaObject = {\n type?: string;\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n};\n\nconst cache = new WeakMap<z.ZodTypeAny, JsonSchemaObject>();\n\n/**\n * Convert a Zod schema to JSON Schema for Anthropic / OpenAI / MCP tool\n * definitions. Results are memoized by schema identity.\n *\n * Uses `jsonSchema7` with `$refStrategy: \"none\"` to produce inlined schemas —\n * no `$defs`, which all three frameworks prefer.\n */\nexport function toJsonSchema(schema: z.ZodTypeAny): JsonSchemaObject {\n const hit = cache.get(schema);\n if (hit) return hit;\n\n const result = zodToJsonSchema(schema, {\n target: \"jsonSchema7\",\n $refStrategy: \"none\",\n }) as JsonSchemaObject;\n\n // Strip the emitted $schema marker — Anthropic and OpenAI don't need it and\n // it wastes tokens in every system prompt.\n const { $schema: _schemaMarker, ...clean } = result;\n void _schemaMarker;\n\n cache.set(schema, clean);\n return clean;\n}\n","const DEFAULT_MAX_BYTES = 262_144; // 256 KB\n\n/**\n * Serialize a tool result to a string, truncating if it exceeds `maxBytes`.\n *\n * Strings pass through. Objects are `JSON.stringify`-ed. When truncation kicks\n * in, the result is a JSON object containing a preview of the first ~80% of\n * the budget plus a hint to narrow the query.\n *\n * Used by the Anthropic / OpenAI / MCP adapters. Vercel AI SDK users see raw\n * objects and handle size themselves.\n */\nexport function clampOutput(\n value: unknown,\n maxBytes: number = DEFAULT_MAX_BYTES,\n): string {\n const serialized =\n typeof value === \"string\" ? value : safeStringify(value);\n\n if (serialized.length <= maxBytes) return serialized;\n\n const previewBudget = Math.floor(maxBytes * 0.8);\n return JSON.stringify({\n truncated: true,\n originalSize: serialized.length,\n preview: serialized.slice(0, previewBudget),\n hint: \"Output exceeded the tool result size limit. Narrow the query: use gm_grep with a more specific pattern, gm_read_file with startLine/endLine, or gm_glob with a prefix.\",\n });\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch (err) {\n return JSON.stringify({\n error: \"Failed to serialize tool result\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n}\n"]}
|