@aigne/afs-git 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-01-16)
4
+
5
+
6
+ ### Features
7
+
8
+ * **afs:** add AFSGit module support mount a git repo to AFS ([e1e030c](https://github.com/AIGNE-io/aigne-framework/commit/e1e030c181860d06c1c945b4acdcf67d9d708662))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **afs:** support read binary file as base64 string ([3480f9f](https://github.com/AIGNE-io/aigne-framework/commit/3480f9fe90647eba3bf2ff37e22c334599b72e35))
14
+
15
+
16
+ ### Dependencies
17
+
18
+ * The following workspace dependencies were updated
19
+ * dependencies
20
+ * @aigne/afs bumped to 1.4.0-beta.10
21
+ * @aigne/core bumped to 1.72.0-beta.24
22
+ * devDependencies
23
+ * @aigne/test-utils bumped to 0.5.69-beta.24
package/LICENSE.md ADDED
@@ -0,0 +1,93 @@
1
+ Elastic License 2.0
2
+
3
+ URL: https://www.elastic.co/licensing/elastic-license
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject to
14
+ the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor’s trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to
37
+ the software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from you
46
+ also gets a copy of these terms.
47
+
48
+ If you modify the software, you must include in any modified copies of the
49
+ software prominent notices stating that you have modified the software.
50
+
51
+ ## No Other Rights
52
+
53
+ These terms do not imply any licenses other than those expressly granted in
54
+ these terms.
55
+
56
+ ## Termination
57
+
58
+ If you use the software in violation of these terms, such use is not licensed,
59
+ and your licenses will automatically terminate. If the licensor provides you
60
+ with a notice of your violation, and you cease all violation of this license no
61
+ later than 30 days after you receive that notice, your licenses will be
62
+ reinstated retroactively. However, if you violate these terms after such
63
+ reinstatement, any additional violation of these terms will cause your licenses
64
+ to terminate automatically and permanently.
65
+
66
+ ## No Liability
67
+
68
+ *As far as the law allows, the software comes as is, without any warranty or
69
+ condition, and the licensor will not be liable to you for any damages arising
70
+ out of these terms or the use or nature of the software, under any kind of
71
+ legal claim.*
72
+
73
+ ## Definitions
74
+
75
+ The **licensor** is the entity offering these terms, and the **software** is the
76
+ software the licensor makes available under these terms, including any portion
77
+ of it.
78
+
79
+ **you** refers to the individual or entity agreeing to these terms.
80
+
81
+ **your company** is any legal entity, sole proprietorship, or other kind of
82
+ organization that you work for, plus all organizations that have control over,
83
+ are under the control of, or are under common control with that
84
+ organization. **control** means ownership of substantially all the assets of an
85
+ entity, or the power to direct its management and policies by vote, contract, or
86
+ otherwise. Control can be direct or indirect.
87
+
88
+ **your licenses** are all the licenses granted to you for the software under
89
+ these terms.
90
+
91
+ **use** means anything you do with the software requiring one of your licenses.
92
+
93
+ **trademark** means trademarks, service marks, and similar rights.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # AFSGit
2
+
3
+ **AFSGit** is an AFS (Agentic File System) module that provides access to Git repository contents through a virtual file system interface. It allows AI agents to navigate different branches, read files, search content, and optionally make modifications using Git worktrees.
4
+
5
+ ## Features
6
+
7
+ - **Branch Navigation**: Access all branches as top-level directories
8
+ - **Read Operations**: Read files using efficient git commands (no worktree needed)
9
+ - **Directory Listing**: List files recursively with depth control
10
+ - **Search**: Search content across branches using git grep
11
+ - **Write Operations**: Modify files with automatic git worktree management
12
+ - **Auto-commit**: Optional automatic commits for write operations
13
+ - **No Workspace Pollution**: Uses git worktrees for modifications, keeping main repository clean
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @aigne/afs-git
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Basic Setup (Read-Only)
24
+
25
+ ```typescript
26
+ import { AFS } from "@aigne/afs";
27
+ import { AFSGit } from "@aigne/afs-git";
28
+
29
+ const afs = new AFS();
30
+
31
+ // Mount a git repository in read-only mode
32
+ afs.mount(new AFSGit({
33
+ repoPath: '/path/to/repo',
34
+ accessMode: 'readonly' // default
35
+ }));
36
+ ```
37
+
38
+ ### Path Structure
39
+
40
+ ```
41
+ / # Root - lists all branches
42
+ ├── main/ # Branch directory
43
+ │ ├── src/
44
+ │ │ └── index.ts # Files accessible at /main/src/index.ts
45
+ │ ├── package.json
46
+ │ └── README.md
47
+ ├── develop/ # Another branch
48
+ │ └── ...
49
+ └── feature-auth/ # Feature branch
50
+ └── ...
51
+ ```
52
+
53
+ ### Read-Only Operations
54
+
55
+ ```typescript
56
+ // List all branches
57
+ const branches = await afs.list('/modules/git');
58
+ // Returns: ['/main', '/develop', '/feature-auth']
59
+
60
+ // List files in a branch
61
+ const files = await afs.list('/modules/git/main');
62
+ // Returns files at root of main branch
63
+
64
+ // List files recursively
65
+ const allFiles = await afs.list('/modules/git/main', { maxDepth: 10 });
66
+
67
+ // Read file content
68
+ const content = await afs.read('/modules/git/main/README.md');
69
+ console.log(content.data?.content);
70
+
71
+ // Search across branch
72
+ const results = await afs.search('/modules/git/main', 'TODO');
73
+ // Uses git grep for fast searching
74
+ ```
75
+
76
+ ### Read-Write Mode with Auto-Commit
77
+
78
+ ```typescript
79
+ import { AFSGit } from "@aigne/afs-git";
80
+
81
+ const afsGit = new AFSGit({
82
+ repoPath: '/path/to/repo',
83
+ accessMode: 'readwrite',
84
+ autoCommit: true,
85
+ commitAuthor: {
86
+ name: 'AI Agent',
87
+ email: 'agent@example.com'
88
+ }
89
+ });
90
+
91
+ afs.mount(afsGit);
92
+
93
+ // Write a new file (creates worktree automatically)
94
+ await afs.write('/modules/git/main/newfile.txt', {
95
+ content: 'Hello World'
96
+ });
97
+ // Automatically committed with message "Update newfile.txt"
98
+
99
+ // Update existing file
100
+ await afs.write('/modules/git/main/src/index.ts', {
101
+ content: updatedCode
102
+ });
103
+
104
+ // Delete file
105
+ await afs.delete('/modules/git/main/oldfile.txt');
106
+ // Automatically committed
107
+
108
+ // Rename/move file
109
+ await afs.rename('/modules/git/main/old.txt', '/modules/git/main/new.txt');
110
+ ```
111
+
112
+ ### Advanced Configuration
113
+
114
+ ```typescript
115
+ const afsGit = new AFSGit({
116
+ repoPath: '/path/to/repo',
117
+ name: 'my-repo',
118
+ description: 'My project repository',
119
+
120
+ // Limit accessible branches
121
+ branches: ['main', 'develop'],
122
+
123
+ // Access control
124
+ accessMode: 'readwrite',
125
+
126
+ // Auto-commit settings
127
+ autoCommit: true,
128
+ commitAuthor: {
129
+ name: 'AI Agent',
130
+ email: 'agent@example.com'
131
+ }
132
+ });
133
+
134
+ // Cleanup worktrees when done
135
+ await afsGit.cleanup();
136
+ ```
137
+
138
+ ## How It Works
139
+
140
+ ### Read-Only Mode
141
+
142
+ In read-only mode, AFSGit uses direct git commands without creating worktrees:
143
+
144
+ - **List operations**: Uses `git ls-tree` to list files
145
+ - **Read operations**: Uses `git show` to read file content
146
+ - **Search operations**: Uses `git grep` for fast content search
147
+
148
+ This is extremely efficient as it doesn't require any file system operations.
149
+
150
+ ### Read-Write Mode
151
+
152
+ When write operations are needed, AFSGit:
153
+
154
+ 1. **Lazy Worktree Creation**: Creates a git worktree only when first write operation occurs
155
+ 2. **Reuses Worktrees**: Subsequent operations on the same branch reuse the existing worktree
156
+ 3. **Current Branch Optimization**: Uses main repository path for the currently checked-out branch
157
+ 4. **Auto-commit**: Optionally commits each change automatically with descriptive messages
158
+
159
+ Worktrees are created in temporary directories and cleaned up when the module is unmounted.
160
+
161
+ ## Configuration Options
162
+
163
+ ### AFSGitOptions
164
+
165
+ ```typescript
166
+ interface AFSGitOptions {
167
+ // Required
168
+ repoPath: string; // Path to git repository
169
+
170
+ // Optional
171
+ name?: string; // Module name (default: repo basename)
172
+ description?: string; // Module description
173
+ branches?: string[]; // Limit accessible branches
174
+ accessMode?: 'readonly' | 'readwrite'; // Default: 'readonly'
175
+ autoCommit?: boolean; // Auto-commit changes (default: false)
176
+ commitAuthor?: { // Author for commits
177
+ name: string;
178
+ email: string;
179
+ };
180
+ }
181
+ ```
182
+
183
+ ## Performance
184
+
185
+ - **Read operations**: Very fast, uses direct git commands
186
+ - **List operations**: Fast for shallow depths, may be slower for deep recursion
187
+ - **Search operations**: Fast, uses optimized git grep
188
+ - **Write operations**: First write to a branch creates worktree (slower), subsequent writes are fast
189
+
190
+ ## Limitations
191
+
192
+ - Write operations are only supported on files, not directories
193
+ - Cannot write to root or branch root paths
194
+ - Cannot rename files across different branches
195
+ - Binary files are supported for read, but may require special handling for write
196
+
197
+ ## Example: AI Agent Code Review
198
+
199
+ ```typescript
200
+ import { AIGNE } from "@aigne/core";
201
+ import { AFS } from "@aigne/afs";
202
+ import { AFSGit } from "@aigne/afs-git";
203
+
204
+ const afs = new AFS();
205
+ afs.mount(new AFSGit({
206
+ repoPath: process.cwd(),
207
+ accessMode: 'readonly'
208
+ }));
209
+
210
+ const aigne = new AIGNE({});
211
+
212
+ // AI agent can now review code across branches
213
+ const agent = AIAgent.from({
214
+ name: "CodeReviewer",
215
+ instructions: "Review code and suggest improvements",
216
+ afs
217
+ });
218
+
219
+ // Agent can list files, read code, search for patterns
220
+ await aigne.invoke(agent, {
221
+ message: "Review the authentication code in src/auth/"
222
+ });
223
+ ```
224
+
225
+ ## License
226
+
227
+ This project is licensed under the [Elastic-2.0](../../LICENSE.md) License.
@@ -0,0 +1,129 @@
1
+ import type { AFSAccessMode, AFSDeleteOptions, AFSDeleteResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleLoadParams, AFSReadOptions, AFSReadResult, AFSRenameOptions, AFSSearchOptions, AFSSearchResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "@aigne/afs";
2
+ import { z } from "zod";
3
+ export interface AFSGitOptions {
4
+ name?: string;
5
+ repoPath: string;
6
+ description?: string;
7
+ branches?: string[];
8
+ /**
9
+ * Access mode for this module.
10
+ * - "readonly": Only read operations are allowed, uses git commands (no worktree)
11
+ * - "readwrite": All operations are allowed, creates worktrees as needed
12
+ * @default "readonly"
13
+ */
14
+ accessMode?: AFSAccessMode;
15
+ /**
16
+ * Automatically commit changes after write operations
17
+ * @default false
18
+ */
19
+ autoCommit?: boolean;
20
+ /**
21
+ * Author information for commits when autoCommit is enabled
22
+ */
23
+ commitAuthor?: {
24
+ name: string;
25
+ email: string;
26
+ };
27
+ }
28
+ export declare class AFSGit implements AFSModule {
29
+ options: AFSGitOptions & {
30
+ cwd?: string;
31
+ };
32
+ static schema(): z.ZodObject<{
33
+ name: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
34
+ repoPath: z.ZodString;
35
+ description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
36
+ branches: z.ZodType<string[] | undefined, z.ZodTypeDef, string[] | undefined>;
37
+ accessMode: z.ZodType<"readonly" | "readwrite" | undefined, z.ZodTypeDef, "readonly" | "readwrite" | undefined>;
38
+ autoCommit: z.ZodType<boolean | undefined, z.ZodTypeDef, boolean | undefined>;
39
+ commitAuthor: z.ZodType<{
40
+ name: string;
41
+ email: string;
42
+ } | undefined, z.ZodTypeDef, {
43
+ name: string;
44
+ email: string;
45
+ } | undefined>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ repoPath: string;
48
+ name?: string | undefined;
49
+ description?: string | undefined;
50
+ branches?: string[] | undefined;
51
+ accessMode?: "readonly" | "readwrite" | undefined;
52
+ autoCommit?: boolean | undefined;
53
+ commitAuthor?: {
54
+ name: string;
55
+ email: string;
56
+ } | undefined;
57
+ }, {
58
+ repoPath: string;
59
+ name?: string | undefined;
60
+ description?: string | undefined;
61
+ branches?: string[] | undefined;
62
+ accessMode?: "readonly" | "readwrite" | undefined;
63
+ autoCommit?: boolean | undefined;
64
+ commitAuthor?: {
65
+ name: string;
66
+ email: string;
67
+ } | undefined;
68
+ }>;
69
+ static load({ filepath, parsed }: AFSModuleLoadParams): Promise<AFSGit>;
70
+ private git;
71
+ private tempBase;
72
+ private worktrees;
73
+ private repoHash;
74
+ constructor(options: AFSGitOptions & {
75
+ cwd?: string;
76
+ });
77
+ name: string;
78
+ description?: string;
79
+ accessMode: AFSAccessMode;
80
+ /**
81
+ * Parse AFS path into branch and file path
82
+ * Branch names may contain slashes and are encoded with ~ in paths
83
+ * Examples:
84
+ * "/" -> { branch: undefined, filePath: "" }
85
+ * "/main" -> { branch: "main", filePath: "" }
86
+ * "/feature~new-feature" -> { branch: "feature/new-feature", filePath: "" }
87
+ * "/main/src/index.ts" -> { branch: "main", filePath: "src/index.ts" }
88
+ */
89
+ private parsePath;
90
+ /**
91
+ * Detect MIME type based on file extension
92
+ */
93
+ private getMimeType;
94
+ /**
95
+ * Check if file is likely binary based on extension
96
+ */
97
+ private isBinaryFile;
98
+ /**
99
+ * Get list of available branches
100
+ */
101
+ private getBranches;
102
+ /**
103
+ * Ensure worktree exists for a branch (lazy creation)
104
+ */
105
+ private ensureWorktree;
106
+ /**
107
+ * List files using git ls-tree (no worktree needed)
108
+ */
109
+ private listWithGitLsTree;
110
+ /**
111
+ * Build AFS path with encoded branch name
112
+ * Branch names with slashes are encoded by replacing / with ~
113
+ * @param branch Branch name (may contain slashes)
114
+ * @param filePath File path within branch
115
+ */
116
+ private buildPath;
117
+ list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
118
+ read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
119
+ write(path: string, entry: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
120
+ delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
121
+ rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
122
+ message?: string;
123
+ }>;
124
+ search(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
125
+ /**
126
+ * Cleanup all worktrees (useful when unmounting)
127
+ */
128
+ cleanup(): Promise<void>;
129
+ }