@aigne/afs-git 1.11.0-beta.10 → 1.11.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -9,6 +9,7 @@ let node_util = require("node:util");
9
9
  let _aigne_afs = require("@aigne/afs");
10
10
  let _aigne_afs_provider = require("@aigne/afs/provider");
11
11
  let _aigne_afs_utils_zod = require("@aigne/afs/utils/zod");
12
+ let _aigne_afs_provider_utils = require("@aigne/afs-provider-utils");
12
13
  let simple_git = require("simple-git");
13
14
  let zod = require("zod");
14
15
 
@@ -43,13 +44,94 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
43
44
  name: "git",
44
45
  description: "Git repository browser with branch-based access.\n- Browse branches, read files at any ref, search across repository\n- Exec actions (readwrite): `diff`, `create-branch`, `commit`, `merge`\n- Virtual `.log/` tree exposes commit history per branch\n- Path structure: `/{branch}/{file-path}` (branch `/` encoded as `~`)",
45
46
  uriTemplate: "git://{localPath+}",
46
- category: "version-control",
47
+ category: "vcs",
47
48
  schema: zod.z.object({
48
49
  localPath: zod.z.string(),
49
50
  branch: zod.z.string().optional(),
50
51
  remoteUrl: zod.z.string().optional()
51
52
  }),
52
- tags: ["git", "version-control"]
53
+ tags: ["git", "version-control"],
54
+ capabilityTags: [
55
+ "read-write",
56
+ "search",
57
+ "auth:none",
58
+ "local"
59
+ ],
60
+ security: {
61
+ riskLevel: "local",
62
+ resourceAccess: ["local-filesystem"],
63
+ requires: ["git"],
64
+ dataSensitivity: ["code"],
65
+ notes: ["Accesses local git repositories; readwrite mode creates worktrees and can commit"]
66
+ },
67
+ capabilities: {
68
+ filesystem: {
69
+ read: true,
70
+ write: true
71
+ },
72
+ process: {
73
+ spawn: true,
74
+ allowedCommands: ["git"]
75
+ }
76
+ }
77
+ };
78
+ }
79
+ static treeSchema() {
80
+ return {
81
+ operations: [
82
+ "list",
83
+ "read",
84
+ "write",
85
+ "delete",
86
+ "search",
87
+ "stat",
88
+ "explain"
89
+ ],
90
+ tree: {
91
+ "/": {
92
+ kind: "git:root",
93
+ operations: ["list", "read"]
94
+ },
95
+ "/{branch}": {
96
+ kind: "git:branch",
97
+ operations: [
98
+ "list",
99
+ "read",
100
+ "search"
101
+ ],
102
+ actions: [
103
+ "diff",
104
+ "create-branch",
105
+ "commit",
106
+ "merge"
107
+ ]
108
+ },
109
+ "/{branch}/{path+}": {
110
+ kind: "git:file",
111
+ operations: [
112
+ "list",
113
+ "read",
114
+ "write",
115
+ "delete",
116
+ "search"
117
+ ]
118
+ },
119
+ "/{branch}/.log": {
120
+ kind: "git:log",
121
+ operations: ["list"]
122
+ },
123
+ "/{branch}/.log/{index}": {
124
+ kind: "git:commit",
125
+ operations: ["read"]
126
+ }
127
+ },
128
+ auth: { type: "none" },
129
+ bestFor: [
130
+ "code browsing",
131
+ "version control",
132
+ "branch comparison"
133
+ ],
134
+ notFor: ["binary storage", "large files"]
53
135
  };
54
136
  }
55
137
  static async load({ basePath, config } = {}) {
@@ -88,15 +170,6 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
88
170
  const repoHash = (0, node_crypto.createHash)("md5").update(options.remoteUrl).digest("hex").substring(0, 8);
89
171
  repoPath = (0, node_path.join)((0, node_os.tmpdir)(), `afs-git-remote-${repoHash}`);
90
172
  } else throw new Error("Either repoPath or remoteUrl must be provided");
91
- if (options.repoPath && !options.remoteUrl) {
92
- const { existsSync, mkdirSync } = require("node:fs");
93
- const { execSync } = require("node:child_process");
94
- if (!existsSync(repoPath)) mkdirSync(repoPath, { recursive: true });
95
- if (!existsSync((0, node_path.join)(repoPath, ".git"))) execSync("git init -b main", {
96
- cwd: repoPath,
97
- stdio: "ignore"
98
- });
99
- }
100
173
  this.repoPath = repoPath;
101
174
  this.name = options.name || repoName;
102
175
  this.description = options.description;
@@ -118,6 +191,15 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
118
191
  */
119
192
  async initialize() {
120
193
  const options = this.options;
194
+ if (options.repoPath && !options.remoteUrl) {
195
+ const { existsSync, mkdirSync } = await import("node:fs");
196
+ const { execSync } = await import("node:child_process");
197
+ if (!existsSync(this.repoPath)) mkdirSync(this.repoPath, { recursive: true });
198
+ if (!existsSync((0, node_path.join)(this.repoPath, ".git"))) execSync("git init -b main", {
199
+ cwd: this.repoPath,
200
+ stdio: "ignore"
201
+ });
202
+ }
121
203
  if (options.remoteUrl) {
122
204
  const targetPath = options.repoPath ? (0, node_path.isAbsolute)(options.repoPath) ? options.repoPath : (0, node_path.join)(options.cwd || process.cwd(), options.repoPath) : this.repoPath;
123
205
  if (!options.repoPath) this.isAutoCloned = true;
@@ -303,14 +385,15 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
303
385
  const worktreePath = this.worktrees.get(branch);
304
386
  if (worktreePath) try {
305
387
  const fullPath = (0, node_path.join)(worktreePath, filePath);
388
+ await this.assertWithinWorktree(fullPath, worktreePath);
306
389
  const stats = await (0, node_fs_promises.stat)(fullPath);
307
390
  if (stats.isDirectory()) {
308
391
  const files = await (0, node_fs_promises.readdir)(fullPath);
309
392
  const afsPath$2 = this.buildBranchPath(branch, filePath);
310
393
  return this.buildEntry(afsPath$2, { meta: { childrenCount: files.length } });
311
394
  }
312
- const mimeType$1 = this.getMimeType(filePath);
313
- const isBinary$1 = this.isBinaryFile(filePath);
395
+ const mimeType$1 = (0, _aigne_afs_provider_utils.getMimeType)(filePath);
396
+ const isBinary$1 = (0, _aigne_afs_provider_utils.isBinaryFile)(filePath);
314
397
  let content$1;
315
398
  const meta$1 = {
316
399
  size: stats.size,
@@ -327,7 +410,9 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
327
410
  createdAt: stats.birthtime,
328
411
  updatedAt: stats.mtime
329
412
  });
330
- } catch {}
413
+ } catch (err) {
414
+ if (err instanceof Error && "code" in err && err.code === "AFS_PERMISSION_DENIED") throw err;
415
+ }
331
416
  const objectType = await this.git.raw([
332
417
  "cat-file",
333
418
  "-t",
@@ -344,8 +429,8 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
344
429
  "-s",
345
430
  `${branch}:${filePath}`
346
431
  ]).then((s) => Number.parseInt(s.trim(), 10));
347
- const mimeType = this.getMimeType(filePath);
348
- const isBinary = this.isBinaryFile(filePath);
432
+ const mimeType = (0, _aigne_afs_provider_utils.getMimeType)(filePath);
433
+ const isBinary = (0, _aigne_afs_provider_utils.isBinaryFile)(filePath);
349
434
  let content;
350
435
  const meta = {
351
436
  size,
@@ -389,9 +474,10 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
389
474
  await this.ready();
390
475
  const branch = this.decodeBranchName(ctx.params.branch);
391
476
  const filePath = ctx.params.path;
392
- const append = ctx.options?.append ?? false;
477
+ const mode = ctx.options?.mode ?? "replace";
393
478
  const worktreePath = await this.ensureWorktree(branch);
394
479
  const fullPath = (0, node_path.join)(worktreePath, filePath);
480
+ await this.assertWithinWorktree(fullPath, worktreePath);
395
481
  await (0, node_fs_promises.mkdir)((0, node_path.dirname)(fullPath), { recursive: true });
396
482
  if (payload.content !== void 0) {
397
483
  let contentToWrite;
@@ -399,7 +485,7 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
399
485
  else contentToWrite = JSON.stringify(payload.content, null, 2);
400
486
  await (0, node_fs_promises.writeFile)(fullPath, contentToWrite, {
401
487
  encoding: "utf8",
402
- flag: append ? "a" : "w"
488
+ flag: mode === "append" ? "a" : "w"
403
489
  });
404
490
  }
405
491
  if (this.options.autoCommit) {
@@ -454,6 +540,7 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
454
540
  const recursive = ctx.options?.recursive ?? false;
455
541
  const worktreePath = await this.ensureWorktree(branch);
456
542
  const fullPath = (0, node_path.join)(worktreePath, filePath);
543
+ await this.assertWithinWorktree(fullPath, worktreePath);
457
544
  let stats;
458
545
  try {
459
546
  stats = await (0, node_fs_promises.stat)(fullPath);
@@ -491,6 +578,8 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
491
578
  const worktreePath = await this.ensureWorktree(oldBranch);
492
579
  const oldFullPath = (0, node_path.join)(worktreePath, oldFilePath);
493
580
  const newFullPath = (0, node_path.join)(worktreePath, newFilePath);
581
+ await this.assertWithinWorktree(oldFullPath, worktreePath);
582
+ await this.assertWithinWorktree(newFullPath, worktreePath);
494
583
  try {
495
584
  await (0, node_fs_promises.stat)(oldFullPath);
496
585
  } catch (error) {
@@ -1197,6 +1286,9 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
1197
1286
  /**
1198
1287
  * Decode branch name (replace ~ with /)
1199
1288
  */
1289
+ async assertWithinWorktree(fullPath, worktreeRoot) {
1290
+ return (0, _aigne_afs_provider_utils.assertPathWithinRoot)(fullPath, worktreeRoot);
1291
+ }
1200
1292
  decodeBranchName(encoded) {
1201
1293
  return encoded.replace(/~/g, "/");
1202
1294
  }
@@ -1397,54 +1489,6 @@ var AFSGit = class AFSGit extends _aigne_afs_provider.AFSBaseProvider {
1397
1489
  }
1398
1490
  }
1399
1491
  /**
1400
- * Detect MIME type based on file extension
1401
- */
1402
- getMimeType(filePath) {
1403
- return {
1404
- png: "image/png",
1405
- jpg: "image/jpeg",
1406
- jpeg: "image/jpeg",
1407
- gif: "image/gif",
1408
- bmp: "image/bmp",
1409
- webp: "image/webp",
1410
- svg: "image/svg+xml",
1411
- ico: "image/x-icon",
1412
- pdf: "application/pdf",
1413
- txt: "text/plain",
1414
- md: "text/markdown",
1415
- js: "text/javascript",
1416
- ts: "text/typescript",
1417
- json: "application/json",
1418
- html: "text/html",
1419
- css: "text/css",
1420
- xml: "text/xml"
1421
- }[filePath.split(".").pop()?.toLowerCase() || ""] || "application/octet-stream";
1422
- }
1423
- /**
1424
- * Check if file is likely binary based on extension
1425
- */
1426
- isBinaryFile(filePath) {
1427
- const ext = filePath.split(".").pop()?.toLowerCase();
1428
- return [
1429
- "png",
1430
- "jpg",
1431
- "jpeg",
1432
- "gif",
1433
- "bmp",
1434
- "webp",
1435
- "ico",
1436
- "pdf",
1437
- "zip",
1438
- "tar",
1439
- "gz",
1440
- "exe",
1441
- "dll",
1442
- "so",
1443
- "dylib",
1444
- "wasm"
1445
- ].includes(ext || "");
1446
- }
1447
- /**
1448
1492
  * Fetch latest changes from remote
1449
1493
  */
1450
1494
  async fetch() {
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { AFSAccessMode, AFSEntry, AFSExecResult, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest } from "@aigne/afs";
1
+ import { AFSAccessMode, AFSEntry, AFSExecResult, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest, ProviderTreeSchema } from "@aigne/afs";
2
2
  import { AFSBaseProvider, RouteContext } from "@aigne/afs/provider";
3
3
  import { z } from "zod";
4
4
 
@@ -120,6 +120,7 @@ declare class AFSGit extends AFSBaseProvider {
120
120
  } | undefined;
121
121
  }, unknown>>;
122
122
  static manifest(): ProviderManifest;
123
+ static treeSchema(): ProviderTreeSchema;
123
124
  static load({
124
125
  basePath,
125
126
  config
@@ -368,6 +369,7 @@ declare class AFSGit extends AFSBaseProvider {
368
369
  /**
369
370
  * Decode branch name (replace ~ with /)
370
371
  */
372
+ private assertWithinWorktree;
371
373
  private decodeBranchName;
372
374
  /**
373
375
  * Encode branch name (replace / with ~)
@@ -416,14 +418,6 @@ declare class AFSGit extends AFSBaseProvider {
416
418
  * Note: list() returns only children, never the path itself (per new semantics)
417
419
  */
418
420
  private listWithGitLsTree;
419
- /**
420
- * Detect MIME type based on file extension
421
- */
422
- private getMimeType;
423
- /**
424
- * Check if file is likely binary based on extension
425
- */
426
- private isBinaryFile;
427
421
  /**
428
422
  * Fetch latest changes from remote
429
423
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { AFSAccessMode, AFSEntry, AFSExecResult, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest } from "@aigne/afs";
1
+ import { AFSAccessMode, AFSEntry, AFSExecResult, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest, ProviderTreeSchema } from "@aigne/afs";
2
2
  import { AFSBaseProvider, RouteContext } from "@aigne/afs/provider";
3
3
  import { z } from "zod";
4
4
 
@@ -120,6 +120,7 @@ declare class AFSGit extends AFSBaseProvider {
120
120
  } | undefined;
121
121
  }, unknown>>;
122
122
  static manifest(): ProviderManifest;
123
+ static treeSchema(): ProviderTreeSchema;
123
124
  static load({
124
125
  basePath,
125
126
  config
@@ -368,6 +369,7 @@ declare class AFSGit extends AFSBaseProvider {
368
369
  /**
369
370
  * Decode branch name (replace ~ with /)
370
371
  */
372
+ private assertWithinWorktree;
371
373
  private decodeBranchName;
372
374
  /**
373
375
  * Encode branch name (replace / with ~)
@@ -416,14 +418,6 @@ declare class AFSGit extends AFSBaseProvider {
416
418
  * Note: list() returns only children, never the path itself (per new semantics)
417
419
  */
418
420
  private listWithGitLsTree;
419
- /**
420
- * Detect MIME type based on file extension
421
- */
422
- private getMimeType;
423
- /**
424
- * Check if file is likely binary based on extension
425
- */
426
- private isBinaryFile;
427
421
  /**
428
422
  * Fetch latest changes from remote
429
423
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import { __require } from "./_virtual/rolldown_runtime.mjs";
2
1
  import { __decorate } from "./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs";
3
2
  import { execFile } from "node:child_process";
4
3
  import { createHash } from "node:crypto";
@@ -9,6 +8,7 @@ import { promisify } from "node:util";
9
8
  import { AFSNotFoundError } from "@aigne/afs";
10
9
  import { AFSBaseProvider, Actions, Delete, Explain, List, Meta, Read, Rename, Search, Stat, Write } from "@aigne/afs/provider";
11
10
  import { camelize, optionalize, zodParse } from "@aigne/afs/utils/zod";
11
+ import { assertPathWithinRoot, getMimeType, isBinaryFile } from "@aigne/afs-provider-utils";
12
12
  import { simpleGit } from "simple-git";
13
13
  import { z } from "zod";
14
14
 
@@ -43,13 +43,94 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
43
43
  name: "git",
44
44
  description: "Git repository browser with branch-based access.\n- Browse branches, read files at any ref, search across repository\n- Exec actions (readwrite): `diff`, `create-branch`, `commit`, `merge`\n- Virtual `.log/` tree exposes commit history per branch\n- Path structure: `/{branch}/{file-path}` (branch `/` encoded as `~`)",
45
45
  uriTemplate: "git://{localPath+}",
46
- category: "version-control",
46
+ category: "vcs",
47
47
  schema: z.object({
48
48
  localPath: z.string(),
49
49
  branch: z.string().optional(),
50
50
  remoteUrl: z.string().optional()
51
51
  }),
52
- tags: ["git", "version-control"]
52
+ tags: ["git", "version-control"],
53
+ capabilityTags: [
54
+ "read-write",
55
+ "search",
56
+ "auth:none",
57
+ "local"
58
+ ],
59
+ security: {
60
+ riskLevel: "local",
61
+ resourceAccess: ["local-filesystem"],
62
+ requires: ["git"],
63
+ dataSensitivity: ["code"],
64
+ notes: ["Accesses local git repositories; readwrite mode creates worktrees and can commit"]
65
+ },
66
+ capabilities: {
67
+ filesystem: {
68
+ read: true,
69
+ write: true
70
+ },
71
+ process: {
72
+ spawn: true,
73
+ allowedCommands: ["git"]
74
+ }
75
+ }
76
+ };
77
+ }
78
+ static treeSchema() {
79
+ return {
80
+ operations: [
81
+ "list",
82
+ "read",
83
+ "write",
84
+ "delete",
85
+ "search",
86
+ "stat",
87
+ "explain"
88
+ ],
89
+ tree: {
90
+ "/": {
91
+ kind: "git:root",
92
+ operations: ["list", "read"]
93
+ },
94
+ "/{branch}": {
95
+ kind: "git:branch",
96
+ operations: [
97
+ "list",
98
+ "read",
99
+ "search"
100
+ ],
101
+ actions: [
102
+ "diff",
103
+ "create-branch",
104
+ "commit",
105
+ "merge"
106
+ ]
107
+ },
108
+ "/{branch}/{path+}": {
109
+ kind: "git:file",
110
+ operations: [
111
+ "list",
112
+ "read",
113
+ "write",
114
+ "delete",
115
+ "search"
116
+ ]
117
+ },
118
+ "/{branch}/.log": {
119
+ kind: "git:log",
120
+ operations: ["list"]
121
+ },
122
+ "/{branch}/.log/{index}": {
123
+ kind: "git:commit",
124
+ operations: ["read"]
125
+ }
126
+ },
127
+ auth: { type: "none" },
128
+ bestFor: [
129
+ "code browsing",
130
+ "version control",
131
+ "branch comparison"
132
+ ],
133
+ notFor: ["binary storage", "large files"]
53
134
  };
54
135
  }
55
136
  static async load({ basePath, config } = {}) {
@@ -88,15 +169,6 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
88
169
  const repoHash = createHash("md5").update(options.remoteUrl).digest("hex").substring(0, 8);
89
170
  repoPath = join(tmpdir(), `afs-git-remote-${repoHash}`);
90
171
  } else throw new Error("Either repoPath or remoteUrl must be provided");
91
- if (options.repoPath && !options.remoteUrl) {
92
- const { existsSync, mkdirSync } = __require("node:fs");
93
- const { execSync } = __require("node:child_process");
94
- if (!existsSync(repoPath)) mkdirSync(repoPath, { recursive: true });
95
- if (!existsSync(join(repoPath, ".git"))) execSync("git init -b main", {
96
- cwd: repoPath,
97
- stdio: "ignore"
98
- });
99
- }
100
172
  this.repoPath = repoPath;
101
173
  this.name = options.name || repoName;
102
174
  this.description = options.description;
@@ -118,6 +190,15 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
118
190
  */
119
191
  async initialize() {
120
192
  const options = this.options;
193
+ if (options.repoPath && !options.remoteUrl) {
194
+ const { existsSync, mkdirSync } = await import("node:fs");
195
+ const { execSync } = await import("node:child_process");
196
+ if (!existsSync(this.repoPath)) mkdirSync(this.repoPath, { recursive: true });
197
+ if (!existsSync(join(this.repoPath, ".git"))) execSync("git init -b main", {
198
+ cwd: this.repoPath,
199
+ stdio: "ignore"
200
+ });
201
+ }
121
202
  if (options.remoteUrl) {
122
203
  const targetPath = options.repoPath ? isAbsolute(options.repoPath) ? options.repoPath : join(options.cwd || process.cwd(), options.repoPath) : this.repoPath;
123
204
  if (!options.repoPath) this.isAutoCloned = true;
@@ -303,14 +384,15 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
303
384
  const worktreePath = this.worktrees.get(branch);
304
385
  if (worktreePath) try {
305
386
  const fullPath = join(worktreePath, filePath);
387
+ await this.assertWithinWorktree(fullPath, worktreePath);
306
388
  const stats = await stat(fullPath);
307
389
  if (stats.isDirectory()) {
308
390
  const files = await readdir(fullPath);
309
391
  const afsPath$2 = this.buildBranchPath(branch, filePath);
310
392
  return this.buildEntry(afsPath$2, { meta: { childrenCount: files.length } });
311
393
  }
312
- const mimeType$1 = this.getMimeType(filePath);
313
- const isBinary$1 = this.isBinaryFile(filePath);
394
+ const mimeType$1 = getMimeType(filePath);
395
+ const isBinary$1 = isBinaryFile(filePath);
314
396
  let content$1;
315
397
  const meta$1 = {
316
398
  size: stats.size,
@@ -327,7 +409,9 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
327
409
  createdAt: stats.birthtime,
328
410
  updatedAt: stats.mtime
329
411
  });
330
- } catch {}
412
+ } catch (err) {
413
+ if (err instanceof Error && "code" in err && err.code === "AFS_PERMISSION_DENIED") throw err;
414
+ }
331
415
  const objectType = await this.git.raw([
332
416
  "cat-file",
333
417
  "-t",
@@ -344,8 +428,8 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
344
428
  "-s",
345
429
  `${branch}:${filePath}`
346
430
  ]).then((s) => Number.parseInt(s.trim(), 10));
347
- const mimeType = this.getMimeType(filePath);
348
- const isBinary = this.isBinaryFile(filePath);
431
+ const mimeType = getMimeType(filePath);
432
+ const isBinary = isBinaryFile(filePath);
349
433
  let content;
350
434
  const meta = {
351
435
  size,
@@ -389,9 +473,10 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
389
473
  await this.ready();
390
474
  const branch = this.decodeBranchName(ctx.params.branch);
391
475
  const filePath = ctx.params.path;
392
- const append = ctx.options?.append ?? false;
476
+ const mode = ctx.options?.mode ?? "replace";
393
477
  const worktreePath = await this.ensureWorktree(branch);
394
478
  const fullPath = join(worktreePath, filePath);
479
+ await this.assertWithinWorktree(fullPath, worktreePath);
395
480
  await mkdir(dirname(fullPath), { recursive: true });
396
481
  if (payload.content !== void 0) {
397
482
  let contentToWrite;
@@ -399,7 +484,7 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
399
484
  else contentToWrite = JSON.stringify(payload.content, null, 2);
400
485
  await writeFile(fullPath, contentToWrite, {
401
486
  encoding: "utf8",
402
- flag: append ? "a" : "w"
487
+ flag: mode === "append" ? "a" : "w"
403
488
  });
404
489
  }
405
490
  if (this.options.autoCommit) {
@@ -454,6 +539,7 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
454
539
  const recursive = ctx.options?.recursive ?? false;
455
540
  const worktreePath = await this.ensureWorktree(branch);
456
541
  const fullPath = join(worktreePath, filePath);
542
+ await this.assertWithinWorktree(fullPath, worktreePath);
457
543
  let stats;
458
544
  try {
459
545
  stats = await stat(fullPath);
@@ -491,6 +577,8 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
491
577
  const worktreePath = await this.ensureWorktree(oldBranch);
492
578
  const oldFullPath = join(worktreePath, oldFilePath);
493
579
  const newFullPath = join(worktreePath, newFilePath);
580
+ await this.assertWithinWorktree(oldFullPath, worktreePath);
581
+ await this.assertWithinWorktree(newFullPath, worktreePath);
494
582
  try {
495
583
  await stat(oldFullPath);
496
584
  } catch (error) {
@@ -1197,6 +1285,9 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
1197
1285
  /**
1198
1286
  * Decode branch name (replace ~ with /)
1199
1287
  */
1288
+ async assertWithinWorktree(fullPath, worktreeRoot) {
1289
+ return assertPathWithinRoot(fullPath, worktreeRoot);
1290
+ }
1200
1291
  decodeBranchName(encoded) {
1201
1292
  return encoded.replace(/~/g, "/");
1202
1293
  }
@@ -1397,54 +1488,6 @@ var AFSGit = class AFSGit extends AFSBaseProvider {
1397
1488
  }
1398
1489
  }
1399
1490
  /**
1400
- * Detect MIME type based on file extension
1401
- */
1402
- getMimeType(filePath) {
1403
- return {
1404
- png: "image/png",
1405
- jpg: "image/jpeg",
1406
- jpeg: "image/jpeg",
1407
- gif: "image/gif",
1408
- bmp: "image/bmp",
1409
- webp: "image/webp",
1410
- svg: "image/svg+xml",
1411
- ico: "image/x-icon",
1412
- pdf: "application/pdf",
1413
- txt: "text/plain",
1414
- md: "text/markdown",
1415
- js: "text/javascript",
1416
- ts: "text/typescript",
1417
- json: "application/json",
1418
- html: "text/html",
1419
- css: "text/css",
1420
- xml: "text/xml"
1421
- }[filePath.split(".").pop()?.toLowerCase() || ""] || "application/octet-stream";
1422
- }
1423
- /**
1424
- * Check if file is likely binary based on extension
1425
- */
1426
- isBinaryFile(filePath) {
1427
- const ext = filePath.split(".").pop()?.toLowerCase();
1428
- return [
1429
- "png",
1430
- "jpg",
1431
- "jpeg",
1432
- "gif",
1433
- "bmp",
1434
- "webp",
1435
- "ico",
1436
- "pdf",
1437
- "zip",
1438
- "tar",
1439
- "gz",
1440
- "exe",
1441
- "dll",
1442
- "so",
1443
- "dylib",
1444
- "wasm"
1445
- ].includes(ext || "");
1446
- }
1447
- /**
1448
1491
  * Fetch latest changes from remote
1449
1492
  */
1450
1493
  async fetch() {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["afsPath","mimeType","isBinary","content","meta"],"sources":["../src/index.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type AFSAccessMode,\n type AFSDeleteOptions,\n type AFSEntry,\n type AFSEntryMetadata,\n type AFSExecResult,\n type AFSExplainOptions,\n type AFSExplainResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSRenameOptions,\n type AFSSearchOptions,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type CapabilitiesManifest,\n type ProviderManifest,\n} from \"@aigne/afs\";\nimport {\n Actions,\n AFSBaseProvider,\n Delete,\n Explain,\n List,\n Meta,\n Read,\n Rename,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { camelize, optionalize, zodParse } from \"@aigne/afs/utils/zod\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { z } from \"zod\";\n\nconst LIST_MAX_LIMIT = 1000;\n\nconst execFileAsync = promisify(execFile);\n\nexport interface AFSGitOptions {\n name?: string;\n /**\n * Local path to git repository.\n * If remoteUrl is provided and repoPath doesn't exist, will clone to this path.\n * If remoteUrl is provided and repoPath is not specified, clones to temp directory.\n */\n repoPath?: string;\n /**\n * Remote repository URL (https or git protocol).\n * If provided, will clone the repository if repoPath doesn't exist.\n * Examples:\n * - https://github.com/user/repo.git\n * - git@github.com:user/repo.git\n */\n remoteUrl?: string;\n description?: string;\n /**\n * List of branches to expose/access.\n * Also used for clone optimization when cloning from remoteUrl:\n * - Single branch (e.g., ['main']): Uses --single-branch for faster clone\n * - Multiple branches: Clones all branches, filters access to specified ones\n * - Not specified: All branches are accessible\n */\n branches?: string[];\n /**\n * Access mode for this module.\n * - \"readonly\": Only read operations are allowed, uses git commands (no worktree)\n * - \"readwrite\": All operations are allowed, creates worktrees as needed\n * @default \"readonly\"\n */\n accessMode?: AFSAccessMode;\n /**\n * Automatically commit changes after write operations\n * @default false\n */\n autoCommit?: boolean;\n /**\n * Author information for commits when autoCommit is enabled\n */\n commitAuthor?: {\n name: string;\n email: string;\n };\n /**\n * Clone depth for shallow clone (only used when cloning from remoteUrl)\n * @default 1\n */\n depth?: number;\n /**\n * Automatically clean up cloned repository on cleanup()\n * Only applies when repository was auto-cloned to temp directory\n * @default true\n */\n autoCleanup?: boolean;\n /**\n * Git clone options (only used when cloning from remoteUrl)\n */\n cloneOptions?: {\n /**\n * Authentication credentials for private repositories\n */\n auth?: {\n username?: string;\n password?: string;\n };\n };\n}\n\nconst afsGitOptionsSchema = camelize(\n z\n .object({\n name: optionalize(z.string()),\n repoPath: optionalize(z.string().describe(\"The path to the git repository\")),\n remoteUrl: optionalize(z.string().describe(\"Remote repository URL (https or git protocol)\")),\n description: optionalize(z.string().describe(\"A description of the repository\")),\n branches: optionalize(z.array(z.string()).describe(\"List of branches to expose\")),\n accessMode: optionalize(\n z.enum([\"readonly\", \"readwrite\"]).describe(\"Access mode for this module\"),\n ),\n autoCommit: optionalize(\n z.boolean().describe(\"Automatically commit changes after write operations\"),\n ),\n commitAuthor: optionalize(\n z.object({\n name: z.string(),\n email: z.string(),\n }),\n ),\n depth: optionalize(z.number().describe(\"Clone depth for shallow clone\")),\n autoCleanup: optionalize(\n z.boolean().describe(\"Automatically clean up cloned repository on cleanup()\"),\n ),\n cloneOptions: optionalize(\n z.object({\n auth: optionalize(\n z.object({\n username: optionalize(z.string()),\n password: optionalize(z.string()),\n }),\n ),\n }),\n ),\n })\n .refine((data) => data.repoPath || data.remoteUrl, {\n message: \"Either repoPath or remoteUrl must be provided\",\n }),\n);\n\nexport class AFSGit extends AFSBaseProvider {\n static schema() {\n return afsGitOptionsSchema;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"git\",\n description:\n \"Git repository browser with branch-based access.\\n- Browse branches, read files at any ref, search across repository\\n- Exec actions (readwrite): `diff`, `create-branch`, `commit`, `merge`\\n- Virtual `.log/` tree exposes commit history per branch\\n- Path structure: `/{branch}/{file-path}` (branch `/` encoded as `~`)\",\n uriTemplate: \"git://{localPath+}\",\n category: \"version-control\",\n schema: z.object({\n localPath: z.string(),\n branch: z.string().optional(),\n remoteUrl: z.string().optional(),\n }),\n tags: [\"git\", \"version-control\"],\n };\n }\n\n static async load({ basePath, config }: AFSModuleLoadParams = {}) {\n const valid = await AFSGit.schema().parseAsync(config);\n const instance = new AFSGit({ ...valid, cwd: basePath });\n await instance.ready();\n return instance;\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n\n private initPromise: Promise<void>;\n private git: SimpleGit;\n private tempBase: string;\n private worktrees: Map<string, string> = new Map();\n private repoHash: string;\n private isAutoCloned = false;\n private clonedPath?: string;\n private repoPath: string;\n\n constructor(\n public options: AFSGitOptions & {\n cwd?: string;\n localPath?: string;\n branch?: string;\n uri?: string;\n },\n ) {\n super();\n\n // Normalize registry-passed template vars\n if ((options as any).localPath && !options.repoPath) {\n options.repoPath = (options as any).localPath;\n }\n if ((options as any).branch && !options.branches) {\n options.branches = [(options as any).branch];\n }\n\n zodParse(afsGitOptionsSchema, options);\n\n // Synchronously determine repoPath to initialize name\n let repoPath: string;\n let repoName: string;\n\n if (options.repoPath) {\n // Use provided repoPath\n repoPath = isAbsolute(options.repoPath)\n ? options.repoPath\n : join(options.cwd || process.cwd(), options.repoPath);\n repoName = basename(repoPath);\n } else if (options.remoteUrl) {\n // Extract repo name from URL for temporary name\n const urlParts = options.remoteUrl.split(\"/\");\n const lastPart = urlParts[urlParts.length - 1];\n repoName = lastPart?.replace(/\\.git$/, \"\") || \"git\";\n\n // Will be updated during async init, use temp path for now\n const repoHash = createHash(\"md5\").update(options.remoteUrl).digest(\"hex\").substring(0, 8);\n repoPath = join(tmpdir(), `afs-git-remote-${repoHash}`);\n } else {\n // This should never happen due to schema validation\n throw new Error(\"Either repoPath or remoteUrl must be provided\");\n }\n\n // Auto-create local repository if it doesn't exist (skip for remoteUrl — will be cloned)\n if (options.repoPath && !options.remoteUrl) {\n const { existsSync, mkdirSync } = require(\"node:fs\") as typeof import(\"node:fs\");\n const { execSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n if (!existsSync(repoPath)) {\n mkdirSync(repoPath, { recursive: true });\n }\n if (!existsSync(join(repoPath, \".git\"))) {\n execSync(\"git init -b main\", { cwd: repoPath, stdio: \"ignore\" });\n }\n }\n\n // Initialize basic properties immediately\n this.repoPath = repoPath;\n this.name = options.name || repoName;\n this.description = options.description;\n this.accessMode = options.accessMode ?? \"readonly\";\n\n // Calculate hash for temp directories\n this.repoHash = createHash(\"md5\").update(repoPath).digest(\"hex\").substring(0, 8);\n this.tempBase = join(tmpdir(), `afs-git-${this.repoHash}`);\n\n // Note: git and other properties will be initialized in initialize() after cloning\n // We need to delay simpleGit() initialization until the directory exists\n this.git = null as any; // Will be set in initialize()\n\n // Start async initialization (cloning if needed)\n this.initPromise = this.initialize();\n }\n\n /**\n * Wait for async initialization to complete\n */\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n /**\n * Async initialization logic (runs in constructor)\n * Handles cloning remote repositories if needed\n */\n private async initialize(): Promise<void> {\n const options = this.options;\n\n // If remoteUrl is provided, handle cloning\n if (options.remoteUrl) {\n const targetPath = options.repoPath\n ? isAbsolute(options.repoPath)\n ? options.repoPath\n : join(options.cwd || process.cwd(), options.repoPath)\n : this.repoPath; // Use temp path set in constructor\n\n // Mark as auto-cloned if we're using temp directory\n if (!options.repoPath) {\n this.isAutoCloned = true;\n }\n\n // Check if targetPath exists and is a valid git repository\n const exists = await stat(targetPath)\n .then(() => true)\n .catch(() => false);\n\n let needsClone = !exists;\n\n // If directory exists but is not a valid git repo, clean it up and re-clone\n if (exists) {\n const tempGit = simpleGit(targetPath);\n const isValidRepo = await tempGit.checkIsRepo().catch(() => false);\n if (!isValidRepo) {\n // Remove invalid directory and re-clone\n await rm(targetPath, { recursive: true, force: true });\n needsClone = true;\n }\n }\n\n if (needsClone) {\n // Determine if single-branch optimization should be used\n const singleBranch = options.branches?.length === 1 ? options.branches[0] : undefined;\n\n await AFSGit.cloneRepository(options.remoteUrl, targetPath, {\n depth: options.depth ?? 1,\n branch: singleBranch,\n auth: options.cloneOptions?.auth,\n });\n }\n\n // Update properties if targetPath differs from constructor initialization\n if (targetPath !== this.repoPath) {\n this.repoPath = targetPath;\n this.repoHash = createHash(\"md5\").update(targetPath).digest(\"hex\").substring(0, 8);\n this.tempBase = join(tmpdir(), `afs-git-${this.repoHash}`);\n }\n\n this.clonedPath = this.isAutoCloned ? targetPath : undefined;\n }\n\n // Now that the directory exists (either it was there or we cloned it), initialize git\n this.git = simpleGit(this.repoPath);\n\n // Validate that the directory is actually a git repository\n const isRepo = await this.git.checkIsRepo();\n if (!isRepo) {\n throw new Error(`Not a git repository: ${this.repoPath}`);\n }\n }\n\n /**\n * Clone a remote repository to local path\n */\n private static async cloneRepository(\n remoteUrl: string,\n targetPath: string,\n options: {\n depth?: number;\n branch?: string;\n auth?: { username?: string; password?: string };\n } = {},\n ): Promise<void> {\n const git = simpleGit();\n\n // Build clone options\n const cloneArgs: string[] = [];\n\n if (options.depth) {\n cloneArgs.push(\"--depth\", options.depth.toString());\n }\n\n if (options.branch) {\n cloneArgs.push(\"--branch\", options.branch, \"--single-branch\");\n }\n\n // Handle authentication in URL if provided\n let cloneUrl = remoteUrl;\n if (options.auth?.username && options.auth?.password) {\n // Insert credentials into HTTPS URL\n if (remoteUrl.startsWith(\"https://\")) {\n const url = new URL(remoteUrl);\n url.username = encodeURIComponent(options.auth.username);\n url.password = encodeURIComponent(options.auth.password);\n cloneUrl = url.toString();\n }\n }\n\n await git.clone(cloneUrl, targetPath, cloneArgs);\n }\n\n // ========== Route Handlers ==========\n\n /**\n * List root (branches)\n * Note: list() returns only children (branches), never the path itself (per new semantics)\n */\n @List(\"/\", { handleDepth: true })\n async listRootHandler(ctx: RouteContext): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const options = ctx.options as { limit?: number; maxDepth?: number };\n const maxDepth = options?.maxDepth ?? 1;\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n // maxDepth: 0 means return no children\n if (maxDepth === 0) {\n return { data: [] };\n }\n\n const branches = await this.getBranches();\n const entries: AFSEntry[] = [];\n\n for (const name of branches) {\n if (entries.length >= limit) break;\n\n const encodedPath = this.buildBranchPath(name);\n\n // Get children count for this branch\n const branchChildrenCount = await this.getChildrenCount(name, \"\");\n\n entries.push(\n this.buildEntry(encodedPath, {\n meta: { kind: \"git:branch\", childrenCount: branchChildrenCount },\n }),\n );\n\n // If maxDepth > 1, also list contents of each branch\n if (maxDepth > 1) {\n const branchResult = await this.listWithGitLsTree(name, \"\", {\n maxDepth: maxDepth - 1,\n limit: limit - entries.length,\n });\n entries.push(...branchResult.data);\n }\n }\n\n return { data: entries };\n }\n\n /**\n * List branch root (matches /main, /develop, etc.)\n */\n @List(\"/:branch\", { handleDepth: true })\n async listBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n return this.listWithGitLsTree(branch, \"\", ctx.options as { maxDepth?: number; limit?: number });\n }\n\n /**\n * List files in branch with subpath (matches /main/src, /main/src/foo, etc.)\n */\n @List(\"/:branch/:path+\", { handleDepth: true })\n async listBranchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n return this.listWithGitLsTree(\n branch,\n filePath,\n ctx.options as { maxDepth?: number; limit?: number },\n );\n }\n\n // ========== Meta Handlers ==========\n // These handlers provide metadata access for all paths via .meta suffix\n\n /**\n * Read root metadata (introspection only, read-only)\n */\n @Meta(\"/\")\n async readRootMetaHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branches = await this.getBranches();\n return this.buildEntry(\"/.meta\", {\n meta: { childrenCount: branches.length, type: \"root\" },\n });\n }\n\n /**\n * Read branch root metadata (introspection only, read-only)\n */\n @Meta(\"/:branch\")\n async readBranchMetaHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const childrenCount = await this.getChildrenCount(branch, \"\");\n const branchPath = `/${this.encodeBranchName(branch)}`;\n const metaPath = `${branchPath}/.meta`;\n const lastCommit = await this.getLastCommit(branch);\n\n return this.buildEntry(metaPath, {\n meta: { childrenCount, type: \"branch\", lastCommit },\n });\n }\n\n /**\n * Read file or directory metadata in branch (introspection only, read-only)\n */\n @Meta(\"/:branch/:path+\")\n async readPathMetaHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n // Check if the path exists\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n const isDir = objectType === \"tree\";\n const metaPath = `/${this.encodeBranchName(branch)}/${filePath}/.meta`;\n\n let childrenCount: number | undefined;\n if (isDir) {\n childrenCount = await this.getChildrenCount(branch, filePath);\n }\n\n return this.buildEntry(metaPath, {\n meta: {\n childrenCount,\n type: isDir ? \"directory\" : \"file\",\n gitObjectType: objectType,\n },\n });\n }\n\n // ========== Regular Read Handlers ==========\n\n /**\n * Read root\n */\n @Read(\"/\")\n async readRootHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branches = await this.getBranches();\n return this.buildEntry(\"/\", {\n meta: { childrenCount: branches.length },\n });\n }\n\n /**\n * Read branch root\n */\n @Read(\"/:branch\")\n async readBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const branchPath = this.buildBranchPath(branch);\n const childrenCount = await this.getChildrenCount(branch, \"\");\n const lastCommit = await this.getLastCommit(branch);\n return this.buildEntry(branchPath, {\n meta: { childrenCount, lastCommit },\n });\n }\n\n /**\n * Read file or directory in branch\n */\n @Read(\"/:branch/:path+\")\n async readBranchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n // Check if there's an active worktree for this branch - read from there first\n // This handles files that were written but may be in a different state than git index\n const worktreePath = this.worktrees.get(branch);\n if (worktreePath) {\n try {\n const fullPath = join(worktreePath, filePath);\n const stats = await stat(fullPath);\n\n if (stats.isDirectory()) {\n // It's a directory - count children\n const files = await readdir(fullPath);\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n meta: { childrenCount: files.length },\n });\n }\n\n // It's a file - read content\n const mimeType = this.getMimeType(filePath);\n const isBinary = this.isBinaryFile(filePath);\n\n let content: string;\n const meta: AFSEntryMetadata = {\n size: stats.size,\n mimeType,\n };\n\n if (isBinary) {\n const buffer = await readFile(fullPath);\n content = buffer.toString(\"base64\");\n meta.contentType = \"base64\";\n } else {\n content = await readFile(fullPath, \"utf8\");\n }\n\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n content,\n meta,\n createdAt: stats.birthtime,\n updatedAt: stats.mtime,\n });\n } catch {\n // File doesn't exist in worktree, fall through to git\n }\n }\n\n // Read from git repository\n // Check if path is a blob (file) or tree (directory)\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n // Path doesn't exist in git\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n if (objectType === \"tree\") {\n // It's a directory\n const afsPath = this.buildBranchPath(branch, filePath);\n const childrenCount = await this.getChildrenCount(branch, filePath);\n return this.buildEntry(afsPath, {\n meta: { childrenCount },\n });\n }\n\n // It's a file, get content\n const size = await this.git\n .raw([\"cat-file\", \"-s\", `${branch}:${filePath}`])\n .then((s) => Number.parseInt(s.trim(), 10));\n\n // Determine mimeType based on file extension\n const mimeType = this.getMimeType(filePath);\n const isBinary = this.isBinaryFile(filePath);\n\n let content: string;\n const meta: AFSEntryMetadata = {\n size,\n mimeType,\n };\n\n if (isBinary) {\n // For binary files, use execFileAsync to get raw buffer\n const { stdout } = await execFileAsync(\"git\", [\"cat-file\", \"-p\", `${branch}:${filePath}`], {\n cwd: this.options.repoPath,\n encoding: \"buffer\",\n maxBuffer: 10 * 1024 * 1024, // 10MB max\n });\n // Store only base64 string without data URL prefix\n content = (stdout as Buffer).toString(\"base64\");\n // Mark content as base64 in metadata\n meta.contentType = \"base64\";\n } else {\n // For text files, use git.show\n content = await this.git.show([`${branch}:${filePath}`]);\n }\n\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n content,\n meta,\n });\n }\n\n /**\n * Write to root is not allowed\n */\n @Write(\"/\")\n async writeRootHandler(): Promise<never> {\n throw new Error(\"Cannot write to root\");\n }\n\n /**\n * Write to branch root is not allowed\n */\n @Write(\"/:branch\")\n async writeBranchRootHandler(): Promise<never> {\n throw new Error(\"Cannot write to branch root\");\n }\n\n /**\n * Write file in branch\n */\n @Write(\"/:branch/:path+\")\n async writeHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<{ data: AFSEntry }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n const filePath = ctx.params.path;\n const options = ctx.options as { append?: boolean };\n const append = options?.append ?? false;\n\n // Create worktree for write operations\n const worktreePath = await this.ensureWorktree(branch);\n const fullPath = join(worktreePath, filePath);\n\n // Ensure parent directory exists\n const parentDir = dirname(fullPath);\n await mkdir(parentDir, { recursive: true });\n\n // Write content\n if (payload.content !== undefined) {\n let contentToWrite: string;\n if (typeof payload.content === \"string\") {\n contentToWrite = payload.content;\n } else {\n contentToWrite = JSON.stringify(payload.content, null, 2);\n }\n await writeFile(fullPath, contentToWrite, { encoding: \"utf8\", flag: append ? \"a\" : \"w\" });\n }\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add(filePath);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Update ${filePath}`);\n }\n\n // Get file stats\n const stats = await stat(fullPath);\n\n const afsPath = this.buildBranchPath(branch, filePath);\n const writtenEntry: AFSEntry = {\n id: afsPath,\n path: afsPath,\n content: payload.content,\n summary: payload.summary,\n createdAt: stats.birthtime,\n updatedAt: stats.mtime,\n meta: {\n ...payload.meta,\n size: stats.size,\n } as AFSEntryMetadata,\n userId: payload.userId,\n sessionId: payload.sessionId,\n linkTo: payload.linkTo,\n };\n\n return { data: writtenEntry };\n }\n\n /**\n * Delete root is not allowed\n */\n @Delete(\"/\")\n async deleteRootHandler(): Promise<never> {\n throw new Error(\"Cannot delete root\");\n }\n\n /**\n * Delete branch root is not allowed\n */\n @Delete(\"/:branch\")\n async deleteBranchRootHandler(ctx: RouteContext<{ branch: string }>): Promise<never> {\n await this.ready();\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n throw new Error(\"Cannot delete branch root\");\n }\n\n /**\n * Delete file in branch\n */\n @Delete(\"/:branch/:path+\")\n async deleteHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<{ message: string }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n const filePath = ctx.params.path;\n const options = ctx.options as AFSDeleteOptions | undefined;\n const recursive = options?.recursive ?? false;\n\n // Create worktree for delete operations\n const worktreePath = await this.ensureWorktree(branch);\n const fullPath = join(worktreePath, filePath);\n\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(fullPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n throw error;\n }\n\n if (stats.isDirectory() && !recursive) {\n throw new Error(\n `Cannot delete directory '/${ctx.params.branch}/${filePath}' without recursive option. Set recursive: true to delete directories.`,\n );\n }\n\n await rm(fullPath, { recursive, force: true });\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add(filePath);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Delete ${filePath}`);\n }\n\n return { message: `Successfully deleted: /${ctx.params.branch}/${filePath}` };\n }\n\n /**\n * Rename file in branch\n */\n @Rename(\"/:branch/:path+\")\n async renameHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n newPath: string,\n ): Promise<{ message: string }> {\n await this.ready();\n\n const oldBranch = this.decodeBranchName(ctx.params.branch);\n const oldFilePath = ctx.params.path;\n\n // Parse new path\n const { branch: newBranch, filePath: newFilePath } = this.parsePath(newPath);\n const options = ctx.options as AFSRenameOptions | undefined;\n const overwrite = options?.overwrite ?? false;\n\n if (!newBranch || !newFilePath) {\n throw new Error(\"Cannot rename to root or branch root\");\n }\n\n if (oldBranch !== newBranch) {\n throw new Error(\"Cannot rename across branches\");\n }\n\n // Create worktree for rename operations\n const worktreePath = await this.ensureWorktree(oldBranch);\n const oldFullPath = join(worktreePath, oldFilePath);\n const newFullPath = join(worktreePath, newFilePath);\n\n // Check if source exists\n try {\n await stat(oldFullPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new AFSNotFoundError(this.buildBranchPath(oldBranch, oldFilePath));\n }\n throw error;\n }\n\n // Check if destination exists\n try {\n await stat(newFullPath);\n if (!overwrite) {\n throw new Error(\n `Destination '${newPath}' already exists. Set overwrite: true to replace it.`,\n );\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n\n // Ensure parent directory exists\n const newParentDir = dirname(newFullPath);\n await mkdir(newParentDir, { recursive: true });\n\n // Perform rename\n await rename(oldFullPath, newFullPath);\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add([oldFilePath, newFilePath]);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Rename ${oldFilePath} to ${newFilePath}`);\n }\n\n return {\n message: `Successfully renamed '/${ctx.params.branch}/${oldFilePath}' to '${newPath}'`,\n };\n }\n\n /**\n * Search files in branch root\n */\n @Search(\"/:branch\")\n async searchBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n return this.searchInBranch(ctx.params.branch, \"\", query, options);\n }\n\n /**\n * Search files in branch path\n */\n @Search(\"/:branch/:path+\")\n async searchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n return this.searchInBranch(ctx.params.branch, ctx.params.path, query, options);\n }\n\n /**\n * Internal search implementation\n */\n private async searchInBranch(\n encodedBranch: string,\n filePath: string,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n await this.ready();\n\n const branch = this.decodeBranchName(encodedBranch);\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n try {\n // Use git grep for searching (no worktree needed)\n const args = [\"grep\", \"-n\", \"-I\"]; // -n for line numbers, -I to skip binary files\n\n if (options?.caseSensitive === false) {\n args.push(\"-i\");\n }\n\n args.push(query, branch);\n\n // Add path filter if specified\n if (filePath) {\n args.push(\"--\", filePath);\n }\n\n const output = await this.git.raw(args);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n\n const entries: AFSEntry[] = [];\n const processedFiles = new Set<string>();\n\n for (const line of lines) {\n // Format when searching in branch: branch:path:linenum:content\n // Try the format with branch prefix first\n let matchPath: string;\n let lineNum: string;\n let content: string;\n\n const matchWithBranch = line.match(/^[^:]+:([^:]+):(\\d+):(.+)$/);\n if (matchWithBranch) {\n matchPath = matchWithBranch[1]!;\n lineNum = matchWithBranch[2]!;\n content = matchWithBranch[3]!;\n } else {\n // Try format without branch: path:linenum:content\n const matchNoBranch = line.match(/^([^:]+):(\\d+):(.+)$/);\n if (!matchNoBranch) continue;\n matchPath = matchNoBranch[1]!;\n lineNum = matchNoBranch[2]!;\n content = matchNoBranch[3]!;\n }\n\n const afsPath = this.buildBranchPath(branch, matchPath);\n\n if (processedFiles.has(afsPath)) continue;\n processedFiles.add(afsPath);\n\n const entry = this.buildEntry(afsPath);\n entry.summary = `Line ${lineNum}: ${content}`;\n entries.push(entry);\n\n if (entries.length >= limit) {\n break;\n }\n }\n\n return {\n data: entries,\n message: entries.length >= limit ? `Results truncated to limit ${limit}` : undefined,\n };\n } catch (error) {\n // git grep returns exit code 1 if no matches found\n if ((error as Error).message.includes(\"did not match any file(s)\")) {\n return { data: [] };\n }\n return { data: [], message: (error as Error).message };\n }\n }\n\n /**\n * Stat root\n */\n @Stat(\"/\")\n async statRootHandler(_ctx: RouteContext): Promise<AFSStatResult> {\n const entry = await this.readRootHandler(_ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n /**\n * Stat branch root\n */\n @Stat(\"/:branch\")\n async statBranchRootHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSStatResult> {\n const entry = await this.readBranchRootHandler(ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n /**\n * Stat file or directory in branch\n */\n @Stat(\"/:branch/:path+\")\n async statHandler(ctx: RouteContext<{ branch: string; path: string }>): Promise<AFSStatResult> {\n const entry = await this.readBranchHandler(ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n // ========== Explain Handlers ==========\n\n /**\n * Explain root → repo info, branch list, default branch\n */\n @Explain(\"/\")\n async explainRootHandler(_ctx: RouteContext): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (_ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branches = await this.getBranches();\n const currentBranch = await this.git.revparse([\"--abbrev-ref\", \"HEAD\"]).then((b) => b.trim());\n\n let remoteUrl: string | undefined;\n try {\n remoteUrl = await this.git.remote([\"get-url\", \"origin\"]).then((u) => u?.trim());\n } catch {\n // No remote configured\n }\n\n const lines: string[] = [];\n lines.push(\"# Git Repository\");\n lines.push(\"\");\n lines.push(`**Provider:** ${this.name}`);\n if (this.description) {\n lines.push(`**Description:** ${this.description}`);\n }\n lines.push(`**Default Branch:** ${currentBranch}`);\n if (remoteUrl) {\n lines.push(`**Remote:** ${remoteUrl}`);\n }\n lines.push(`**Branches:** ${branches.length}`);\n lines.push(\"\");\n lines.push(\"## Branches\");\n lines.push(\"\");\n for (const branch of branches) {\n lines.push(`- ${branch}`);\n }\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n /**\n * Explain branch → branch name, HEAD commit, file count\n */\n @Explain(\"/:branch\")\n async explainBranchHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n const lastCommit = await this.getLastCommit(branch);\n const fileCount = await this.getTreeFileCount(branch, \"\");\n\n const lines: string[] = [];\n lines.push(`# Branch: ${branch}`);\n lines.push(\"\");\n lines.push(`**HEAD Commit:** ${lastCommit.shortHash} - ${lastCommit.message}`);\n lines.push(`**Author:** ${lastCommit.author}`);\n lines.push(`**Date:** ${lastCommit.date}`);\n lines.push(`**Files:** ${fileCount} entries in tree`);\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n /**\n * Explain file or directory → path, size, last modified commit\n */\n @Explain(\"/:branch/:path+\")\n async explainPathHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n const isDir = objectType === \"tree\";\n const lines: string[] = [];\n\n lines.push(`# ${basename(filePath)}`);\n lines.push(\"\");\n lines.push(`**Path:** ${filePath}`);\n lines.push(`**Type:** ${isDir ? \"directory\" : \"file\"}`);\n\n if (!isDir) {\n const size = await this.git\n .raw([\"cat-file\", \"-s\", `${branch}:${filePath}`])\n .then((s) => Number.parseInt(s.trim(), 10));\n lines.push(`**Size:** ${size} bytes`);\n }\n\n // Get last commit that modified this path\n try {\n const logOutput = await this.git.raw([\n \"log\",\n \"-1\",\n \"--format=%H%n%h%n%an%n%aI%n%s\",\n branch,\n \"--\",\n filePath,\n ]);\n const logLines = logOutput.trim().split(\"\\n\");\n if (logLines.length >= 5) {\n lines.push(\"\");\n lines.push(\"## Last Modified\");\n lines.push(`**Commit:** ${logLines[1]} - ${logLines[4]}`);\n lines.push(`**Author:** ${logLines[2]}`);\n lines.push(`**Date:** ${logLines[3]}`);\n }\n } catch {\n // Ignore log errors\n }\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n // ========== Capabilities ==========\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilitiesHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const operations = [\"list\", \"read\", \"stat\", \"explain\", \"search\"];\n if (this.accessMode === \"readwrite\") {\n operations.push(\"write\", \"delete\", \"rename\");\n }\n\n const actionCatalogs: CapabilitiesManifest[\"actions\"] = [];\n\n // diff is available in both modes conceptually, but exec() enforces readwrite\n // Include all actions in readwrite mode\n if (this.accessMode === \"readwrite\") {\n actionCatalogs.push({\n description: \"Git workflow actions\",\n catalog: [\n {\n name: \"diff\",\n description: \"Compare two branches or refs\",\n inputSchema: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Source ref\" },\n to: { type: \"string\", description: \"Target ref\" },\n path: { type: \"string\", description: \"Optional path filter\" },\n },\n required: [\"from\", \"to\"],\n },\n },\n {\n name: \"create-branch\",\n description: \"Create a new branch\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"New branch name\" },\n from: { type: \"string\", description: \"Source ref (defaults to current HEAD)\" },\n },\n required: [\"name\"],\n },\n },\n {\n name: \"commit\",\n description: \"Commit staged changes\",\n inputSchema: {\n type: \"object\",\n properties: {\n message: { type: \"string\", description: \"Commit message\" },\n author: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n email: { type: \"string\" },\n },\n },\n },\n required: [\"message\"],\n },\n },\n {\n name: \"merge\",\n description: \"Merge a branch into the current branch\",\n inputSchema: {\n type: \"object\",\n properties: {\n branch: { type: \"string\", description: \"Branch to merge\" },\n message: { type: \"string\", description: \"Custom merge message\" },\n },\n required: [\"branch\"],\n },\n },\n ],\n discovery: {\n pathTemplate: \"/:branch/.actions\",\n note: \"Git workflow actions (readwrite mode only)\",\n },\n });\n }\n\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.name,\n description: this.description || \"Git repository provider\",\n tools: [],\n actions: actionCatalogs,\n operations: this.getOperationsDeclaration(),\n };\n\n return {\n id: \"/.meta/.capabilities\",\n path: \"/.meta/.capabilities\",\n content: manifest,\n meta: { kind: \"afs:capabilities\", operations },\n };\n }\n\n // ========== Git Actions ==========\n\n /**\n * List available actions for a branch\n */\n @Actions(\"/:branch\")\n async listBranchActions(ctx: RouteContext<{ branch: string }>): Promise<AFSListResult> {\n if (this.accessMode !== \"readwrite\") {\n return { data: [] };\n }\n\n const basePath = `/${ctx.params.branch}/.actions`;\n return {\n data: [\n {\n id: \"diff\",\n path: `${basePath}/diff`,\n summary: \"Compare two branches or refs\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Source ref\" },\n to: { type: \"string\", description: \"Target ref\" },\n path: { type: \"string\", description: \"Optional path filter\" },\n },\n required: [\"from\", \"to\"],\n },\n },\n },\n {\n id: \"create-branch\",\n path: `${basePath}/create-branch`,\n summary: \"Create a new branch from this ref\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"New branch name\" },\n from: { type: \"string\", description: \"Source ref (defaults to current HEAD)\" },\n },\n required: [\"name\"],\n },\n },\n },\n {\n id: \"commit\",\n path: `${basePath}/commit`,\n summary: \"Commit staged changes\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n message: { type: \"string\", description: \"Commit message\" },\n author: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n email: { type: \"string\" },\n },\n },\n },\n required: [\"message\"],\n },\n },\n },\n {\n id: \"merge\",\n path: `${basePath}/merge`,\n summary: \"Merge another branch into this branch\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n branch: { type: \"string\", description: \"Branch to merge\" },\n message: { type: \"string\", description: \"Custom merge message\" },\n },\n required: [\"branch\"],\n },\n },\n },\n ],\n };\n }\n\n /**\n * diff action — compare two branches or refs\n */\n @Actions.Exec(\"/:branch\", \"diff\")\n async diffAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const from = args.from as string;\n const to = args.to as string;\n const pathFilter = args.path as string | undefined;\n\n if (!from || !to) {\n return {\n success: false,\n error: { code: \"INVALID_ARGS\", message: \"from and to are required\" },\n };\n }\n\n try {\n // Get diff stat\n const diffArgs = [\"diff\", \"--stat\", \"--name-only\", `${from}...${to}`];\n if (pathFilter) {\n diffArgs.push(\"--\", pathFilter);\n }\n const statOutput = await this.git.raw(diffArgs);\n const fileLines = statOutput\n .trim()\n .split(\"\\n\")\n .filter((l) => l.trim());\n const files = fileLines.map((path) => ({ path }));\n\n // Get diff patch\n const patchArgs = [\"diff\", `${from}...${to}`];\n if (pathFilter) {\n patchArgs.push(\"--\", pathFilter);\n }\n const patch = await this.git.raw(patchArgs);\n\n return {\n success: true,\n data: {\n from,\n to,\n files,\n patch,\n filesChanged: files.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"DIFF_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * create-branch action — create a new branch\n */\n @Actions.Exec(\"/:branch\", \"create-branch\")\n async createBranchAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const name = args.name as string;\n const from = args.from as string | undefined;\n\n if (!name) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"name is required\" } };\n }\n\n // Validate branch name - reject path traversal\n if (name.includes(\"..\")) {\n return {\n success: false,\n error: { code: \"INVALID_NAME\", message: \"Branch name contains invalid characters\" },\n };\n }\n\n try {\n if (from) {\n await this.git.raw([\"branch\", name, from]);\n } else {\n await this.git.raw([\"branch\", name]);\n }\n\n // Get the hash of the new branch\n const hash = await this.git.revparse([name]).then((h) => h.trim());\n\n return {\n success: true,\n data: { branch: name, hash },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"CREATE_BRANCH_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * commit action — commit staged changes\n */\n @Actions.Exec(\"/:branch\", \"commit\")\n async commitAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const message = args.message as string;\n if (!message) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"message is required\" } };\n }\n\n const author = args.author as { name?: string; email?: string } | undefined;\n\n try {\n const git = simpleGit(this.repoPath);\n\n // Check for staged changes\n const status = await git.status();\n if (\n status.staged.length === 0 &&\n status.files.filter((f) => f.index !== \" \" && f.index !== \"?\").length === 0\n ) {\n return {\n success: false,\n error: { code: \"NO_CHANGES\", message: \"No staged changes to commit\" },\n };\n }\n\n // Configure author if provided\n if (author?.name) {\n await git.addConfig(\"user.name\", author.name, undefined, \"local\");\n }\n if (author?.email) {\n await git.addConfig(\"user.email\", author.email, undefined, \"local\");\n }\n\n const result = await git.commit(message);\n\n return {\n success: true,\n data: {\n hash: result.commit || \"\",\n message,\n filesChanged: result.summary.changes,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"COMMIT_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * merge action — merge a branch into current branch\n */\n @Actions.Exec(\"/:branch\", \"merge\")\n async mergeAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const branch = args.branch as string;\n if (!branch) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"branch is required\" } };\n }\n\n const customMessage = args.message as string | undefined;\n\n try {\n const git = simpleGit(this.repoPath);\n\n // Verify the branch exists\n const branches = await git.branchLocal();\n if (!branches.all.includes(branch)) {\n return {\n success: false,\n error: { code: \"BRANCH_NOT_FOUND\", message: `Branch '${branch}' not found` },\n };\n }\n\n const mergeArgs = [branch];\n if (customMessage) {\n mergeArgs.push(\"-m\", customMessage);\n }\n\n const result = await git.merge(mergeArgs);\n\n // Get the resulting commit hash\n const hash = await git.revparse([\"HEAD\"]).then((h) => h.trim());\n\n return {\n success: true,\n data: {\n hash,\n merged: branch,\n conflicts: result.conflicts || [],\n },\n };\n } catch (error) {\n // Abort merge if there was a conflict\n try {\n const git = simpleGit(this.repoPath);\n await git.merge([\"--abort\"]);\n } catch {\n // Ignore abort errors\n }\n\n return {\n success: false,\n error: {\n code: \"MERGE_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n // ========== .log/ Virtual Tree ==========\n\n /**\n * List .log/ → commit list with pagination\n */\n @List(\"/:branch/.log\")\n async listLogHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSListResult> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n const options = ctx.options as { limit?: number; offset?: number };\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const offset = options?.offset || 0;\n\n const commits = await this.getCommitList(branch, limit, offset);\n const branchEncoded = this.encodeBranchName(branch);\n\n const entries: AFSEntry[] = commits.map((commit, i) =>\n this.buildEntry(`/${branchEncoded}/.log/${offset + i}`, {\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n }),\n );\n\n return { data: entries };\n }\n\n /**\n * Read .log/{index} → commit diff/patch content\n */\n @Read(\"/:branch/.log/:index\")\n async readLogEntryHandler(\n ctx: RouteContext<{ branch: string; index: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const index = Number.parseInt(ctx.params.index, 10);\n\n if (Number.isNaN(index) || index < 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${ctx.params.index}`);\n }\n\n const commits = await this.getCommitList(branch, 1, index);\n if (commits.length === 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${index}`);\n }\n\n const commit = commits[0]!;\n\n // Get diff for this commit\n let diff: string;\n try {\n diff = await this.git.raw([\"show\", \"--stat\", \"--patch\", commit.hash]);\n } catch {\n diff = \"\";\n }\n\n const branchEncoded = this.encodeBranchName(branch);\n return this.buildEntry(`/${branchEncoded}/.log/${index}`, {\n content: diff,\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n });\n }\n\n /**\n * Read .log/{index}/.meta → commit metadata only (no diff)\n */\n @Read(\"/:branch/.log/:index/.meta\")\n async readLogEntryMetaHandler(\n ctx: RouteContext<{ branch: string; index: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const index = Number.parseInt(ctx.params.index, 10);\n\n if (Number.isNaN(index) || index < 0) {\n throw new AFSNotFoundError(\n `/${this.encodeBranchName(branch)}/.log/${ctx.params.index}/.meta`,\n );\n }\n\n const commits = await this.getCommitList(branch, 1, index);\n if (commits.length === 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${index}/.meta`);\n }\n\n const commit = commits[0]!;\n const branchEncoded = this.encodeBranchName(branch);\n return this.buildEntry(`/${branchEncoded}/.log/${index}/.meta`, {\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n });\n }\n\n // ========== Private Helper Methods ==========\n\n /**\n * Decode branch name (replace ~ with /)\n */\n private decodeBranchName(encoded: string): string {\n return encoded.replace(/~/g, \"/\");\n }\n\n /**\n * Encode branch name (replace / with ~)\n */\n private encodeBranchName(branch: string): string {\n return branch.replace(/\\//g, \"~\");\n }\n\n /**\n * Parse AFS path into branch and file path\n * Branch names may contain slashes and are encoded with ~ in paths\n */\n private parsePath(path: string): { branch?: string; filePath: string } {\n const normalized = join(\"/\", path); // Ensure leading slash\n const segments = normalized.split(\"/\").filter(Boolean);\n\n if (segments.length === 0) {\n return { branch: undefined, filePath: \"\" };\n }\n\n // Decode branch name (first segment): replace ~ with /\n const branch = segments[0]!.replace(/~/g, \"/\");\n const filePath = segments.slice(1).join(\"/\");\n\n return { branch, filePath };\n }\n\n /**\n * Build AFS path with encoded branch name\n * Branch names with slashes are encoded by replacing / with ~\n */\n private buildBranchPath(branch: string, filePath?: string): string {\n const encodedBranch = this.encodeBranchName(branch);\n if (!filePath) {\n return `/${encodedBranch}`;\n }\n return `/${encodedBranch}/${filePath}`;\n }\n\n /**\n * Get list of available branches\n */\n private async getBranches(): Promise<string[]> {\n const branchSummary = await this.git.branchLocal();\n const allBranches = branchSummary.all;\n\n // Filter by allowed branches if specified\n if (this.options.branches && this.options.branches.length > 0) {\n return allBranches.filter((branch) => this.options.branches!.includes(branch));\n }\n\n return allBranches;\n }\n\n /**\n * Check if a branch exists, throw AFSNotFoundError if not\n */\n private async ensureBranchExists(branch: string): Promise<void> {\n const branches = await this.getBranches();\n if (!branches.includes(branch)) {\n throw new AFSNotFoundError(this.buildBranchPath(branch));\n }\n }\n\n /**\n * Get the number of children for a tree (directory) in git\n */\n private async getChildrenCount(branch: string, path: string): Promise<number> {\n try {\n const treeish = path ? `${branch}:${path}` : branch;\n const output = await this.git.raw([\"ls-tree\", treeish]);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n return lines.length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get the last commit on a branch\n */\n private async getLastCommit(\n branch: string,\n ): Promise<{ hash: string; shortHash: string; author: string; date: string; message: string }> {\n const output = await this.git.raw([\"log\", \"-1\", \"--format=%H%n%h%n%an%n%aI%n%s\", branch]);\n const lines = output.trim().split(\"\\n\");\n return {\n hash: lines[0] || \"\",\n shortHash: lines[1] || \"\",\n author: lines[2] || \"\",\n date: lines[3] || \"\",\n message: lines[4] || \"\",\n };\n }\n\n /**\n * Count total files in a tree (recursively)\n */\n private async getTreeFileCount(branch: string, path: string): Promise<number> {\n try {\n const treeish = path ? `${branch}:${path}` : branch;\n const output = await this.git.raw([\"ls-tree\", \"-r\", treeish]);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n return lines.length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get a list of commits on a branch with limit/offset\n */\n private async getCommitList(\n branch: string,\n limit: number,\n offset: number,\n ): Promise<{ hash: string; shortHash: string; author: string; date: string; message: string }[]> {\n try {\n const args = [\n \"log\",\n `--skip=${offset}`,\n `-${limit}`,\n \"--format=%H%n%h%n%an%n%aI%n%s%n---COMMIT_SEP---\",\n branch,\n ];\n const output = await this.git.raw(args);\n const blocks = output.split(\"---COMMIT_SEP---\").filter((b) => b.trim());\n\n return blocks.map((block) => {\n const lines = block.trim().split(\"\\n\");\n return {\n hash: lines[0] || \"\",\n shortHash: lines[1] || \"\",\n author: lines[2] || \"\",\n date: lines[3] || \"\",\n message: lines[4] || \"\",\n };\n });\n } catch {\n return [];\n }\n }\n\n /**\n * Ensure worktree exists for a branch (lazy creation)\n */\n private async ensureWorktree(branch: string): Promise<string> {\n if (this.worktrees.has(branch)) {\n return this.worktrees.get(branch)!;\n }\n\n // Check if this is the current branch in the main repo\n const currentBranch = await this.git.revparse([\"--abbrev-ref\", \"HEAD\"]);\n if (currentBranch.trim() === branch) {\n // Use the main repo path for the current branch\n this.worktrees.set(branch, this.repoPath);\n return this.repoPath;\n }\n\n const worktreePath = join(this.tempBase, branch);\n\n // Check if worktree directory already exists\n const exists = await stat(worktreePath)\n .then(() => true)\n .catch(() => false);\n\n if (!exists) {\n await mkdir(this.tempBase, { recursive: true });\n await this.git.raw([\"worktree\", \"add\", worktreePath, branch]);\n }\n\n this.worktrees.set(branch, worktreePath);\n return worktreePath;\n }\n\n /**\n * List files using git ls-tree (no worktree needed)\n * Note: list() returns only children, never the path itself (per new semantics)\n */\n private async listWithGitLsTree(\n branch: string,\n path: string,\n options?: { maxDepth?: number; limit?: number },\n ): Promise<AFSListResult> {\n const maxDepth = options?.maxDepth ?? 1;\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n const entries: AFSEntry[] = [];\n const targetPath = path || \"\";\n const treeish = targetPath ? `${branch}:${targetPath}` : branch;\n\n try {\n // Check if the path exists and is a directory\n const pathType = await this.git\n .raw([\"cat-file\", \"-t\", treeish])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (pathType === null) {\n // Path doesn't exist\n throw new AFSNotFoundError(this.buildBranchPath(branch, path));\n }\n\n // If it's a file (blob), it has no children\n if (pathType === \"blob\") {\n return { data: [] };\n }\n\n // It's a directory\n // maxDepth: 0 means return no children\n if (maxDepth === 0) {\n return { data: [] };\n }\n\n // List directory contents via BFS\n interface QueueItem {\n path: string;\n depth: number;\n }\n\n const queue: QueueItem[] = [{ path: targetPath, depth: 0 }];\n\n while (queue.length > 0) {\n const item = queue.shift()!;\n const { path: itemPath, depth } = item;\n\n // List directory contents\n const itemTreeish = itemPath ? `${branch}:${itemPath}` : branch;\n const output = await this.git.raw([\"ls-tree\", \"-l\", itemTreeish]);\n\n const lines = output\n .split(\"\\n\")\n .filter((line) => line.trim())\n .slice(0, limit - entries.length);\n\n for (const line of lines) {\n // Format: <mode> <type> <hash> <size (with padding)> <name>\n const match = line.match(/^(\\d+)\\s+(blob|tree)\\s+(\\w+)\\s+(-|\\d+)\\s+(.+)$/);\n if (!match) continue;\n\n const type = match[2]!;\n const sizeStr = match[4]!;\n const name = match[5]!;\n const isDirectory = type === \"tree\";\n const size = sizeStr === \"-\" ? undefined : Number.parseInt(sizeStr, 10);\n\n const fullPath = itemPath ? `${itemPath}/${name}` : name;\n const afsPath = this.buildBranchPath(branch, fullPath);\n\n // For directories, get children count\n const childrenCount = isDirectory\n ? await this.getChildrenCount(branch, fullPath)\n : undefined;\n\n entries.push(\n this.buildEntry(afsPath, {\n meta: { kind: isDirectory ? \"git:directory\" : \"git:file\", size, childrenCount },\n }),\n );\n\n // Add to queue if it's a directory and we haven't reached max depth\n if (isDirectory && depth + 1 < maxDepth) {\n queue.push({ path: fullPath, depth: depth + 1 });\n }\n\n // Check limit\n if (entries.length >= limit) {\n return { data: entries };\n }\n }\n }\n\n return { data: entries };\n } catch (error) {\n // Re-throw AFSNotFoundError as-is\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw new Error(`Failed to list: ${(error as Error).message}`);\n }\n }\n\n /**\n * Detect MIME type based on file extension\n */\n private getMimeType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n const mimeTypes: Record<string, string> = {\n // Images\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n webp: \"image/webp\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n // Documents\n pdf: \"application/pdf\",\n txt: \"text/plain\",\n md: \"text/markdown\",\n // Code\n js: \"text/javascript\",\n ts: \"text/typescript\",\n json: \"application/json\",\n html: \"text/html\",\n css: \"text/css\",\n xml: \"text/xml\",\n };\n return mimeTypes[ext || \"\"] || \"application/octet-stream\";\n }\n\n /**\n * Check if file is likely binary based on extension\n */\n private isBinaryFile(filePath: string): boolean {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n const binaryExtensions = [\n \"png\",\n \"jpg\",\n \"jpeg\",\n \"gif\",\n \"bmp\",\n \"webp\",\n \"ico\",\n \"pdf\",\n \"zip\",\n \"tar\",\n \"gz\",\n \"exe\",\n \"dll\",\n \"so\",\n \"dylib\",\n \"wasm\",\n ];\n return binaryExtensions.includes(ext || \"\");\n }\n\n // ========== Public Git Operations ==========\n\n /**\n * Fetch latest changes from remote\n */\n async fetch(): Promise<void> {\n await this.ready();\n await this.git.fetch();\n }\n\n /**\n * Pull latest changes from remote for current branch\n */\n async pull(): Promise<void> {\n await this.ready();\n await this.git.pull();\n }\n\n /**\n * Push local changes to remote\n */\n async push(branch?: string): Promise<void> {\n await this.ready();\n if (branch) {\n await this.git.push(\"origin\", branch);\n } else {\n await this.git.push();\n }\n }\n\n /**\n * Cleanup all worktrees (useful when unmounting)\n */\n async cleanup(): Promise<void> {\n await this.ready();\n for (const [_branch, worktreePath] of this.worktrees) {\n try {\n await this.git.raw([\"worktree\", \"remove\", worktreePath, \"--force\"]);\n } catch (_error) {\n // Ignore errors during cleanup\n }\n }\n this.worktrees.clear();\n\n // Remove temp directory\n try {\n await rm(this.tempBase, { recursive: true, force: true });\n } catch {\n // Ignore errors\n }\n\n // Cleanup cloned repository if auto-cloned and autoCleanup enabled\n const autoCleanup = this.options.autoCleanup ?? true;\n if (this.isAutoCloned && autoCleanup && this.clonedPath) {\n try {\n await rm(this.clonedPath, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSGit, AFSGitOptions> = AFSGit;\n\nexport default AFSGit;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["afsPath","mimeType","isBinary","content","meta"],"sources":["../src/index.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n type AFSAccessMode,\n type AFSDeleteOptions,\n type AFSEntry,\n type AFSEntryMetadata,\n type AFSExecResult,\n type AFSExplainOptions,\n type AFSExplainResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSRenameOptions,\n type AFSSearchOptions,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type AFSWriteOptions,\n type CapabilitiesManifest,\n type ProviderManifest,\n type ProviderTreeSchema,\n} from \"@aigne/afs\";\nimport {\n Actions,\n AFSBaseProvider,\n Delete,\n Explain,\n List,\n Meta,\n Read,\n Rename,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { camelize, optionalize, zodParse } from \"@aigne/afs/utils/zod\";\nimport { assertPathWithinRoot, getMimeType, isBinaryFile } from \"@aigne/afs-provider-utils\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { z } from \"zod\";\n\nconst LIST_MAX_LIMIT = 1000;\n\nconst execFileAsync = promisify(execFile);\n\nexport interface AFSGitOptions {\n name?: string;\n /**\n * Local path to git repository.\n * If remoteUrl is provided and repoPath doesn't exist, will clone to this path.\n * If remoteUrl is provided and repoPath is not specified, clones to temp directory.\n */\n repoPath?: string;\n /**\n * Remote repository URL (https or git protocol).\n * If provided, will clone the repository if repoPath doesn't exist.\n * Examples:\n * - https://github.com/user/repo.git\n * - git@github.com:user/repo.git\n */\n remoteUrl?: string;\n description?: string;\n /**\n * List of branches to expose/access.\n * Also used for clone optimization when cloning from remoteUrl:\n * - Single branch (e.g., ['main']): Uses --single-branch for faster clone\n * - Multiple branches: Clones all branches, filters access to specified ones\n * - Not specified: All branches are accessible\n */\n branches?: string[];\n /**\n * Access mode for this module.\n * - \"readonly\": Only read operations are allowed, uses git commands (no worktree)\n * - \"readwrite\": All operations are allowed, creates worktrees as needed\n * @default \"readonly\"\n */\n accessMode?: AFSAccessMode;\n /**\n * Automatically commit changes after write operations\n * @default false\n */\n autoCommit?: boolean;\n /**\n * Author information for commits when autoCommit is enabled\n */\n commitAuthor?: {\n name: string;\n email: string;\n };\n /**\n * Clone depth for shallow clone (only used when cloning from remoteUrl)\n * @default 1\n */\n depth?: number;\n /**\n * Automatically clean up cloned repository on cleanup()\n * Only applies when repository was auto-cloned to temp directory\n * @default true\n */\n autoCleanup?: boolean;\n /**\n * Git clone options (only used when cloning from remoteUrl)\n */\n cloneOptions?: {\n /**\n * Authentication credentials for private repositories\n */\n auth?: {\n username?: string;\n password?: string;\n };\n };\n}\n\nconst afsGitOptionsSchema = camelize(\n z\n .object({\n name: optionalize(z.string()),\n repoPath: optionalize(z.string().describe(\"The path to the git repository\")),\n remoteUrl: optionalize(z.string().describe(\"Remote repository URL (https or git protocol)\")),\n description: optionalize(z.string().describe(\"A description of the repository\")),\n branches: optionalize(z.array(z.string()).describe(\"List of branches to expose\")),\n accessMode: optionalize(\n z.enum([\"readonly\", \"readwrite\"]).describe(\"Access mode for this module\"),\n ),\n autoCommit: optionalize(\n z.boolean().describe(\"Automatically commit changes after write operations\"),\n ),\n commitAuthor: optionalize(\n z.object({\n name: z.string(),\n email: z.string(),\n }),\n ),\n depth: optionalize(z.number().describe(\"Clone depth for shallow clone\")),\n autoCleanup: optionalize(\n z.boolean().describe(\"Automatically clean up cloned repository on cleanup()\"),\n ),\n cloneOptions: optionalize(\n z.object({\n auth: optionalize(\n z.object({\n username: optionalize(z.string()),\n password: optionalize(z.string()),\n }),\n ),\n }),\n ),\n })\n .refine((data) => data.repoPath || data.remoteUrl, {\n message: \"Either repoPath or remoteUrl must be provided\",\n }),\n);\n\nexport class AFSGit extends AFSBaseProvider {\n static schema() {\n return afsGitOptionsSchema;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"git\",\n description:\n \"Git repository browser with branch-based access.\\n- Browse branches, read files at any ref, search across repository\\n- Exec actions (readwrite): `diff`, `create-branch`, `commit`, `merge`\\n- Virtual `.log/` tree exposes commit history per branch\\n- Path structure: `/{branch}/{file-path}` (branch `/` encoded as `~`)\",\n uriTemplate: \"git://{localPath+}\",\n category: \"vcs\",\n schema: z.object({\n localPath: z.string(),\n branch: z.string().optional(),\n remoteUrl: z.string().optional(),\n }),\n tags: [\"git\", \"version-control\"],\n capabilityTags: [\"read-write\", \"search\", \"auth:none\", \"local\"],\n security: {\n riskLevel: \"local\",\n resourceAccess: [\"local-filesystem\"],\n requires: [\"git\"],\n dataSensitivity: [\"code\"],\n notes: [\"Accesses local git repositories; readwrite mode creates worktrees and can commit\"],\n },\n capabilities: {\n filesystem: { read: true, write: true },\n process: { spawn: true, allowedCommands: [\"git\"] },\n },\n };\n }\n\n static treeSchema(): ProviderTreeSchema {\n return {\n operations: [\"list\", \"read\", \"write\", \"delete\", \"search\", \"stat\", \"explain\"],\n tree: {\n \"/\": { kind: \"git:root\", operations: [\"list\", \"read\"] },\n \"/{branch}\": {\n kind: \"git:branch\",\n operations: [\"list\", \"read\", \"search\"],\n actions: [\"diff\", \"create-branch\", \"commit\", \"merge\"],\n },\n \"/{branch}/{path+}\": {\n kind: \"git:file\",\n operations: [\"list\", \"read\", \"write\", \"delete\", \"search\"],\n },\n \"/{branch}/.log\": { kind: \"git:log\", operations: [\"list\"] },\n \"/{branch}/.log/{index}\": { kind: \"git:commit\", operations: [\"read\"] },\n },\n auth: { type: \"none\" },\n bestFor: [\"code browsing\", \"version control\", \"branch comparison\"],\n notFor: [\"binary storage\", \"large files\"],\n };\n }\n\n static async load({ basePath, config }: AFSModuleLoadParams = {}) {\n const valid = await AFSGit.schema().parseAsync(config);\n const instance = new AFSGit({ ...valid, cwd: basePath });\n await instance.ready();\n return instance;\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n\n private initPromise: Promise<void>;\n private git: SimpleGit;\n private tempBase: string;\n private worktrees: Map<string, string> = new Map();\n private repoHash: string;\n private isAutoCloned = false;\n private clonedPath?: string;\n private repoPath: string;\n\n constructor(\n public options: AFSGitOptions & {\n cwd?: string;\n localPath?: string;\n branch?: string;\n uri?: string;\n },\n ) {\n super();\n\n // Normalize registry-passed template vars\n if ((options as any).localPath && !options.repoPath) {\n options.repoPath = (options as any).localPath;\n }\n if ((options as any).branch && !options.branches) {\n options.branches = [(options as any).branch];\n }\n\n zodParse(afsGitOptionsSchema, options);\n\n // Synchronously determine repoPath to initialize name\n let repoPath: string;\n let repoName: string;\n\n if (options.repoPath) {\n // Use provided repoPath\n repoPath = isAbsolute(options.repoPath)\n ? options.repoPath\n : join(options.cwd || process.cwd(), options.repoPath);\n repoName = basename(repoPath);\n } else if (options.remoteUrl) {\n // Extract repo name from URL for temporary name\n const urlParts = options.remoteUrl.split(\"/\");\n const lastPart = urlParts[urlParts.length - 1];\n repoName = lastPart?.replace(/\\.git$/, \"\") || \"git\";\n\n // Will be updated during async init, use temp path for now\n const repoHash = createHash(\"md5\").update(options.remoteUrl).digest(\"hex\").substring(0, 8);\n repoPath = join(tmpdir(), `afs-git-remote-${repoHash}`);\n } else {\n // This should never happen due to schema validation\n throw new Error(\"Either repoPath or remoteUrl must be provided\");\n }\n\n // Initialize basic properties immediately\n this.repoPath = repoPath;\n this.name = options.name || repoName;\n this.description = options.description;\n this.accessMode = options.accessMode ?? \"readonly\";\n\n // Calculate hash for temp directories\n this.repoHash = createHash(\"md5\").update(repoPath).digest(\"hex\").substring(0, 8);\n this.tempBase = join(tmpdir(), `afs-git-${this.repoHash}`);\n\n // Note: git and other properties will be initialized in initialize() after cloning\n // We need to delay simpleGit() initialization until the directory exists\n this.git = null as any; // Will be set in initialize()\n\n // Start async initialization (cloning if needed)\n this.initPromise = this.initialize();\n }\n\n /**\n * Wait for async initialization to complete\n */\n async ready(): Promise<void> {\n await this.initPromise;\n }\n\n /**\n * Async initialization logic (runs in constructor)\n * Handles cloning remote repositories if needed\n */\n private async initialize(): Promise<void> {\n const options = this.options;\n\n // Auto-create local repository if it doesn't exist (skip for remoteUrl — will be cloned)\n if (options.repoPath && !options.remoteUrl) {\n const { existsSync, mkdirSync } = await import(\"node:fs\");\n const { execSync } = await import(\"node:child_process\");\n if (!existsSync(this.repoPath)) {\n mkdirSync(this.repoPath, { recursive: true });\n }\n if (!existsSync(join(this.repoPath, \".git\"))) {\n execSync(\"git init -b main\", { cwd: this.repoPath, stdio: \"ignore\" });\n }\n }\n\n // If remoteUrl is provided, handle cloning\n if (options.remoteUrl) {\n const targetPath = options.repoPath\n ? isAbsolute(options.repoPath)\n ? options.repoPath\n : join(options.cwd || process.cwd(), options.repoPath)\n : this.repoPath; // Use temp path set in constructor\n\n // Mark as auto-cloned if we're using temp directory\n if (!options.repoPath) {\n this.isAutoCloned = true;\n }\n\n // Check if targetPath exists and is a valid git repository\n const exists = await stat(targetPath)\n .then(() => true)\n .catch(() => false);\n\n let needsClone = !exists;\n\n // If directory exists but is not a valid git repo, clean it up and re-clone\n if (exists) {\n const tempGit = simpleGit(targetPath);\n const isValidRepo = await tempGit.checkIsRepo().catch(() => false);\n if (!isValidRepo) {\n // Remove invalid directory and re-clone\n await rm(targetPath, { recursive: true, force: true });\n needsClone = true;\n }\n }\n\n if (needsClone) {\n // Determine if single-branch optimization should be used\n const singleBranch = options.branches?.length === 1 ? options.branches[0] : undefined;\n\n await AFSGit.cloneRepository(options.remoteUrl, targetPath, {\n depth: options.depth ?? 1,\n branch: singleBranch,\n auth: options.cloneOptions?.auth,\n });\n }\n\n // Update properties if targetPath differs from constructor initialization\n if (targetPath !== this.repoPath) {\n this.repoPath = targetPath;\n this.repoHash = createHash(\"md5\").update(targetPath).digest(\"hex\").substring(0, 8);\n this.tempBase = join(tmpdir(), `afs-git-${this.repoHash}`);\n }\n\n this.clonedPath = this.isAutoCloned ? targetPath : undefined;\n }\n\n // Now that the directory exists (either it was there or we cloned it), initialize git\n this.git = simpleGit(this.repoPath);\n\n // Validate that the directory is actually a git repository\n const isRepo = await this.git.checkIsRepo();\n if (!isRepo) {\n throw new Error(`Not a git repository: ${this.repoPath}`);\n }\n }\n\n /**\n * Clone a remote repository to local path\n */\n private static async cloneRepository(\n remoteUrl: string,\n targetPath: string,\n options: {\n depth?: number;\n branch?: string;\n auth?: { username?: string; password?: string };\n } = {},\n ): Promise<void> {\n const git = simpleGit();\n\n // Build clone options\n const cloneArgs: string[] = [];\n\n if (options.depth) {\n cloneArgs.push(\"--depth\", options.depth.toString());\n }\n\n if (options.branch) {\n cloneArgs.push(\"--branch\", options.branch, \"--single-branch\");\n }\n\n // Handle authentication in URL if provided\n let cloneUrl = remoteUrl;\n if (options.auth?.username && options.auth?.password) {\n // Insert credentials into HTTPS URL\n if (remoteUrl.startsWith(\"https://\")) {\n const url = new URL(remoteUrl);\n url.username = encodeURIComponent(options.auth.username);\n url.password = encodeURIComponent(options.auth.password);\n cloneUrl = url.toString();\n }\n }\n\n await git.clone(cloneUrl, targetPath, cloneArgs);\n }\n\n // ========== Route Handlers ==========\n\n /**\n * List root (branches)\n * Note: list() returns only children (branches), never the path itself (per new semantics)\n */\n @List(\"/\", { handleDepth: true })\n async listRootHandler(ctx: RouteContext): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const options = ctx.options as { limit?: number; maxDepth?: number };\n const maxDepth = options?.maxDepth ?? 1;\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n // maxDepth: 0 means return no children\n if (maxDepth === 0) {\n return { data: [] };\n }\n\n const branches = await this.getBranches();\n const entries: AFSEntry[] = [];\n\n for (const name of branches) {\n if (entries.length >= limit) break;\n\n const encodedPath = this.buildBranchPath(name);\n\n // Get children count for this branch\n const branchChildrenCount = await this.getChildrenCount(name, \"\");\n\n entries.push(\n this.buildEntry(encodedPath, {\n meta: { kind: \"git:branch\", childrenCount: branchChildrenCount },\n }),\n );\n\n // If maxDepth > 1, also list contents of each branch\n if (maxDepth > 1) {\n const branchResult = await this.listWithGitLsTree(name, \"\", {\n maxDepth: maxDepth - 1,\n limit: limit - entries.length,\n });\n entries.push(...branchResult.data);\n }\n }\n\n return { data: entries };\n }\n\n /**\n * List branch root (matches /main, /develop, etc.)\n */\n @List(\"/:branch\", { handleDepth: true })\n async listBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n return this.listWithGitLsTree(branch, \"\", ctx.options as { maxDepth?: number; limit?: number });\n }\n\n /**\n * List files in branch with subpath (matches /main/src, /main/src/foo, etc.)\n */\n @List(\"/:branch/:path+\", { handleDepth: true })\n async listBranchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n return this.listWithGitLsTree(\n branch,\n filePath,\n ctx.options as { maxDepth?: number; limit?: number },\n );\n }\n\n // ========== Meta Handlers ==========\n // These handlers provide metadata access for all paths via .meta suffix\n\n /**\n * Read root metadata (introspection only, read-only)\n */\n @Meta(\"/\")\n async readRootMetaHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branches = await this.getBranches();\n return this.buildEntry(\"/.meta\", {\n meta: { childrenCount: branches.length, type: \"root\" },\n });\n }\n\n /**\n * Read branch root metadata (introspection only, read-only)\n */\n @Meta(\"/:branch\")\n async readBranchMetaHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const childrenCount = await this.getChildrenCount(branch, \"\");\n const branchPath = `/${this.encodeBranchName(branch)}`;\n const metaPath = `${branchPath}/.meta`;\n const lastCommit = await this.getLastCommit(branch);\n\n return this.buildEntry(metaPath, {\n meta: { childrenCount, type: \"branch\", lastCommit },\n });\n }\n\n /**\n * Read file or directory metadata in branch (introspection only, read-only)\n */\n @Meta(\"/:branch/:path+\")\n async readPathMetaHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n // Check if the path exists\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n const isDir = objectType === \"tree\";\n const metaPath = `/${this.encodeBranchName(branch)}/${filePath}/.meta`;\n\n let childrenCount: number | undefined;\n if (isDir) {\n childrenCount = await this.getChildrenCount(branch, filePath);\n }\n\n return this.buildEntry(metaPath, {\n meta: {\n childrenCount,\n type: isDir ? \"directory\" : \"file\",\n gitObjectType: objectType,\n },\n });\n }\n\n // ========== Regular Read Handlers ==========\n\n /**\n * Read root\n */\n @Read(\"/\")\n async readRootHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branches = await this.getBranches();\n return this.buildEntry(\"/\", {\n meta: { childrenCount: branches.length },\n });\n }\n\n /**\n * Read branch root\n */\n @Read(\"/:branch\")\n async readBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const branchPath = this.buildBranchPath(branch);\n const childrenCount = await this.getChildrenCount(branch, \"\");\n const lastCommit = await this.getLastCommit(branch);\n return this.buildEntry(branchPath, {\n meta: { childrenCount, lastCommit },\n });\n }\n\n /**\n * Read file or directory in branch\n */\n @Read(\"/:branch/:path+\")\n async readBranchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n // Check if there's an active worktree for this branch - read from there first\n // This handles files that were written but may be in a different state than git index\n const worktreePath = this.worktrees.get(branch);\n if (worktreePath) {\n try {\n const fullPath = join(worktreePath, filePath);\n await this.assertWithinWorktree(fullPath, worktreePath);\n const stats = await stat(fullPath);\n\n if (stats.isDirectory()) {\n // It's a directory - count children\n const files = await readdir(fullPath);\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n meta: { childrenCount: files.length },\n });\n }\n\n // It's a file - read content\n const mimeType = getMimeType(filePath);\n const isBinary = isBinaryFile(filePath);\n\n let content: string;\n const meta: AFSEntryMetadata = {\n size: stats.size,\n mimeType,\n };\n\n if (isBinary) {\n const buffer = await readFile(fullPath);\n content = buffer.toString(\"base64\");\n meta.contentType = \"base64\";\n } else {\n content = await readFile(fullPath, \"utf8\");\n }\n\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n content,\n meta,\n createdAt: stats.birthtime,\n updatedAt: stats.mtime,\n });\n } catch (err: unknown) {\n // Re-throw security errors — only fall through for \"not found\" / filesystem errors\n if (\n err instanceof Error &&\n \"code\" in err &&\n (err as { code: string }).code === \"AFS_PERMISSION_DENIED\"\n ) {\n throw err;\n }\n // File doesn't exist in worktree, fall through to git\n }\n }\n\n // Read from git repository\n // Check if path is a blob (file) or tree (directory)\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n // Path doesn't exist in git\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n if (objectType === \"tree\") {\n // It's a directory\n const afsPath = this.buildBranchPath(branch, filePath);\n const childrenCount = await this.getChildrenCount(branch, filePath);\n return this.buildEntry(afsPath, {\n meta: { childrenCount },\n });\n }\n\n // It's a file, get content\n const size = await this.git\n .raw([\"cat-file\", \"-s\", `${branch}:${filePath}`])\n .then((s) => Number.parseInt(s.trim(), 10));\n\n // Determine mimeType based on file extension\n const mimeType = getMimeType(filePath);\n const isBinary = isBinaryFile(filePath);\n\n let content: string;\n const meta: AFSEntryMetadata = {\n size,\n mimeType,\n };\n\n if (isBinary) {\n // For binary files, use execFileAsync to get raw buffer\n const { stdout } = await execFileAsync(\"git\", [\"cat-file\", \"-p\", `${branch}:${filePath}`], {\n cwd: this.options.repoPath,\n encoding: \"buffer\",\n maxBuffer: 10 * 1024 * 1024, // 10MB max\n });\n // Store only base64 string without data URL prefix\n content = (stdout as Buffer).toString(\"base64\");\n // Mark content as base64 in metadata\n meta.contentType = \"base64\";\n } else {\n // For text files, use git.show\n content = await this.git.show([`${branch}:${filePath}`]);\n }\n\n const afsPath = this.buildBranchPath(branch, filePath);\n return this.buildEntry(afsPath, {\n content,\n meta,\n });\n }\n\n /**\n * Write to root is not allowed\n */\n @Write(\"/\")\n async writeRootHandler(): Promise<never> {\n throw new Error(\"Cannot write to root\");\n }\n\n /**\n * Write to branch root is not allowed\n */\n @Write(\"/:branch\")\n async writeBranchRootHandler(): Promise<never> {\n throw new Error(\"Cannot write to branch root\");\n }\n\n /**\n * Write file in branch\n */\n @Write(\"/:branch/:path+\")\n async writeHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<{ data: AFSEntry }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n const filePath = ctx.params.path;\n const options = ctx.options as AFSWriteOptions | undefined;\n const mode = options?.mode ?? \"replace\";\n\n // Create worktree for write operations\n const worktreePath = await this.ensureWorktree(branch);\n const fullPath = join(worktreePath, filePath);\n await this.assertWithinWorktree(fullPath, worktreePath);\n\n // Ensure parent directory exists\n const parentDir = dirname(fullPath);\n await mkdir(parentDir, { recursive: true });\n\n // Write content\n if (payload.content !== undefined) {\n let contentToWrite: string;\n if (typeof payload.content === \"string\") {\n contentToWrite = payload.content;\n } else {\n contentToWrite = JSON.stringify(payload.content, null, 2);\n }\n await writeFile(fullPath, contentToWrite, {\n encoding: \"utf8\",\n flag: mode === \"append\" ? \"a\" : \"w\",\n });\n }\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add(filePath);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Update ${filePath}`);\n }\n\n // Get file stats\n const stats = await stat(fullPath);\n\n const afsPath = this.buildBranchPath(branch, filePath);\n const writtenEntry: AFSEntry = {\n id: afsPath,\n path: afsPath,\n content: payload.content,\n summary: payload.summary,\n createdAt: stats.birthtime,\n updatedAt: stats.mtime,\n meta: {\n ...payload.meta,\n size: stats.size,\n } as AFSEntryMetadata,\n userId: payload.userId,\n sessionId: payload.sessionId,\n linkTo: payload.linkTo,\n };\n\n return { data: writtenEntry };\n }\n\n /**\n * Delete root is not allowed\n */\n @Delete(\"/\")\n async deleteRootHandler(): Promise<never> {\n throw new Error(\"Cannot delete root\");\n }\n\n /**\n * Delete branch root is not allowed\n */\n @Delete(\"/:branch\")\n async deleteBranchRootHandler(ctx: RouteContext<{ branch: string }>): Promise<never> {\n await this.ready();\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n throw new Error(\"Cannot delete branch root\");\n }\n\n /**\n * Delete file in branch\n */\n @Delete(\"/:branch/:path+\")\n async deleteHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<{ message: string }> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n const filePath = ctx.params.path;\n const options = ctx.options as AFSDeleteOptions | undefined;\n const recursive = options?.recursive ?? false;\n\n // Create worktree for delete operations\n const worktreePath = await this.ensureWorktree(branch);\n const fullPath = join(worktreePath, filePath);\n await this.assertWithinWorktree(fullPath, worktreePath);\n\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(fullPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n throw error;\n }\n\n if (stats.isDirectory() && !recursive) {\n throw new Error(\n `Cannot delete directory '/${ctx.params.branch}/${filePath}' without recursive option. Set recursive: true to delete directories.`,\n );\n }\n\n await rm(fullPath, { recursive, force: true });\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add(filePath);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Delete ${filePath}`);\n }\n\n return { message: `Successfully deleted: /${ctx.params.branch}/${filePath}` };\n }\n\n /**\n * Rename file in branch\n */\n @Rename(\"/:branch/:path+\")\n async renameHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n newPath: string,\n ): Promise<{ message: string }> {\n await this.ready();\n\n const oldBranch = this.decodeBranchName(ctx.params.branch);\n const oldFilePath = ctx.params.path;\n\n // Parse new path\n const { branch: newBranch, filePath: newFilePath } = this.parsePath(newPath);\n const options = ctx.options as AFSRenameOptions | undefined;\n const overwrite = options?.overwrite ?? false;\n\n if (!newBranch || !newFilePath) {\n throw new Error(\"Cannot rename to root or branch root\");\n }\n\n if (oldBranch !== newBranch) {\n throw new Error(\"Cannot rename across branches\");\n }\n\n // Create worktree for rename operations\n const worktreePath = await this.ensureWorktree(oldBranch);\n const oldFullPath = join(worktreePath, oldFilePath);\n const newFullPath = join(worktreePath, newFilePath);\n await this.assertWithinWorktree(oldFullPath, worktreePath);\n await this.assertWithinWorktree(newFullPath, worktreePath);\n\n // Check if source exists\n try {\n await stat(oldFullPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new AFSNotFoundError(this.buildBranchPath(oldBranch, oldFilePath));\n }\n throw error;\n }\n\n // Check if destination exists\n try {\n await stat(newFullPath);\n if (!overwrite) {\n throw new Error(\n `Destination '${newPath}' already exists. Set overwrite: true to replace it.`,\n );\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n\n // Ensure parent directory exists\n const newParentDir = dirname(newFullPath);\n await mkdir(newParentDir, { recursive: true });\n\n // Perform rename\n await rename(oldFullPath, newFullPath);\n\n // Auto commit if enabled\n if (this.options.autoCommit) {\n const gitInstance = simpleGit(worktreePath);\n await gitInstance.add([oldFilePath, newFilePath]);\n\n if (this.options.commitAuthor) {\n await gitInstance.addConfig(\n \"user.name\",\n this.options.commitAuthor.name,\n undefined,\n \"local\",\n );\n await gitInstance.addConfig(\n \"user.email\",\n this.options.commitAuthor.email,\n undefined,\n \"local\",\n );\n }\n\n await gitInstance.commit(`Rename ${oldFilePath} to ${newFilePath}`);\n }\n\n return {\n message: `Successfully renamed '/${ctx.params.branch}/${oldFilePath}' to '${newPath}'`,\n };\n }\n\n /**\n * Search files in branch root\n */\n @Search(\"/:branch\")\n async searchBranchRootHandler(\n ctx: RouteContext<{ branch: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n return this.searchInBranch(ctx.params.branch, \"\", query, options);\n }\n\n /**\n * Search files in branch path\n */\n @Search(\"/:branch/:path+\")\n async searchHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n return this.searchInBranch(ctx.params.branch, ctx.params.path, query, options);\n }\n\n /**\n * Internal search implementation\n */\n private async searchInBranch(\n encodedBranch: string,\n filePath: string,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n await this.ready();\n\n const branch = this.decodeBranchName(encodedBranch);\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n try {\n // Use git grep for searching (no worktree needed)\n const args = [\"grep\", \"-n\", \"-I\"]; // -n for line numbers, -I to skip binary files\n\n if (options?.caseSensitive === false) {\n args.push(\"-i\");\n }\n\n args.push(query, branch);\n\n // Add path filter if specified\n if (filePath) {\n args.push(\"--\", filePath);\n }\n\n const output = await this.git.raw(args);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n\n const entries: AFSEntry[] = [];\n const processedFiles = new Set<string>();\n\n for (const line of lines) {\n // Format when searching in branch: branch:path:linenum:content\n // Try the format with branch prefix first\n let matchPath: string;\n let lineNum: string;\n let content: string;\n\n const matchWithBranch = line.match(/^[^:]+:([^:]+):(\\d+):(.+)$/);\n if (matchWithBranch) {\n matchPath = matchWithBranch[1]!;\n lineNum = matchWithBranch[2]!;\n content = matchWithBranch[3]!;\n } else {\n // Try format without branch: path:linenum:content\n const matchNoBranch = line.match(/^([^:]+):(\\d+):(.+)$/);\n if (!matchNoBranch) continue;\n matchPath = matchNoBranch[1]!;\n lineNum = matchNoBranch[2]!;\n content = matchNoBranch[3]!;\n }\n\n const afsPath = this.buildBranchPath(branch, matchPath);\n\n if (processedFiles.has(afsPath)) continue;\n processedFiles.add(afsPath);\n\n const entry = this.buildEntry(afsPath);\n entry.summary = `Line ${lineNum}: ${content}`;\n entries.push(entry);\n\n if (entries.length >= limit) {\n break;\n }\n }\n\n return {\n data: entries,\n message: entries.length >= limit ? `Results truncated to limit ${limit}` : undefined,\n };\n } catch (error) {\n // git grep returns exit code 1 if no matches found\n if ((error as Error).message.includes(\"did not match any file(s)\")) {\n return { data: [] };\n }\n return { data: [], message: (error as Error).message };\n }\n }\n\n /**\n * Stat root\n */\n @Stat(\"/\")\n async statRootHandler(_ctx: RouteContext): Promise<AFSStatResult> {\n const entry = await this.readRootHandler(_ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n /**\n * Stat branch root\n */\n @Stat(\"/:branch\")\n async statBranchRootHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSStatResult> {\n const entry = await this.readBranchRootHandler(ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n /**\n * Stat file or directory in branch\n */\n @Stat(\"/:branch/:path+\")\n async statHandler(ctx: RouteContext<{ branch: string; path: string }>): Promise<AFSStatResult> {\n const entry = await this.readBranchHandler(ctx);\n if (!entry) {\n return { data: undefined };\n }\n // Return entry without content\n const { content: _content, ...rest } = entry;\n return { data: rest };\n }\n\n // ========== Explain Handlers ==========\n\n /**\n * Explain root → repo info, branch list, default branch\n */\n @Explain(\"/\")\n async explainRootHandler(_ctx: RouteContext): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (_ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branches = await this.getBranches();\n const currentBranch = await this.git.revparse([\"--abbrev-ref\", \"HEAD\"]).then((b) => b.trim());\n\n let remoteUrl: string | undefined;\n try {\n remoteUrl = await this.git.remote([\"get-url\", \"origin\"]).then((u) => u?.trim());\n } catch {\n // No remote configured\n }\n\n const lines: string[] = [];\n lines.push(\"# Git Repository\");\n lines.push(\"\");\n lines.push(`**Provider:** ${this.name}`);\n if (this.description) {\n lines.push(`**Description:** ${this.description}`);\n }\n lines.push(`**Default Branch:** ${currentBranch}`);\n if (remoteUrl) {\n lines.push(`**Remote:** ${remoteUrl}`);\n }\n lines.push(`**Branches:** ${branches.length}`);\n lines.push(\"\");\n lines.push(\"## Branches\");\n lines.push(\"\");\n for (const branch of branches) {\n lines.push(`- ${branch}`);\n }\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n /**\n * Explain branch → branch name, HEAD commit, file count\n */\n @Explain(\"/:branch\")\n async explainBranchHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n const lastCommit = await this.getLastCommit(branch);\n const fileCount = await this.getTreeFileCount(branch, \"\");\n\n const lines: string[] = [];\n lines.push(`# Branch: ${branch}`);\n lines.push(\"\");\n lines.push(`**HEAD Commit:** ${lastCommit.shortHash} - ${lastCommit.message}`);\n lines.push(`**Author:** ${lastCommit.author}`);\n lines.push(`**Date:** ${lastCommit.date}`);\n lines.push(`**Files:** ${fileCount} entries in tree`);\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n /**\n * Explain file or directory → path, size, last modified commit\n */\n @Explain(\"/:branch/:path+\")\n async explainPathHandler(\n ctx: RouteContext<{ branch: string; path: string }>,\n ): Promise<AFSExplainResult> {\n await this.ready();\n\n const format = (ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const filePath = ctx.params.path;\n\n const objectType = await this.git\n .raw([\"cat-file\", \"-t\", `${branch}:${filePath}`])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (objectType === null) {\n throw new AFSNotFoundError(this.buildBranchPath(branch, filePath));\n }\n\n const isDir = objectType === \"tree\";\n const lines: string[] = [];\n\n lines.push(`# ${basename(filePath)}`);\n lines.push(\"\");\n lines.push(`**Path:** ${filePath}`);\n lines.push(`**Type:** ${isDir ? \"directory\" : \"file\"}`);\n\n if (!isDir) {\n const size = await this.git\n .raw([\"cat-file\", \"-s\", `${branch}:${filePath}`])\n .then((s) => Number.parseInt(s.trim(), 10));\n lines.push(`**Size:** ${size} bytes`);\n }\n\n // Get last commit that modified this path\n try {\n const logOutput = await this.git.raw([\n \"log\",\n \"-1\",\n \"--format=%H%n%h%n%an%n%aI%n%s\",\n branch,\n \"--\",\n filePath,\n ]);\n const logLines = logOutput.trim().split(\"\\n\");\n if (logLines.length >= 5) {\n lines.push(\"\");\n lines.push(\"## Last Modified\");\n lines.push(`**Commit:** ${logLines[1]} - ${logLines[4]}`);\n lines.push(`**Author:** ${logLines[2]}`);\n lines.push(`**Date:** ${logLines[3]}`);\n }\n } catch {\n // Ignore log errors\n }\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n // ========== Capabilities ==========\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilitiesHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n const operations = [\"list\", \"read\", \"stat\", \"explain\", \"search\"];\n if (this.accessMode === \"readwrite\") {\n operations.push(\"write\", \"delete\", \"rename\");\n }\n\n const actionCatalogs: CapabilitiesManifest[\"actions\"] = [];\n\n // diff is available in both modes conceptually, but exec() enforces readwrite\n // Include all actions in readwrite mode\n if (this.accessMode === \"readwrite\") {\n actionCatalogs.push({\n description: \"Git workflow actions\",\n catalog: [\n {\n name: \"diff\",\n description: \"Compare two branches or refs\",\n inputSchema: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Source ref\" },\n to: { type: \"string\", description: \"Target ref\" },\n path: { type: \"string\", description: \"Optional path filter\" },\n },\n required: [\"from\", \"to\"],\n },\n },\n {\n name: \"create-branch\",\n description: \"Create a new branch\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"New branch name\" },\n from: { type: \"string\", description: \"Source ref (defaults to current HEAD)\" },\n },\n required: [\"name\"],\n },\n },\n {\n name: \"commit\",\n description: \"Commit staged changes\",\n inputSchema: {\n type: \"object\",\n properties: {\n message: { type: \"string\", description: \"Commit message\" },\n author: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n email: { type: \"string\" },\n },\n },\n },\n required: [\"message\"],\n },\n },\n {\n name: \"merge\",\n description: \"Merge a branch into the current branch\",\n inputSchema: {\n type: \"object\",\n properties: {\n branch: { type: \"string\", description: \"Branch to merge\" },\n message: { type: \"string\", description: \"Custom merge message\" },\n },\n required: [\"branch\"],\n },\n },\n ],\n discovery: {\n pathTemplate: \"/:branch/.actions\",\n note: \"Git workflow actions (readwrite mode only)\",\n },\n });\n }\n\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.name,\n description: this.description || \"Git repository provider\",\n tools: [],\n actions: actionCatalogs,\n operations: this.getOperationsDeclaration(),\n };\n\n return {\n id: \"/.meta/.capabilities\",\n path: \"/.meta/.capabilities\",\n content: manifest,\n meta: { kind: \"afs:capabilities\", operations },\n };\n }\n\n // ========== Git Actions ==========\n\n /**\n * List available actions for a branch\n */\n @Actions(\"/:branch\")\n async listBranchActions(ctx: RouteContext<{ branch: string }>): Promise<AFSListResult> {\n if (this.accessMode !== \"readwrite\") {\n return { data: [] };\n }\n\n const basePath = `/${ctx.params.branch}/.actions`;\n return {\n data: [\n {\n id: \"diff\",\n path: `${basePath}/diff`,\n summary: \"Compare two branches or refs\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Source ref\" },\n to: { type: \"string\", description: \"Target ref\" },\n path: { type: \"string\", description: \"Optional path filter\" },\n },\n required: [\"from\", \"to\"],\n },\n },\n },\n {\n id: \"create-branch\",\n path: `${basePath}/create-branch`,\n summary: \"Create a new branch from this ref\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"New branch name\" },\n from: { type: \"string\", description: \"Source ref (defaults to current HEAD)\" },\n },\n required: [\"name\"],\n },\n },\n },\n {\n id: \"commit\",\n path: `${basePath}/commit`,\n summary: \"Commit staged changes\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n message: { type: \"string\", description: \"Commit message\" },\n author: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n email: { type: \"string\" },\n },\n },\n },\n required: [\"message\"],\n },\n },\n },\n {\n id: \"merge\",\n path: `${basePath}/merge`,\n summary: \"Merge another branch into this branch\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n inputSchema: {\n type: \"object\",\n properties: {\n branch: { type: \"string\", description: \"Branch to merge\" },\n message: { type: \"string\", description: \"Custom merge message\" },\n },\n required: [\"branch\"],\n },\n },\n },\n ],\n };\n }\n\n /**\n * diff action — compare two branches or refs\n */\n @Actions.Exec(\"/:branch\", \"diff\")\n async diffAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const from = args.from as string;\n const to = args.to as string;\n const pathFilter = args.path as string | undefined;\n\n if (!from || !to) {\n return {\n success: false,\n error: { code: \"INVALID_ARGS\", message: \"from and to are required\" },\n };\n }\n\n try {\n // Get diff stat\n const diffArgs = [\"diff\", \"--stat\", \"--name-only\", `${from}...${to}`];\n if (pathFilter) {\n diffArgs.push(\"--\", pathFilter);\n }\n const statOutput = await this.git.raw(diffArgs);\n const fileLines = statOutput\n .trim()\n .split(\"\\n\")\n .filter((l) => l.trim());\n const files = fileLines.map((path) => ({ path }));\n\n // Get diff patch\n const patchArgs = [\"diff\", `${from}...${to}`];\n if (pathFilter) {\n patchArgs.push(\"--\", pathFilter);\n }\n const patch = await this.git.raw(patchArgs);\n\n return {\n success: true,\n data: {\n from,\n to,\n files,\n patch,\n filesChanged: files.length,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"DIFF_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * create-branch action — create a new branch\n */\n @Actions.Exec(\"/:branch\", \"create-branch\")\n async createBranchAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const name = args.name as string;\n const from = args.from as string | undefined;\n\n if (!name) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"name is required\" } };\n }\n\n // Validate branch name - reject path traversal\n if (name.includes(\"..\")) {\n return {\n success: false,\n error: { code: \"INVALID_NAME\", message: \"Branch name contains invalid characters\" },\n };\n }\n\n try {\n if (from) {\n await this.git.raw([\"branch\", name, from]);\n } else {\n await this.git.raw([\"branch\", name]);\n }\n\n // Get the hash of the new branch\n const hash = await this.git.revparse([name]).then((h) => h.trim());\n\n return {\n success: true,\n data: { branch: name, hash },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"CREATE_BRANCH_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * commit action — commit staged changes\n */\n @Actions.Exec(\"/:branch\", \"commit\")\n async commitAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const message = args.message as string;\n if (!message) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"message is required\" } };\n }\n\n const author = args.author as { name?: string; email?: string } | undefined;\n\n try {\n const git = simpleGit(this.repoPath);\n\n // Check for staged changes\n const status = await git.status();\n if (\n status.staged.length === 0 &&\n status.files.filter((f) => f.index !== \" \" && f.index !== \"?\").length === 0\n ) {\n return {\n success: false,\n error: { code: \"NO_CHANGES\", message: \"No staged changes to commit\" },\n };\n }\n\n // Configure author if provided\n if (author?.name) {\n await git.addConfig(\"user.name\", author.name, undefined, \"local\");\n }\n if (author?.email) {\n await git.addConfig(\"user.email\", author.email, undefined, \"local\");\n }\n\n const result = await git.commit(message);\n\n return {\n success: true,\n data: {\n hash: result.commit || \"\",\n message,\n filesChanged: result.summary.changes,\n },\n };\n } catch (error) {\n return {\n success: false,\n error: {\n code: \"COMMIT_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n /**\n * merge action — merge a branch into current branch\n */\n @Actions.Exec(\"/:branch\", \"merge\")\n async mergeAction(\n _ctx: RouteContext<{ branch: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n await this.ready();\n\n const branch = args.branch as string;\n if (!branch) {\n return { success: false, error: { code: \"INVALID_ARGS\", message: \"branch is required\" } };\n }\n\n const customMessage = args.message as string | undefined;\n\n try {\n const git = simpleGit(this.repoPath);\n\n // Verify the branch exists\n const branches = await git.branchLocal();\n if (!branches.all.includes(branch)) {\n return {\n success: false,\n error: { code: \"BRANCH_NOT_FOUND\", message: `Branch '${branch}' not found` },\n };\n }\n\n const mergeArgs = [branch];\n if (customMessage) {\n mergeArgs.push(\"-m\", customMessage);\n }\n\n const result = await git.merge(mergeArgs);\n\n // Get the resulting commit hash\n const hash = await git.revparse([\"HEAD\"]).then((h) => h.trim());\n\n return {\n success: true,\n data: {\n hash,\n merged: branch,\n conflicts: result.conflicts || [],\n },\n };\n } catch (error) {\n // Abort merge if there was a conflict\n try {\n const git = simpleGit(this.repoPath);\n await git.merge([\"--abort\"]);\n } catch {\n // Ignore abort errors\n }\n\n return {\n success: false,\n error: {\n code: \"MERGE_FAILED\",\n message: (error as Error).message.replace(this.repoPath, \"<repo>\"),\n },\n };\n }\n }\n\n // ========== .log/ Virtual Tree ==========\n\n /**\n * List .log/ → commit list with pagination\n */\n @List(\"/:branch/.log\")\n async listLogHandler(ctx: RouteContext<{ branch: string }>): Promise<AFSListResult> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n\n const options = ctx.options as { limit?: number; offset?: number };\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const offset = options?.offset || 0;\n\n const commits = await this.getCommitList(branch, limit, offset);\n const branchEncoded = this.encodeBranchName(branch);\n\n const entries: AFSEntry[] = commits.map((commit, i) =>\n this.buildEntry(`/${branchEncoded}/.log/${offset + i}`, {\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n }),\n );\n\n return { data: entries };\n }\n\n /**\n * Read .log/{index} → commit diff/patch content\n */\n @Read(\"/:branch/.log/:index\")\n async readLogEntryHandler(\n ctx: RouteContext<{ branch: string; index: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const index = Number.parseInt(ctx.params.index, 10);\n\n if (Number.isNaN(index) || index < 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${ctx.params.index}`);\n }\n\n const commits = await this.getCommitList(branch, 1, index);\n if (commits.length === 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${index}`);\n }\n\n const commit = commits[0]!;\n\n // Get diff for this commit\n let diff: string;\n try {\n diff = await this.git.raw([\"show\", \"--stat\", \"--patch\", commit.hash]);\n } catch {\n diff = \"\";\n }\n\n const branchEncoded = this.encodeBranchName(branch);\n return this.buildEntry(`/${branchEncoded}/.log/${index}`, {\n content: diff,\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n });\n }\n\n /**\n * Read .log/{index}/.meta → commit metadata only (no diff)\n */\n @Read(\"/:branch/.log/:index/.meta\")\n async readLogEntryMetaHandler(\n ctx: RouteContext<{ branch: string; index: string }>,\n ): Promise<AFSEntry | undefined> {\n await this.ready();\n\n const branch = this.decodeBranchName(ctx.params.branch);\n await this.ensureBranchExists(branch);\n const index = Number.parseInt(ctx.params.index, 10);\n\n if (Number.isNaN(index) || index < 0) {\n throw new AFSNotFoundError(\n `/${this.encodeBranchName(branch)}/.log/${ctx.params.index}/.meta`,\n );\n }\n\n const commits = await this.getCommitList(branch, 1, index);\n if (commits.length === 0) {\n throw new AFSNotFoundError(`/${this.encodeBranchName(branch)}/.log/${index}/.meta`);\n }\n\n const commit = commits[0]!;\n const branchEncoded = this.encodeBranchName(branch);\n return this.buildEntry(`/${branchEncoded}/.log/${index}/.meta`, {\n meta: {\n hash: commit.hash,\n shortHash: commit.shortHash,\n author: commit.author,\n date: commit.date,\n message: commit.message,\n },\n });\n }\n\n // ========== Private Helper Methods ==========\n\n /**\n * Decode branch name (replace ~ with /)\n */\n private async assertWithinWorktree(fullPath: string, worktreeRoot: string): Promise<void> {\n return assertPathWithinRoot(fullPath, worktreeRoot);\n }\n\n private decodeBranchName(encoded: string): string {\n return encoded.replace(/~/g, \"/\");\n }\n\n /**\n * Encode branch name (replace / with ~)\n */\n private encodeBranchName(branch: string): string {\n return branch.replace(/\\//g, \"~\");\n }\n\n /**\n * Parse AFS path into branch and file path\n * Branch names may contain slashes and are encoded with ~ in paths\n */\n private parsePath(path: string): { branch?: string; filePath: string } {\n const normalized = join(\"/\", path); // Ensure leading slash\n const segments = normalized.split(\"/\").filter(Boolean);\n\n if (segments.length === 0) {\n return { branch: undefined, filePath: \"\" };\n }\n\n // Decode branch name (first segment): replace ~ with /\n const branch = segments[0]!.replace(/~/g, \"/\");\n const filePath = segments.slice(1).join(\"/\");\n\n return { branch, filePath };\n }\n\n /**\n * Build AFS path with encoded branch name\n * Branch names with slashes are encoded by replacing / with ~\n */\n private buildBranchPath(branch: string, filePath?: string): string {\n const encodedBranch = this.encodeBranchName(branch);\n if (!filePath) {\n return `/${encodedBranch}`;\n }\n return `/${encodedBranch}/${filePath}`;\n }\n\n /**\n * Get list of available branches\n */\n private async getBranches(): Promise<string[]> {\n const branchSummary = await this.git.branchLocal();\n const allBranches = branchSummary.all;\n\n // Filter by allowed branches if specified\n if (this.options.branches && this.options.branches.length > 0) {\n return allBranches.filter((branch) => this.options.branches!.includes(branch));\n }\n\n return allBranches;\n }\n\n /**\n * Check if a branch exists, throw AFSNotFoundError if not\n */\n private async ensureBranchExists(branch: string): Promise<void> {\n const branches = await this.getBranches();\n if (!branches.includes(branch)) {\n throw new AFSNotFoundError(this.buildBranchPath(branch));\n }\n }\n\n /**\n * Get the number of children for a tree (directory) in git\n */\n private async getChildrenCount(branch: string, path: string): Promise<number> {\n try {\n const treeish = path ? `${branch}:${path}` : branch;\n const output = await this.git.raw([\"ls-tree\", treeish]);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n return lines.length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get the last commit on a branch\n */\n private async getLastCommit(\n branch: string,\n ): Promise<{ hash: string; shortHash: string; author: string; date: string; message: string }> {\n const output = await this.git.raw([\"log\", \"-1\", \"--format=%H%n%h%n%an%n%aI%n%s\", branch]);\n const lines = output.trim().split(\"\\n\");\n return {\n hash: lines[0] || \"\",\n shortHash: lines[1] || \"\",\n author: lines[2] || \"\",\n date: lines[3] || \"\",\n message: lines[4] || \"\",\n };\n }\n\n /**\n * Count total files in a tree (recursively)\n */\n private async getTreeFileCount(branch: string, path: string): Promise<number> {\n try {\n const treeish = path ? `${branch}:${path}` : branch;\n const output = await this.git.raw([\"ls-tree\", \"-r\", treeish]);\n const lines = output.split(\"\\n\").filter((line) => line.trim());\n return lines.length;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get a list of commits on a branch with limit/offset\n */\n private async getCommitList(\n branch: string,\n limit: number,\n offset: number,\n ): Promise<{ hash: string; shortHash: string; author: string; date: string; message: string }[]> {\n try {\n const args = [\n \"log\",\n `--skip=${offset}`,\n `-${limit}`,\n \"--format=%H%n%h%n%an%n%aI%n%s%n---COMMIT_SEP---\",\n branch,\n ];\n const output = await this.git.raw(args);\n const blocks = output.split(\"---COMMIT_SEP---\").filter((b) => b.trim());\n\n return blocks.map((block) => {\n const lines = block.trim().split(\"\\n\");\n return {\n hash: lines[0] || \"\",\n shortHash: lines[1] || \"\",\n author: lines[2] || \"\",\n date: lines[3] || \"\",\n message: lines[4] || \"\",\n };\n });\n } catch {\n return [];\n }\n }\n\n /**\n * Ensure worktree exists for a branch (lazy creation)\n */\n private async ensureWorktree(branch: string): Promise<string> {\n if (this.worktrees.has(branch)) {\n return this.worktrees.get(branch)!;\n }\n\n // Check if this is the current branch in the main repo\n const currentBranch = await this.git.revparse([\"--abbrev-ref\", \"HEAD\"]);\n if (currentBranch.trim() === branch) {\n // Use the main repo path for the current branch\n this.worktrees.set(branch, this.repoPath);\n return this.repoPath;\n }\n\n const worktreePath = join(this.tempBase, branch);\n\n // Check if worktree directory already exists\n const exists = await stat(worktreePath)\n .then(() => true)\n .catch(() => false);\n\n if (!exists) {\n await mkdir(this.tempBase, { recursive: true });\n await this.git.raw([\"worktree\", \"add\", worktreePath, branch]);\n }\n\n this.worktrees.set(branch, worktreePath);\n return worktreePath;\n }\n\n /**\n * List files using git ls-tree (no worktree needed)\n * Note: list() returns only children, never the path itself (per new semantics)\n */\n private async listWithGitLsTree(\n branch: string,\n path: string,\n options?: { maxDepth?: number; limit?: number },\n ): Promise<AFSListResult> {\n const maxDepth = options?.maxDepth ?? 1;\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n\n const entries: AFSEntry[] = [];\n const targetPath = path || \"\";\n const treeish = targetPath ? `${branch}:${targetPath}` : branch;\n\n try {\n // Check if the path exists and is a directory\n const pathType = await this.git\n .raw([\"cat-file\", \"-t\", treeish])\n .then((t) => t.trim())\n .catch(() => null);\n\n if (pathType === null) {\n // Path doesn't exist\n throw new AFSNotFoundError(this.buildBranchPath(branch, path));\n }\n\n // If it's a file (blob), it has no children\n if (pathType === \"blob\") {\n return { data: [] };\n }\n\n // It's a directory\n // maxDepth: 0 means return no children\n if (maxDepth === 0) {\n return { data: [] };\n }\n\n // List directory contents via BFS\n interface QueueItem {\n path: string;\n depth: number;\n }\n\n const queue: QueueItem[] = [{ path: targetPath, depth: 0 }];\n\n while (queue.length > 0) {\n const item = queue.shift()!;\n const { path: itemPath, depth } = item;\n\n // List directory contents\n const itemTreeish = itemPath ? `${branch}:${itemPath}` : branch;\n const output = await this.git.raw([\"ls-tree\", \"-l\", itemTreeish]);\n\n const lines = output\n .split(\"\\n\")\n .filter((line) => line.trim())\n .slice(0, limit - entries.length);\n\n for (const line of lines) {\n // Format: <mode> <type> <hash> <size (with padding)> <name>\n const match = line.match(/^(\\d+)\\s+(blob|tree)\\s+(\\w+)\\s+(-|\\d+)\\s+(.+)$/);\n if (!match) continue;\n\n const type = match[2]!;\n const sizeStr = match[4]!;\n const name = match[5]!;\n const isDirectory = type === \"tree\";\n const size = sizeStr === \"-\" ? undefined : Number.parseInt(sizeStr, 10);\n\n const fullPath = itemPath ? `${itemPath}/${name}` : name;\n const afsPath = this.buildBranchPath(branch, fullPath);\n\n // For directories, get children count\n const childrenCount = isDirectory\n ? await this.getChildrenCount(branch, fullPath)\n : undefined;\n\n entries.push(\n this.buildEntry(afsPath, {\n meta: { kind: isDirectory ? \"git:directory\" : \"git:file\", size, childrenCount },\n }),\n );\n\n // Add to queue if it's a directory and we haven't reached max depth\n if (isDirectory && depth + 1 < maxDepth) {\n queue.push({ path: fullPath, depth: depth + 1 });\n }\n\n // Check limit\n if (entries.length >= limit) {\n return { data: entries };\n }\n }\n }\n\n return { data: entries };\n } catch (error) {\n // Re-throw AFSNotFoundError as-is\n if (error instanceof AFSNotFoundError) {\n throw error;\n }\n throw new Error(`Failed to list: ${(error as Error).message}`);\n }\n }\n\n // ========== Public Git Operations ==========\n\n /**\n * Fetch latest changes from remote\n */\n async fetch(): Promise<void> {\n await this.ready();\n await this.git.fetch();\n }\n\n /**\n * Pull latest changes from remote for current branch\n */\n async pull(): Promise<void> {\n await this.ready();\n await this.git.pull();\n }\n\n /**\n * Push local changes to remote\n */\n async push(branch?: string): Promise<void> {\n await this.ready();\n if (branch) {\n await this.git.push(\"origin\", branch);\n } else {\n await this.git.push();\n }\n }\n\n /**\n * Cleanup all worktrees (useful when unmounting)\n */\n async cleanup(): Promise<void> {\n await this.ready();\n for (const [_branch, worktreePath] of this.worktrees) {\n try {\n await this.git.raw([\"worktree\", \"remove\", worktreePath, \"--force\"]);\n } catch (_error) {\n // Ignore errors during cleanup\n }\n }\n this.worktrees.clear();\n\n // Remove temp directory\n try {\n await rm(this.tempBase, { recursive: true, force: true });\n } catch {\n // Ignore errors\n }\n\n // Cleanup cloned repository if auto-cloned and autoCleanup enabled\n const autoCleanup = this.options.autoCleanup ?? true;\n if (this.isAutoCloned && autoCleanup && this.clonedPath) {\n try {\n await rm(this.clonedPath, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSGit, AFSGitOptions> = AFSGit;\n\nexport default AFSGit;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/afs-git",
3
- "version": "1.11.0-beta.10",
3
+ "version": "1.11.0-beta.12",
4
4
  "description": "AIGNE AFS module for git storage",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -35,7 +35,8 @@
35
35
  "dependencies": {
36
36
  "simple-git": "^3.27.0",
37
37
  "zod": "^4.0.0",
38
- "@aigne/afs": "^1.11.0-beta.10"
38
+ "@aigne/afs": "^1.11.0-beta.12",
39
+ "@aigne/afs-provider-utils": "^1.11.0-beta.12"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@types/bun": "^1.3.6",
@@ -44,8 +45,8 @@
44
45
  "tsdown": "0.20.0-beta.3",
45
46
  "typescript": "5.9.2",
46
47
  "@aigne/scripts": "0.0.0",
47
- "@aigne/afs-testing": "1.11.0-beta.10",
48
- "@aigne/typescript-config": "0.0.0"
48
+ "@aigne/typescript-config": "0.0.0",
49
+ "@aigne/afs-testing": "1.11.0-beta.12"
49
50
  },
50
51
  "scripts": {
51
52
  "build": "tsdown",
@@ -1,7 +0,0 @@
1
- import { createRequire } from "node:module";
2
-
3
- //#region rolldown:runtime
4
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
-
6
- //#endregion
7
- export { __require };