imcodes 2026.3.138 → 2026.3.139

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 (38) hide show
  1. package/dist/agent/session-manager.d.ts.map +1 -1
  2. package/dist/agent/session-manager.js +6 -0
  3. package/dist/agent/session-manager.js.map +1 -1
  4. package/dist/daemon/command-handler.d.ts.map +1 -1
  5. package/dist/daemon/command-handler.js +8 -0
  6. package/dist/daemon/command-handler.js.map +1 -1
  7. package/dist/daemon/lifecycle.d.ts.map +1 -1
  8. package/dist/daemon/lifecycle.js +25 -0
  9. package/dist/daemon/lifecycle.js.map +1 -1
  10. package/dist/daemon/repo-handler.d.ts +7 -0
  11. package/dist/daemon/repo-handler.d.ts.map +1 -0
  12. package/dist/daemon/repo-handler.js +301 -0
  13. package/dist/daemon/repo-handler.js.map +1 -0
  14. package/dist/repo/cache.d.ts +12 -0
  15. package/dist/repo/cache.d.ts.map +1 -0
  16. package/dist/repo/cache.js +46 -0
  17. package/dist/repo/cache.js.map +1 -0
  18. package/dist/repo/detector.d.ts +25 -0
  19. package/dist/repo/detector.d.ts.map +1 -0
  20. package/dist/repo/detector.js +237 -0
  21. package/dist/repo/detector.js.map +1 -0
  22. package/dist/repo/github-provider.d.ts +15 -0
  23. package/dist/repo/github-provider.d.ts.map +1 -0
  24. package/dist/repo/github-provider.js +170 -0
  25. package/dist/repo/github-provider.js.map +1 -0
  26. package/dist/repo/gitlab-provider.d.ts +17 -0
  27. package/dist/repo/gitlab-provider.d.ts.map +1 -0
  28. package/dist/repo/gitlab-provider.js +202 -0
  29. package/dist/repo/gitlab-provider.js.map +1 -0
  30. package/dist/repo/provider.d.ts +26 -0
  31. package/dist/repo/provider.d.ts.map +1 -0
  32. package/dist/repo/provider.js +6 -0
  33. package/dist/repo/provider.js.map +1 -0
  34. package/dist/repo/types.d.ts +77 -0
  35. package/dist/repo/types.d.ts.map +1 -0
  36. package/dist/repo/types.js +4 -0
  37. package/dist/repo/types.js.map +1 -0
  38. package/package.json +1 -1
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ /**
3
+ * Daemon-side WS command handler for repo.* commands.
4
+ * Routes repo detection and list operations through cached providers.
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.handleRepoCommand = handleRepoCommand;
11
+ const detector_js_1 = require("../repo/detector.js");
12
+ const cache_js_1 = require("../repo/cache.js");
13
+ const github_provider_js_1 = require("../repo/github-provider.js");
14
+ const gitlab_provider_js_1 = require("../repo/gitlab-provider.js");
15
+ const session_store_js_1 = require("../store/session-store.js");
16
+ const logger_js_1 = __importDefault(require("../util/logger.js"));
17
+ // ---------------------------------------------------------------------------
18
+ // Concurrency limiter — max 3 concurrent CLI calls per projectDir
19
+ // ---------------------------------------------------------------------------
20
+ const MAX_CONCURRENT = 3;
21
+ const inflightCounts = new Map();
22
+ const queues = new Map();
23
+ async function withConcurrencyLimit(projectDir, fn) {
24
+ const current = inflightCounts.get(projectDir) ?? 0;
25
+ if (current < MAX_CONCURRENT) {
26
+ inflightCounts.set(projectDir, current + 1);
27
+ try {
28
+ await fn();
29
+ }
30
+ finally {
31
+ release(projectDir);
32
+ }
33
+ return;
34
+ }
35
+ // Queue excess
36
+ await new Promise((resolve, reject) => {
37
+ let q = queues.get(projectDir);
38
+ if (!q) {
39
+ q = [];
40
+ queues.set(projectDir, q);
41
+ }
42
+ q.push({ fn, resolve, reject });
43
+ });
44
+ }
45
+ function release(projectDir) {
46
+ const count = (inflightCounts.get(projectDir) ?? 1) - 1;
47
+ if (count <= 0) {
48
+ inflightCounts.delete(projectDir);
49
+ }
50
+ else {
51
+ inflightCounts.set(projectDir, count);
52
+ }
53
+ const q = queues.get(projectDir);
54
+ if (q && q.length > 0) {
55
+ const next = q.shift();
56
+ if (q.length === 0)
57
+ queues.delete(projectDir);
58
+ inflightCounts.set(projectDir, (inflightCounts.get(projectDir) ?? 0) + 1);
59
+ next.fn().then(() => { release(projectDir); next.resolve(); }, (err) => { release(projectDir); next.reject(err); });
60
+ }
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Validation helpers
64
+ // ---------------------------------------------------------------------------
65
+ const VALID_STATES = new Set(['open', 'closed', 'merged', 'all']);
66
+ const BRANCH_RE = /^[a-zA-Z0-9_./-]+$/;
67
+ function isValidState(v) {
68
+ return typeof v === 'string' && VALID_STATES.has(v);
69
+ }
70
+ function isValidBranch(v) {
71
+ return typeof v === 'string' && v.length <= 256 && BRANCH_RE.test(v);
72
+ }
73
+ function isValidPage(v) {
74
+ return typeof v === 'number' && Number.isInteger(v) && v >= 1 && v <= 100;
75
+ }
76
+ function validateProjectDir(projectDir) {
77
+ if (typeof projectDir !== 'string' || !projectDir)
78
+ return false;
79
+ const knownDirs = new Set((0, session_store_js_1.listSessions)().map((s) => s.projectDir));
80
+ return knownDirs.has(projectDir);
81
+ }
82
+ // ---------------------------------------------------------------------------
83
+ // Provider factory from cached detection
84
+ // ---------------------------------------------------------------------------
85
+ function createProvider(ctx, projectDir) {
86
+ if (!ctx.info || ctx.status !== 'ok')
87
+ return null;
88
+ const { platform, owner, repo } = ctx.info;
89
+ if (platform === 'github')
90
+ return new github_provider_js_1.GitHubProvider(owner, repo, projectDir);
91
+ if (platform === 'gitlab')
92
+ return new gitlab_provider_js_1.GitLabProvider(owner, repo, projectDir);
93
+ return null;
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // Individual command handlers
97
+ // ---------------------------------------------------------------------------
98
+ async function handleDetect(cmd, serverLink) {
99
+ const projectDir = cmd.projectDir;
100
+ const requestId = cmd.requestId;
101
+ const cacheKey = cache_js_1.RepoCache.buildKey(projectDir, 'detect');
102
+ const cached = cache_js_1.repoCache.get(cacheKey);
103
+ if (cached) {
104
+ serverLink.send({ type: 'repo.detect_response', requestId, projectDir, ...cached });
105
+ return;
106
+ }
107
+ const ctx = await (0, detector_js_1.detectRepo)(projectDir);
108
+ cache_js_1.repoCache.set(cacheKey, ctx, projectDir, ctx.status !== 'ok');
109
+ serverLink.send({ type: 'repo.detect_response', requestId, projectDir, ...ctx });
110
+ }
111
+ async function handleListIssues(cmd, serverLink) {
112
+ const projectDir = cmd.projectDir;
113
+ const requestId = cmd.requestId;
114
+ const opts = {};
115
+ if (cmd.state !== undefined)
116
+ opts.state = cmd.state;
117
+ if (cmd.page !== undefined)
118
+ opts.page = cmd.page;
119
+ const cacheKey = cache_js_1.RepoCache.buildKey(projectDir, 'issues', { ...opts });
120
+ const cached = cache_js_1.repoCache.get(cacheKey);
121
+ if (cached) {
122
+ serverLink.send({ type: 'repo.issues_response', requestId, ...cached });
123
+ return;
124
+ }
125
+ const provider = await getProvider(projectDir, requestId, serverLink);
126
+ if (!provider)
127
+ return;
128
+ try {
129
+ const result = await provider.listIssues(opts);
130
+ cache_js_1.repoCache.set(cacheKey, result, projectDir);
131
+ serverLink.send({ type: 'repo.issues_response', requestId, ...result });
132
+ }
133
+ catch (err) {
134
+ sendError(serverLink, requestId, 'cli_error', err);
135
+ }
136
+ }
137
+ async function handleListPRs(cmd, serverLink) {
138
+ const projectDir = cmd.projectDir;
139
+ const requestId = cmd.requestId;
140
+ const opts = {};
141
+ if (cmd.state !== undefined)
142
+ opts.state = cmd.state;
143
+ if (cmd.page !== undefined)
144
+ opts.page = cmd.page;
145
+ const cacheKey = cache_js_1.RepoCache.buildKey(projectDir, 'prs', { ...opts });
146
+ const cached = cache_js_1.repoCache.get(cacheKey);
147
+ if (cached) {
148
+ serverLink.send({ type: 'repo.prs_response', requestId, ...cached });
149
+ return;
150
+ }
151
+ const provider = await getProvider(projectDir, requestId, serverLink);
152
+ if (!provider)
153
+ return;
154
+ try {
155
+ const result = await provider.listPRs(opts);
156
+ cache_js_1.repoCache.set(cacheKey, result, projectDir);
157
+ serverLink.send({ type: 'repo.prs_response', requestId, ...result });
158
+ }
159
+ catch (err) {
160
+ sendError(serverLink, requestId, 'cli_error', err);
161
+ }
162
+ }
163
+ async function handleListBranches(cmd, serverLink) {
164
+ const projectDir = cmd.projectDir;
165
+ const requestId = cmd.requestId;
166
+ const cacheKey = cache_js_1.RepoCache.buildKey(projectDir, 'branches');
167
+ const cached = cache_js_1.repoCache.get(cacheKey);
168
+ if (cached) {
169
+ serverLink.send({ type: 'repo.branches_response', requestId, ...cached });
170
+ return;
171
+ }
172
+ const provider = await getProvider(projectDir, requestId, serverLink);
173
+ if (!provider)
174
+ return;
175
+ try {
176
+ const result = await provider.listBranches();
177
+ cache_js_1.repoCache.set(cacheKey, result, projectDir);
178
+ serverLink.send({ type: 'repo.branches_response', requestId, ...result });
179
+ }
180
+ catch (err) {
181
+ sendError(serverLink, requestId, 'cli_error', err);
182
+ }
183
+ }
184
+ async function handleListCommits(cmd, serverLink) {
185
+ const projectDir = cmd.projectDir;
186
+ const requestId = cmd.requestId;
187
+ const opts = {};
188
+ if (cmd.branch !== undefined)
189
+ opts.branch = cmd.branch;
190
+ if (cmd.page !== undefined)
191
+ opts.page = cmd.page;
192
+ const cacheKey = cache_js_1.RepoCache.buildKey(projectDir, 'commits', { ...opts });
193
+ const cached = cache_js_1.repoCache.get(cacheKey);
194
+ if (cached) {
195
+ serverLink.send({ type: 'repo.commits_response', requestId, ...cached });
196
+ return;
197
+ }
198
+ const provider = await getProvider(projectDir, requestId, serverLink);
199
+ if (!provider)
200
+ return;
201
+ try {
202
+ const result = await provider.listCommits(opts);
203
+ cache_js_1.repoCache.set(cacheKey, result, projectDir);
204
+ serverLink.send({ type: 'repo.commits_response', requestId, ...result });
205
+ }
206
+ catch (err) {
207
+ sendError(serverLink, requestId, 'cli_error', err);
208
+ }
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Shared helpers
212
+ // ---------------------------------------------------------------------------
213
+ /** Resolve a RepoProvider from the detection cache (or run fresh detection). */
214
+ async function getProvider(projectDir, requestId, serverLink) {
215
+ const detectKey = cache_js_1.RepoCache.buildKey(projectDir, 'detect');
216
+ let ctx = cache_js_1.repoCache.get(detectKey);
217
+ if (!ctx) {
218
+ ctx = await (0, detector_js_1.detectRepo)(projectDir);
219
+ cache_js_1.repoCache.set(detectKey, ctx, projectDir, ctx.status !== 'ok');
220
+ }
221
+ const provider = createProvider(ctx, projectDir);
222
+ if (!provider) {
223
+ serverLink.send({
224
+ type: 'repo.error',
225
+ requestId,
226
+ error: 'not_detected',
227
+ status: ctx.status,
228
+ });
229
+ return null;
230
+ }
231
+ return provider;
232
+ }
233
+ /** Extract typed error code from provider errors, fall back to default. */
234
+ function extractErrorCode(err, fallback) {
235
+ if (typeof err === 'string')
236
+ return err;
237
+ if (err && typeof err === 'object' && 'code' in err && typeof err.code === 'string') {
238
+ return err.code;
239
+ }
240
+ return fallback;
241
+ }
242
+ function sendError(serverLink, requestId, fallbackError, err) {
243
+ const error = err ? extractErrorCode(err, fallbackError) : fallbackError;
244
+ if (err) {
245
+ logger_js_1.default.error({ err }, `repo handler: ${error}`);
246
+ }
247
+ serverLink.send({ type: 'repo.error', requestId, error });
248
+ }
249
+ // ---------------------------------------------------------------------------
250
+ // Main exported handler
251
+ // ---------------------------------------------------------------------------
252
+ function handleRepoCommand(cmd, serverLink) {
253
+ const requestId = cmd.requestId;
254
+ const projectDir = cmd.projectDir;
255
+ // projectDir validation for all commands
256
+ if (!validateProjectDir(projectDir)) {
257
+ serverLink.send({ type: 'repo.error', requestId, error: 'invalid_params' });
258
+ return;
259
+ }
260
+ // Input schema validation
261
+ if (cmd.state !== undefined && !isValidState(cmd.state)) {
262
+ serverLink.send({ type: 'repo.error', requestId, error: 'invalid_params' });
263
+ return;
264
+ }
265
+ if (cmd.branch !== undefined && !isValidBranch(cmd.branch)) {
266
+ serverLink.send({ type: 'repo.error', requestId, error: 'invalid_params' });
267
+ return;
268
+ }
269
+ if (cmd.page !== undefined && !isValidPage(cmd.page)) {
270
+ serverLink.send({ type: 'repo.error', requestId, error: 'invalid_params' });
271
+ return;
272
+ }
273
+ // Strip any browser-sent provider field
274
+ delete cmd.provider;
275
+ const run = async () => {
276
+ switch (cmd.type) {
277
+ case 'repo.detect':
278
+ await handleDetect(cmd, serverLink);
279
+ break;
280
+ case 'repo.list_issues':
281
+ await handleListIssues(cmd, serverLink);
282
+ break;
283
+ case 'repo.list_prs':
284
+ await handleListPRs(cmd, serverLink);
285
+ break;
286
+ case 'repo.list_branches':
287
+ await handleListBranches(cmd, serverLink);
288
+ break;
289
+ case 'repo.list_commits':
290
+ await handleListCommits(cmd, serverLink);
291
+ break;
292
+ default:
293
+ logger_js_1.default.warn({ type: cmd.type }, 'repo: unknown subcommand');
294
+ }
295
+ };
296
+ void withConcurrencyLimit(projectDir, run).catch((err) => {
297
+ logger_js_1.default.error({ err, type: cmd.type }, 'repo handler failed');
298
+ serverLink.send({ type: 'repo.error', requestId, error: 'cli_error' });
299
+ });
300
+ }
301
+ //# sourceMappingURL=repo-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-handler.js","sourceRoot":"","sources":["../../src/daemon/repo-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /** Daemon-side TTL cache for repo data. */
2
+ export declare class RepoCache {
3
+ private store;
4
+ static buildKey(projectDir: string, resource: string, params?: Record<string, unknown>): string;
5
+ get<T>(key: string): T | null;
6
+ set<T>(key: string, data: T, projectDir: string, errorState?: boolean): void;
7
+ /** Invalidate entries for a projectDir, optionally scoped to a resource. */
8
+ invalidate(projectDir: string, resource?: string): void;
9
+ invalidateAll(): void;
10
+ }
11
+ export declare const repoCache: RepoCache;
12
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/repo/cache.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAY3C,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAA0C;IAEvD,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAK/F,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAU7B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,IAAI;IAS1E,4EAA4E;IAC5E,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IASvD,aAAa,IAAI,IAAI;CAGtB;AAED,eAAO,MAAM,SAAS,WAAkB,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /** Daemon-side TTL cache for repo data. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.repoCache = exports.RepoCache = void 0;
5
+ const DEFAULT_TTL_MS = 30_000; // 30s for successful results
6
+ const ERROR_TTL_MS = 5_000; // 5s for error states
7
+ class RepoCache {
8
+ store = new Map();
9
+ static buildKey(projectDir, resource, params) {
10
+ const paramStr = params ? JSON.stringify(params, Object.keys(params).sort()) : '';
11
+ return `${projectDir}:${resource}:${paramStr}`;
12
+ }
13
+ get(key) {
14
+ const entry = this.store.get(key);
15
+ if (!entry)
16
+ return null;
17
+ if (Date.now() - entry.cachedAt > entry.ttlMs) {
18
+ this.store.delete(key);
19
+ return null;
20
+ }
21
+ return entry.data;
22
+ }
23
+ set(key, data, projectDir, errorState = false) {
24
+ this.store.set(key, {
25
+ data,
26
+ cachedAt: Date.now(),
27
+ ttlMs: errorState ? ERROR_TTL_MS : DEFAULT_TTL_MS,
28
+ projectDir,
29
+ });
30
+ }
31
+ /** Invalidate entries for a projectDir, optionally scoped to a resource. */
32
+ invalidate(projectDir, resource) {
33
+ const prefix = resource ? `${projectDir}:${resource}:` : `${projectDir}:`;
34
+ for (const key of this.store.keys()) {
35
+ if (key.startsWith(prefix)) {
36
+ this.store.delete(key);
37
+ }
38
+ }
39
+ }
40
+ invalidateAll() {
41
+ this.store.clear();
42
+ }
43
+ }
44
+ exports.RepoCache = RepoCache;
45
+ exports.repoCache = new RepoCache();
46
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/repo/cache.ts"],"names":[],"mappings":";AAAA,2CAA2C;;;AAE3C,MAAM,cAAc,GAAG,MAAM,CAAC,CAAI,6BAA6B;AAC/D,MAAM,YAAY,GAAG,KAAK,CAAC,CAAO,sBAAsB;AASxD,MAAa,SAAS;IACZ,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEvD,MAAM,CAAC,QAAQ,CAAC,UAAkB,EAAE,QAAgB,EAAE,MAAgC;QACpF,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO,GAAG,UAAU,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;IACjD,CAAC;IAED,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAC9C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,UAAkB,EAAE,UAAU,GAAG,KAAK;QACjE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;YACpB,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc;YACjD,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED,4EAA4E;IAC5E,UAAU,CAAC,UAAkB,EAAE,QAAiB;QAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;QAC1E,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,aAAa;QACX,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAxCD,8BAwCC;AAEY,QAAA,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /** Repo detection — platform, CLI, auth, branch. */
2
+ import type { RepoContext } from './types.js';
3
+ interface ParsedRemote {
4
+ name: string;
5
+ url: string;
6
+ host: string;
7
+ owner: string;
8
+ repo: string;
9
+ }
10
+ /** Parse a single remote URL (HTTPS or SSH) into components. */
11
+ declare function parseRemoteUrl(url: string): {
12
+ host: string;
13
+ owner: string;
14
+ repo: string;
15
+ } | null;
16
+ /** Parse `git remote -v` output into structured remotes. */
17
+ declare function parseRemotes(output: string): ParsedRemote[];
18
+ /** Compare semver strings. Returns -1, 0, or 1. */
19
+ declare function compareSemver(a: string, b: string): number;
20
+ /** Extract version string from CLI output. */
21
+ declare function extractVersion(output: string): string | null;
22
+ /** Main detection entry point. */
23
+ export declare function detectRepo(projectDir: string): Promise<RepoContext>;
24
+ export { parseRemoteUrl, parseRemotes, compareSemver, extractVersion };
25
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/repo/detector.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAkD,MAAM,YAAY,CAAC;AAa9F,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gEAAgE;AAChE,iBAAS,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAczF;AAED,4DAA4D;AAC5D,iBAAS,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAgBpD;AAsBD,mDAAmD;AACnD,iBAAS,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,8CAA8C;AAC9C,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrD;AAmED,kCAAkC;AAClC,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkFzE;AAGD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /** Repo detection — platform, CLI, auth, branch. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.detectRepo = detectRepo;
5
+ exports.parseRemoteUrl = parseRemoteUrl;
6
+ exports.parseRemotes = parseRemotes;
7
+ exports.compareSemver = compareSemver;
8
+ exports.extractVersion = extractVersion;
9
+ const node_child_process_1 = require("node:child_process");
10
+ const node_util_1 = require("node:util");
11
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
12
+ const GH_MIN_VERSION = '2.0.0';
13
+ const GLAB_MIN_VERSION = '1.22.0';
14
+ // Known hosts — checked before CLI probe
15
+ const KNOWN_HOSTS = {
16
+ 'github.com': 'github',
17
+ 'gitlab.com': 'gitlab',
18
+ };
19
+ /** Parse a single remote URL (HTTPS or SSH) into components. */
20
+ function parseRemoteUrl(url) {
21
+ // HTTPS: https://github.com/owner/repo.git
22
+ const httpsMatch = url.match(/^https?:\/\/([^/]+)\/([^/]+)\/([^/\s]+?)(?:\.git)?$/);
23
+ if (httpsMatch)
24
+ return { host: httpsMatch[1], owner: httpsMatch[2], repo: httpsMatch[3] };
25
+ // SSH: git@github.com:owner/repo.git
26
+ const sshMatch = url.match(/^git@([^:]+):([^/]+)\/([^/\s]+?)(?:\.git)?$/);
27
+ if (sshMatch)
28
+ return { host: sshMatch[1], owner: sshMatch[2], repo: sshMatch[3] };
29
+ // SSH with ssh:// prefix: ssh://git@github.com/owner/repo.git
30
+ const sshUrlMatch = url.match(/^ssh:\/\/[^@]+@([^/]+)\/([^/]+)\/([^/\s]+?)(?:\.git)?$/);
31
+ if (sshUrlMatch)
32
+ return { host: sshUrlMatch[1], owner: sshUrlMatch[2], repo: sshUrlMatch[3] };
33
+ return null;
34
+ }
35
+ /** Parse `git remote -v` output into structured remotes. */
36
+ function parseRemotes(output) {
37
+ const seen = new Set();
38
+ const remotes = [];
39
+ for (const line of output.split('\n')) {
40
+ // format: origin\thttps://github.com/o/r.git (fetch)
41
+ const match = line.match(/^(\S+)\s+(\S+)\s+\(fetch\)/);
42
+ if (!match)
43
+ continue;
44
+ const [, name, url] = match;
45
+ if (seen.has(name))
46
+ continue;
47
+ seen.add(name);
48
+ const parsed = parseRemoteUrl(url);
49
+ if (parsed) {
50
+ remotes.push({ name, url, ...parsed });
51
+ }
52
+ }
53
+ return remotes;
54
+ }
55
+ /** Determine platform for a host — known hosts first, then CLI probe. */
56
+ async function detectPlatform(host) {
57
+ // 1. Known hosts
58
+ if (KNOWN_HOSTS[host])
59
+ return KNOWN_HOSTS[host];
60
+ // 2. CLI auth host probe — try gh first, then glab
61
+ try {
62
+ await execFileAsync('gh', ['auth', 'status', '--hostname', host], { timeout: 5000 });
63
+ return 'github';
64
+ }
65
+ catch { /* not a gh host or gh not installed */ }
66
+ try {
67
+ // glab doesn't have --hostname, check config
68
+ const { stdout } = await execFileAsync('glab', ['config', 'get', 'host'], { timeout: 5000 });
69
+ if (stdout.trim() === host)
70
+ return 'gitlab';
71
+ }
72
+ catch { /* not a glab host or glab not installed */ }
73
+ return 'unknown';
74
+ }
75
+ /** Compare semver strings. Returns -1, 0, or 1. */
76
+ function compareSemver(a, b) {
77
+ const pa = a.split('.').map(Number);
78
+ const pb = b.split('.').map(Number);
79
+ for (let i = 0; i < 3; i++) {
80
+ const va = pa[i] ?? 0;
81
+ const vb = pb[i] ?? 0;
82
+ if (va < vb)
83
+ return -1;
84
+ if (va > vb)
85
+ return 1;
86
+ }
87
+ return 0;
88
+ }
89
+ /** Extract version string from CLI output. */
90
+ function extractVersion(output) {
91
+ const match = output.match(/(\d+\.\d+\.\d+)/);
92
+ return match ? match[1] : null;
93
+ }
94
+ /** Check CLI availability and version. */
95
+ async function checkCli(platform, cwd) {
96
+ const cli = platform === 'github' ? 'gh' : 'glab';
97
+ const minVersion = platform === 'github' ? GH_MIN_VERSION : GLAB_MIN_VERSION;
98
+ // Check if CLI exists
99
+ try {
100
+ await execFileAsync('which', [cli], { timeout: 3000 });
101
+ }
102
+ catch {
103
+ return { status: 'cli_missing' };
104
+ }
105
+ // Check version
106
+ try {
107
+ const { stdout } = await execFileAsync(cli, ['--version'], { timeout: 3000, cwd });
108
+ const version = extractVersion(stdout);
109
+ if (!version)
110
+ return { status: 'cli_outdated', cliMinVersion: minVersion };
111
+ if (compareSemver(version, minVersion) < 0) {
112
+ return { status: 'cli_outdated', cliVersion: version, cliMinVersion: minVersion };
113
+ }
114
+ return { status: 'ok', cliVersion: version };
115
+ }
116
+ catch {
117
+ return { status: 'cli_missing' };
118
+ }
119
+ }
120
+ /** Check CLI auth status. */
121
+ async function checkAuth(platform, host) {
122
+ try {
123
+ if (platform === 'github') {
124
+ await execFileAsync('gh', ['auth', 'status', '--hostname', host], { timeout: 5000 });
125
+ }
126
+ else {
127
+ await execFileAsync('glab', ['auth', 'status'], { timeout: 5000 });
128
+ }
129
+ return true;
130
+ }
131
+ catch {
132
+ return false;
133
+ }
134
+ }
135
+ /** Get current git branch. */
136
+ async function getCurrentBranch(cwd) {
137
+ try {
138
+ const { stdout } = await execFileAsync('git', ['branch', '--show-current'], { cwd, timeout: 3000 });
139
+ return stdout.trim() || undefined;
140
+ }
141
+ catch {
142
+ return undefined;
143
+ }
144
+ }
145
+ /** Get default branch from git. */
146
+ async function getDefaultBranch(cwd) {
147
+ try {
148
+ const { stdout } = await execFileAsync('git', ['symbolic-ref', 'refs/remotes/origin/HEAD', '--short'], { cwd, timeout: 3000 });
149
+ // Returns e.g. "origin/main" — strip the remote prefix
150
+ const full = stdout.trim();
151
+ return full.replace(/^[^/]+\//, '') || undefined;
152
+ }
153
+ catch {
154
+ return undefined;
155
+ }
156
+ }
157
+ /** Main detection entry point. */
158
+ async function detectRepo(projectDir) {
159
+ // 1. Parse remotes
160
+ let remoteOutput;
161
+ try {
162
+ const { stdout } = await execFileAsync('git', ['remote', '-v'], { cwd: projectDir, timeout: 5000 });
163
+ remoteOutput = stdout;
164
+ }
165
+ catch {
166
+ return { info: null, status: 'no_repo' };
167
+ }
168
+ const remotes = parseRemotes(remoteOutput);
169
+ if (remotes.length === 0) {
170
+ return { info: null, status: 'no_repo' };
171
+ }
172
+ // 2. Select remote — prefer 'origin', else multiple_remotes
173
+ let selected;
174
+ if (remotes.length === 1) {
175
+ selected = remotes[0];
176
+ }
177
+ else {
178
+ const origin = remotes.find((r) => r.name === 'origin');
179
+ if (origin) {
180
+ selected = origin;
181
+ }
182
+ else {
183
+ return {
184
+ info: null,
185
+ status: 'multiple_remotes',
186
+ remotes: remotes.map((r) => ({ name: r.name, url: r.url, platform: KNOWN_HOSTS[r.host] ?? 'unknown' })),
187
+ };
188
+ }
189
+ }
190
+ // 3. Detect platform
191
+ const platform = await detectPlatform(selected.host);
192
+ if (platform === 'unknown') {
193
+ return { info: null, status: 'unknown_platform' };
194
+ }
195
+ // 4. Check CLI
196
+ const cliCheck = await checkCli(platform, projectDir);
197
+ if (cliCheck.status !== 'ok') {
198
+ return {
199
+ info: { platform, owner: selected.owner, repo: selected.repo, remoteUrl: selected.url },
200
+ status: cliCheck.status,
201
+ cliVersion: cliCheck.cliVersion,
202
+ cliMinVersion: cliCheck.cliMinVersion,
203
+ };
204
+ }
205
+ // 5. Check auth
206
+ const cliAuth = await checkAuth(platform, selected.host);
207
+ if (!cliAuth) {
208
+ return {
209
+ info: { platform, owner: selected.owner, repo: selected.repo, remoteUrl: selected.url },
210
+ status: 'unauthorized',
211
+ cliVersion: cliCheck.cliVersion,
212
+ cliAuth: false,
213
+ };
214
+ }
215
+ // 6. Get branch info
216
+ const [currentBranch, defaultBranch] = await Promise.all([
217
+ getCurrentBranch(projectDir),
218
+ getDefaultBranch(projectDir),
219
+ ]);
220
+ return {
221
+ info: {
222
+ platform,
223
+ owner: selected.owner,
224
+ repo: selected.repo,
225
+ remoteUrl: selected.url,
226
+ defaultBranch,
227
+ currentBranch,
228
+ ...(selected.host !== 'github.com' && selected.host !== 'gitlab.com'
229
+ ? { apiUrl: `https://${selected.host}${platform === 'github' ? '/api/v3' : '/api/v4'}` }
230
+ : {}),
231
+ },
232
+ status: 'ok',
233
+ cliVersion: cliCheck.cliVersion,
234
+ cliAuth: true,
235
+ };
236
+ }
237
+ //# sourceMappingURL=detector.js.map