@coderook/cli 0.34.11 → 0.36.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/.claude-plugin/plugin.json +1 -1
- package/README.md +71 -0
- package/dist/cbx/src/core/worktree.js +29 -2
- package/dist/cli/src/api.js +16 -0
- package/dist/cli/src/cli.js +97 -0
- package/dist/cli/src/github_bridge.js +403 -0
- package/dist/cli/src/mods_command.js +518 -0
- package/dist/cli/src/zip_writer.js +188 -0
- package/package.json +1 -1
- package/skills/coderook/SKILL.md +45 -1
|
@@ -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.
|
|
5
|
+
"version": "0.36.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ACCA Gaming Productions",
|
|
8
8
|
"url": "https://coderook.com"
|
package/README.md
CHANGED
|
@@ -194,6 +194,33 @@ Tests whenever a line is proposed or saved onto, and its result is a required
|
|
|
194
194
|
check. `--on-save` runs an action on every save, and `--by-hand` only when
|
|
195
195
|
somebody starts it.
|
|
196
196
|
|
|
197
|
+
Every proposal also has a `coderook/malware` check: what the line adds or
|
|
198
|
+
changes is scanned before it can land, and a finding names the file and stops
|
|
199
|
+
the proposal being applied.
|
|
200
|
+
|
|
201
|
+
### Reviewing proposals on GitHub
|
|
202
|
+
|
|
203
|
+
CodeRabbit, Blacksmith and most CI only connect to GitHub, so `cbx github`
|
|
204
|
+
keeps a GitHub repository as a mirror: each open proposal becomes a pull
|
|
205
|
+
request there, whatever is installed on it reviews and builds it, and the
|
|
206
|
+
results come back to the proposal as checks (`github/<check>`,
|
|
207
|
+
`review/<reviewer>`).
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
cbx github setup my-name/my-game-mirror token, secret, workflow
|
|
211
|
+
cbx submit save the workflow into the project
|
|
212
|
+
cbx github sync --repo my-name/my-game-mirror mirror once from here
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
`setup` makes a token that reaches this project only and can only read it and
|
|
216
|
+
report checks, stores it as the repository's `CODEROOK_TOKEN` secret (with the
|
|
217
|
+
GitHub CLI; otherwise it prints it once), and writes
|
|
218
|
+
`.github/workflows/coderook-bridge.yml`, which then runs on GitHub every ten
|
|
219
|
+
minutes. Add `CODEROOK_BRIDGE_PUSH`, a fine-grained GitHub token with Contents
|
|
220
|
+
and Pull requests read and write: GitHub's own workflow token cannot start
|
|
221
|
+
other workflows, so CI would never run. Results are advice unless named in
|
|
222
|
+
`CODEROOK_REQUIRED` (or `--required`). Use a repository nothing else pushes to.
|
|
223
|
+
|
|
197
224
|
A **protected** line refuses saves made straight onto it — from `cbx submit`,
|
|
198
225
|
the desktop application and `git push` alike — so the way in is a line of your
|
|
199
226
|
own and a proposal. It also cannot be put back on an earlier save, and a merge
|
|
@@ -452,6 +479,10 @@ no need for a second project that only holds releases. `--downloads private`
|
|
|
452
479
|
takes them back. Without a release name it changes an existing release and
|
|
453
480
|
leaves its notes alone.
|
|
454
481
|
|
|
482
|
+
Every attached file is scanned for malware before anybody outside the project
|
|
483
|
+
can download it, usually within a minute; one that fails is never offered, and
|
|
484
|
+
whoever attached it and the owner are told what was found.
|
|
485
|
+
|
|
455
486
|
`cbx releases` marks each one `public`, `downloads public` or `private`, and
|
|
456
487
|
for a public project prints the addresses an app or a script reads, which
|
|
457
488
|
need no account:
|
|
@@ -462,6 +493,46 @@ https://api.coderook.com/v1/public/projects/OWNER/SLUG/releases
|
|
|
462
493
|
https://api.coderook.com/v1/public/projects/OWNER/SLUG/updates electron-updater's generic provider
|
|
463
494
|
```
|
|
464
495
|
|
|
496
|
+
## Mod repositories for games
|
|
497
|
+
|
|
498
|
+
A mod repository is where a game's players get mods from. The game's maker
|
|
499
|
+
sets one up and its rules; modders publish with their own accounts; nothing is
|
|
500
|
+
listed until it passes those rules and a malware scan.
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
cbx mods create my-game --name "My Game" --allow .png,.ogg,.json --nested .pak
|
|
504
|
+
cbx mods builds my-game --new a build secret for the game, shown once
|
|
505
|
+
cbx mods builds my-game --register secret.bin or your own, never printed
|
|
506
|
+
cbx mods info my-game the address and public key to pin
|
|
507
|
+
cbx mods settings my-game --uploads owner change the rules
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Rules: `--allow` and `--block` for file types (programs and scripts such as
|
|
511
|
+
`.exe`, `.dll`, `.ps1` and `.js` are refused in every repository, and so is a
|
|
512
|
+
file that is really a program whatever it is called), `--nested` for archive
|
|
513
|
+
types that are opened and checked too, `--manifest` and `--fields` for the
|
|
514
|
+
manifest each part carries (`mod.json` by default) and which of its fields must
|
|
515
|
+
match, `--max-part`, `--max-files`, `--max-parts` and `--max-ratio` for size,
|
|
516
|
+
and `--uploads anyone|owner`.
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
cbx mods publish ./BetterTrees --repo my-game zip, upload, wait for the checks
|
|
520
|
+
cbx mods publish ./HD-Art --repo my-game --part animals one part of a bigger mod
|
|
521
|
+
cbx mods list my-game your mods and how their checks went
|
|
522
|
+
cbx mods remove better-trees --repo my-game
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
`publish` reads the folder's manifest for the mod's id, name, folder and
|
|
526
|
+
version (`--id`, `--name`, `--folder` and `--version` override it), writes the
|
|
527
|
+
manifest the repository expects into the zip, uploads in pieces that are
|
|
528
|
+
retried, and waits up to 30 minutes for the result; `--no-wait` returns
|
|
529
|
+
straight away. A rejected part says what was wrong, file by file.
|
|
530
|
+
|
|
531
|
+
The owner also has `cbx mods reports`, `cbx mods block <username> --take-down`,
|
|
532
|
+
`cbx mods list --all`, `cbx mods remove --as-owner` and `cbx mods delete`.
|
|
533
|
+
How the game signs its requests and checks the catalogue is at
|
|
534
|
+
<https://coderook.com/docs#mod-repositories>.
|
|
535
|
+
|
|
465
536
|
## Building for every platform
|
|
466
537
|
|
|
467
538
|
```
|
|
@@ -1614,10 +1614,29 @@ const SECRET_SUFFIXES = [".pem", ".key", ".p12", ".pfx", ".keystore", ".jks"];
|
|
|
1614
1614
|
the answer be a rule — one line in .gitignore covers the lot, where a list
|
|
1615
1615
|
of the files inside it would go stale the moment the program ran again.
|
|
1616
1616
|
*/
|
|
1617
|
+
/** Chromium's disk cache: an index beside data_N blocks, Cache_Data, or the js/wasm code cache. */
|
|
1618
|
+
async function looksLikeBrowserCache(directory) {
|
|
1619
|
+
const names = new Set((await (0, promises_1.readdir)(directory).catch(() => [])).map((name) => name.toLowerCase()));
|
|
1620
|
+
if (names.has("cache_data") || names.has("index-dir"))
|
|
1621
|
+
return true;
|
|
1622
|
+
if (names.has("index") && names.has("data_0"))
|
|
1623
|
+
return true;
|
|
1624
|
+
return names.has("js") && names.has("wasm");
|
|
1625
|
+
}
|
|
1617
1626
|
const PRIVATE_DIRECTORIES = [
|
|
1618
1627
|
{
|
|
1619
|
-
match: /^(Local Storage|Session Storage|IndexedDB|Service Worker
|
|
1628
|
+
match: /^(Local Storage|Session Storage|IndexedDB|Service Worker)$/i,
|
|
1629
|
+
because: "a browser profile, which holds the sites you are signed in to",
|
|
1630
|
+
},
|
|
1631
|
+
/*
|
|
1632
|
+
"Cache" is also an ordinary name for source: FreeType keeps ftcache.c in
|
|
1633
|
+
`src/cache`, and a Godot checkout was refused as "a browser profile" for
|
|
1634
|
+
it. So these three only count when what is inside is a browser's cache.
|
|
1635
|
+
*/
|
|
1636
|
+
{
|
|
1637
|
+
match: /^(Cache|Code Cache|GPUCache)$/i,
|
|
1620
1638
|
because: "a browser profile, which holds the sites you are signed in to",
|
|
1639
|
+
inside: looksLikeBrowserCache,
|
|
1621
1640
|
},
|
|
1622
1641
|
{ match: /^\.wrangler$/i, because: "local service state, including emulated databases" },
|
|
1623
1642
|
{ match: /^\.aws$/i, because: "cloud credentials" },
|
|
@@ -1667,7 +1686,15 @@ async function detectPrivateDirectories(root) {
|
|
|
1667
1686
|
continue;
|
|
1668
1687
|
const full = node_path_1.default.join(directory, entry.name);
|
|
1669
1688
|
const relative = node_path_1.default.relative(root, full).split(node_path_1.default.sep).join("/");
|
|
1670
|
-
|
|
1689
|
+
let rule;
|
|
1690
|
+
for (const candidate of PRIVATE_DIRECTORIES) {
|
|
1691
|
+
if (!candidate.match.test(entry.name))
|
|
1692
|
+
continue;
|
|
1693
|
+
if (candidate.inside && !(await candidate.inside(full)))
|
|
1694
|
+
continue;
|
|
1695
|
+
rule = candidate;
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
1671
1698
|
if (rule) {
|
|
1672
1699
|
found.push({
|
|
1673
1700
|
path: relative,
|
package/dist/cli/src/api.js
CHANGED
|
@@ -45,6 +45,8 @@ exports.changeWorkflow = changeWorkflow;
|
|
|
45
45
|
exports.runs = runs;
|
|
46
46
|
exports.runLogs = runLogs;
|
|
47
47
|
exports.tokens = tokens;
|
|
48
|
+
exports.createToken = createToken;
|
|
49
|
+
exports.reportMergeCheck = reportMergeCheck;
|
|
48
50
|
exports.revokeToken = revokeToken;
|
|
49
51
|
exports.deleteProject = deleteProject;
|
|
50
52
|
exports.projectLabels = projectLabels;
|
|
@@ -806,6 +808,20 @@ async function tokens() {
|
|
|
806
808
|
createdAt: String(row.createdAt ?? ""),
|
|
807
809
|
}));
|
|
808
810
|
}
|
|
811
|
+
/** Make a token. Limited to one project when `repositoryId` is given; shown once. */
|
|
812
|
+
async function createToken(input) {
|
|
813
|
+
return call("/v1/account/tokens", {
|
|
814
|
+
method: "POST",
|
|
815
|
+
body: input,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
/** Say how a check on a proposal went; the same name again replaces it. */
|
|
819
|
+
async function reportMergeCheck(mergeTrackId, name, input) {
|
|
820
|
+
await call(`/v1/merge-tracks/${mergeTrackId}/checks/${encodeURIComponent(name)}`, {
|
|
821
|
+
method: "PUT",
|
|
822
|
+
body: input,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
809
825
|
async function revokeToken(tokenId) {
|
|
810
826
|
await call(`/v1/account/tokens/${encodeURIComponent(tokenId)}`, {
|
|
811
827
|
method: "DELETE",
|
package/dist/cli/src/cli.js
CHANGED
|
@@ -31,6 +31,8 @@ const attach_command_js_1 = require("./attach_command.js");
|
|
|
31
31
|
const build_command_js_1 = require("./build_command.js");
|
|
32
32
|
const node_check_js_1 = require("./node_check.js");
|
|
33
33
|
const pages_command_js_1 = require("./pages_command.js");
|
|
34
|
+
const mods_command_js_1 = require("./mods_command.js");
|
|
35
|
+
const github_bridge_js_1 = require("./github_bridge.js");
|
|
34
36
|
const project_commands_js_1 = require("./project_commands.js");
|
|
35
37
|
const track_commands_js_1 = require("./track_commands.js");
|
|
36
38
|
const tracks_js_1 = require("../../cbx/src/core/tracks.js");
|
|
@@ -2792,6 +2794,101 @@ const SPECS = [
|
|
|
2792
2794
|
],
|
|
2793
2795
|
run: pages_command_js_1.commandPages,
|
|
2794
2796
|
},
|
|
2797
|
+
{
|
|
2798
|
+
name: "github",
|
|
2799
|
+
group: "Your projects",
|
|
2800
|
+
summary: "review and test proposals with GitHub tools (CodeRabbit, Blacksmith, Actions)",
|
|
2801
|
+
usage: "github <setup|sync> …",
|
|
2802
|
+
detail: "Mirrors a project's open proposals to pull requests in a GitHub repository,\n" +
|
|
2803
|
+
"so tools that only connect to GitHub review and build them, and reports\n" +
|
|
2804
|
+
"what they conclude back to each proposal as checks. A required check that\n" +
|
|
2805
|
+
"fails stops the proposal being applied, like any other check.\n\n" +
|
|
2806
|
+
"It runs on GitHub, in a workflow setup writes into the project. CodeRook\n" +
|
|
2807
|
+
"never holds a GitHub credential; GitHub holds a CodeRook token that reaches\n" +
|
|
2808
|
+
"this project only and can read it and report checks, nothing else.\n\n" +
|
|
2809
|
+
" setup <owner>/<repo> [folder] make the token, write the workflow\n" +
|
|
2810
|
+
" sync [--repo <owner>/<repo>] mirror and report once (what the workflow runs)\n\n" +
|
|
2811
|
+
"Use a GitHub repository nothing else pushes to: the mirror only moves\n" +
|
|
2812
|
+
"forward, and a branch changed on GitHub is left alone and reported.",
|
|
2813
|
+
options: [
|
|
2814
|
+
{ flags: "--repo <owner/repo>", description: "sync: the GitHub repository (default: the one the workflow runs in)" },
|
|
2815
|
+
{ flags: "--project <slug>", description: "sync: the CodeRook project (default: this folder's)" },
|
|
2816
|
+
{ flags: "--required <names>", description: "checks that must pass, e.g. \"github/build,review/coderabbitai[bot]\"" },
|
|
2817
|
+
{ flags: "--force", description: "setup: write the workflow again" },
|
|
2818
|
+
],
|
|
2819
|
+
examples: [
|
|
2820
|
+
"cbx github setup my-name/my-game-mirror",
|
|
2821
|
+
"cbx submit",
|
|
2822
|
+
"cbx github sync --repo my-name/my-game-mirror",
|
|
2823
|
+
],
|
|
2824
|
+
run: github_bridge_js_1.commandGithub,
|
|
2825
|
+
},
|
|
2826
|
+
{
|
|
2827
|
+
name: "mods",
|
|
2828
|
+
group: "Your projects",
|
|
2829
|
+
summary: "mod repositories for games: set one up, publish to one",
|
|
2830
|
+
usage: "mods <create|repos|info|settings|builds|list|publish|remove|block|reports|delete> …",
|
|
2831
|
+
detail: "A mod repository is where a game's players get mods from. Its owner\n" +
|
|
2832
|
+
"sets the rules — which file types a mod may hold, archives opened and\n" +
|
|
2833
|
+
"checked too, the manifest each upload carries, size limits, and whether\n" +
|
|
2834
|
+
"anybody or only the owner may upload. Modders publish with their own\n" +
|
|
2835
|
+
"CodeRook accounts; nothing is listed until it passes the rules and a\n" +
|
|
2836
|
+
"malware scan, and anything that runs (.exe, .dll, scripts) is refused\n" +
|
|
2837
|
+
"in every repository. The game's client reads a catalogue signed with\n" +
|
|
2838
|
+
"the repository's own key: see coderook.com/docs#mod-repositories.\n\n" +
|
|
2839
|
+
" create <repo> --name \"Game\" set one up; prints its address and public key\n" +
|
|
2840
|
+
" repos the repositories you run\n" +
|
|
2841
|
+
" info <repo> a repository's rules, for anybody\n" +
|
|
2842
|
+
" settings <repo> [rules…] change the rules (owner)\n" +
|
|
2843
|
+
" builds <repo> game builds allowed to read it (owner)\n" +
|
|
2844
|
+
" publish <folder|zip> --repo <repo> upload a mod; waits for its checks\n" +
|
|
2845
|
+
" list <repo> [--all] your mods and how their checks went\n" +
|
|
2846
|
+
" remove <mod> --repo <repo> take a mod down\n" +
|
|
2847
|
+
" block <username> --repo <repo> stop an uploader (owner)\n" +
|
|
2848
|
+
" reports <repo> what players reported (owner)\n" +
|
|
2849
|
+
" delete <repo> delete a repository and everything in it",
|
|
2850
|
+
options: [
|
|
2851
|
+
{ flags: "--name <text>", description: "create/settings: the game's name" },
|
|
2852
|
+
{ flags: "--allow <exts>", description: "create/settings: file types a mod may hold, e.g. .png,.json" },
|
|
2853
|
+
{ flags: "--nested <exts>", description: "create/settings: archives inside a mod that are opened and checked too" },
|
|
2854
|
+
{ flags: "--manifest <file|none>", description: "create/settings: the manifest every part carries (default mod.json)" },
|
|
2855
|
+
{ flags: "--fields <list>", description: "create/settings: manifest fields that must match: id,name,folder,version" },
|
|
2856
|
+
{ flags: "--uploads <anyone|owner>", description: "create/settings: who may upload" },
|
|
2857
|
+
{ flags: "--max-part <size>", description: "create/settings: largest part, e.g. 2GB" },
|
|
2858
|
+
{ flags: "--register <file>", description: "builds: register the build secret in this file (never printed)" },
|
|
2859
|
+
{ flags: "--new", description: "builds: have the service make a build secret (shown once)" },
|
|
2860
|
+
{ flags: "--off <id>", description: "builds: turn a build off" },
|
|
2861
|
+
{ flags: "--repo <repo>", description: "publish/list/remove/block: which repository" },
|
|
2862
|
+
{ flags: "--part <id>", description: "publish: which part of the mod this is (default main)" },
|
|
2863
|
+
{ flags: "--id <mod>", description: "publish: the mod's id (default: manifest, then folder name)" },
|
|
2864
|
+
{ flags: "--version <v>", description: "publish: the mod's version" },
|
|
2865
|
+
{ flags: "--folder <name>", description: "publish: the folder the game installs it into" },
|
|
2866
|
+
{ flags: "--part-name <text>", description: "publish: a readable name for the part" },
|
|
2867
|
+
{ flags: "--about <text>", description: "create/settings/publish: a description" },
|
|
2868
|
+
{ flags: "--notice <text>", description: "publish: a notice shown with the mod (credits, licences)" },
|
|
2869
|
+
{ flags: "--block <exts>", description: "create/settings: more file types to refuse" },
|
|
2870
|
+
{ flags: "--max-files <n>", description: "create/settings: most files in a part" },
|
|
2871
|
+
{ flags: "--max-ratio <n>", description: "create/settings: how many times its size a part may unpack to" },
|
|
2872
|
+
{ flags: "--max-parts <n>", description: "create/settings: most parts in a mod" },
|
|
2873
|
+
{ flags: "--expires <date>", description: "builds: when a registered build stops working" },
|
|
2874
|
+
{ flags: "--all", description: "list: every mod in the repository (owner)" },
|
|
2875
|
+
{ flags: "--as-owner", description: "remove: as the repository's owner, any mod" },
|
|
2876
|
+
{ flags: "--disable", description: "settings: stop serving and taking uploads" },
|
|
2877
|
+
{ flags: "--enable", description: "settings: start again" },
|
|
2878
|
+
{ flags: "--undo", description: "block: let the uploader back in" },
|
|
2879
|
+
{ flags: "-y, --yes", description: "remove/delete: without asking" },
|
|
2880
|
+
{ flags: "--no-wait", description: "publish: do not wait for the checks" },
|
|
2881
|
+
{ flags: "--take-down", description: "block: also hide the uploader's mods" },
|
|
2882
|
+
],
|
|
2883
|
+
examples: [
|
|
2884
|
+
'cbx mods create my-game --name "My Game" --allow .png,.ogg,.json --nested .pak',
|
|
2885
|
+
"cbx mods builds my-game --register release/build-secret.bin",
|
|
2886
|
+
"cbx mods publish ./mods/BetterTrees --repo my-game",
|
|
2887
|
+
"cbx mods list my-game",
|
|
2888
|
+
"cbx mods publish ./HD-Art --repo zt1 --part animals",
|
|
2889
|
+
],
|
|
2890
|
+
run: mods_command_js_1.commandMods,
|
|
2891
|
+
},
|
|
2795
2892
|
{
|
|
2796
2893
|
name: "issues",
|
|
2797
2894
|
group: "Your projects",
|