@starterculture/devkeep-actions 0.4.1 → 0.5.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/dist/consolidate-release.js +154 -6
- package/dist/crypting-candidates-scan.js +156 -8
- package/dist/draft-log-entry.js +159 -32
- package/dist/draft-release-notes.js +157 -32
- package/dist/sync-onboarding.js +157 -32
- package/package.json +1 -1
|
@@ -127,6 +127,157 @@ function defaultModelFor(tier) {
|
|
|
127
127
|
return current.id;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// ../../modules/core/dist/redactSecrets.js
|
|
131
|
+
var REDACTED = "[REDACTED]";
|
|
132
|
+
var KNOWN_SECRET_PATTERNS = [
|
|
133
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
134
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
135
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
136
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
137
|
+
/sk-[A-Za-z0-9]{20,}/g,
|
|
138
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
139
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
140
|
+
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
141
|
+
];
|
|
142
|
+
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
143
|
+
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
144
|
+
function redactText(text) {
|
|
145
|
+
let result = text;
|
|
146
|
+
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
147
|
+
result = result.replace(pattern, REDACTED);
|
|
148
|
+
}
|
|
149
|
+
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ../../modules/core/dist/ciHealth.js
|
|
154
|
+
var EMPTY_ACTION_HEALTH = {
|
|
155
|
+
lastSuccessAt: null,
|
|
156
|
+
lastFailureAt: null,
|
|
157
|
+
lastFailureMessage: null,
|
|
158
|
+
lastFailureRunUrl: null,
|
|
159
|
+
consecutiveFailures: 0
|
|
160
|
+
};
|
|
161
|
+
var MAX_MESSAGE_CHARS = 2e3;
|
|
162
|
+
function healthPath(projectName) {
|
|
163
|
+
return `projects/${projectName}/health.json`;
|
|
164
|
+
}
|
|
165
|
+
function describeError(error) {
|
|
166
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : typeof error === "string" ? error : JSON.stringify(error);
|
|
167
|
+
const text = raw ?? "Unknown error";
|
|
168
|
+
return redactText(text.length > MAX_MESSAGE_CHARS ? `${text.slice(0, MAX_MESSAGE_CHARS)}\u2026` : text);
|
|
169
|
+
}
|
|
170
|
+
function applySuccess(current, source, now) {
|
|
171
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
172
|
+
return {
|
|
173
|
+
...current,
|
|
174
|
+
// The failure details are deliberately kept, not cleared: "it failed
|
|
175
|
+
// on Tuesday and has worked since" is worth being able to read.
|
|
176
|
+
[source]: { ...previous, lastSuccessAt: now.toISOString(), consecutiveFailures: 0 }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function applyFailure(current, source, error, runUrl, now) {
|
|
180
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
181
|
+
return {
|
|
182
|
+
...current,
|
|
183
|
+
[source]: {
|
|
184
|
+
...previous,
|
|
185
|
+
lastFailureAt: now.toISOString(),
|
|
186
|
+
lastFailureMessage: describeError(error),
|
|
187
|
+
lastFailureRunUrl: runUrl,
|
|
188
|
+
consecutiveFailures: previous.consecutiveFailures + 1
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function getHealthFile(octokit, { owner, repo, projectName }) {
|
|
193
|
+
try {
|
|
194
|
+
const { data } = await octokit.rest.repos.getContent({ owner, repo, path: healthPath(projectName) });
|
|
195
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
196
|
+
return { health: {} };
|
|
197
|
+
}
|
|
198
|
+
return { health: JSON.parse(Buffer.from(data.content, "base64").toString("utf-8")), sha: data.sha };
|
|
199
|
+
} catch {
|
|
200
|
+
return { health: {} };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function writeHealth(octokit, params, update, message) {
|
|
204
|
+
const { owner, repo, projectName, branch } = params;
|
|
205
|
+
await retryOnConflict(async () => {
|
|
206
|
+
const { health, sha } = await getHealthFile(octokit, params);
|
|
207
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
208
|
+
owner,
|
|
209
|
+
repo,
|
|
210
|
+
path: healthPath(projectName),
|
|
211
|
+
message,
|
|
212
|
+
content: Buffer.from(JSON.stringify(update(health), null, 2), "utf-8").toString("base64"),
|
|
213
|
+
branch,
|
|
214
|
+
sha
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async function recordSuccess(octokit, params, source, now = /* @__PURE__ */ new Date()) {
|
|
219
|
+
await writeHealth(octokit, params, (h) => applySuccess(h, source, now), `Record ${source} success: ${params.projectName}`);
|
|
220
|
+
}
|
|
221
|
+
async function recordFailure(octokit, params, source, error, runUrl, now = /* @__PURE__ */ new Date()) {
|
|
222
|
+
await writeHealth(octokit, params, (h) => applyFailure(h, source, error, runUrl, now), `Record ${source} failure: ${params.projectName}`);
|
|
223
|
+
}
|
|
224
|
+
function currentRunUrl(env) {
|
|
225
|
+
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;
|
|
226
|
+
if (!GITHUB_SERVER_URL || !GITHUB_REPOSITORY || !GITHUB_RUN_ID) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ../../modules/core/dist/ciEntrypoint.js
|
|
233
|
+
var VAULT_BRANCH = "main";
|
|
234
|
+
function healthParams(env) {
|
|
235
|
+
const projectName = env.PROJECT_NAME;
|
|
236
|
+
const vaultRepo = env.VAULT_REPO;
|
|
237
|
+
const token = env.DEVKEEP_GITHUB_TOKEN;
|
|
238
|
+
if (!projectName || !vaultRepo || !token) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const [owner, repo] = vaultRepo.split("/");
|
|
242
|
+
if (!owner || !repo) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return { owner, repo, projectName, branch: VAULT_BRANCH };
|
|
246
|
+
}
|
|
247
|
+
var defaultDeps = {
|
|
248
|
+
env: process.env,
|
|
249
|
+
createGithubClient,
|
|
250
|
+
recordSuccess,
|
|
251
|
+
recordFailure,
|
|
252
|
+
logError: console.error,
|
|
253
|
+
exit: (code) => process.exit(code)
|
|
254
|
+
};
|
|
255
|
+
async function runCiEntrypoint(source, main2, deps = defaultDeps) {
|
|
256
|
+
const params = healthParams(deps.env);
|
|
257
|
+
const octokit = params ? deps.createGithubClient(deps.env.DEVKEEP_GITHUB_TOKEN) : null;
|
|
258
|
+
try {
|
|
259
|
+
await main2();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
deps.logError(error);
|
|
262
|
+
if (params && octokit) {
|
|
263
|
+
try {
|
|
264
|
+
await deps.recordFailure(octokit, params, source, error, currentRunUrl(deps.env));
|
|
265
|
+
} catch (recordingError) {
|
|
266
|
+
deps.logError(`Could not record the failure to the vault: ${String(recordingError)}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
deps.exit(1);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (params && octokit) {
|
|
273
|
+
try {
|
|
274
|
+
await deps.recordSuccess(octokit, params, source);
|
|
275
|
+
} catch (recordingError) {
|
|
276
|
+
deps.logError(`Ran successfully, but could not record it to the vault: ${String(recordingError)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
130
281
|
// ../../modules/devlore/dist/ciUsage.js
|
|
131
282
|
var EMPTY_PROJECT_USAGE = {
|
|
132
283
|
draftLogEntry: ZERO_USAGE,
|
|
@@ -429,14 +580,14 @@ function requireEnv(env, name) {
|
|
|
429
580
|
}
|
|
430
581
|
return value;
|
|
431
582
|
}
|
|
432
|
-
var
|
|
583
|
+
var defaultDeps2 = {
|
|
433
584
|
env: process.env,
|
|
434
585
|
consolidateRelease,
|
|
435
586
|
createGithubClient,
|
|
436
587
|
createClaudeClient,
|
|
437
588
|
log: console.log
|
|
438
589
|
};
|
|
439
|
-
async function main(deps =
|
|
590
|
+
async function main(deps = defaultDeps2) {
|
|
440
591
|
const { env } = deps;
|
|
441
592
|
const projectName = requireEnv(env, "PROJECT_NAME");
|
|
442
593
|
const [projectOwner, projectRepoName] = requireEnv(env, "PROJECT_REPO").split("/");
|
|
@@ -459,10 +610,7 @@ async function main(deps = defaultDeps) {
|
|
|
459
610
|
deps.log(`Opened consolidation PR #${result.prNumber}: ${result.prUrl}`);
|
|
460
611
|
}
|
|
461
612
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
462
|
-
main
|
|
463
|
-
console.error(error);
|
|
464
|
-
process.exit(1);
|
|
465
|
-
});
|
|
613
|
+
void runCiEntrypoint("consolidateRelease", main);
|
|
466
614
|
}
|
|
467
615
|
export {
|
|
468
616
|
main,
|
|
@@ -24,6 +24,157 @@ async function retryOnConflict(attempt, maxAttempts = 3) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// ../../modules/core/dist/redactSecrets.js
|
|
28
|
+
var REDACTED = "[REDACTED]";
|
|
29
|
+
var KNOWN_SECRET_PATTERNS = [
|
|
30
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
31
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
32
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
33
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
34
|
+
/sk-[A-Za-z0-9]{20,}/g,
|
|
35
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
36
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
37
|
+
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
38
|
+
];
|
|
39
|
+
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
40
|
+
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
41
|
+
function redactText(text) {
|
|
42
|
+
let result = text;
|
|
43
|
+
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
44
|
+
result = result.replace(pattern, REDACTED);
|
|
45
|
+
}
|
|
46
|
+
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ../../modules/core/dist/ciHealth.js
|
|
51
|
+
var EMPTY_ACTION_HEALTH = {
|
|
52
|
+
lastSuccessAt: null,
|
|
53
|
+
lastFailureAt: null,
|
|
54
|
+
lastFailureMessage: null,
|
|
55
|
+
lastFailureRunUrl: null,
|
|
56
|
+
consecutiveFailures: 0
|
|
57
|
+
};
|
|
58
|
+
var MAX_MESSAGE_CHARS = 2e3;
|
|
59
|
+
function healthPath(projectName) {
|
|
60
|
+
return `projects/${projectName}/health.json`;
|
|
61
|
+
}
|
|
62
|
+
function describeError(error) {
|
|
63
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : typeof error === "string" ? error : JSON.stringify(error);
|
|
64
|
+
const text = raw ?? "Unknown error";
|
|
65
|
+
return redactText(text.length > MAX_MESSAGE_CHARS ? `${text.slice(0, MAX_MESSAGE_CHARS)}\u2026` : text);
|
|
66
|
+
}
|
|
67
|
+
function applySuccess(current, source, now) {
|
|
68
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
69
|
+
return {
|
|
70
|
+
...current,
|
|
71
|
+
// The failure details are deliberately kept, not cleared: "it failed
|
|
72
|
+
// on Tuesday and has worked since" is worth being able to read.
|
|
73
|
+
[source]: { ...previous, lastSuccessAt: now.toISOString(), consecutiveFailures: 0 }
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function applyFailure(current, source, error, runUrl, now) {
|
|
77
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
78
|
+
return {
|
|
79
|
+
...current,
|
|
80
|
+
[source]: {
|
|
81
|
+
...previous,
|
|
82
|
+
lastFailureAt: now.toISOString(),
|
|
83
|
+
lastFailureMessage: describeError(error),
|
|
84
|
+
lastFailureRunUrl: runUrl,
|
|
85
|
+
consecutiveFailures: previous.consecutiveFailures + 1
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async function getHealthFile(octokit, { owner, repo, projectName }) {
|
|
90
|
+
try {
|
|
91
|
+
const { data } = await octokit.rest.repos.getContent({ owner, repo, path: healthPath(projectName) });
|
|
92
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
93
|
+
return { health: {} };
|
|
94
|
+
}
|
|
95
|
+
return { health: JSON.parse(Buffer.from(data.content, "base64").toString("utf-8")), sha: data.sha };
|
|
96
|
+
} catch {
|
|
97
|
+
return { health: {} };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function writeHealth(octokit, params, update, message) {
|
|
101
|
+
const { owner, repo, projectName, branch } = params;
|
|
102
|
+
await retryOnConflict(async () => {
|
|
103
|
+
const { health, sha } = await getHealthFile(octokit, params);
|
|
104
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
105
|
+
owner,
|
|
106
|
+
repo,
|
|
107
|
+
path: healthPath(projectName),
|
|
108
|
+
message,
|
|
109
|
+
content: Buffer.from(JSON.stringify(update(health), null, 2), "utf-8").toString("base64"),
|
|
110
|
+
branch,
|
|
111
|
+
sha
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function recordSuccess(octokit, params, source, now = /* @__PURE__ */ new Date()) {
|
|
116
|
+
await writeHealth(octokit, params, (h) => applySuccess(h, source, now), `Record ${source} success: ${params.projectName}`);
|
|
117
|
+
}
|
|
118
|
+
async function recordFailure(octokit, params, source, error, runUrl, now = /* @__PURE__ */ new Date()) {
|
|
119
|
+
await writeHealth(octokit, params, (h) => applyFailure(h, source, error, runUrl, now), `Record ${source} failure: ${params.projectName}`);
|
|
120
|
+
}
|
|
121
|
+
function currentRunUrl(env) {
|
|
122
|
+
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;
|
|
123
|
+
if (!GITHUB_SERVER_URL || !GITHUB_REPOSITORY || !GITHUB_RUN_ID) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ../../modules/core/dist/ciEntrypoint.js
|
|
130
|
+
var VAULT_BRANCH = "main";
|
|
131
|
+
function healthParams(env) {
|
|
132
|
+
const projectName = env.PROJECT_NAME;
|
|
133
|
+
const vaultRepo = env.VAULT_REPO;
|
|
134
|
+
const token = env.DEVKEEP_GITHUB_TOKEN;
|
|
135
|
+
if (!projectName || !vaultRepo || !token) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const [owner, repo] = vaultRepo.split("/");
|
|
139
|
+
if (!owner || !repo) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return { owner, repo, projectName, branch: VAULT_BRANCH };
|
|
143
|
+
}
|
|
144
|
+
var defaultDeps = {
|
|
145
|
+
env: process.env,
|
|
146
|
+
createGithubClient,
|
|
147
|
+
recordSuccess,
|
|
148
|
+
recordFailure,
|
|
149
|
+
logError: console.error,
|
|
150
|
+
exit: (code) => process.exit(code)
|
|
151
|
+
};
|
|
152
|
+
async function runCiEntrypoint(source, main2, deps = defaultDeps) {
|
|
153
|
+
const params = healthParams(deps.env);
|
|
154
|
+
const octokit = params ? deps.createGithubClient(deps.env.DEVKEEP_GITHUB_TOKEN) : null;
|
|
155
|
+
try {
|
|
156
|
+
await main2();
|
|
157
|
+
} catch (error) {
|
|
158
|
+
deps.logError(error);
|
|
159
|
+
if (params && octokit) {
|
|
160
|
+
try {
|
|
161
|
+
await deps.recordFailure(octokit, params, source, error, currentRunUrl(deps.env));
|
|
162
|
+
} catch (recordingError) {
|
|
163
|
+
deps.logError(`Could not record the failure to the vault: ${String(recordingError)}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
deps.exit(1);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (params && octokit) {
|
|
170
|
+
try {
|
|
171
|
+
await deps.recordSuccess(octokit, params, source);
|
|
172
|
+
} catch (recordingError) {
|
|
173
|
+
deps.logError(`Ran successfully, but could not record it to the vault: ${String(recordingError)}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
27
178
|
// ../../modules/devlore/dist/diff.js
|
|
28
179
|
function toDiffFile(file) {
|
|
29
180
|
return {
|
|
@@ -70,8 +221,8 @@ var SECRET_PREFIX_PATTERNS = [
|
|
|
70
221
|
// JWT-shaped
|
|
71
222
|
];
|
|
72
223
|
var PEM_BLOCK_PATTERN = /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
|
|
73
|
-
var
|
|
74
|
-
var SECRET_ASSIGNMENT_PATTERN = new RegExp(`(?:[A-Za-z0-9]+[_-])*${
|
|
224
|
+
var SECRET_KEYWORD2 = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
225
|
+
var SECRET_ASSIGNMENT_PATTERN = new RegExp(`(?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD2}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*["']([^"'\`]+)["']`, "i");
|
|
75
226
|
|
|
76
227
|
// ../../modules/devcrypt/dist/candidateScan.js
|
|
77
228
|
function addedLines(patch) {
|
|
@@ -332,13 +483,13 @@ function requireEnv(env, name) {
|
|
|
332
483
|
}
|
|
333
484
|
return value;
|
|
334
485
|
}
|
|
335
|
-
var
|
|
486
|
+
var defaultDeps2 = {
|
|
336
487
|
env: process.env,
|
|
337
488
|
scanCryptingCandidates,
|
|
338
489
|
createGithubClient,
|
|
339
490
|
log: console.log
|
|
340
491
|
};
|
|
341
|
-
async function main(deps =
|
|
492
|
+
async function main(deps = defaultDeps2) {
|
|
342
493
|
const { env } = deps;
|
|
343
494
|
const [projectOwner, projectRepoName] = requireEnv(env, "PROJECT_REPO").split("/");
|
|
344
495
|
const [vaultOwner, vaultRepo] = requireEnv(env, "VAULT_REPO").split("/");
|
|
@@ -360,10 +511,7 @@ async function main(deps = defaultDeps) {
|
|
|
360
511
|
deps.log(`Flagged ${result.candidatesFlagged} crypting candidate(s)`);
|
|
361
512
|
}
|
|
362
513
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
363
|
-
main
|
|
364
|
-
console.error(error);
|
|
365
|
-
process.exit(1);
|
|
366
|
-
});
|
|
514
|
+
void runCiEntrypoint("cryptingCandidatesScan", main);
|
|
367
515
|
}
|
|
368
516
|
export {
|
|
369
517
|
main,
|
package/dist/draft-log-entry.js
CHANGED
|
@@ -127,6 +127,157 @@ function defaultModelFor(tier) {
|
|
|
127
127
|
return current.id;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// ../../modules/core/dist/redactSecrets.js
|
|
131
|
+
var REDACTED = "[REDACTED]";
|
|
132
|
+
var KNOWN_SECRET_PATTERNS = [
|
|
133
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
134
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
135
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
136
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
137
|
+
/sk-[A-Za-z0-9]{20,}/g,
|
|
138
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
139
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
140
|
+
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
141
|
+
];
|
|
142
|
+
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
143
|
+
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
144
|
+
function redactText(text) {
|
|
145
|
+
let result = text;
|
|
146
|
+
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
147
|
+
result = result.replace(pattern, REDACTED);
|
|
148
|
+
}
|
|
149
|
+
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ../../modules/core/dist/ciHealth.js
|
|
154
|
+
var EMPTY_ACTION_HEALTH = {
|
|
155
|
+
lastSuccessAt: null,
|
|
156
|
+
lastFailureAt: null,
|
|
157
|
+
lastFailureMessage: null,
|
|
158
|
+
lastFailureRunUrl: null,
|
|
159
|
+
consecutiveFailures: 0
|
|
160
|
+
};
|
|
161
|
+
var MAX_MESSAGE_CHARS = 2e3;
|
|
162
|
+
function healthPath(projectName) {
|
|
163
|
+
return `projects/${projectName}/health.json`;
|
|
164
|
+
}
|
|
165
|
+
function describeError(error) {
|
|
166
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : typeof error === "string" ? error : JSON.stringify(error);
|
|
167
|
+
const text = raw ?? "Unknown error";
|
|
168
|
+
return redactText(text.length > MAX_MESSAGE_CHARS ? `${text.slice(0, MAX_MESSAGE_CHARS)}\u2026` : text);
|
|
169
|
+
}
|
|
170
|
+
function applySuccess(current, source, now) {
|
|
171
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
172
|
+
return {
|
|
173
|
+
...current,
|
|
174
|
+
// The failure details are deliberately kept, not cleared: "it failed
|
|
175
|
+
// on Tuesday and has worked since" is worth being able to read.
|
|
176
|
+
[source]: { ...previous, lastSuccessAt: now.toISOString(), consecutiveFailures: 0 }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function applyFailure(current, source, error, runUrl, now) {
|
|
180
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
181
|
+
return {
|
|
182
|
+
...current,
|
|
183
|
+
[source]: {
|
|
184
|
+
...previous,
|
|
185
|
+
lastFailureAt: now.toISOString(),
|
|
186
|
+
lastFailureMessage: describeError(error),
|
|
187
|
+
lastFailureRunUrl: runUrl,
|
|
188
|
+
consecutiveFailures: previous.consecutiveFailures + 1
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function getHealthFile(octokit, { owner, repo, projectName }) {
|
|
193
|
+
try {
|
|
194
|
+
const { data } = await octokit.rest.repos.getContent({ owner, repo, path: healthPath(projectName) });
|
|
195
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
196
|
+
return { health: {} };
|
|
197
|
+
}
|
|
198
|
+
return { health: JSON.parse(Buffer.from(data.content, "base64").toString("utf-8")), sha: data.sha };
|
|
199
|
+
} catch {
|
|
200
|
+
return { health: {} };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function writeHealth(octokit, params, update, message) {
|
|
204
|
+
const { owner, repo, projectName, branch } = params;
|
|
205
|
+
await retryOnConflict(async () => {
|
|
206
|
+
const { health, sha } = await getHealthFile(octokit, params);
|
|
207
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
208
|
+
owner,
|
|
209
|
+
repo,
|
|
210
|
+
path: healthPath(projectName),
|
|
211
|
+
message,
|
|
212
|
+
content: Buffer.from(JSON.stringify(update(health), null, 2), "utf-8").toString("base64"),
|
|
213
|
+
branch,
|
|
214
|
+
sha
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async function recordSuccess(octokit, params, source, now = /* @__PURE__ */ new Date()) {
|
|
219
|
+
await writeHealth(octokit, params, (h) => applySuccess(h, source, now), `Record ${source} success: ${params.projectName}`);
|
|
220
|
+
}
|
|
221
|
+
async function recordFailure(octokit, params, source, error, runUrl, now = /* @__PURE__ */ new Date()) {
|
|
222
|
+
await writeHealth(octokit, params, (h) => applyFailure(h, source, error, runUrl, now), `Record ${source} failure: ${params.projectName}`);
|
|
223
|
+
}
|
|
224
|
+
function currentRunUrl(env) {
|
|
225
|
+
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;
|
|
226
|
+
if (!GITHUB_SERVER_URL || !GITHUB_REPOSITORY || !GITHUB_RUN_ID) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ../../modules/core/dist/ciEntrypoint.js
|
|
233
|
+
var VAULT_BRANCH = "main";
|
|
234
|
+
function healthParams(env) {
|
|
235
|
+
const projectName = env.PROJECT_NAME;
|
|
236
|
+
const vaultRepo = env.VAULT_REPO;
|
|
237
|
+
const token = env.DEVKEEP_GITHUB_TOKEN;
|
|
238
|
+
if (!projectName || !vaultRepo || !token) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const [owner, repo] = vaultRepo.split("/");
|
|
242
|
+
if (!owner || !repo) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return { owner, repo, projectName, branch: VAULT_BRANCH };
|
|
246
|
+
}
|
|
247
|
+
var defaultDeps = {
|
|
248
|
+
env: process.env,
|
|
249
|
+
createGithubClient,
|
|
250
|
+
recordSuccess,
|
|
251
|
+
recordFailure,
|
|
252
|
+
logError: console.error,
|
|
253
|
+
exit: (code) => process.exit(code)
|
|
254
|
+
};
|
|
255
|
+
async function runCiEntrypoint(source, main2, deps = defaultDeps) {
|
|
256
|
+
const params = healthParams(deps.env);
|
|
257
|
+
const octokit = params ? deps.createGithubClient(deps.env.DEVKEEP_GITHUB_TOKEN) : null;
|
|
258
|
+
try {
|
|
259
|
+
await main2();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
deps.logError(error);
|
|
262
|
+
if (params && octokit) {
|
|
263
|
+
try {
|
|
264
|
+
await deps.recordFailure(octokit, params, source, error, currentRunUrl(deps.env));
|
|
265
|
+
} catch (recordingError) {
|
|
266
|
+
deps.logError(`Could not record the failure to the vault: ${String(recordingError)}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
deps.exit(1);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (params && octokit) {
|
|
273
|
+
try {
|
|
274
|
+
await deps.recordSuccess(octokit, params, source);
|
|
275
|
+
} catch (recordingError) {
|
|
276
|
+
deps.logError(`Ran successfully, but could not record it to the vault: ${String(recordingError)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
130
281
|
// ../../modules/devlore/dist/ciUsage.js
|
|
131
282
|
var EMPTY_PROJECT_USAGE = {
|
|
132
283
|
draftLogEntry: ZERO_USAGE,
|
|
@@ -484,19 +635,6 @@ function routeDiffByModule(files, manifest) {
|
|
|
484
635
|
}
|
|
485
636
|
|
|
486
637
|
// ../../modules/devlore/dist/redact.js
|
|
487
|
-
var REDACTED = "[REDACTED]";
|
|
488
|
-
var KNOWN_SECRET_PATTERNS = [
|
|
489
|
-
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
490
|
-
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
491
|
-
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
492
|
-
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
493
|
-
/sk-[A-Za-z0-9]{20,}/g,
|
|
494
|
-
/AKIA[0-9A-Z]{16}/g,
|
|
495
|
-
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
496
|
-
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
497
|
-
];
|
|
498
|
-
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
499
|
-
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
500
638
|
var SENSITIVE_FILENAME_PATTERNS = [
|
|
501
639
|
/(^|\/)\.env(\..+)?$/,
|
|
502
640
|
/\.pem$/,
|
|
@@ -508,14 +646,6 @@ var SENSITIVE_FILENAME_PATTERNS = [
|
|
|
508
646
|
/credentials\.json$/,
|
|
509
647
|
/secrets?\.(json|ya?ml|toml)$/
|
|
510
648
|
];
|
|
511
|
-
function redactText(text) {
|
|
512
|
-
let result = text;
|
|
513
|
-
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
514
|
-
result = result.replace(pattern, REDACTED);
|
|
515
|
-
}
|
|
516
|
-
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
517
|
-
return result;
|
|
518
|
-
}
|
|
519
649
|
function isSensitiveFilename(filename) {
|
|
520
650
|
return SENSITIVE_FILENAME_PATTERNS.some((pattern) => pattern.test(filename));
|
|
521
651
|
}
|
|
@@ -533,7 +663,7 @@ function redactProjectDiff(diff) {
|
|
|
533
663
|
}
|
|
534
664
|
|
|
535
665
|
// ../../modules/devlore/dist/actions/draftLogEntry.js
|
|
536
|
-
var
|
|
666
|
+
var VAULT_BRANCH2 = "main";
|
|
537
667
|
var MODEL_TIER = "balanced";
|
|
538
668
|
var MAX_TOKENS = 2048;
|
|
539
669
|
function logEntryPath(projectName, commitSha, moduleId) {
|
|
@@ -567,7 +697,7 @@ async function syncProductDoc(projectOctokit, vaultOctokit, { projectOwner, proj
|
|
|
567
697
|
path: productDocPath(projectName, moduleId),
|
|
568
698
|
message: `Sync PRODUCT.md: ${projectName}@${headSha.slice(0, 7)}`,
|
|
569
699
|
content: Buffer.from(redactedDoc, "utf-8").toString("base64"),
|
|
570
|
-
branch:
|
|
700
|
+
branch: VAULT_BRANCH2,
|
|
571
701
|
sha: existing.sha
|
|
572
702
|
});
|
|
573
703
|
});
|
|
@@ -600,7 +730,7 @@ ${entryBody}
|
|
|
600
730
|
path: entryPath,
|
|
601
731
|
message: `Draft log entry: ${projectName}@${shortSha}${moduleName ? ` (${moduleName})` : ""}`,
|
|
602
732
|
content: Buffer.from(entryContent, "utf-8").toString("base64"),
|
|
603
|
-
branch:
|
|
733
|
+
branch: VAULT_BRANCH2
|
|
604
734
|
}));
|
|
605
735
|
let decisionPath = null;
|
|
606
736
|
if (decisionEntry) {
|
|
@@ -615,7 +745,7 @@ ${decisionEntry}
|
|
|
615
745
|
path: decisionPath,
|
|
616
746
|
message: `Draft decision entry: ${projectName}@${shortSha}${moduleName ? ` (${moduleName})` : ""}`,
|
|
617
747
|
content: Buffer.from(decisionContent, "utf-8").toString("base64"),
|
|
618
|
-
branch:
|
|
748
|
+
branch: VAULT_BRANCH2
|
|
619
749
|
}));
|
|
620
750
|
}
|
|
621
751
|
return { moduleId, logEntryPath: entryPath, decisionEntryPath: decisionPath, usage };
|
|
@@ -668,7 +798,7 @@ async function draftLogEntry({ projectOctokit, vaultOctokit, claude, projectOwne
|
|
|
668
798
|
});
|
|
669
799
|
}
|
|
670
800
|
const totalUsage = results.reduce((total, r) => addTokenUsage(total, r.usage), ZERO_USAGE);
|
|
671
|
-
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch:
|
|
801
|
+
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch: VAULT_BRANCH2 }, "draftLogEntry", totalUsage);
|
|
672
802
|
return results;
|
|
673
803
|
}
|
|
674
804
|
|
|
@@ -680,14 +810,14 @@ function requireEnv(env, name) {
|
|
|
680
810
|
}
|
|
681
811
|
return value;
|
|
682
812
|
}
|
|
683
|
-
var
|
|
813
|
+
var defaultDeps2 = {
|
|
684
814
|
env: process.env,
|
|
685
815
|
draftLogEntry,
|
|
686
816
|
createGithubClient,
|
|
687
817
|
createClaudeClient,
|
|
688
818
|
log: console.log
|
|
689
819
|
};
|
|
690
|
-
async function main(deps =
|
|
820
|
+
async function main(deps = defaultDeps2) {
|
|
691
821
|
const { env } = deps;
|
|
692
822
|
const projectName = requireEnv(env, "PROJECT_NAME");
|
|
693
823
|
const [projectOwner, projectRepoName] = requireEnv(env, "PROJECT_REPO").split("/");
|
|
@@ -717,10 +847,7 @@ async function main(deps = defaultDeps) {
|
|
|
717
847
|
}
|
|
718
848
|
}
|
|
719
849
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
720
|
-
main
|
|
721
|
-
console.error(error);
|
|
722
|
-
process.exit(1);
|
|
723
|
-
});
|
|
850
|
+
void runCiEntrypoint("draftLogEntry", main);
|
|
724
851
|
}
|
|
725
852
|
export {
|
|
726
853
|
main,
|
|
@@ -127,6 +127,157 @@ function defaultModelFor(tier) {
|
|
|
127
127
|
return current.id;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// ../../modules/core/dist/redactSecrets.js
|
|
131
|
+
var REDACTED = "[REDACTED]";
|
|
132
|
+
var KNOWN_SECRET_PATTERNS = [
|
|
133
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
134
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
135
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
136
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
137
|
+
/sk-[A-Za-z0-9]{20,}/g,
|
|
138
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
139
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
140
|
+
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
141
|
+
];
|
|
142
|
+
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
143
|
+
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
144
|
+
function redactText(text) {
|
|
145
|
+
let result = text;
|
|
146
|
+
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
147
|
+
result = result.replace(pattern, REDACTED);
|
|
148
|
+
}
|
|
149
|
+
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ../../modules/core/dist/ciHealth.js
|
|
154
|
+
var EMPTY_ACTION_HEALTH = {
|
|
155
|
+
lastSuccessAt: null,
|
|
156
|
+
lastFailureAt: null,
|
|
157
|
+
lastFailureMessage: null,
|
|
158
|
+
lastFailureRunUrl: null,
|
|
159
|
+
consecutiveFailures: 0
|
|
160
|
+
};
|
|
161
|
+
var MAX_MESSAGE_CHARS = 2e3;
|
|
162
|
+
function healthPath(projectName) {
|
|
163
|
+
return `projects/${projectName}/health.json`;
|
|
164
|
+
}
|
|
165
|
+
function describeError(error) {
|
|
166
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : typeof error === "string" ? error : JSON.stringify(error);
|
|
167
|
+
const text = raw ?? "Unknown error";
|
|
168
|
+
return redactText(text.length > MAX_MESSAGE_CHARS ? `${text.slice(0, MAX_MESSAGE_CHARS)}\u2026` : text);
|
|
169
|
+
}
|
|
170
|
+
function applySuccess(current, source, now) {
|
|
171
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
172
|
+
return {
|
|
173
|
+
...current,
|
|
174
|
+
// The failure details are deliberately kept, not cleared: "it failed
|
|
175
|
+
// on Tuesday and has worked since" is worth being able to read.
|
|
176
|
+
[source]: { ...previous, lastSuccessAt: now.toISOString(), consecutiveFailures: 0 }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function applyFailure(current, source, error, runUrl, now) {
|
|
180
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
181
|
+
return {
|
|
182
|
+
...current,
|
|
183
|
+
[source]: {
|
|
184
|
+
...previous,
|
|
185
|
+
lastFailureAt: now.toISOString(),
|
|
186
|
+
lastFailureMessage: describeError(error),
|
|
187
|
+
lastFailureRunUrl: runUrl,
|
|
188
|
+
consecutiveFailures: previous.consecutiveFailures + 1
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function getHealthFile(octokit, { owner, repo, projectName }) {
|
|
193
|
+
try {
|
|
194
|
+
const { data } = await octokit.rest.repos.getContent({ owner, repo, path: healthPath(projectName) });
|
|
195
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
196
|
+
return { health: {} };
|
|
197
|
+
}
|
|
198
|
+
return { health: JSON.parse(Buffer.from(data.content, "base64").toString("utf-8")), sha: data.sha };
|
|
199
|
+
} catch {
|
|
200
|
+
return { health: {} };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function writeHealth(octokit, params, update, message) {
|
|
204
|
+
const { owner, repo, projectName, branch } = params;
|
|
205
|
+
await retryOnConflict(async () => {
|
|
206
|
+
const { health, sha } = await getHealthFile(octokit, params);
|
|
207
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
208
|
+
owner,
|
|
209
|
+
repo,
|
|
210
|
+
path: healthPath(projectName),
|
|
211
|
+
message,
|
|
212
|
+
content: Buffer.from(JSON.stringify(update(health), null, 2), "utf-8").toString("base64"),
|
|
213
|
+
branch,
|
|
214
|
+
sha
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async function recordSuccess(octokit, params, source, now = /* @__PURE__ */ new Date()) {
|
|
219
|
+
await writeHealth(octokit, params, (h) => applySuccess(h, source, now), `Record ${source} success: ${params.projectName}`);
|
|
220
|
+
}
|
|
221
|
+
async function recordFailure(octokit, params, source, error, runUrl, now = /* @__PURE__ */ new Date()) {
|
|
222
|
+
await writeHealth(octokit, params, (h) => applyFailure(h, source, error, runUrl, now), `Record ${source} failure: ${params.projectName}`);
|
|
223
|
+
}
|
|
224
|
+
function currentRunUrl(env) {
|
|
225
|
+
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;
|
|
226
|
+
if (!GITHUB_SERVER_URL || !GITHUB_REPOSITORY || !GITHUB_RUN_ID) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ../../modules/core/dist/ciEntrypoint.js
|
|
233
|
+
var VAULT_BRANCH = "main";
|
|
234
|
+
function healthParams(env) {
|
|
235
|
+
const projectName = env.PROJECT_NAME;
|
|
236
|
+
const vaultRepo = env.VAULT_REPO;
|
|
237
|
+
const token = env.DEVKEEP_GITHUB_TOKEN;
|
|
238
|
+
if (!projectName || !vaultRepo || !token) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const [owner, repo] = vaultRepo.split("/");
|
|
242
|
+
if (!owner || !repo) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return { owner, repo, projectName, branch: VAULT_BRANCH };
|
|
246
|
+
}
|
|
247
|
+
var defaultDeps = {
|
|
248
|
+
env: process.env,
|
|
249
|
+
createGithubClient,
|
|
250
|
+
recordSuccess,
|
|
251
|
+
recordFailure,
|
|
252
|
+
logError: console.error,
|
|
253
|
+
exit: (code) => process.exit(code)
|
|
254
|
+
};
|
|
255
|
+
async function runCiEntrypoint(source, main2, deps = defaultDeps) {
|
|
256
|
+
const params = healthParams(deps.env);
|
|
257
|
+
const octokit = params ? deps.createGithubClient(deps.env.DEVKEEP_GITHUB_TOKEN) : null;
|
|
258
|
+
try {
|
|
259
|
+
await main2();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
deps.logError(error);
|
|
262
|
+
if (params && octokit) {
|
|
263
|
+
try {
|
|
264
|
+
await deps.recordFailure(octokit, params, source, error, currentRunUrl(deps.env));
|
|
265
|
+
} catch (recordingError) {
|
|
266
|
+
deps.logError(`Could not record the failure to the vault: ${String(recordingError)}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
deps.exit(1);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (params && octokit) {
|
|
273
|
+
try {
|
|
274
|
+
await deps.recordSuccess(octokit, params, source);
|
|
275
|
+
} catch (recordingError) {
|
|
276
|
+
deps.logError(`Ran successfully, but could not record it to the vault: ${String(recordingError)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
130
281
|
// ../../modules/devlore/dist/prompt.js
|
|
131
282
|
function buildReleaseNotesPrompt(input) {
|
|
132
283
|
return [
|
|
@@ -150,29 +301,6 @@ function buildReleaseNotesPrompt(input) {
|
|
|
150
301
|
].join("\n");
|
|
151
302
|
}
|
|
152
303
|
|
|
153
|
-
// ../../modules/devlore/dist/redact.js
|
|
154
|
-
var REDACTED = "[REDACTED]";
|
|
155
|
-
var KNOWN_SECRET_PATTERNS = [
|
|
156
|
-
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
157
|
-
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
158
|
-
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
159
|
-
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
160
|
-
/sk-[A-Za-z0-9]{20,}/g,
|
|
161
|
-
/AKIA[0-9A-Z]{16}/g,
|
|
162
|
-
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
163
|
-
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
164
|
-
];
|
|
165
|
-
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
166
|
-
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
167
|
-
function redactText(text) {
|
|
168
|
-
let result = text;
|
|
169
|
-
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
170
|
-
result = result.replace(pattern, REDACTED);
|
|
171
|
-
}
|
|
172
|
-
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
173
|
-
return result;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
304
|
// ../../modules/devlore/dist/ciUsage.js
|
|
177
305
|
var EMPTY_PROJECT_USAGE = {
|
|
178
306
|
draftLogEntry: ZERO_USAGE,
|
|
@@ -354,7 +482,7 @@ function releaseNotesDir(projectName) {
|
|
|
354
482
|
var MODEL_TIER = "balanced";
|
|
355
483
|
var MAX_TOKENS = 2e4;
|
|
356
484
|
var MAX_CONTINUATIONS = 8;
|
|
357
|
-
var
|
|
485
|
+
var VAULT_BRANCH2 = "main";
|
|
358
486
|
async function draftReleaseNotes({ projectOctokit, vaultOctokit, claude, projectOwner, projectRepoName, vaultOwner, vaultRepoName, projectName, tag }) {
|
|
359
487
|
const { logEntries, previousTag } = await selectLogEntriesSincePreviousRelease({
|
|
360
488
|
vaultOctokit,
|
|
@@ -386,11 +514,11 @@ ${text.trim()}
|
|
|
386
514
|
path,
|
|
387
515
|
message: `Draft release notes: ${projectName} ${tag}`,
|
|
388
516
|
content: Buffer.from(content, "utf-8").toString("base64"),
|
|
389
|
-
branch:
|
|
517
|
+
branch: VAULT_BRANCH2,
|
|
390
518
|
sha: await getExistingSha(vaultOctokit, vaultOwner, vaultRepoName, path)
|
|
391
519
|
});
|
|
392
520
|
if (usage.inputTokens > 0 || usage.outputTokens > 0) {
|
|
393
|
-
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch:
|
|
521
|
+
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch: VAULT_BRANCH2 }, "releaseNotes", usage);
|
|
394
522
|
}
|
|
395
523
|
return { path, previousTag, entryCount: logEntries.length, content, usage };
|
|
396
524
|
}
|
|
@@ -411,14 +539,14 @@ function requireEnv(env, name) {
|
|
|
411
539
|
}
|
|
412
540
|
return value;
|
|
413
541
|
}
|
|
414
|
-
var
|
|
542
|
+
var defaultDeps2 = {
|
|
415
543
|
env: process.env,
|
|
416
544
|
draftReleaseNotes,
|
|
417
545
|
createGithubClient,
|
|
418
546
|
createClaudeClient,
|
|
419
547
|
log: console.log
|
|
420
548
|
};
|
|
421
|
-
async function main(deps =
|
|
549
|
+
async function main(deps = defaultDeps2) {
|
|
422
550
|
const { env } = deps;
|
|
423
551
|
const projectName = requireEnv(env, "PROJECT_NAME");
|
|
424
552
|
const [projectOwner, projectRepoName] = requireEnv(env, "PROJECT_REPO").split("/");
|
|
@@ -440,10 +568,7 @@ async function main(deps = defaultDeps) {
|
|
|
440
568
|
deps.log(`Drafted release notes: ${result.path} (previous tag: ${result.previousTag ?? "none"}, ${result.entryCount} entries)`);
|
|
441
569
|
}
|
|
442
570
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
443
|
-
main
|
|
444
|
-
console.error(error);
|
|
445
|
-
process.exit(1);
|
|
446
|
-
});
|
|
571
|
+
void runCiEntrypoint("releaseNotes", main);
|
|
447
572
|
}
|
|
448
573
|
export {
|
|
449
574
|
main,
|
package/dist/sync-onboarding.js
CHANGED
|
@@ -127,6 +127,157 @@ function defaultModelFor(tier) {
|
|
|
127
127
|
return current.id;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// ../../modules/core/dist/redactSecrets.js
|
|
131
|
+
var REDACTED = "[REDACTED]";
|
|
132
|
+
var KNOWN_SECRET_PATTERNS = [
|
|
133
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
134
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
135
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
136
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
137
|
+
/sk-[A-Za-z0-9]{20,}/g,
|
|
138
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
139
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
140
|
+
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
141
|
+
];
|
|
142
|
+
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
143
|
+
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
144
|
+
function redactText(text) {
|
|
145
|
+
let result = text;
|
|
146
|
+
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
147
|
+
result = result.replace(pattern, REDACTED);
|
|
148
|
+
}
|
|
149
|
+
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ../../modules/core/dist/ciHealth.js
|
|
154
|
+
var EMPTY_ACTION_HEALTH = {
|
|
155
|
+
lastSuccessAt: null,
|
|
156
|
+
lastFailureAt: null,
|
|
157
|
+
lastFailureMessage: null,
|
|
158
|
+
lastFailureRunUrl: null,
|
|
159
|
+
consecutiveFailures: 0
|
|
160
|
+
};
|
|
161
|
+
var MAX_MESSAGE_CHARS = 2e3;
|
|
162
|
+
function healthPath(projectName) {
|
|
163
|
+
return `projects/${projectName}/health.json`;
|
|
164
|
+
}
|
|
165
|
+
function describeError(error) {
|
|
166
|
+
const raw = error instanceof Error ? `${error.name}: ${error.message}` : typeof error === "string" ? error : JSON.stringify(error);
|
|
167
|
+
const text = raw ?? "Unknown error";
|
|
168
|
+
return redactText(text.length > MAX_MESSAGE_CHARS ? `${text.slice(0, MAX_MESSAGE_CHARS)}\u2026` : text);
|
|
169
|
+
}
|
|
170
|
+
function applySuccess(current, source, now) {
|
|
171
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
172
|
+
return {
|
|
173
|
+
...current,
|
|
174
|
+
// The failure details are deliberately kept, not cleared: "it failed
|
|
175
|
+
// on Tuesday and has worked since" is worth being able to read.
|
|
176
|
+
[source]: { ...previous, lastSuccessAt: now.toISOString(), consecutiveFailures: 0 }
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function applyFailure(current, source, error, runUrl, now) {
|
|
180
|
+
const previous = current[source] ?? EMPTY_ACTION_HEALTH;
|
|
181
|
+
return {
|
|
182
|
+
...current,
|
|
183
|
+
[source]: {
|
|
184
|
+
...previous,
|
|
185
|
+
lastFailureAt: now.toISOString(),
|
|
186
|
+
lastFailureMessage: describeError(error),
|
|
187
|
+
lastFailureRunUrl: runUrl,
|
|
188
|
+
consecutiveFailures: previous.consecutiveFailures + 1
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function getHealthFile(octokit, { owner, repo, projectName }) {
|
|
193
|
+
try {
|
|
194
|
+
const { data } = await octokit.rest.repos.getContent({ owner, repo, path: healthPath(projectName) });
|
|
195
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
196
|
+
return { health: {} };
|
|
197
|
+
}
|
|
198
|
+
return { health: JSON.parse(Buffer.from(data.content, "base64").toString("utf-8")), sha: data.sha };
|
|
199
|
+
} catch {
|
|
200
|
+
return { health: {} };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function writeHealth(octokit, params, update, message) {
|
|
204
|
+
const { owner, repo, projectName, branch } = params;
|
|
205
|
+
await retryOnConflict(async () => {
|
|
206
|
+
const { health, sha } = await getHealthFile(octokit, params);
|
|
207
|
+
await octokit.rest.repos.createOrUpdateFileContents({
|
|
208
|
+
owner,
|
|
209
|
+
repo,
|
|
210
|
+
path: healthPath(projectName),
|
|
211
|
+
message,
|
|
212
|
+
content: Buffer.from(JSON.stringify(update(health), null, 2), "utf-8").toString("base64"),
|
|
213
|
+
branch,
|
|
214
|
+
sha
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
async function recordSuccess(octokit, params, source, now = /* @__PURE__ */ new Date()) {
|
|
219
|
+
await writeHealth(octokit, params, (h) => applySuccess(h, source, now), `Record ${source} success: ${params.projectName}`);
|
|
220
|
+
}
|
|
221
|
+
async function recordFailure(octokit, params, source, error, runUrl, now = /* @__PURE__ */ new Date()) {
|
|
222
|
+
await writeHealth(octokit, params, (h) => applyFailure(h, source, error, runUrl, now), `Record ${source} failure: ${params.projectName}`);
|
|
223
|
+
}
|
|
224
|
+
function currentRunUrl(env) {
|
|
225
|
+
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID } = env;
|
|
226
|
+
if (!GITHUB_SERVER_URL || !GITHUB_REPOSITORY || !GITHUB_RUN_ID) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ../../modules/core/dist/ciEntrypoint.js
|
|
233
|
+
var VAULT_BRANCH = "main";
|
|
234
|
+
function healthParams(env) {
|
|
235
|
+
const projectName = env.PROJECT_NAME;
|
|
236
|
+
const vaultRepo = env.VAULT_REPO;
|
|
237
|
+
const token = env.DEVKEEP_GITHUB_TOKEN;
|
|
238
|
+
if (!projectName || !vaultRepo || !token) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const [owner, repo] = vaultRepo.split("/");
|
|
242
|
+
if (!owner || !repo) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return { owner, repo, projectName, branch: VAULT_BRANCH };
|
|
246
|
+
}
|
|
247
|
+
var defaultDeps = {
|
|
248
|
+
env: process.env,
|
|
249
|
+
createGithubClient,
|
|
250
|
+
recordSuccess,
|
|
251
|
+
recordFailure,
|
|
252
|
+
logError: console.error,
|
|
253
|
+
exit: (code) => process.exit(code)
|
|
254
|
+
};
|
|
255
|
+
async function runCiEntrypoint(source, main2, deps = defaultDeps) {
|
|
256
|
+
const params = healthParams(deps.env);
|
|
257
|
+
const octokit = params ? deps.createGithubClient(deps.env.DEVKEEP_GITHUB_TOKEN) : null;
|
|
258
|
+
try {
|
|
259
|
+
await main2();
|
|
260
|
+
} catch (error) {
|
|
261
|
+
deps.logError(error);
|
|
262
|
+
if (params && octokit) {
|
|
263
|
+
try {
|
|
264
|
+
await deps.recordFailure(octokit, params, source, error, currentRunUrl(deps.env));
|
|
265
|
+
} catch (recordingError) {
|
|
266
|
+
deps.logError(`Could not record the failure to the vault: ${String(recordingError)}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
deps.exit(1);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (params && octokit) {
|
|
273
|
+
try {
|
|
274
|
+
await deps.recordSuccess(octokit, params, source);
|
|
275
|
+
} catch (recordingError) {
|
|
276
|
+
deps.logError(`Ran successfully, but could not record it to the vault: ${String(recordingError)}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
130
281
|
// ../../modules/devlore/dist/decisionEntries.js
|
|
131
282
|
function decisionEntriesDir(projectName) {
|
|
132
283
|
return `projects/${projectName}/decisions`;
|
|
@@ -186,29 +337,6 @@ ${input.decisions.join("\n\n")}` : "",
|
|
|
186
337
|
].filter((line) => line !== "").join("\n");
|
|
187
338
|
}
|
|
188
339
|
|
|
189
|
-
// ../../modules/devlore/dist/redact.js
|
|
190
|
-
var REDACTED = "[REDACTED]";
|
|
191
|
-
var KNOWN_SECRET_PATTERNS = [
|
|
192
|
-
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
193
|
-
/gh[pousr]_[A-Za-z0-9]{36,}/g,
|
|
194
|
-
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
195
|
-
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
196
|
-
/sk-[A-Za-z0-9]{20,}/g,
|
|
197
|
-
/AKIA[0-9A-Z]{16}/g,
|
|
198
|
-
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
199
|
-
/eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
|
|
200
|
-
];
|
|
201
|
-
var SECRET_KEYWORD = "(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL)";
|
|
202
|
-
var ASSIGNMENT_PATTERN = new RegExp(`((?:[A-Za-z0-9]+[_-])*${SECRET_KEYWORD}(?:[_-][A-Za-z0-9]+)*\\s*[:=]\\s*)(["']?)([^"'\`\\s]+)\\2`, "gi");
|
|
203
|
-
function redactText(text) {
|
|
204
|
-
let result = text;
|
|
205
|
-
for (const pattern of KNOWN_SECRET_PATTERNS) {
|
|
206
|
-
result = result.replace(pattern, REDACTED);
|
|
207
|
-
}
|
|
208
|
-
result = result.replace(ASSIGNMENT_PATTERN, (_match, prefix, quote) => `${prefix}${quote}${REDACTED}${quote}`);
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
340
|
// ../../modules/devlore/dist/ciUsage.js
|
|
213
341
|
var EMPTY_PROJECT_USAGE = {
|
|
214
342
|
draftLogEntry: ZERO_USAGE,
|
|
@@ -358,7 +486,7 @@ function isNotFound4(error) {
|
|
|
358
486
|
var MODEL_TIER = "balanced";
|
|
359
487
|
var MAX_TOKENS = 2e4;
|
|
360
488
|
var MAX_CONTINUATIONS = 8;
|
|
361
|
-
var
|
|
489
|
+
var VAULT_BRANCH2 = "main";
|
|
362
490
|
async function readVaultFile(octokit, owner, repo, path) {
|
|
363
491
|
const { data } = await octokit.rest.repos.getContent({ owner, repo, path }).catch(() => ({ data: null }));
|
|
364
492
|
return data && !Array.isArray(data) && data.type === "file" ? Buffer.from(data.content, "base64").toString("utf-8") : "";
|
|
@@ -403,12 +531,12 @@ ${text.trim()}
|
|
|
403
531
|
path: vaultPath,
|
|
404
532
|
message: `Mirror onboarding guide: ${projectName}`,
|
|
405
533
|
content: Buffer.from(mirrored, "utf-8").toString("base64"),
|
|
406
|
-
branch:
|
|
534
|
+
branch: VAULT_BRANCH2,
|
|
407
535
|
sha: existingVault.sha
|
|
408
536
|
});
|
|
409
537
|
}
|
|
410
538
|
if (usage.inputTokens > 0 || usage.outputTokens > 0) {
|
|
411
|
-
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch:
|
|
539
|
+
await recordUsage(vaultOctokit, { owner: vaultOwner, repo: vaultRepoName, projectName, branch: VAULT_BRANCH2 }, "syncOnboarding", usage);
|
|
412
540
|
}
|
|
413
541
|
return { path: ONBOARDING_PATH, vaultPath, content, usage };
|
|
414
542
|
}
|
|
@@ -421,14 +549,14 @@ function requireEnv(env, name) {
|
|
|
421
549
|
}
|
|
422
550
|
return value;
|
|
423
551
|
}
|
|
424
|
-
var
|
|
552
|
+
var defaultDeps2 = {
|
|
425
553
|
env: process.env,
|
|
426
554
|
syncOnboarding,
|
|
427
555
|
createGithubClient,
|
|
428
556
|
createClaudeClient,
|
|
429
557
|
log: console.log
|
|
430
558
|
};
|
|
431
|
-
async function main(deps =
|
|
559
|
+
async function main(deps = defaultDeps2) {
|
|
432
560
|
const { env } = deps;
|
|
433
561
|
const projectName = requireEnv(env, "PROJECT_NAME");
|
|
434
562
|
const [projectOwner, projectRepoName] = requireEnv(env, "PROJECT_REPO").split("/");
|
|
@@ -448,10 +576,7 @@ async function main(deps = defaultDeps) {
|
|
|
448
576
|
deps.log(`Synced onboarding guide: ${result.path} (mirrored to ${result.vaultPath})`);
|
|
449
577
|
}
|
|
450
578
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
451
|
-
main
|
|
452
|
-
console.error(error);
|
|
453
|
-
process.exit(1);
|
|
454
|
-
});
|
|
579
|
+
void runCiEntrypoint("syncOnboarding", main);
|
|
455
580
|
}
|
|
456
581
|
export {
|
|
457
582
|
main,
|