just-git 1.2.6 → 1.2.8

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 CHANGED
@@ -18,29 +18,6 @@ npm install just-git
18
18
 
19
19
  ### Client
20
20
 
21
- ```ts
22
- import { createGit, MemoryFileSystem } from "just-git";
23
-
24
- const fs = new MemoryFileSystem();
25
- const git = createGit({
26
- identity: { name: "Alice", email: "alice@example.com" },
27
- credentials: (url) => ({ type: "bearer", token: process.env.GITHUB_TOKEN! }),
28
- hooks: {
29
- beforeCommand: ({ command }) => {
30
- if (command === "push") return { reject: true, message: "push requires approval" };
31
- },
32
- },
33
- });
34
-
35
- await git.exec("git init", { fs, cwd: "/repo" });
36
- await fs.writeFile("/repo/README.md", "# Hello\n");
37
- await git.exec("git add .", { fs, cwd: "/repo" });
38
- await git.exec('git commit -m "initial commit"', { fs, cwd: "/repo" });
39
- await git.exec("git log --oneline", { fs, cwd: "/repo" });
40
- ```
41
-
42
- `MemoryFileSystem` is a minimal in-memory filesystem for standalone use. Tokenization handles single and double quotes; pass `env` as a plain object when needed (e.g. `GIT_AUTHOR_NAME`). The `FileSystem` interface is built around [just-bash](https://github.com/vercel-labs/just-bash)'s implementations. For anything beyond bare git commands, it's recommended to use just-git as a custom command in just-bash:
43
-
44
21
  ```ts
45
22
  import { Bash } from "just-bash";
46
23
  import { createGit } from "just-git";
@@ -54,76 +31,61 @@ await bash.exec("echo 'hello' > README.md");
54
31
  await bash.exec("git add . && git commit -m 'initial commit'");
55
32
  ```
56
33
 
57
- ### Server
58
-
59
- Stand up a git server with built-in storage (SQLite or [PostgreSQL](docs/SERVER.md#pgstorage)), branch protection, and push hooks:
34
+ Pass a `Git` instance into [just-bash](https://github.com/vercel-labs/just-bash) as a custom command and you get pipes, redirects, `&&` chaining, and the full shell environment alongside git. For standalone use without just-bash, `MemoryFileSystem` provides a minimal in-memory filesystem and `git.exec` accepts a command string with basic quote-aware splitting:
60
35
 
61
36
  ```ts
62
- import { createGitServer, BunSqliteStorage } from "just-git/server";
63
- import { Database } from "bun:sqlite";
64
-
65
- const storage = new BunSqliteStorage(new Database("repos.sqlite"));
37
+ import { createGit, MemoryFileSystem } from "just-git";
66
38
 
67
- const server = createGitServer({
68
- resolveRepo: (path) => storage.repo(path),
39
+ const fs = new MemoryFileSystem();
40
+ const git = createGit({
41
+ fs,
42
+ identity: { name: "Alice", email: "alice@example.com" },
43
+ credentials: (url) => ({ type: "bearer", token: process.env.GITHUB_TOKEN! }),
69
44
  hooks: {
70
- preReceive: ({ updates }) => {
71
- if (updates.some((u) => u.ref === "refs/heads/main" && !u.isFF))
72
- return { reject: true, message: "no force-push to main" };
73
- },
74
- postReceive: ({ repoPath, updates }) => {
75
- console.log(`${repoPath}: ${updates.length} ref(s) updated`);
45
+ beforeCommand: ({ command }) => {
46
+ if (command === "push") return { reject: true, message: "push requires approval" };
76
47
  },
77
48
  },
78
49
  });
79
50
 
80
- Bun.serve({ fetch: server.fetch });
81
- // git clone http://localhost:3000/my-repo works with real git
51
+ await git.exec("git init");
52
+ await fs.writeFile("/README.md", "# Hello\n");
53
+ await git.exec("git add .");
54
+ await git.exec('git commit -m "initial commit"');
82
55
  ```
83
56
 
84
- Uses web-standard `Request`/`Response`. Works with Bun, Hono, Cloudflare Workers, or any fetch-compatible runtime. For Node.js, use `toNodeHandler(server)` with `http.createServer` and `BetterSqlite3Storage` for `better-sqlite3`. See [SERVER.md](docs/SERVER.md) for the full API.
57
+ `createGit` also supports [command restrictions, network policies, and config overrides](docs/CLIENT.md#options) for sandboxing, a [lifecycle hooks API](docs/CLIENT.md#hooks) covering pre-commit secret scanning to push gating, and [cross-VFS remote resolution](docs/CLIENT.md#multi-agent-collaboration) for multi-agent collaboration. See [CLIENT.md](docs/CLIENT.md) for the full reference.
85
58
 
86
- ## createGit options
87
-
88
- `createGit(options?)` accepts:
89
-
90
- | Option | Description |
91
- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
92
- | `identity` | Author/committer override. With `locked: true`, always wins over env vars and git config. Without `locked`, acts as a fallback. |
93
- | `credentials` | `(url) => HttpAuth \| null` callback for Smart HTTP transport auth. |
94
- | `disabled` | `GitCommandName[]` of subcommands to block (e.g. `["push", "rebase"]`). |
95
- | `network` | `{ allowed?: string[], fetch? }` to restrict HTTP access. Set to `false` to block all network access. |
96
- | `config` | `{ locked?, defaults? }` config overrides. `locked` values always win over `.git/config`; `defaults` supply fallbacks when a key is absent. |
97
- | `hooks` | Lifecycle hooks for pre/post command interception, commit gating, message enforcement, and audit logging. |
98
- | `resolveRemote` | `(url) => GitRepo \| null` callback for cross-VFS remote resolution (multi-agent setups). |
99
-
100
- See [CLIENT.md](docs/CLIENT.md) for detailed usage, config overrides, and multi-agent collaboration.
101
-
102
- ## Client hooks
59
+ ### Server
103
60
 
104
- Hooks fire at specific points inside command execution. Pre-hooks can reject the operation by returning `{ reject: true, message? }`. Post-hooks are observational. All hook payloads include `repo: GitRepo` for [programmatic repo access](docs/REPO.md).
61
+ Stand up a git server with built-in storage (SQLite or PostgreSQL), branch protection, auth, and push hooks:
105
62
 
106
63
  ```ts
107
- import { createGit } from "just-git";
64
+ import { createGitServer, createStandardHooks, BunSqliteStorage } from "just-git/server";
108
65
  import { getChangedFiles } from "just-git/repo";
66
+ import { Database } from "bun:sqlite";
109
67
 
110
- const git = createGit({
111
- hooks: {
112
- preCommit: ({ index }) => {
113
- const forbidden = index.entries.filter((e) => /\.(env|pem|key)$/.test(e.path));
114
- if (forbidden.length) {
115
- return { reject: true, message: `Blocked: ${forbidden.map((e) => e.path).join(", ")}` };
68
+ const storage = new BunSqliteStorage(new Database("repos.sqlite"));
69
+
70
+ const server = createGitServer({
71
+ resolveRepo: (path) => storage.repo(path),
72
+ hooks: createStandardHooks({
73
+ protectedBranches: ["main"],
74
+ authorizePush: (request) => request.headers.has("Authorization"),
75
+ onPush: async ({ repo, repoPath, updates }) => {
76
+ for (const u of updates) {
77
+ const files = await getChangedFiles(repo, u.oldHash, u.newHash);
78
+ console.log(`${repoPath}: ${u.ref} — ${files.length} files changed`);
116
79
  }
117
80
  },
118
- postCommit: async ({ repo, hash, branch, parents }) => {
119
- const files = await getChangedFiles(repo, parents[0] ?? null, hash);
120
- onAgentCommit({ hash, branch, changedFiles: files });
121
- },
122
- },
81
+ }),
123
82
  });
83
+
84
+ Bun.serve({ fetch: server.fetch });
85
+ // git clone http://localhost:3000/my-repo ← works with real git
124
86
  ```
125
87
 
126
- Combine multiple hook sets with `composeGitHooks(auditHooks, policyHooks, loggingHooks)`. See [HOOKS.md](docs/HOOKS.md) for the full type reference and [CLIENT.md](docs/CLIENT.md) for more examples.
88
+ Uses web-standard `Request`/`Response`. Works with Bun, Hono, Cloudflare Workers, or any fetch-compatible runtime. For Node.js, use `toNodeHandler(server)` with `http.createServer` and `BetterSqlite3Storage` for `better-sqlite3`. Use `withAuth` to gate clone and fetch access as well. See [SERVER.md](docs/SERVER.md) for the full API.
127
89
 
128
90
  ## Repo module
129
91
 
@@ -141,10 +103,6 @@ const result = await mergeTrees(repo, oursCommit, theirsCommit);
141
103
 
142
104
  See [REPO.md](docs/REPO.md) for the full API, the `GitRepo` interface, and the hybrid worktree pattern.
143
105
 
144
- ## Multi-agent collaboration
145
-
146
- Multiple agents can clone, fetch, push, and pull across isolated in-memory filesystems within the same process via the `resolveRemote` option, without needing a network or shared filesystem. Concurrent pushes are automatically serialized with proper non-fast-forward rejection. See [CLIENT.md](docs/CLIENT.md#multi-agent-collaboration) and [`examples/multi-agent.ts`](examples/multi-agent.ts).
147
-
148
106
  ## Commands
149
107
 
150
108
  34 commands: `init`, `clone`, `fetch`, `push`, `pull`, `add`, `rm`, `mv`, `commit`, `status`, `log`, `show`, `diff`, `blame`, `branch`, `tag`, `checkout`, `switch`, `restore`, `reset`, `merge`, `rebase`, `cherry-pick`, `revert`, `stash`, `remote`, `config`, `bisect`, `clean`, `reflog`, `gc`, `repack`, `rev-parse`, `ls-files`. See [CLI.md](docs/CLI.md) for full usage details.
package/dist/index.d.ts CHANGED
@@ -32,6 +32,12 @@ type GitCommandName = "init" | "clone" | "fetch" | "pull" | "push" | "add" | "bl
32
32
  * this instance.
33
33
  */
34
34
  interface GitOptions {
35
+ /**
36
+ * Default filesystem for {@link Git.exec}. When set, `exec` calls
37
+ * don't need to pass `fs` in the context. Ignored by `execute`
38
+ * (just-bash always provides its own filesystem).
39
+ */
40
+ fs?: FileSystem;
35
41
  hooks?: GitHooks;
36
42
  credentials?: CredentialProvider;
37
43
  identity?: IdentityOverride;
@@ -64,8 +70,10 @@ interface GitOptions {
64
70
  }
65
71
  /** Simplified context for {@link Git.exec}. */
66
72
  interface ExecContext {
67
- fs: FileSystem;
68
- cwd: string;
73
+ /** Filesystem to operate on. Falls back to the `fs` set in {@link GitOptions}. */
74
+ fs?: FileSystem;
75
+ /** Working directory. Defaults to `"/"`. */
76
+ cwd?: string;
69
77
  env?: Record<string, string>;
70
78
  stdin?: string;
71
79
  }
@@ -77,13 +85,13 @@ interface ExecContext {
77
85
  * to make `git` available inside a virtual shell.
78
86
  *
79
87
  * ```ts
80
- * const git = createGit();
81
- * const fs = new MemoryFileSystem();
82
- * await git.exec("init", { fs, cwd: "/repo" });
88
+ * const git = createGit({ fs: new MemoryFileSystem() });
89
+ * await git.exec("init");
83
90
  * ```
84
91
  */
85
92
  declare class Git {
86
93
  readonly name = "git";
94
+ private defaultFs;
87
95
  private blocked;
88
96
  private hooks;
89
97
  private inner;
@@ -98,10 +106,10 @@ declare class Git {
98
106
  * features like pipes, redirections, variable expansion, or `&&`.
99
107
  *
100
108
  * ```ts
101
- * await git.exec('commit -m "initial commit"', { fs, cwd: "/repo" });
109
+ * await git.exec('commit -m "initial commit"');
102
110
  * ```
103
111
  */
104
- exec: (command: string, ctx: ExecContext) => Promise<ExecResult>;
112
+ exec: (command: string, ctx?: ExecContext) => Promise<ExecResult>;
105
113
  execute: (args: string[], ctx: CommandContext) => Promise<ExecResult>;
106
114
  }
107
115
  /** Create a new {@link Git} command handler with the given options. */