@coderook/cli 0.38.2 → 0.40.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.
@@ -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, with cbx or plain git, from Claude Code.",
5
- "version": "0.38.2",
5
+ "version": "0.40.0",
6
6
  "author": {
7
7
  "name": "ACCA Gaming Productions",
8
8
  "url": "https://coderook.com"
package/README.md CHANGED
@@ -258,6 +258,26 @@ command refuses rather than waiting. Going private never asks.
258
258
  A public project's page offers only its named versions that have not been
259
259
  hidden (see `cbx promote` and `cbx mark --hide`).
260
260
 
261
+ ## Project settings
262
+
263
+ Everything on the website's Settings screen has a command, and each one shows
264
+ what is set when given nothing to change:
265
+
266
+ ```
267
+ cbx about --name "Night Owl Diner" --description "…" name and description
268
+ cbx line-rules main --protect --approvals 1 --checks build,test --code-owners on
269
+ cbx upload-rules --ignore .coderookignore --encrypt on --warn-large 512
270
+ cbx assistant automated --review on --describe on the pull-request assistant
271
+ cbx hooks --test | --deliveries | --redeliver <id> | --on <id>
272
+ cbx people --change sam@example.com --role admin or --remove, --cancel-invite
273
+ cbx security policy --on --text SECURITY.md
274
+ cbx hand-over sam my-project offer it to another owner
275
+ ```
276
+
277
+ The one exception is AI access. `cbx ai` shows what a project lets AI do;
278
+ changing it is for a person, on the website (Settings → Access & AI) or in
279
+ the desktop app. The service refuses the change from any token.
280
+
261
281
  ## Pages
262
282
 
263
283
  A public project can be served as a website: a Unity WebGL build, a Godot web
@@ -519,6 +539,9 @@ cbx issue close 12 --duplicate-of 9 or --reason not-planned
519
539
  cbx issue label 12 bug,ui --remove to take them off
520
540
  cbx issue assign 12 sam or none
521
541
  cbx issue labels --starter
542
+ cbx issue labels add crash --colour d73a4a or change, remove
543
+ cbx issue rules add auto-label --words crash,freeze --label crash
544
+ cbx issue rules off 2 on, change, remove by number
522
545
  ```
523
546
 
524
547
  ## Forks and security reports
@@ -529,6 +552,7 @@ cbx fork offer fix-export --title "…" offer a line back as a pull request
529
552
  cbx fork sync the original's latest, on "upstream"
530
553
  cbx security report sam/editor --title "…" --severity high
531
554
  cbx security list | view S-3 | reply S-3 -m "…" | mark S-3 fixed
555
+ cbx security policy --on --text SECURITY.md
532
556
  ```
533
557
 
534
558
  ## Releases and app downloads
@@ -21,7 +21,6 @@ exports.resolveMergeConflict = resolveMergeConflict;
21
21
  exports.applyMerge = applyMerge;
22
22
  exports.cancelMerge = cancelMerge;
23
23
  exports.aiAccess = aiAccess;
24
- exports.setAiAccess = setAiAccess;
25
24
  exports.updateProject = updateProject;
26
25
  exports.pages = pages;
27
26
  exports.setPages = setPages;
@@ -37,6 +36,9 @@ exports.createIssue = createIssue;
37
36
  exports.releases = releases;
38
37
  exports.collaborators = collaborators;
39
38
  exports.invite = invite;
39
+ exports.setCollaboratorRole = setCollaboratorRole;
40
+ exports.removeCollaborator = removeCollaborator;
41
+ exports.revokeInvite = revokeInvite;
40
42
  exports.acceptInvite = acceptInvite;
41
43
  exports.watch = watch;
42
44
  exports.setWatch = setWatch;
@@ -63,6 +65,10 @@ exports.undoTo = undoTo;
63
65
  exports.webhooks = webhooks;
64
66
  exports.addWebhook = addWebhook;
65
67
  exports.removeWebhook = removeWebhook;
68
+ exports.updateWebhook = updateWebhook;
69
+ exports.webhookDeliveries = webhookDeliveries;
70
+ exports.testWebhook = testWebhook;
71
+ exports.redeliverWebhook = redeliverWebhook;
66
72
  exports.collisionCheck = collisionCheck;
67
73
  /** The small part of the API the command-line tool needs directly. */
68
74
  const network_js_1 = require("./network.js");
@@ -425,24 +431,16 @@ async function aiAccess(repositoryId) {
425
431
  aiRequest: allowed("request"),
426
432
  };
427
433
  }
428
- /**
429
- * Change one answer.
430
- *
431
- * One at a time, matching the site: each is a separate decision, and sending
432
- * all four would make turning off downloads look like it needed a view about
433
- * indexing as well.
434
- */
435
- async function setAiAccess(repositoryId, change) {
436
- await call(`/v1/repositories/${encodeURIComponent(repositoryId)}`, {
437
- method: "PATCH",
438
- body: change,
439
- });
440
- }
434
+ /*
435
+ There is no setter for these. What AI may do with a project is changed by a
436
+ person on the website or in the desktop app; the service refuses it from
437
+ any token (ai_access_person_only), and this tool only ever holds one.
438
+ */
441
439
  /**
442
440
  * Change what a project says about itself.
443
441
  *
444
- * The same PATCH the AI switches use, which is where these live: a handful of
445
- * columns on the repository rather than a resource of their own.
442
+ * A PATCH on the repository, which is where these live: a handful of columns
443
+ * rather than a resource of their own.
446
444
  */
447
445
  async function updateProject(repositoryId, change) {
448
446
  await call(`/v1/repositories/${encodeURIComponent(repositoryId)}`, {
@@ -700,11 +698,13 @@ async function collaborators(repositoryId) {
700
698
  const body = await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/collaborators`);
701
699
  return {
702
700
  collaborators: (body.collaborators ?? []).map((row) => ({
701
+ userId: String(row.userId ?? ""),
703
702
  displayName: String(row.displayName ?? ""),
704
703
  email: String(row.email ?? ""),
705
704
  role: String(row.role ?? "member"),
706
705
  })),
707
706
  invites: (body.invites ?? []).map((row) => ({
707
+ id: String(row.id ?? ""),
708
708
  email: String(row.email ?? ""),
709
709
  role: String(row.role ?? "member"),
710
710
  expiresAt: String(row.expiresAt ?? row.expires_at ?? ""),
@@ -715,6 +715,18 @@ async function invite(repositoryId, input) {
715
715
  const row = await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/invites`, { method: "POST", body: input });
716
716
  return typeof row?.inviteUrl === "string" ? { inviteUrl: row.inviteUrl } : {};
717
717
  }
718
+ /** Give one of the project's people another role. Admins only. */
719
+ async function setCollaboratorRole(repositoryId, userId, role) {
720
+ await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/collaborators/${encodeURIComponent(userId)}`, { method: "PATCH", body: { role } });
721
+ }
722
+ /** Take somebody off the project. Admins only. */
723
+ async function removeCollaborator(repositoryId, userId) {
724
+ await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/collaborators/${encodeURIComponent(userId)}`, { method: "DELETE" });
725
+ }
726
+ /** Withdraw an invite nobody has accepted yet. */
727
+ async function revokeInvite(repositoryId, inviteId) {
728
+ await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" });
729
+ }
718
730
  /** Join a project from an invite link (or the token inside it). */
719
731
  async function acceptInvite(token) {
720
732
  return call("/v1/invites/accept", {
@@ -936,6 +948,26 @@ async function addWebhook(repositoryId, url, events) {
936
948
  async function removeWebhook(repositoryId, webhookId) {
937
949
  await call(`/v1/repositories/${encodeURIComponent(repositoryId)}/webhooks/${encodeURIComponent(webhookId)}`, { method: "DELETE" });
938
950
  }
951
+ const webhookRoute = (repositoryId, webhookId) => `/v1/repositories/${encodeURIComponent(repositoryId)}/webhooks/${encodeURIComponent(webhookId)}`;
952
+ /** Which events a webhook gets (empty is every one), or switch it back on. */
953
+ async function updateWebhook(repositoryId, webhookId, change) {
954
+ await call(webhookRoute(repositoryId, webhookId), { method: "PATCH", body: change });
955
+ }
956
+ /** The twenty most recent, newest first. */
957
+ async function webhookDeliveries(repositoryId, webhookId) {
958
+ const body = await call(`${webhookRoute(repositoryId, webhookId)}/deliveries`);
959
+ return body.deliveries ?? [];
960
+ }
961
+ /** Send a signed "ping" now and say how the receiver answered. */
962
+ async function testWebhook(repositoryId, webhookId) {
963
+ const body = await call(`${webhookRoute(repositoryId, webhookId)}/test`, { method: "POST" });
964
+ return body.delivery;
965
+ }
966
+ /** Send an earlier delivery's event again, as a new delivery. */
967
+ async function redeliverWebhook(repositoryId, webhookId, deliveryId) {
968
+ const body = await call(`${webhookRoute(repositoryId, webhookId)}/deliveries/${encodeURIComponent(deliveryId)}/redeliver`, { method: "POST" });
969
+ return body.delivery;
970
+ }
939
971
  /**
940
972
  * What would collide if this folder published right now.
941
973
  *