@chappibunny/repolens 0.9.0 → 1.1.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/CHANGELOG.md +76 -0
- package/README.md +63 -33
- package/package.json +1 -1
- package/src/ai/generate-sections.js +0 -6
- package/src/ai/provider.js +30 -19
- package/src/cli.js +35 -15
- package/src/core/config-schema.js +61 -12
- package/src/init.js +2 -5
- package/src/migrate.js +2 -2
- package/src/publishers/github-wiki.js +454 -0
- package/src/publishers/index.js +24 -2
- package/src/publishers/notion.js +2 -2
- package/src/publishers/publish.js +2 -1
- package/src/utils/branch.js +27 -0
- package/src/utils/rate-limit.js +4 -2
- package/src/utils/telemetry.js +6 -2
- package/src/utils/update-check.js +2 -2
- package/src/utils/validate.js +33 -24
package/src/utils/branch.js
CHANGED
|
@@ -112,6 +112,33 @@ export function shouldPublishToConfluence(config, currentBranch = getCurrentBran
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Check if current branch should publish to GitHub Wiki
|
|
117
|
+
* Based on config.github_wiki.branches setting
|
|
118
|
+
*/
|
|
119
|
+
export function shouldPublishToGitHubWiki(config, currentBranch = getCurrentBranch()) {
|
|
120
|
+
if (!config.github_wiki) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!config.github_wiki.branches || config.github_wiki.branches.length === 0) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return config.github_wiki.branches.some(pattern => {
|
|
129
|
+
if (pattern === currentBranch) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (pattern.includes("*")) {
|
|
134
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
135
|
+
return regex.test(currentBranch);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return false;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
115
142
|
/**
|
|
116
143
|
* Get branch-qualified page title
|
|
117
144
|
*/
|
package/src/utils/rate-limit.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* to prevent abuse and respect API limits.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { warn } from "./logger.js";
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Rate limiter class using token bucket algorithm
|
|
10
12
|
*/
|
|
@@ -193,7 +195,7 @@ export async function executeNotionRequest(fn, options = {}) {
|
|
|
193
195
|
if (options.onRetry) {
|
|
194
196
|
options.onRetry(attempt, maxRetries, delay, error);
|
|
195
197
|
} else {
|
|
196
|
-
|
|
198
|
+
warn(
|
|
197
199
|
`Notion API retry ${attempt}/${maxRetries} after ${Math.round(delay)}ms (${error.message})`
|
|
198
200
|
);
|
|
199
201
|
}
|
|
@@ -221,7 +223,7 @@ export async function executeAIRequest(fn, options = {}) {
|
|
|
221
223
|
if (options.onRetry) {
|
|
222
224
|
options.onRetry(attempt, maxRetries, delay, error);
|
|
223
225
|
} else {
|
|
224
|
-
|
|
226
|
+
warn(
|
|
225
227
|
`AI API retry ${attempt}/${maxRetries} after ${Math.round(delay)}ms (${error.message})`
|
|
226
228
|
);
|
|
227
229
|
}
|
package/src/utils/telemetry.js
CHANGED
|
@@ -33,8 +33,10 @@ export function initTelemetry() {
|
|
|
33
33
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
34
34
|
const version = packageJson.version || "unknown";
|
|
35
35
|
|
|
36
|
+
const dsn = process.env.REPOLENS_SENTRY_DSN || "https://082083dbf5899ed7e65dfd9b8dc72f90@o4511014913703936.ingest.de.sentry.io/4511014919209040";
|
|
37
|
+
|
|
36
38
|
Sentry.init({
|
|
37
|
-
dsn
|
|
39
|
+
dsn,
|
|
38
40
|
|
|
39
41
|
// Release tracking
|
|
40
42
|
release: `repolens@${version}`,
|
|
@@ -412,8 +414,10 @@ function ensureSentryForFeedback() {
|
|
|
412
414
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
413
415
|
const version = packageJson.version || "unknown";
|
|
414
416
|
|
|
417
|
+
const dsn = process.env.REPOLENS_SENTRY_DSN || "https://082083dbf5899ed7e65dfd9b8dc72f90@o4511014913703936.ingest.de.sentry.io/4511014919209040";
|
|
418
|
+
|
|
415
419
|
Sentry.init({
|
|
416
|
-
dsn
|
|
420
|
+
dsn,
|
|
417
421
|
release: `repolens@${version}`,
|
|
418
422
|
environment: process.env.NODE_ENV || "production",
|
|
419
423
|
sampleRate: 1.0, // Always send feedback
|
|
@@ -104,7 +104,7 @@ export async function checkForUpdates() {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
function showUpdateMessage(current, latest) {
|
|
107
|
-
|
|
107
|
+
info("");
|
|
108
108
|
warn("┌────────────────────────────────────────────────────────────┐");
|
|
109
109
|
warn("│ 📦 Update Available │");
|
|
110
110
|
warn("├────────────────────────────────────────────────────────────┤");
|
|
@@ -118,7 +118,7 @@ function showUpdateMessage(current, latest) {
|
|
|
118
118
|
warn("│ │");
|
|
119
119
|
warn("│ Release notes: https://github.com/CHAPIBUNNY/repolens │");
|
|
120
120
|
warn("└────────────────────────────────────────────────────────────┘");
|
|
121
|
-
|
|
121
|
+
info("");
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
export async function forceCheckForUpdates() {
|
package/src/utils/validate.js
CHANGED
|
@@ -103,13 +103,13 @@ function validateScanConfig(scan) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (scan.
|
|
107
|
-
if (!Array.isArray(scan.
|
|
108
|
-
errors.push("scan.
|
|
106
|
+
if (scan.ignore) {
|
|
107
|
+
if (!Array.isArray(scan.ignore)) {
|
|
108
|
+
errors.push("scan.ignore must be an array of glob patterns");
|
|
109
109
|
} else {
|
|
110
|
-
for (const pattern of scan.
|
|
110
|
+
for (const pattern of scan.ignore) {
|
|
111
111
|
if (typeof pattern !== "string") {
|
|
112
|
-
errors.push(`Invalid pattern in scan.
|
|
112
|
+
errors.push(`Invalid pattern in scan.ignore: ${pattern} (must be string)`);
|
|
113
113
|
continue; // Skip further checks if not a string
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -135,7 +135,7 @@ function validatePublishers(publishers) {
|
|
|
135
135
|
return errors;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
const validPublishers = ["notion", "markdown", "confluence"];
|
|
138
|
+
const validPublishers = ["notion", "markdown", "confluence", "github_wiki"];
|
|
139
139
|
|
|
140
140
|
if (Array.isArray(publishers)) {
|
|
141
141
|
for (const pub of publishers) {
|
|
@@ -207,33 +207,34 @@ function checkNotionWarnings(notion) {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
210
|
-
* Validate domains configuration
|
|
210
|
+
* Validate domains configuration (object format: { key: { match: [], description? } })
|
|
211
211
|
*/
|
|
212
212
|
function validateDomains(domains) {
|
|
213
213
|
const errors = [];
|
|
214
214
|
|
|
215
|
-
if (
|
|
216
|
-
errors.push("domains must be an
|
|
215
|
+
if (typeof domains !== "object" || Array.isArray(domains)) {
|
|
216
|
+
errors.push("domains must be an object");
|
|
217
217
|
return errors;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
for (const domain of domains) {
|
|
221
|
-
if (
|
|
222
|
-
errors.push(
|
|
220
|
+
for (const [key, domain] of Object.entries(domains)) {
|
|
221
|
+
if (typeof domain !== "object" || Array.isArray(domain)) {
|
|
222
|
+
errors.push(`domains.${key} must be an object`);
|
|
223
|
+
continue;
|
|
223
224
|
}
|
|
224
225
|
|
|
225
|
-
if (!domain.
|
|
226
|
-
errors.push(`
|
|
226
|
+
if (!domain.match || !Array.isArray(domain.match)) {
|
|
227
|
+
errors.push(`domains.${key} must have a 'match' array`);
|
|
227
228
|
} else {
|
|
228
|
-
for (const pattern of domain.
|
|
229
|
+
for (const pattern of domain.match) {
|
|
229
230
|
if (typeof pattern !== "string") {
|
|
230
|
-
errors.push(`Invalid pattern in
|
|
231
|
+
errors.push(`Invalid pattern in domains.${key}.match: ${pattern}`);
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
if (domain.description && typeof domain.description !== "string") {
|
|
236
|
-
errors.push(`
|
|
237
|
+
errors.push(`domains.${key}.description must be a string`);
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
@@ -319,17 +320,25 @@ function checkForInjection(config) {
|
|
|
319
320
|
});
|
|
320
321
|
}
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
323
|
+
if (config.scan?.ignore && Array.isArray(config.scan.ignore)) {
|
|
324
|
+
config.scan.ignore.forEach((pattern, i) => {
|
|
325
|
+
if (typeof pattern === "string") {
|
|
326
|
+
checkString(pattern, `scan.ignore[${i}]`);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Check domain patterns (object format: { key: { match: [] } })
|
|
332
|
+
if (config.domains && typeof config.domains === "object" && !Array.isArray(config.domains)) {
|
|
333
|
+
for (const [domainKey, domain] of Object.entries(config.domains)) {
|
|
334
|
+
if (domain.match && Array.isArray(domain.match)) {
|
|
335
|
+
domain.match.forEach((pattern, j) => {
|
|
327
336
|
if (typeof pattern === "string") {
|
|
328
|
-
checkString(pattern, `domains
|
|
337
|
+
checkString(pattern, `domains.${domainKey}.match[${j}]`);
|
|
329
338
|
}
|
|
330
339
|
});
|
|
331
340
|
}
|
|
332
|
-
}
|
|
341
|
+
}
|
|
333
342
|
}
|
|
334
343
|
|
|
335
344
|
return errors;
|