npm package: @morphllm/gitmorph-sdk
Description: TypeScript SDK for GitMorph
Latest version: 0.2.2

# @morphllm/gitmorph-sdk

Agent-native TypeScript SDK for reading, searching, and navigating Git repositories through [GitMorph](https://gitmorph.com). No cloning. Every operation is a single HTTP call against a server-side mirror.

Built for AI coding agents that need to understand codebases: read files with line ranges, grep across repos, glob for file patterns, list directories, walk commits. All server-side, all fast.

```bash
npm install @morphllm/gitmorph-sdk
```

## Quick start

```ts
import { GitMorph } from "@morphllm/gitmorph-sdk";

const gm = new GitMorph();
const repo = gm.repo("facebook/react");

// Read a file
const file = await repo.readFile("package.json");

// Grep for a pattern
const results = await repo.grep({ pattern: "useState" });

// Glob for files
const tsFiles = await repo.glob({ patterns: ["**/*.ts"] });
```

## Give your agent access to any repo

Paste this into Claude Code (or any agent with tool-use) to give it read access to any mirrored repository:

````
You have access to the @morphllm/gitmorph-sdk for reading Git repositories without cloning.
The SDK is already installed and authenticated via ~/.config/gm/config.json.

To use it, write a quick TypeScript script and run it with `npx tsx`:

```ts
import { GitMorph } from "@morphllm/gitmorph-sdk";
const gm = new GitMorph();
const repo = gm.repo("owner/repo");
```

Available methods on `repo`:
- `repo.readFile(path, { ref?, lines?: [{ start, end }] })` - read a file, optionally specific line ranges (1-indexed, inclusive)
- `repo.getFileContents(paths[], { ref? })` - batch read multiple files in one call
- `repo.grep({ pattern, language?, caseSensitive?, maxMatches?, page? })` - server-side code search within the repo
- `repo.glob({ patterns[], ref?, prefix?, sizes?, limit? })` - find files matching glob patterns (e.g. `["**/*.ts", "!**/*.test.ts"]`)
- `repo.listDir({ path?, ref?, recursive? })` - list directory contents
- `repo.listBranches({ page?, limit? })` - list branches
- `repo.listCommits({ sha?, path?, since?, until?, page?, limit? })` - list commits

Available methods on `gm` (instance-wide):
- `gm.grepAll({ pattern, language?, page?, limit?, sortByStars? })` - search code across ALL repos
- `gm.mirror(source, options?)` - mirror a GitHub/GitLab/Gitea repo (e.g. `gm.mirror("facebook/react")`)
- `gm.getRepositoryInfo("owner/repo")` - get repo metadata

Use these to explore, search, and read code. Prefer grep and glob over listing directories manually.
````

## Auth

Credentials resolve in order:

1. Constructor options: `new GitMorph({ token: "...", host: "..." })`
2. Environment variables: `GM_TOKEN`, `GM_HOST`
3. Config file: `~/.config/gm/config.json`

The host defaults to `gitmorph.com` if not set.

## API reference

### `GitMorph` (client)

| Method | Description |
|--------|-------------|
| `gm.repo("owner/repo")` | Get a repo handle for file/search operations |
| `gm.getRepositoryInfo("owner/repo")` | Repo metadata (branches, stars, language, etc.) |
| `gm.mirror(source, opts?)` | Mirror a repo from GitHub/GitLab/Gitea into GitMorph |
| `gm.grepAll({ pattern, ... })` | Search code across all repos on the instance |

### `GitMorphRepo` (per-repo operations)

| Method | Description |
|--------|-------------|
| `repo.readFile(path, opts?)` | Read a file, optionally specific line ranges |
| `repo.getFileContents(paths[], opts?)` | Batch read multiple files in one call |
| `repo.grep({ pattern, ... })` | Server-side code search within this repo |
| `repo.glob({ patterns[], ... })` | Find files matching glob patterns |
| `repo.listDir(opts?)` | List directory contents (optionally recursive) |
| `repo.listBranches(opts?)` | List branches with latest commit info |
| `repo.listCommits(opts?)` | List commits with filtering by path, date range |

### Read files

```ts
// Full file
const file = await repo.readFile("src/index.ts");
// file.content, file.totalLines

// Specific line ranges (1-indexed, inclusive)
const snippet = await repo.readFile("src/index.ts", {
  ref: "main",
  lines: [{ start: 10, end: 25 }, { start: 100, end: 110 }],
});
```

### Batch read

```ts
const files = await repo.getFileContents([
  "package.json",
  "tsconfig.json",
  "src/index.ts",
]);
// Returns (FileContentEntry | null)[] -- null for files that don't exist
```

### Grep (single repo)

```ts
const result = await repo.grep({
  pattern: "createServer",
  language: "TypeScript",
  caseSensitive: true,
  maxMatches: 20,
});

for (const match of result.matches) {
  console.log(`${match.path}:${match.lineNumber}  ${match.lineContent}`);
  // match.submatches[] has character offsets within the line
}
```

### Grep all (cross-repo)

```ts
const result = await gm.grepAll({
  pattern: "fastApply",
  language: "TypeScript",
  sortByStars: true,
  limit: 10,
});

for (const match of result.matches) {
  console.log(`${match.repoName}  ${match.filename}`);
  for (const line of match.lines) {
    console.log(`  L${line.num}: ${line.content}`);
  }
}
```

### Glob

```ts
const result = await repo.glob({
  patterns: ["src/**/*.ts", "!**/*.test.ts", "!**/*.spec.ts"],
  prefix: "src/",
  limit: 500,
});

for (const entry of result.entries) {
  console.log(`${entry.path}  ${entry.size} bytes`);
}
```

### List directory

```ts
// Top-level
const root = await repo.listDir();

// Subdirectory, recursive
const src = await repo.listDir({ path: "src", recursive: true, ref: "develop" });

for (const entry of src.entries) {
  console.log(`${entry.type === "dir" ? "d" : "f"}  ${entry.path}`);
}
```

### Branches

```ts
const branches = await repo.listBranches({ limit: 50 });
for (const b of branches) {
  console.log(`${b.name}  ${b.commit.id.slice(0, 8)}  ${b.commit.message}`);
}
```

### Commits

```ts
const commits = await repo.listCommits({
  sha: "main",
  path: "src/",
  since: "2025-01-01T00:00:00Z",
  limit: 20,
});

for (const c of commits) {
  console.log(`${c.sha.slice(0, 8)}  ${c.author.name}  ${c.message}`);
}
```

### Mirror

```ts
// Shorthand (defaults to GitHub)
const { repository, repo } = await gm.mirror("facebook/react");

// Full URL with options
const { repository } = await gm.mirror("https://gitlab.com/org/repo", {
  private: true,
  issues: true,
  pullRequests: true,
  releases: true,
});

// repo is a GitMorphRepo handle, ready to use immediately
const files = await repo.glob({ patterns: ["**/*.ts"] });
```

## Error handling

All errors extend `GitMorphError`:

```ts
import {
  GitMorphError,
  ApiError,
  AuthenticationError,
  GrepError,
  MirrorError,
} from "@morphllm/gitmorph-sdk";

try {
  await repo.readFile("missing.txt");
} catch (err) {
  if (err instanceof ApiError) {
    console.log(err.status, err.url); // 404, https://gitmorph.com/api/v1/...
  }
}
```

| Error class | When |
|-------------|------|
| `AuthenticationError` | No token found in options, env, or config file |
| `ApiError` | HTTP error from the API (has `.status` and `.url`) |
| `GrepError` | Invalid grep pattern or search failure |
| `MirrorError` | Mirror/migrate operation failed |

## License

MIT