@structured-world/gitlab-mcp 6.15.0 → 6.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +49 -0
  2. package/dist/src/cli-utils.d.ts +12 -0
  3. package/dist/src/cli-utils.js +151 -0
  4. package/dist/src/cli-utils.js.map +1 -0
  5. package/dist/src/discovery/auto.d.ts +22 -0
  6. package/dist/src/discovery/auto.js +170 -0
  7. package/dist/src/discovery/auto.js.map +1 -0
  8. package/dist/src/discovery/git-remote.d.ts +19 -0
  9. package/dist/src/discovery/git-remote.js +197 -0
  10. package/dist/src/discovery/git-remote.js.map +1 -0
  11. package/dist/src/discovery/index.d.ts +3 -0
  12. package/dist/src/discovery/index.js +16 -0
  13. package/dist/src/discovery/index.js.map +1 -0
  14. package/dist/src/discovery/profile-matcher.d.ts +8 -0
  15. package/dist/src/discovery/profile-matcher.js +40 -0
  16. package/dist/src/discovery/profile-matcher.js.map +1 -0
  17. package/dist/src/entities/core/schema-readonly.d.ts +4 -4
  18. package/dist/src/entities/mrs/schema-readonly.d.ts +1 -1
  19. package/dist/src/entities/pipelines/schema-readonly.d.ts +3 -3
  20. package/dist/src/main.js +120 -30
  21. package/dist/src/main.js.map +1 -1
  22. package/dist/src/profiles/index.d.ts +3 -1
  23. package/dist/src/profiles/index.js +17 -1
  24. package/dist/src/profiles/index.js.map +1 -1
  25. package/dist/src/profiles/project-loader.d.ts +12 -0
  26. package/dist/src/profiles/project-loader.js +214 -0
  27. package/dist/src/profiles/project-loader.js.map +1 -0
  28. package/dist/src/profiles/scope-enforcer.d.ts +24 -0
  29. package/dist/src/profiles/scope-enforcer.js +128 -0
  30. package/dist/src/profiles/scope-enforcer.js.map +1 -0
  31. package/dist/src/profiles/types.d.ts +55 -0
  32. package/dist/src/profiles/types.js +41 -1
  33. package/dist/src/profiles/types.js.map +1 -1
  34. package/dist/src/utils/namespace.d.ts +1 -0
  35. package/dist/src/utils/namespace.js +11 -0
  36. package/dist/src/utils/namespace.js.map +1 -1
  37. package/dist/structured-world-gitlab-mcp-6.17.0.tgz +0 -0
  38. package/dist/tsconfig.build.tsbuildinfo +1 -1
  39. package/package.json +1 -1
  40. package/dist/structured-world-gitlab-mcp-6.15.0.tgz +0 -0
package/README.md CHANGED
@@ -187,6 +187,55 @@ docker run -i --rm \
187
187
  }
188
188
  ```
189
189
 
190
+ ## Auto-Discovery
191
+
192
+ The `--auto` flag automatically detects GitLab configuration from the current git repository's remote URL.
193
+
194
+ ### Usage
195
+
196
+ ```bash
197
+ # Auto-discover from current directory
198
+ gitlab-mcp --auto
199
+
200
+ # Auto-discover from specific directory
201
+ gitlab-mcp --auto --cwd /path/to/repo
202
+
203
+ # Use specific remote (default: origin)
204
+ gitlab-mcp --auto --remote upstream
205
+
206
+ # Dry-run: see what would be detected without applying
207
+ gitlab-mcp --auto --dry-run
208
+ ```
209
+
210
+ ### Configuration Priority
211
+
212
+ When multiple configuration sources are available, they are applied in this order (highest to lowest priority):
213
+
214
+ | Priority | Source | What it provides |
215
+ |----------|--------|------------------|
216
+ | 1 (highest) | `--profile` CLI argument | Selects user profile (host, auth, features) |
217
+ | 2 | Project config files (`.gitlab-mcp/`) | Adds restrictions and tool selection |
218
+ | 3 (lowest) | Auto-discovered profile | Fallback profile selection from git remote |
219
+
220
+ **Important notes:**
221
+
222
+ - **`--profile` always wins**: If you specify `--profile work`, it will be used even if auto-discovery detected a different profile. A warning is logged when this happens.
223
+ - **Project config adds restrictions**: The `.gitlab-mcp/` directory configuration (preset.yaml, profile.yaml) adds restrictions ON TOP of the selected profile - it doesn't replace it.
224
+ - **Auto-discovery sets defaults**: Even when a higher-priority source is used, auto-discovery still sets `GITLAB_DEFAULT_PROJECT` and `GITLAB_DEFAULT_NAMESPACE` from the git remote.
225
+
226
+ ### How Auto-Discovery Works
227
+
228
+ 1. Parses git remote URL (SSH or HTTPS format)
229
+ 2. Extracts GitLab host and project path
230
+ 3. Matches host to configured user profiles
231
+ 4. Sets default project context for convenience
232
+
233
+ **Supported URL formats:**
234
+ - SSH: `git@gitlab.company.com:group/project.git`
235
+ - SSH with port: `ssh://git@gitlab.company.com:2222/group/project.git`
236
+ - HTTPS: `https://gitlab.company.com/group/project.git`
237
+ - HTTPS with port: `https://gitlab.company.com:8443/group/project.git`
238
+
190
239
  ## Transport Modes
191
240
 
192
241
  The GitLab MCP Server automatically selects the appropriate transport mode based on your configuration:
@@ -0,0 +1,12 @@
1
+ import { ProjectConfig } from "./profiles";
2
+ export interface CliArgs {
3
+ profileName?: string;
4
+ noProjectConfig: boolean;
5
+ showProjectConfig: boolean;
6
+ auto: boolean;
7
+ cwd?: string;
8
+ dryRun: boolean;
9
+ remoteName?: string;
10
+ }
11
+ export declare function parseCliArgs(argv?: string[]): CliArgs;
12
+ export declare function displayProjectConfig(config: ProjectConfig | null, output?: (msg: string) => void): void;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCliArgs = parseCliArgs;
4
+ exports.displayProjectConfig = displayProjectConfig;
5
+ const logger_1 = require("./logger");
6
+ const profiles_1 = require("./profiles");
7
+ function parseCliArgs(argv = process.argv) {
8
+ const args = argv.slice(2);
9
+ const result = {
10
+ noProjectConfig: false,
11
+ showProjectConfig: false,
12
+ auto: false,
13
+ dryRun: false,
14
+ };
15
+ let profileCount = 0;
16
+ for (let i = 0; i < args.length; i++) {
17
+ const arg = args[i];
18
+ if (arg === "--profile") {
19
+ const value = args[i + 1];
20
+ if (!value || value.startsWith("--")) {
21
+ logger_1.logger.error("--profile requires a profile name (e.g., --profile work)");
22
+ throw new Error("--profile requires a profile name");
23
+ }
24
+ profileCount++;
25
+ if (profileCount === 1) {
26
+ result.profileName = value;
27
+ }
28
+ i++;
29
+ }
30
+ else if (arg === "--no-project-config") {
31
+ result.noProjectConfig = true;
32
+ }
33
+ else if (arg === "--show-project-config") {
34
+ result.showProjectConfig = true;
35
+ }
36
+ else if (arg === "--auto") {
37
+ result.auto = true;
38
+ }
39
+ else if (arg === "--cwd") {
40
+ const value = args[i + 1];
41
+ if (!value || value.startsWith("--")) {
42
+ logger_1.logger.error("--cwd requires a directory path (e.g., --cwd /path/to/repo)");
43
+ throw new Error("--cwd requires a directory path");
44
+ }
45
+ result.cwd = value;
46
+ i++;
47
+ }
48
+ else if (arg === "--dry-run") {
49
+ result.dryRun = true;
50
+ }
51
+ else if (arg === "--remote") {
52
+ const value = args[i + 1];
53
+ if (!value || value.startsWith("--")) {
54
+ logger_1.logger.error("--remote requires a remote name (e.g., --remote upstream)");
55
+ throw new Error("--remote requires a remote name");
56
+ }
57
+ result.remoteName = value;
58
+ i++;
59
+ }
60
+ }
61
+ if (profileCount > 1) {
62
+ logger_1.logger.warn({ count: profileCount }, "Multiple --profile flags detected, using first value");
63
+ }
64
+ return result;
65
+ }
66
+ function displayProjectConfig(config, output = console.log) {
67
+ if (!config) {
68
+ output("No project configuration found in current directory or parent directories.");
69
+ output("\nTo create a project config, add .gitlab-mcp/ directory with:");
70
+ output(" - preset.yaml (restrictions: scope, denied_actions, features)");
71
+ output(" - profile.yaml (tool selection: extends, additional_tools)");
72
+ return;
73
+ }
74
+ const summary = (0, profiles_1.getProjectConfigSummary)(config);
75
+ output("Project Configuration");
76
+ output("=====================");
77
+ output(`Path: ${config.configPath}`);
78
+ output("");
79
+ if (config.preset) {
80
+ output("Preset (restrictions):");
81
+ if (config.preset.description) {
82
+ output(` Description: ${config.preset.description}`);
83
+ }
84
+ if (config.preset.scope) {
85
+ if (config.preset.scope.project) {
86
+ output(` Scope: project "${config.preset.scope.project}"`);
87
+ }
88
+ else if (config.preset.scope.namespace) {
89
+ output(` Scope: namespace "${config.preset.scope.namespace}/*"`);
90
+ }
91
+ else if (config.preset.scope.projects) {
92
+ output(` Scope: ${config.preset.scope.projects.length} projects`);
93
+ for (const p of config.preset.scope.projects) {
94
+ output(` - ${p}`);
95
+ }
96
+ }
97
+ }
98
+ if (config.preset.read_only) {
99
+ output(" Read-only: yes");
100
+ }
101
+ if (config.preset.denied_actions?.length) {
102
+ output(` Denied actions: ${config.preset.denied_actions.join(", ")}`);
103
+ }
104
+ if (config.preset.denied_tools?.length) {
105
+ output(` Denied tools: ${config.preset.denied_tools.join(", ")}`);
106
+ }
107
+ if (config.preset.features) {
108
+ const features = Object.entries(config.preset.features)
109
+ .filter(([, v]) => v !== undefined)
110
+ .map(([k, v]) => `${k}=${v}`)
111
+ .join(", ");
112
+ if (features) {
113
+ output(` Features: ${features}`);
114
+ }
115
+ }
116
+ output("");
117
+ }
118
+ if (config.profile) {
119
+ output("Profile (tool selection):");
120
+ if (config.profile.description) {
121
+ output(` Description: ${config.profile.description}`);
122
+ }
123
+ if (config.profile.extends) {
124
+ output(` Extends: ${config.profile.extends}`);
125
+ }
126
+ if (config.profile.additional_tools?.length) {
127
+ output(` Additional tools: ${config.profile.additional_tools.join(", ")}`);
128
+ }
129
+ if (config.profile.denied_tools?.length) {
130
+ output(` Denied tools: ${config.profile.denied_tools.join(", ")}`);
131
+ }
132
+ if (config.profile.features) {
133
+ const features = Object.entries(config.profile.features)
134
+ .filter(([, v]) => v !== undefined)
135
+ .map(([k, v]) => `${k}=${v}`)
136
+ .join(", ");
137
+ if (features) {
138
+ output(` Features: ${features}`);
139
+ }
140
+ }
141
+ output("");
142
+ }
143
+ output("Summary:");
144
+ if (summary.presetSummary) {
145
+ output(` Preset: ${summary.presetSummary}`);
146
+ }
147
+ if (summary.profileSummary) {
148
+ output(` Profile: ${summary.profileSummary}`);
149
+ }
150
+ }
151
+ //# sourceMappingURL=cli-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-utils.js","sourceRoot":"","sources":["../../src/cli-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { GitRemoteInfo } from "./git-remote";
2
+ import { ProfileMatchResult } from "./profile-matcher";
3
+ import { ProjectConfig } from "../profiles";
4
+ export interface AutoDiscoveryOptions {
5
+ repoPath?: string;
6
+ remoteName?: string;
7
+ noProjectConfig?: boolean;
8
+ dryRun?: boolean;
9
+ }
10
+ export interface AutoDiscoveryResult {
11
+ host: string;
12
+ projectPath: string;
13
+ remote: GitRemoteInfo;
14
+ matchedProfile: ProfileMatchResult | null;
15
+ projectConfig: ProjectConfig | null;
16
+ apiUrl: string;
17
+ profileApplied: boolean;
18
+ projectConfigApplied: boolean;
19
+ availableRemotes: GitRemoteInfo[];
20
+ }
21
+ export declare function autoDiscover(options?: AutoDiscoveryOptions): Promise<AutoDiscoveryResult | null>;
22
+ export declare function formatDiscoveryResult(result: AutoDiscoveryResult): string;
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.autoDiscover = autoDiscover;
4
+ exports.formatDiscoveryResult = formatDiscoveryResult;
5
+ const git_remote_1 = require("./git-remote");
6
+ const profile_matcher_1 = require("./profile-matcher");
7
+ const profiles_1 = require("../profiles");
8
+ const logger_1 = require("../logger");
9
+ const namespace_1 = require("../utils/namespace");
10
+ async function autoDiscover(options = {}) {
11
+ const repoPath = options.repoPath ?? process.cwd();
12
+ logger_1.logger.info({ path: repoPath }, "Starting auto-discovery");
13
+ const remote = await (0, git_remote_1.parseGitRemote)({
14
+ repoPath,
15
+ remoteName: options.remoteName,
16
+ });
17
+ if (!remote) {
18
+ logger_1.logger.warn({ path: repoPath }, "Auto-discovery: No git remote found");
19
+ return null;
20
+ }
21
+ logger_1.logger.info({
22
+ host: remote.host,
23
+ projectPath: remote.projectPath,
24
+ remote: remote.remoteName,
25
+ }, "Detected git remote");
26
+ const availableRemotes = await (0, git_remote_1.listGitRemotes)(repoPath);
27
+ const matchedProfile = await (0, profile_matcher_1.findProfileByHost)(remote.host);
28
+ if (matchedProfile) {
29
+ logger_1.logger.info({
30
+ profile: matchedProfile.profileName,
31
+ matchType: matchedProfile.matchType,
32
+ }, "Matched host to user profile");
33
+ }
34
+ else {
35
+ logger_1.logger.debug({ host: remote.host }, "No matching user profile found");
36
+ }
37
+ let projectConfig = null;
38
+ if (!options.noProjectConfig) {
39
+ projectConfig = await (0, profiles_1.findProjectConfig)(repoPath);
40
+ if (projectConfig) {
41
+ logger_1.logger.info({ path: projectConfig.configPath }, "Found project configuration");
42
+ }
43
+ }
44
+ const apiUrl = `https://${remote.host}`;
45
+ const result = {
46
+ host: remote.host,
47
+ projectPath: remote.projectPath,
48
+ remote,
49
+ matchedProfile,
50
+ projectConfig,
51
+ apiUrl,
52
+ profileApplied: false,
53
+ projectConfigApplied: false,
54
+ availableRemotes,
55
+ };
56
+ if (!options.dryRun) {
57
+ if (matchedProfile) {
58
+ try {
59
+ await (0, profiles_1.loadAndApplyProfile)(matchedProfile.profileName);
60
+ result.profileApplied = true;
61
+ logger_1.logger.info({ profile: matchedProfile.profileName }, "Applied matched profile");
62
+ }
63
+ catch (error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ logger_1.logger.error({ error: message }, "Failed to apply matched profile");
66
+ }
67
+ }
68
+ else {
69
+ if (!process.env.GITLAB_API_URL) {
70
+ process.env.GITLAB_API_URL = apiUrl;
71
+ logger_1.logger.info({ apiUrl }, "Set GITLAB_API_URL from discovered host");
72
+ }
73
+ }
74
+ if (projectConfig) {
75
+ result.projectConfigApplied = true;
76
+ logger_1.logger.debug({ config: projectConfig }, "Project config loaded (enforcement pending)");
77
+ }
78
+ setDefaultContext(remote.projectPath);
79
+ }
80
+ return result;
81
+ }
82
+ function setDefaultContext(projectPath) {
83
+ if (!process.env.GITLAB_DEFAULT_PROJECT) {
84
+ process.env.GITLAB_DEFAULT_PROJECT = projectPath;
85
+ logger_1.logger.debug({ project: projectPath }, "Set default project context");
86
+ }
87
+ if (!process.env.GITLAB_DEFAULT_NAMESPACE) {
88
+ const namespace = (0, namespace_1.extractNamespaceFromPath)(projectPath);
89
+ if (namespace) {
90
+ process.env.GITLAB_DEFAULT_NAMESPACE = namespace;
91
+ logger_1.logger.debug({ namespace }, "Set default namespace context");
92
+ }
93
+ }
94
+ }
95
+ function formatDiscoveryResult(result) {
96
+ const lines = [];
97
+ lines.push("Auto-discovery Results");
98
+ lines.push("======================");
99
+ lines.push("");
100
+ lines.push("Git Remote:");
101
+ lines.push(` Remote: ${result.remote.remoteName}`);
102
+ lines.push(` Host: ${result.host}`);
103
+ lines.push(` Project: ${result.projectPath}`);
104
+ lines.push(` Protocol: ${result.remote.protocol}`);
105
+ lines.push(` URL: ${result.remote.url}`);
106
+ lines.push("");
107
+ if (result.availableRemotes.length > 1) {
108
+ lines.push("Available Remotes:");
109
+ for (const remote of result.availableRemotes) {
110
+ const selected = remote.remoteName === result.remote.remoteName ? " (selected)" : "";
111
+ lines.push(` ${remote.remoteName}: ${remote.host}/${remote.projectPath}${selected}`);
112
+ }
113
+ lines.push("");
114
+ }
115
+ lines.push("Profile Match:");
116
+ if (result.matchedProfile) {
117
+ lines.push(` Profile: ${result.matchedProfile.profileName}`);
118
+ lines.push(` Match Type: ${result.matchedProfile.matchType}`);
119
+ if (result.matchedProfile.profile.authType) {
120
+ lines.push(` Auth: ${result.matchedProfile.profile.authType}`);
121
+ }
122
+ if (result.matchedProfile.profile.readOnly) {
123
+ lines.push(` Mode: read-only`);
124
+ }
125
+ }
126
+ else {
127
+ lines.push(` No matching profile found`);
128
+ lines.push(` Will use: ${result.apiUrl} (from discovered host)`);
129
+ lines.push(` Auth: GITLAB_TOKEN environment variable required`);
130
+ }
131
+ lines.push("");
132
+ lines.push("Project Configuration:");
133
+ if (result.projectConfig) {
134
+ lines.push(` Path: ${result.projectConfig.configPath}`);
135
+ if (result.projectConfig.preset) {
136
+ lines.push(` Preset: ${result.projectConfig.preset.description ?? "custom restrictions"}`);
137
+ if (result.projectConfig.preset.scope) {
138
+ const scope = result.projectConfig.preset.scope;
139
+ if (scope.project) {
140
+ lines.push(` Scope: project "${scope.project}"`);
141
+ }
142
+ else if (scope.namespace) {
143
+ lines.push(` Scope: namespace "${scope.namespace}/*"`);
144
+ }
145
+ else if (scope.projects) {
146
+ lines.push(` Scope: ${scope.projects.length} projects`);
147
+ }
148
+ }
149
+ if (result.projectConfig.preset.read_only) {
150
+ lines.push(` Mode: read-only`);
151
+ }
152
+ }
153
+ if (result.projectConfig.profile) {
154
+ lines.push(` Profile: ${result.projectConfig.profile.description ?? "custom tool selection"}`);
155
+ if (result.projectConfig.profile.extends) {
156
+ lines.push(` Extends: ${result.projectConfig.profile.extends}`);
157
+ }
158
+ }
159
+ }
160
+ else {
161
+ lines.push(` No .gitlab-mcp/ directory found`);
162
+ }
163
+ lines.push("");
164
+ lines.push("Default Context:");
165
+ lines.push(` Project: ${result.projectPath}`);
166
+ const namespace = (0, namespace_1.extractNamespaceFromPath)(result.projectPath) ?? result.projectPath;
167
+ lines.push(` Namespace: ${namespace}`);
168
+ return lines.join("\n");
169
+ }
170
+ //# sourceMappingURL=auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../../../src/discovery/auto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface GitRemoteInfo {
2
+ host: string;
3
+ projectPath: string;
4
+ protocol: "ssh" | "https";
5
+ url: string;
6
+ remoteName: string;
7
+ }
8
+ export interface ParseGitRemoteOptions {
9
+ remoteName?: string;
10
+ repoPath?: string;
11
+ }
12
+ export declare function parseRemoteUrl(url: string): Omit<GitRemoteInfo, "remoteName"> | null;
13
+ export declare function parseGitConfig(content: string): Map<string, string>;
14
+ export declare function selectBestRemote(remotes: Map<string, string>, preferredRemote?: string): {
15
+ name: string;
16
+ url: string;
17
+ } | null;
18
+ export declare function parseGitRemote(options?: ParseGitRemoteOptions): Promise<GitRemoteInfo | null>;
19
+ export declare function listGitRemotes(repoPath?: string): Promise<GitRemoteInfo[]>;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseRemoteUrl = parseRemoteUrl;
37
+ exports.parseGitConfig = parseGitConfig;
38
+ exports.selectBestRemote = selectBestRemote;
39
+ exports.parseGitRemote = parseGitRemote;
40
+ exports.listGitRemotes = listGitRemotes;
41
+ const fs = __importStar(require("fs/promises"));
42
+ const path = __importStar(require("path"));
43
+ const logger_1 = require("../logger");
44
+ function parseRemoteUrl(url) {
45
+ const normalizedUrl = url.trim();
46
+ const sshMatch = normalizedUrl.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
47
+ if (sshMatch) {
48
+ return {
49
+ host: sshMatch[1],
50
+ projectPath: normalizeProjectPath(sshMatch[2]),
51
+ protocol: "ssh",
52
+ url: normalizedUrl,
53
+ };
54
+ }
55
+ const sshProtocolMatch = normalizedUrl.match(/^ssh:\/\/git@([^/:]+)(?::(\d+))?\/(.+?)(?:\.git)?$/);
56
+ if (sshProtocolMatch) {
57
+ const sshHost = sshProtocolMatch[2]
58
+ ? `${sshProtocolMatch[1]}:${sshProtocolMatch[2]}`
59
+ : sshProtocolMatch[1];
60
+ return {
61
+ host: sshHost,
62
+ projectPath: normalizeProjectPath(sshProtocolMatch[3]),
63
+ protocol: "ssh",
64
+ url: normalizedUrl,
65
+ };
66
+ }
67
+ const httpsMatch = normalizedUrl.match(/^https?:\/\/([^/:]+)(?::(\d+))?\/(.+?)(?:\.git)?$/);
68
+ if (httpsMatch) {
69
+ const httpsHost = httpsMatch[2] ? `${httpsMatch[1]}:${httpsMatch[2]}` : httpsMatch[1];
70
+ return {
71
+ host: httpsHost,
72
+ projectPath: normalizeProjectPath(httpsMatch[3]),
73
+ protocol: "https",
74
+ url: normalizedUrl,
75
+ };
76
+ }
77
+ logger_1.logger.debug({ url: normalizedUrl }, "Could not parse remote URL");
78
+ return null;
79
+ }
80
+ function normalizeProjectPath(projectPath) {
81
+ return projectPath.replace(/^\/+|\/+$/g, "");
82
+ }
83
+ function parseGitConfig(content) {
84
+ const remotes = new Map();
85
+ const lines = content.split(/\r?\n/);
86
+ let currentRemote = null;
87
+ for (const rawLine of lines) {
88
+ const line = rawLine.trim();
89
+ if (line.length === 0) {
90
+ continue;
91
+ }
92
+ const remoteHeaderMatch = line.match(/^\[remote\s+"([^"]+)"\]\s*$/);
93
+ if (remoteHeaderMatch) {
94
+ currentRemote = remoteHeaderMatch[1];
95
+ continue;
96
+ }
97
+ if (line.startsWith("[") && line.endsWith("]")) {
98
+ currentRemote = null;
99
+ continue;
100
+ }
101
+ if (currentRemote === null) {
102
+ continue;
103
+ }
104
+ const urlMatch = line.match(/^url\s*=\s*(.+)$/);
105
+ if (urlMatch) {
106
+ const url = urlMatch[1].trim();
107
+ if (url !== "") {
108
+ remotes.set(currentRemote, url);
109
+ }
110
+ }
111
+ }
112
+ return remotes;
113
+ }
114
+ function selectBestRemote(remotes, preferredRemote) {
115
+ if (remotes.size === 0) {
116
+ return null;
117
+ }
118
+ if (preferredRemote) {
119
+ const url = remotes.get(preferredRemote);
120
+ if (url !== undefined) {
121
+ return { name: preferredRemote, url };
122
+ }
123
+ }
124
+ const originUrl = remotes.get("origin");
125
+ if (originUrl !== undefined) {
126
+ return { name: "origin", url: originUrl };
127
+ }
128
+ const firstEntry = remotes.entries().next();
129
+ if (firstEntry.done) {
130
+ return null;
131
+ }
132
+ const [name, url] = firstEntry.value;
133
+ return { name, url };
134
+ }
135
+ async function parseGitRemote(options = {}) {
136
+ const repoPath = options.repoPath ?? process.cwd();
137
+ const gitConfigPath = path.join(repoPath, ".git", "config");
138
+ try {
139
+ await fs.access(gitConfigPath);
140
+ }
141
+ catch {
142
+ logger_1.logger.debug({ path: repoPath }, "No .git/config found - not a git repository");
143
+ return null;
144
+ }
145
+ let content;
146
+ try {
147
+ content = await fs.readFile(gitConfigPath, "utf-8");
148
+ }
149
+ catch (error) {
150
+ const message = error instanceof Error ? error.message : String(error);
151
+ logger_1.logger.warn({ error: message, path: gitConfigPath }, "Failed to read git config");
152
+ return null;
153
+ }
154
+ const remotes = parseGitConfig(content);
155
+ if (remotes.size === 0) {
156
+ logger_1.logger.debug({ path: repoPath }, "No remotes found in git config");
157
+ return null;
158
+ }
159
+ const selected = selectBestRemote(remotes, options.remoteName);
160
+ if (!selected) {
161
+ return null;
162
+ }
163
+ const parsed = parseRemoteUrl(selected.url);
164
+ if (!parsed) {
165
+ logger_1.logger.warn({ remote: selected.name, url: selected.url }, "Could not parse remote URL format");
166
+ return null;
167
+ }
168
+ logger_1.logger.debug({
169
+ remote: selected.name,
170
+ host: parsed.host,
171
+ projectPath: parsed.projectPath,
172
+ protocol: parsed.protocol,
173
+ }, "Parsed git remote");
174
+ return {
175
+ ...parsed,
176
+ remoteName: selected.name,
177
+ };
178
+ }
179
+ async function listGitRemotes(repoPath) {
180
+ const gitConfigPath = path.join(repoPath ?? process.cwd(), ".git", "config");
181
+ try {
182
+ const content = await fs.readFile(gitConfigPath, "utf-8");
183
+ const remotes = parseGitConfig(content);
184
+ const result = [];
185
+ for (const [name, url] of remotes) {
186
+ const parsed = parseRemoteUrl(url);
187
+ if (parsed) {
188
+ result.push({ ...parsed, remoteName: name });
189
+ }
190
+ }
191
+ return result;
192
+ }
193
+ catch {
194
+ return [];
195
+ }
196
+ }
197
+ //# sourceMappingURL=git-remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-remote.js","sourceRoot":"","sources":["../../../src/discovery/git-remote.ts"],"names":[],"mappings":"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"}