@coderook/cli 0.31.5 → 0.31.6
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "coderook",
|
|
3
3
|
"displayName": "CodeRook",
|
|
4
4
|
"description": "Save, browse and restore whole-snapshot versions of a project on CodeRook, from Claude Code.",
|
|
5
|
-
"version": "0.31.
|
|
5
|
+
"version": "0.31.6",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ACCA Gaming Productions",
|
|
8
8
|
"url": "https://coderook.com"
|
package/dist/cli/src/api.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.projects = projects;
|
|
|
10
10
|
exports.findPublicProject = findPublicProject;
|
|
11
11
|
exports.findProject = findProject;
|
|
12
12
|
exports.health = health;
|
|
13
|
+
exports.requestReviews = requestReviews;
|
|
13
14
|
exports.openProposal = openProposal;
|
|
14
15
|
exports.proposals = proposals;
|
|
15
16
|
exports.mergeTracks = mergeTracks;
|
|
@@ -267,6 +268,11 @@ async function health() {
|
|
|
267
268
|
});
|
|
268
269
|
return (await response.json());
|
|
269
270
|
}
|
|
271
|
+
/** Ask people, by username, to review a merge. */
|
|
272
|
+
async function requestReviews(mergeTrackId, usernames) {
|
|
273
|
+
const body = await call(`/v1/merge-tracks/${mergeTrackId}/review-requests`, { method: "POST", body: { reviewers: usernames } });
|
|
274
|
+
return body.asked;
|
|
275
|
+
}
|
|
270
276
|
/** Offer a line of work to another, usually main. */
|
|
271
277
|
async function openProposal(repositoryId, input) {
|
|
272
278
|
return call(`/v1/repositories/${repositoryId}/proposals`, {
|
package/dist/cli/src/cli.js
CHANGED
|
@@ -1667,6 +1667,17 @@ async function commandMerge(parsed) {
|
|
|
1667
1667
|
const folder = folderFor({ ...parsed, positional: parsed.positional.slice(1) });
|
|
1668
1668
|
const summary = await findMerge(folder, reference);
|
|
1669
1669
|
const detail = await (0, api_js_1.mergeTrack)(summary.id);
|
|
1670
|
+
/*
|
|
1671
|
+
Asking people to look. Named the way people name each other, and said
|
|
1672
|
+
back by name, so a typo in a username is visible rather than silent.
|
|
1673
|
+
*/
|
|
1674
|
+
const ask = flagText(parsed, "ask");
|
|
1675
|
+
if (ask) {
|
|
1676
|
+
const asked = await (0, api_js_1.requestReviews)(summary.id, ask.split(",").map((name) => name.trim()).filter(Boolean));
|
|
1677
|
+
console.log(asked.length
|
|
1678
|
+
? `Asked ${asked.map((person) => person.displayName).join(", ")} to review ${summary.reference}.`
|
|
1679
|
+
: "Nobody new was asked.");
|
|
1680
|
+
}
|
|
1670
1681
|
if (hasFlag(parsed, "cancel")) {
|
|
1671
1682
|
await (0, api_js_1.cancelMerge)(summary.id);
|
|
1672
1683
|
console.log(`${summary.reference} cancelled. Your upload is still stored and nothing published was touched.`);
|
|
@@ -1714,6 +1725,20 @@ async function commandMerge(parsed) {
|
|
|
1714
1725
|
for (const blocked of now.provisional.blockedByChecks ?? []) {
|
|
1715
1726
|
console.log(` ${red("check")} ${blocked}`);
|
|
1716
1727
|
}
|
|
1728
|
+
for (const one of now.changeRequest?.reviews ?? []) {
|
|
1729
|
+
if (one.verdict === "comment" && !one.body)
|
|
1730
|
+
continue;
|
|
1731
|
+
const said = one.verdict === "approve"
|
|
1732
|
+
? accent("approved")
|
|
1733
|
+
: one.verdict === "request_changes"
|
|
1734
|
+
? red("asked for changes")
|
|
1735
|
+
: dim("commented");
|
|
1736
|
+
console.log(` ${one.reviewerName ?? "A reviewer"} ${said}${one.body ? dim(`: ${one.body}`) : ""}`);
|
|
1737
|
+
}
|
|
1738
|
+
const waiting = (now.changeRequest?.requested ?? []).filter((person) => !person.reviewed);
|
|
1739
|
+
if (waiting.length) {
|
|
1740
|
+
console.log(dim(` waiting on ${waiting.map((person) => person.displayName).join(", ")}`));
|
|
1741
|
+
}
|
|
1717
1742
|
}
|
|
1718
1743
|
console.log(`
|
|
1719
1744
|
${accent(now.mergeTrack.reference)} · ${now.provisional.fileCount} files · ` +
|
|
@@ -2556,12 +2581,16 @@ const SPECS = [
|
|
|
2556
2581
|
options: [
|
|
2557
2582
|
{ flags: "--ship <action>", description: "its builds become downloads on the version" },
|
|
2558
2583
|
{ flags: "--no-ship <action>", description: "keep its files without attaching them" },
|
|
2584
|
+
{ flags: "--on-save <action>", description: "run it on every save" },
|
|
2585
|
+
{ flags: "--on-proposal <action>", description: "run it on proposals; its result becomes a check" },
|
|
2586
|
+
{ flags: "--by-hand <action>", description: "run it only when somebody starts it" },
|
|
2559
2587
|
{ flags: "--project <name>", description: "which project" },
|
|
2560
2588
|
],
|
|
2561
2589
|
examples: [
|
|
2562
2590
|
"cbx actions",
|
|
2563
2591
|
'cbx actions --ship "Windows installer"',
|
|
2564
2592
|
'cbx actions --no-ship "Windows installer"',
|
|
2593
|
+
'cbx actions --on-proposal Tests',
|
|
2565
2594
|
],
|
|
2566
2595
|
run: service_commands_js_1.commandWorkflows,
|
|
2567
2596
|
},
|
|
@@ -2686,6 +2715,7 @@ const SPECS = [
|
|
|
2686
2715
|
{ flags: "--theirs", description: "keep theirs" },
|
|
2687
2716
|
{ flags: "--both", description: "keep both" },
|
|
2688
2717
|
{ flags: "--drop", description: "abandon the upload" },
|
|
2718
|
+
{ flags: "--ask <usernames>", description: "ask people to review it, comma separated" },
|
|
2689
2719
|
],
|
|
2690
2720
|
run: commandMerge,
|
|
2691
2721
|
},
|
|
@@ -314,6 +314,46 @@ async function commandWorkflows(parsed) {
|
|
|
314
314
|
}
|
|
315
315
|
console.log("");
|
|
316
316
|
}
|
|
317
|
+
/*
|
|
318
|
+
When an action runs. A trigger used to be a label nothing acted on; now a
|
|
319
|
+
save or a proposal really does start the actions that asked for it, so
|
|
320
|
+
choosing is worth a flag.
|
|
321
|
+
*/
|
|
322
|
+
const WHEN = [
|
|
323
|
+
["on-save", "version_saved", "runs on every save"],
|
|
324
|
+
["on-proposal", "merge_opened", "runs when a line is proposed, and again on each save to it"],
|
|
325
|
+
["by-hand", "manual", "runs when somebody starts it"],
|
|
326
|
+
];
|
|
327
|
+
for (const [flag, trigger, meaning] of WHEN) {
|
|
328
|
+
const named = parsed.flags.get(flag);
|
|
329
|
+
if (named === undefined)
|
|
330
|
+
continue;
|
|
331
|
+
if (typeof named !== "string" || !named.trim()) {
|
|
332
|
+
console.error(red("Which action?") + dim(` cbx actions --${flag} "Tests"`));
|
|
333
|
+
return 1;
|
|
334
|
+
}
|
|
335
|
+
const target = found.find((workflow) => workflow.name.toLowerCase() === named.trim().toLowerCase());
|
|
336
|
+
if (!target) {
|
|
337
|
+
console.error(red(`${project.name} has no action called ${named.trim()}.`));
|
|
338
|
+
if (found.length) {
|
|
339
|
+
console.error(dim(` It has: ${found.map((one) => one.name).join(", ")}`));
|
|
340
|
+
}
|
|
341
|
+
return 1;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
await (0, api_js_1.changeWorkflow)(project.id, target.id, { trigger });
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
console.error(red(error instanceof Error ? error.message : String(error)));
|
|
348
|
+
return 1;
|
|
349
|
+
}
|
|
350
|
+
target.trigger = trigger;
|
|
351
|
+
console.log(green(`${target.name} ${meaning}.`));
|
|
352
|
+
if (trigger === "merge_opened") {
|
|
353
|
+
console.log(dim(" Its result becomes a required check on the proposal."));
|
|
354
|
+
}
|
|
355
|
+
console.log("");
|
|
356
|
+
}
|
|
317
357
|
if (!found.length) {
|
|
318
358
|
console.log(dim("No actions on this project."));
|
|
319
359
|
return 0;
|
|
@@ -256,8 +256,36 @@ class Tracks {
|
|
|
256
256
|
ready: body.provisional?.ready ?? false,
|
|
257
257
|
unresolvedPaths: body.provisional?.unresolvedPaths ?? [],
|
|
258
258
|
blockedByChecks: body.provisional?.blockedByChecks ?? [],
|
|
259
|
+
proposal: body.proposal ?? null,
|
|
260
|
+
request: body.changeRequest
|
|
261
|
+
? { ...body.changeRequest, requested: body.changeRequest.requested ?? [] }
|
|
262
|
+
: null,
|
|
259
263
|
};
|
|
260
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Offer a line to another, usually main.
|
|
267
|
+
*
|
|
268
|
+
* The service reads both lines, combines what it can, and answers with the
|
|
269
|
+
* merge it opened — which the window then shows like any other.
|
|
270
|
+
*/
|
|
271
|
+
async propose(repositoryId, input) {
|
|
272
|
+
const body = await this.call(`/v1/repositories/${repositoryId}/proposals`, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
body: JSON.stringify(input.body ? input : { from: input.from, into: input.into, title: input.title }),
|
|
275
|
+
});
|
|
276
|
+
return {
|
|
277
|
+
mergeTrackId: body.mergeTrack.id,
|
|
278
|
+
reference: body.mergeTrack.reference,
|
|
279
|
+
unresolved: body.conflicts.unresolved,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/** Say where you stand on a proposal. */
|
|
283
|
+
async review(mergeTrackId, verdict, note) {
|
|
284
|
+
await this.call(`/v1/merge-tracks/${mergeTrackId}/review`, {
|
|
285
|
+
method: "PUT",
|
|
286
|
+
body: JSON.stringify(note ? { verdict, body: note } : { verdict }),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
261
289
|
/**
|
|
262
290
|
* One side of a conflict, as text.
|
|
263
291
|
*
|