@cybedefend/vibedefend 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -5
- package/dist/api/projects.js +158 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/custom-regions.js +5 -0
- package/dist/custom-regions.js.map +1 -1
- package/dist/endpoints.js +59 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/git.js +103 -0
- package/dist/git.js.map +1 -0
- package/dist/hook-runner.js +548 -277
- package/dist/hooks/runtime/fetch-rules.js +5 -3
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/judge-injection.js +65 -0
- package/dist/hooks/runtime/judge-injection.js.map +1 -0
- package/dist/hooks/runtime/repo-link-cache.js +116 -0
- package/dist/hooks/runtime/repo-link-cache.js.map +1 -0
- package/dist/hooks/runtime/resolve.js +79 -0
- package/dist/hooks/runtime/resolve.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +5 -3
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +10 -7
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/dist/install.js +142 -88
- package/dist/install.js.map +1 -1
- package/dist/link.js +325 -0
- package/dist/link.js.map +1 -0
- package/dist/login.js +2 -23
- package/dist/login.js.map +1 -1
- package/dist/logout.js +87 -0
- package/dist/logout.js.map +1 -0
- package/dist/org-gate.js +110 -0
- package/dist/org-gate.js.map +1 -0
- package/dist/prompts.js +5 -7
- package/dist/prompts.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,8 +19,15 @@ Works on **macOS, Linux, and Windows** (PowerShell, cmd, bash, zsh, fish,
|
|
|
19
19
|
Git Bash — pick any). Requires **Node 18.17 or later** — most users already
|
|
20
20
|
have it because Claude Code / Cursor / Codex ship with a bundled Node.
|
|
21
21
|
|
|
22
|
-
The installer is fully interactive
|
|
23
|
-
|
|
22
|
+
The installer is fully interactive, and signs you in **first**:
|
|
23
|
+
|
|
24
|
+
1. **Pick a region** (EU / US).
|
|
25
|
+
2. **Sign in** — your browser opens for a one-time CybeDefend sign-in
|
|
26
|
+
(skipped if you're already signed in from a previous run).
|
|
27
|
+
3. **Organization check** — if your account doesn't belong to an
|
|
28
|
+
organization yet, the dashboard on-boarding page opens and the installer
|
|
29
|
+
waits while you create or join one (Ctrl-C to skip and finish later).
|
|
30
|
+
4. **Pick which agents to wire** (auto-detected), confirm. That's it.
|
|
24
31
|
|
|
25
32
|
Prefer a global install?
|
|
26
33
|
|
|
@@ -67,23 +74,43 @@ toggle any on or off.
|
|
|
67
74
|
## Commands
|
|
68
75
|
|
|
69
76
|
```
|
|
70
|
-
vibedefend install Set up MCP + hooks (interactive)
|
|
77
|
+
vibedefend install Set up MCP + hooks (interactive, signs you in first)
|
|
71
78
|
vibedefend update Refresh hooks to the latest version
|
|
72
79
|
vibedefend update --self Upgrade the CLI itself
|
|
73
80
|
vibedefend status Read-only install report
|
|
74
81
|
vibedefend doctor Diagnose and repair common issues
|
|
75
82
|
vibedefend login (Re-)authenticate against the CybeDefend API
|
|
83
|
+
vibedefend logout Clear stored credentials (a fresh sign-in next run)
|
|
84
|
+
vibedefend link Link a repo to a CybeDefend project
|
|
76
85
|
vibedefend uninstall Remove every VibeDefend-installed file
|
|
77
86
|
vibedefend --help Full help
|
|
78
87
|
```
|
|
79
88
|
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
## Linking a repo to its project
|
|
90
|
+
|
|
91
|
+
For **projects imported from GitHub or GitLab, there is nothing to do**:
|
|
92
|
+
VibeDefend reads the repo's `origin` remote and resolves the matching
|
|
93
|
+
CybeDefend project automatically on the first hook call.
|
|
94
|
+
|
|
95
|
+
For any other repo (no remote, a mirror, a monorepo subfolder, an
|
|
96
|
+
unimported project…), link it once:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
vibedefend link # interactive: auto-detect, or pick org → project
|
|
100
|
+
vibedefend link --project <uuid> # non-interactive, if you know the project UUID
|
|
101
|
+
# or without a global install:
|
|
102
|
+
npx -y @cybedefend/vibedefend@latest link --project <PROJECT_ID>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`link` writes a `.cybedefend/config.json` next to your code:
|
|
82
106
|
|
|
83
107
|
```json
|
|
84
108
|
{ "projectId": "<your-cybedefend-project-uuid>" }
|
|
85
109
|
```
|
|
86
110
|
|
|
111
|
+
That file is now **optional** for GitHub/GitLab-linked projects, but it
|
|
112
|
+
remains a supported override everywhere — when present, it always wins over
|
|
113
|
+
git-origin auto-resolution (as does the `CYBEDEFEND_PROJECT_ID` env var).
|
|
87
114
|
You can grab the UUID from the project page on the EU dashboard
|
|
88
115
|
([eu.cybedefend.com](https://eu.cybedefend.com)) or the US dashboard
|
|
89
116
|
([us.cybedefend.com](https://us.cybedefend.com)).
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway API client for project discovery.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the injectable-`fetchImpl` pattern of `hooks/runtime/api.ts`:
|
|
5
|
+
* every call is bounded by `AbortSignal.timeout(...)` (these run on the
|
|
6
|
+
* critical path of the user's edit) and returns `null` on ANY failure —
|
|
7
|
+
* network throw, non-2xx, or malformed JSON — so hook callers stay
|
|
8
|
+
* fail-open. `null` NEVER means "no results"; it means "could not tell".
|
|
9
|
+
* An empty result is an empty array.
|
|
10
|
+
*/
|
|
11
|
+
const RESOLVE_TIMEOUT_MS = 4_000;
|
|
12
|
+
const LIST_TIMEOUT_MS = 10_000;
|
|
13
|
+
/** Unwrap a gateway `{success,data,message}` envelope to its `data`, else the root. */
|
|
14
|
+
function unwrap(body) {
|
|
15
|
+
if (!body || typeof body !== 'object')
|
|
16
|
+
return {};
|
|
17
|
+
const root = body;
|
|
18
|
+
const data = root.data;
|
|
19
|
+
return data ?? root;
|
|
20
|
+
}
|
|
21
|
+
/** First array found among `body`, `body.data`, or `body[<key>]`. */
|
|
22
|
+
function firstArray(body, key) {
|
|
23
|
+
if (Array.isArray(body))
|
|
24
|
+
return body;
|
|
25
|
+
if (body && typeof body === 'object') {
|
|
26
|
+
const r = body;
|
|
27
|
+
if (Array.isArray(r.data))
|
|
28
|
+
return r.data;
|
|
29
|
+
if (Array.isArray(r[key]))
|
|
30
|
+
return r[key];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
function str(v) {
|
|
35
|
+
return typeof v === 'string' ? v : v == null ? '' : String(v);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* GET {apiBase}/user/projects/resolve?provider=&slug=&host=
|
|
39
|
+
*
|
|
40
|
+
* Returns the list of projects the caller can access whose configured
|
|
41
|
+
* repository matches `{provider, slug, host}`. `null` on any error.
|
|
42
|
+
* The `host` query param is only sent when provided.
|
|
43
|
+
*/
|
|
44
|
+
export async function resolveProjectByRepository(apiBase, token, q, deps = {}) {
|
|
45
|
+
const f = deps.fetchImpl ?? globalThis.fetch;
|
|
46
|
+
const params = new URLSearchParams({ provider: q.provider, slug: q.slug });
|
|
47
|
+
if (q.host)
|
|
48
|
+
params.set('host', q.host);
|
|
49
|
+
const url = `${apiBase}/user/projects/resolve?${params.toString()}`;
|
|
50
|
+
let res;
|
|
51
|
+
try {
|
|
52
|
+
res = await f(url, {
|
|
53
|
+
method: 'GET',
|
|
54
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
55
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? RESOLVE_TIMEOUT_MS),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (!res.ok)
|
|
62
|
+
return null;
|
|
63
|
+
let body;
|
|
64
|
+
try {
|
|
65
|
+
body = await res.json();
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const data = unwrap(body);
|
|
71
|
+
const rawMatches = Array.isArray(data.matches) ? data.matches : [];
|
|
72
|
+
return rawMatches.map((raw) => {
|
|
73
|
+
const m = (raw ?? {});
|
|
74
|
+
return {
|
|
75
|
+
projectId: str(m.projectId),
|
|
76
|
+
organizationId: str(m.organizationId),
|
|
77
|
+
projectName: str(m.projectName),
|
|
78
|
+
provider: str(m.provider),
|
|
79
|
+
repository: str(m.repository),
|
|
80
|
+
// Missing → enabled (default-on). Only an explicit `false` disables.
|
|
81
|
+
vibedefendEnabled: m.vibedefendEnabled !== false,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* GET {apiBase}/organizations
|
|
87
|
+
*
|
|
88
|
+
* Returns `[{id, name}]` for the organizations the caller belongs to, or
|
|
89
|
+
* `null` on any error.
|
|
90
|
+
*/
|
|
91
|
+
export async function listOrganizations(apiBase, token, deps = {}) {
|
|
92
|
+
const f = deps.fetchImpl ?? globalThis.fetch;
|
|
93
|
+
const url = `${apiBase}/organizations`;
|
|
94
|
+
let res;
|
|
95
|
+
try {
|
|
96
|
+
res = await f(url, {
|
|
97
|
+
method: 'GET',
|
|
98
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
99
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? LIST_TIMEOUT_MS),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (!res.ok)
|
|
106
|
+
return null;
|
|
107
|
+
let body;
|
|
108
|
+
try {
|
|
109
|
+
body = await res.json();
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return firstArray(body, 'organizations').map((raw) => {
|
|
115
|
+
const o = (raw ?? {});
|
|
116
|
+
return { id: str(o.id), name: str(o.name) };
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* GET {apiBase}/mcp/organization/:id/projects[?search=]
|
|
121
|
+
*
|
|
122
|
+
* Returns `[{projectId, name}]` for the org, optionally filtered by
|
|
123
|
+
* `search`, or `null` on any error.
|
|
124
|
+
*/
|
|
125
|
+
export async function listProjects(apiBase, token, orgId, search, deps = {}) {
|
|
126
|
+
const f = deps.fetchImpl ?? globalThis.fetch;
|
|
127
|
+
let url = `${apiBase}/mcp/organization/${encodeURIComponent(orgId)}/projects`;
|
|
128
|
+
if (search)
|
|
129
|
+
url += `?${new URLSearchParams({ search }).toString()}`;
|
|
130
|
+
let res;
|
|
131
|
+
try {
|
|
132
|
+
res = await f(url, {
|
|
133
|
+
method: 'GET',
|
|
134
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
135
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? LIST_TIMEOUT_MS),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
if (!res.ok)
|
|
142
|
+
return null;
|
|
143
|
+
let body;
|
|
144
|
+
try {
|
|
145
|
+
body = await res.json();
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return firstArray(body, 'projects').map((raw) => {
|
|
151
|
+
const p = (raw ?? {});
|
|
152
|
+
return {
|
|
153
|
+
projectId: str(p.projectId ?? p.id),
|
|
154
|
+
name: str(p.name ?? p.projectName),
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/api/projects.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -7,6 +7,7 @@ export const REGIONS = [
|
|
|
7
7
|
apiBase: 'https://api-eu.cybedefend.com',
|
|
8
8
|
mcpName: 'cybedefend',
|
|
9
9
|
dev: false,
|
|
10
|
+
dashboardUrl: 'https://eu.cybedefend.com',
|
|
10
11
|
},
|
|
11
12
|
{
|
|
12
13
|
id: 'us',
|
|
@@ -16,6 +17,7 @@ export const REGIONS = [
|
|
|
16
17
|
apiBase: 'https://api-us.cybedefend.com',
|
|
17
18
|
mcpName: 'cybedefend',
|
|
18
19
|
dev: false,
|
|
20
|
+
dashboardUrl: 'https://us.cybedefend.com',
|
|
19
21
|
},
|
|
20
22
|
];
|
|
21
23
|
/**
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAwCA,MAAM,CAAC,MAAM,OAAO,GAA4B;IAC9C;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,kFAAkF;QACpF,MAAM,EAAE,mCAAmC;QAC3C,OAAO,EAAE,+BAA+B;QACxC,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,KAAK;QACV,YAAY,EAAE,2BAA2B;KAC1C;IACD;QACE,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,0EAA0E;QAC5E,MAAM,EAAE,mCAAmC;QAC3C,OAAO,EAAE,+BAA+B;QACxC,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,KAAK;QACV,YAAY,EAAE,2BAA2B;KAC1C;CACO,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,CAAC;IAClB,eAAe,EAAE,KAAK;IACtB,UAAU,EAAE,IAAI;IAChB,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,cAAc,EAAE,IAAI;CACZ,CAAC"}
|
package/dist/custom-regions.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* The file is a JSON array of `RegionConfig` objects. Each entry needs
|
|
16
16
|
* the six string fields `id`, `label`, `description`, `mcpUrl`,
|
|
17
17
|
* `apiBase`, `mcpName`. `dev` is optional (defaults to `false`).
|
|
18
|
+
* `dashboardUrl` is optional (defaults to derivation from `apiBase` —
|
|
19
|
+
* see `deriveDashboardUrl` in `src/endpoints.ts`).
|
|
18
20
|
*
|
|
19
21
|
* The loader never throws — bad JSON or malformed entries log a warning
|
|
20
22
|
* and degrade to "no custom regions" so a broken file can't break the
|
|
@@ -90,6 +92,9 @@ function parseRegionsFile(path) {
|
|
|
90
92
|
apiBase: obj.apiBase,
|
|
91
93
|
mcpName: obj.mcpName,
|
|
92
94
|
dev: typeof obj.dev === 'boolean' ? obj.dev : false,
|
|
95
|
+
dashboardUrl: typeof obj.dashboardUrl === 'string' && obj.dashboardUrl.length > 0
|
|
96
|
+
? obj.dashboardUrl
|
|
97
|
+
: undefined,
|
|
93
98
|
});
|
|
94
99
|
});
|
|
95
100
|
if (valid.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-regions.js","sourceRoot":"","sources":["../src/custom-regions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"custom-regions.js","sourceRoot":"","sources":["../src/custom-regions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the Logto OIDC endpoint from a gateway `apiBase` when not
|
|
3
|
+
* explicitly configured.
|
|
4
|
+
*
|
|
5
|
+
* Conventions (checked in order):
|
|
6
|
+
* - `https://api.cybedefend.com` → `https://auth.cybedefend.com`
|
|
7
|
+
* - `https://api-us.cybedefend.com` → `https://auth-us.cybedefend.com`
|
|
8
|
+
* - `http://localhost:3000` → `http://localhost:3003`
|
|
9
|
+
* - anything else → returned unchanged (deterministic
|
|
10
|
+
* fallback so callers at least get *a* URL, even if it's wrong, rather
|
|
11
|
+
* than an exception).
|
|
12
|
+
*
|
|
13
|
+
* This was previously duplicated as `install.ts#deriveLogtoEndpoint`
|
|
14
|
+
* (api./api-xx. only) and `login.ts#deriveLogtoEndpointFromApiBase`
|
|
15
|
+
* (api./api-xx./localhost). This is the union of both — the localhost
|
|
16
|
+
* branch now also applies to the install.ts call site, which is a
|
|
17
|
+
* strict behavior improvement (it previously left localhost apiBases
|
|
18
|
+
* unchanged, i.e. pointed the login flow at the gateway port instead of
|
|
19
|
+
* Logto's).
|
|
20
|
+
*/
|
|
21
|
+
export function deriveLogtoEndpoint(apiBase) {
|
|
22
|
+
if (apiBase.includes('://api.')) {
|
|
23
|
+
return apiBase.replace('://api.', '://auth.');
|
|
24
|
+
}
|
|
25
|
+
if (apiBase.match(/\/\/api-[a-z]+\./)) {
|
|
26
|
+
return apiBase.replace('://api-', '://auth-');
|
|
27
|
+
}
|
|
28
|
+
if (apiBase.includes('localhost:3000')) {
|
|
29
|
+
return apiBase.replace(':3000', ':3003');
|
|
30
|
+
}
|
|
31
|
+
return apiBase;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Derive the dashboard URL for a region.
|
|
35
|
+
*
|
|
36
|
+
* An explicit `region.dashboardUrl` always wins. Otherwise, derive from
|
|
37
|
+
* `apiBase` using the same "api" hostname convention as the Gateway:
|
|
38
|
+
* - `https://api-us.cybedefend.com` → `https://us.cybedefend.com`
|
|
39
|
+
* - `https://api.cybedefend.com` → `https://cybedefend.com`
|
|
40
|
+
* - `http://localhost:3000` → `http://localhost:3002`
|
|
41
|
+
* - anything else → returned unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export function deriveDashboardUrl(region) {
|
|
44
|
+
if (region.dashboardUrl) {
|
|
45
|
+
return region.dashboardUrl;
|
|
46
|
+
}
|
|
47
|
+
const { apiBase } = region;
|
|
48
|
+
if (apiBase.match(/\/\/api-[a-z]+\./)) {
|
|
49
|
+
return apiBase.replace('://api-', '://');
|
|
50
|
+
}
|
|
51
|
+
if (apiBase.includes('://api.')) {
|
|
52
|
+
return apiBase.replace('://api.', '://');
|
|
53
|
+
}
|
|
54
|
+
if (apiBase.includes('localhost:3000')) {
|
|
55
|
+
return apiBase.replace(':3000', ':3002');
|
|
56
|
+
}
|
|
57
|
+
return apiBase;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAC3B,IAAI,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git origin remote detection + parsing.
|
|
3
|
+
*
|
|
4
|
+
* Used by `vibedefend link` to auto-detect which CybeDefend project a repo
|
|
5
|
+
* corresponds to: read `origin`'s URL via `git remote get-url origin`, then
|
|
6
|
+
* parse it into a provider + host + slug the gateway can match against a
|
|
7
|
+
* project's configured repo.
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync } from 'node:child_process';
|
|
10
|
+
/**
|
|
11
|
+
* Parse a git remote URL into { provider, host, slug }.
|
|
12
|
+
*
|
|
13
|
+
* Supports:
|
|
14
|
+
* - https(s)/git/ssh URLs with a `://` scheme, e.g.
|
|
15
|
+
* `https://github.com/o/r.git`, `ssh://git@gitlab.com/g/sg/p.git`
|
|
16
|
+
* - scp-like syntax, e.g. `git@github.com:o/r.git`
|
|
17
|
+
*
|
|
18
|
+
* `provider` is derived from a substring match on the host ("github" /
|
|
19
|
+
* "gitlab"), so self-hosted instances (`gitlab.example.com`, GitHub
|
|
20
|
+
* Enterprise) are still recognized. An unrecognized host still yields a
|
|
21
|
+
* result with `provider: null` — the caller can fall back to a manual
|
|
22
|
+
* project pick rather than failing outright.
|
|
23
|
+
*
|
|
24
|
+
* Returns `null` when the input can't be parsed into a host + non-empty
|
|
25
|
+
* slug at all (empty string, not a URL, no path component).
|
|
26
|
+
*
|
|
27
|
+
* Whitespace is trimmed, a trailing `.git` suffix is stripped from the
|
|
28
|
+
* slug, and any embedded userinfo (`user:pass@`) is ignored.
|
|
29
|
+
*/
|
|
30
|
+
export function parseRemoteUrl(url) {
|
|
31
|
+
const trimmed = url.trim();
|
|
32
|
+
if (trimmed.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
let host;
|
|
35
|
+
let rawPath;
|
|
36
|
+
if (trimmed.includes('://')) {
|
|
37
|
+
let parsed;
|
|
38
|
+
try {
|
|
39
|
+
parsed = new URL(trimmed);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (!parsed.hostname)
|
|
45
|
+
return null;
|
|
46
|
+
host = parsed.hostname;
|
|
47
|
+
rawPath = parsed.pathname;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// scp-like syntax: [user@]host:path (no "://" present).
|
|
51
|
+
const scpMatch = /^(?:[^@\s]+@)?([^:\s/]+):(.+)$/.exec(trimmed);
|
|
52
|
+
if (!scpMatch)
|
|
53
|
+
return null;
|
|
54
|
+
// Lowercase to match the `://` branch: WHATWG URL parsing ASCII-folds
|
|
55
|
+
// `hostname`, so both branches must agree on casing for the same host.
|
|
56
|
+
host = scpMatch[1].toLowerCase();
|
|
57
|
+
rawPath = scpMatch[2];
|
|
58
|
+
}
|
|
59
|
+
const slug = rawPath
|
|
60
|
+
.replace(/^\/+/, '')
|
|
61
|
+
.replace(/\/+$/, '')
|
|
62
|
+
.replace(/\.git$/i, '');
|
|
63
|
+
if (slug.length === 0)
|
|
64
|
+
return null;
|
|
65
|
+
return { provider: detectProvider(host), host, slug };
|
|
66
|
+
}
|
|
67
|
+
function detectProvider(host) {
|
|
68
|
+
const lower = host.toLowerCase();
|
|
69
|
+
if (lower.includes('github'))
|
|
70
|
+
return 'github';
|
|
71
|
+
if (lower.includes('gitlab'))
|
|
72
|
+
return 'gitlab';
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const GIT_REMOTE_TIMEOUT_MS = 3000;
|
|
76
|
+
/**
|
|
77
|
+
* Read the `origin` remote's URL for the git repo at `cwd` via
|
|
78
|
+
* `git remote get-url origin`. Returns `null` when `cwd` isn't a git repo,
|
|
79
|
+
* there's no `origin` remote, or the command otherwise fails/times out —
|
|
80
|
+
* never throws.
|
|
81
|
+
*/
|
|
82
|
+
export function getOriginRemote(cwd, deps = {}) {
|
|
83
|
+
const execImpl = deps.execImpl ?? defaultExecImpl;
|
|
84
|
+
const result = execImpl('git', ['remote', 'get-url', 'origin'], {
|
|
85
|
+
cwd,
|
|
86
|
+
timeoutMs: GIT_REMOTE_TIMEOUT_MS,
|
|
87
|
+
});
|
|
88
|
+
if (result.status !== 0)
|
|
89
|
+
return null;
|
|
90
|
+
const url = result.stdout.trim();
|
|
91
|
+
return url.length > 0 ? url : null;
|
|
92
|
+
}
|
|
93
|
+
function defaultExecImpl(cmd, args, opts) {
|
|
94
|
+
const result = spawnSync(cmd, args, {
|
|
95
|
+
cwd: opts.cwd,
|
|
96
|
+
encoding: 'utf8',
|
|
97
|
+
timeout: opts.timeoutMs,
|
|
98
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
99
|
+
windowsHide: true,
|
|
100
|
+
});
|
|
101
|
+
return { status: result.status, stdout: result.stdout ?? '' };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|