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.
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +6 -0
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/daemon/command-handler.d.ts.map +1 -1
- package/dist/daemon/command-handler.js +8 -0
- package/dist/daemon/command-handler.js.map +1 -1
- package/dist/daemon/lifecycle.d.ts.map +1 -1
- package/dist/daemon/lifecycle.js +25 -0
- package/dist/daemon/lifecycle.js.map +1 -1
- package/dist/daemon/repo-handler.d.ts +7 -0
- package/dist/daemon/repo-handler.d.ts.map +1 -0
- package/dist/daemon/repo-handler.js +301 -0
- package/dist/daemon/repo-handler.js.map +1 -0
- package/dist/repo/cache.d.ts +12 -0
- package/dist/repo/cache.d.ts.map +1 -0
- package/dist/repo/cache.js +46 -0
- package/dist/repo/cache.js.map +1 -0
- package/dist/repo/detector.d.ts +25 -0
- package/dist/repo/detector.d.ts.map +1 -0
- package/dist/repo/detector.js +237 -0
- package/dist/repo/detector.js.map +1 -0
- package/dist/repo/github-provider.d.ts +15 -0
- package/dist/repo/github-provider.d.ts.map +1 -0
- package/dist/repo/github-provider.js +170 -0
- package/dist/repo/github-provider.js.map +1 -0
- package/dist/repo/gitlab-provider.d.ts +17 -0
- package/dist/repo/gitlab-provider.d.ts.map +1 -0
- package/dist/repo/gitlab-provider.js +202 -0
- package/dist/repo/gitlab-provider.js.map +1 -0
- package/dist/repo/provider.d.ts +26 -0
- package/dist/repo/provider.d.ts.map +1 -0
- package/dist/repo/provider.js +6 -0
- package/dist/repo/provider.js.map +1 -0
- package/dist/repo/types.d.ts +77 -0
- package/dist/repo/types.d.ts.map +1 -0
- package/dist/repo/types.js +4 -0
- package/dist/repo/types.js.map +1 -0
- 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":";AAAA;;;GAGG;;;;;AA8SH,8CAqDC;AAjWD,qDAAiD;AACjD,+CAAwD;AACxD,mEAA4D;AAC5D,mEAA4D;AAG5D,gEAAyD;AAEzD,kEAAuC;AAEvC,8EAA8E;AAC9E,kEAAkE;AAClE,8EAA8E;AAE9E,MAAM,cAAc,GAAG,CAAC,CAAC;AAQzB,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AACjD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;AAE/C,KAAK,UAAU,oBAAoB,CAAC,UAAkB,EAAE,EAAuB;IAC7E,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,cAAc,EAAE,CAAC;QAC7B,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,CAAC;QACb,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,UAAU,CAAC,CAAC;QACtB,CAAC;QACD,OAAO;IACT,CAAC;IAED,eAAe;IACf,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG,EAAE,CAAC;YACP,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,UAAkB;IACjC,MAAM,KAAK,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAG,CAAC;QACxB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9C,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CACZ,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAC9C,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACpD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AAClE,MAAM,SAAS,GAAG,oBAAoB,CAAC;AAEvC,SAAS,YAAY,CAAC,CAAU;IAC9B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,aAAa,CAAC,CAAU;IAC/B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,WAAW,CAAC,CAAU;IAC7B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;AAC5E,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAmB;IAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAChE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAA,+BAAY,GAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IACnE,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED,8EAA8E;AAC9E,yCAAyC;AACzC,8EAA8E;AAE9E,SAAS,cAAc,CAAC,GAAgB,EAAE,UAAkB;IAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClD,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;IAC3C,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,mCAAc,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9E,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,mCAAc,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,8BAA8B;AAC9B,8EAA8E;AAE9E,KAAK,UAAU,YAAY,CACzB,GAA4B,EAC5B,UAAsB;IAEtB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IAEtD,MAAM,QAAQ,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,oBAAS,CAAC,GAAG,CAAc,QAAQ,CAAC,CAAC;IACpD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACpF,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,IAAA,wBAAU,EAAC,UAAU,CAAC,CAAC;IACzC,oBAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;IAC9D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,GAA4B,EAC5B,UAAsB;IAEtB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IAEtD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAe,CAAC;IAC9D,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAc,CAAC;IAE3D,MAAM,QAAQ,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,oBAAS,CAAC,GAAG,CAAU,QAAQ,CAAC,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,GAAG,MAAgB,EAAE,CAAC,CAAC;QAClF,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/C,oBAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,GAA4B,EAC5B,UAAsB;IAEtB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IAEtD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAe,CAAC;IAC9D,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAc,CAAC;IAE3D,MAAM,QAAQ,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,oBAAS,CAAC,GAAG,CAAU,QAAQ,CAAC,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,GAAG,MAAgB,EAAE,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C,oBAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,GAA4B,EAC5B,UAAsB;IAEtB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IAEtD,MAAM,QAAQ,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,oBAAS,CAAC,GAAG,CAAU,QAAQ,CAAC,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,SAAS,EAAE,GAAG,MAAgB,EAAE,CAAC,CAAC;QACpF,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC7C,oBAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,GAA4B,EAC5B,UAAsB;IAEtB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IAEtD,MAAM,IAAI,GAAsB,EAAE,CAAC;IACnC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAgB,CAAC;IACjE,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAc,CAAC;IAE3D,MAAM,QAAQ,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,oBAAS,CAAC,GAAG,CAAU,QAAQ,CAAC,CAAC;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,SAAS,EAAE,GAAG,MAAgB,EAAE,CAAC,CAAC;QACnF,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACtE,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChD,oBAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,gFAAgF;AAChF,KAAK,UAAU,WAAW,CACxB,UAAkB,EAClB,SAA6B,EAC7B,UAAsB;IAEtB,MAAM,SAAS,GAAG,oBAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,GAAG,GAAG,oBAAS,CAAC,GAAG,CAAc,SAAS,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,MAAM,IAAA,wBAAU,EAAC,UAAU,CAAC,CAAC;QACnC,oBAAS,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,YAAY;YAClB,SAAS;YACT,KAAK,EAAE,cAA2B;YAClC,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,SAAS,gBAAgB,CAAC,GAAY,EAAE,QAAmB;IACzD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAgB,CAAC;IACrD,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,IAAI,OAAQ,GAAW,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7F,OAAQ,GAAW,CAAC,IAAiB,CAAC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAChB,UAAsB,EACtB,SAA6B,EAC7B,aAAwB,EACxB,GAAa;IAEb,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IACzE,IAAI,GAAG,EAAE,CAAC;QACR,mBAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,iBAAiB,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,SAAgB,iBAAiB,CAAC,GAA4B,EAAE,UAAsB;IACpF,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IACtD,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IAElC,yCAAyC;IACzC,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;QACpC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,gBAA6B,EAAE,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IAED,0BAA0B;IAC1B,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,gBAA6B,EAAE,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,gBAA6B,EAAE,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,gBAA6B,EAAE,CAAC,CAAC;QACzF,OAAO;IACT,CAAC;IAED,wCAAwC;IACxC,OAAO,GAAG,CAAC,QAAQ,CAAC;IAEpB,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;QACpC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,aAAa;gBAChB,MAAM,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACpC,MAAM;YACR,KAAK,kBAAkB;gBACrB,MAAM,gBAAgB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACxC,MAAM;YACR,KAAK,eAAe;gBAClB,MAAM,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACrC,MAAM;YACR,KAAK,oBAAoB;gBACvB,MAAM,kBAAkB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBAC1C,MAAM;YACR,KAAK,mBAAmB;gBACtB,MAAM,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACzC,MAAM;YACR;gBACE,mBAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,0BAA0B,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,oBAAoB,CAAC,UAAoB,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjE,mBAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC7D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,WAAwB,EAAE,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -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
|