@coderook/cli 0.14.0 → 0.15.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/README.md CHANGED
@@ -122,36 +122,69 @@ it helps, raw where it does not, and a SHA-256 for every chunk and file.
122
122
  Extraction is verified and atomic — a damaged bundle fails rather than leaving
123
123
  a half-written tree.
124
124
 
125
- ## Claude Code and Codex
125
+ ## Claude Code
126
126
 
127
- CodeRook can be a tool your assistant uses while it works. Both speak the same
128
- protocol, so one server covers them.
127
+ ```
128
+ coderook skill
129
+ ```
130
+
131
+ That is the whole setup. It writes a short guide into Claude Code's skills
132
+ folder, and from then on you ask for what you want in ordinary words:
133
+
134
+ > save this to CodeRook
135
+
136
+ > what have I changed?
137
+
138
+ > what versions does this project have?
139
+
140
+ Claude works out which commands to run. You can also call it by name with
141
+ `/coderook`.
142
+
143
+ `coderook skill --project` writes it into `./.claude` instead of your home
144
+ folder, so it travels with the repository and everybody who clones it has it
145
+ too.
146
+
147
+ Sign in once per machine first — `coderook sign-in` — or set `CODEROOK_TOKEN`
148
+ in automation. The skill will not save anything without asking you first, and
149
+ never deletes.
150
+
151
+ ## A structured connection instead
152
+
153
+ The skill teaches Claude the command line, which needs no configuration. If you
154
+ would rather it had structured tools, there is an MCP server as well. It works
155
+ with Codex too, which is the reason it exists.
129
156
 
130
157
  Claude Code:
131
158
 
132
159
  ```
133
- claude mcp add coderook -- coderook mcp
160
+ claude mcp add --scope user coderook -- npx -y @coderook/cli mcp
134
161
  ```
135
162
 
136
163
  Codex, in `~/.codex/config.toml`:
137
164
 
138
165
  ```toml
139
166
  [mcp_servers.coderook]
140
- command = "coderook"
141
- args = ["mcp"]
167
+ command = "npx"
168
+ args = ["-y", "@coderook/cli", "mcp"]
142
169
  ```
143
170
 
144
- It offers five things, all of which read: your projects, a project's versions,
145
- the files in a version, one file's contents at a version, and what has changed
146
- in a local folder.
171
+ To share it with everyone on a project, commit this beside the code:
147
172
 
148
- It cannot save a version, delete anything, or sign in or out. That is
149
- deliberate — an assistant that goes wrong can waste your time but not your
150
- work, and saving stays something a person types. A project whose owner has
151
- turned off machine reading is refused in words rather than as a status code.
173
+ ```json
174
+ // .mcp.json
175
+ {
176
+ "mcpServers": {
177
+ "coderook": {
178
+ "command": "npx",
179
+ "args": ["-y", "@coderook/cli", "mcp"]
180
+ }
181
+ }
182
+ }
183
+ ```
152
184
 
153
- The server is launched by the assistant and exits with it; there is no reason
154
- to run `coderook mcp` by hand.
185
+ It offers five things, all of which read: your projects, a project's versions,
186
+ the files in a version, one file's contents at a version, and what has changed
187
+ in a local folder. It cannot save, delete, or sign in or out.
155
188
 
156
189
  ## Checking things
157
190
 
@@ -26,6 +26,7 @@ const progress_js_1 = require("./progress.js");
26
26
  const project_commands_js_1 = require("./project_commands.js");
27
27
  const track_commands_js_1 = require("./track_commands.js");
28
28
  const mcp_js_1 = require("./mcp.js");
29
+ const skill_command_js_1 = require("./skill_command.js");
29
30
  const service_commands_js_1 = require("./service_commands.js");
30
31
  const worktree_js_1 = require("../../desktop-app/src/main/worktree.js");
31
32
  const upload_js_1 = require("../../desktop-app/src/main/upload.js");
@@ -1444,6 +1445,38 @@ const SPECS = [
1444
1445
  examples: ["coderook runner my-game --labels windows,signing"],
1445
1446
  run: commandRunner,
1446
1447
  },
1448
+ {
1449
+ /*
1450
+ The other way to hand this to an assistant is a plugin marketplace,
1451
+ and marketplaces live in git repositories — an odd thing to require
1452
+ of people using a version host that is deliberately not git. A skill
1453
+ is a file in a folder, and this already knows where the folder is.
1454
+ */
1455
+ name: "skill",
1456
+ group: "Other",
1457
+ summary: "teach Claude Code about CodeRook",
1458
+ usage: "skill [--project]",
1459
+ detail: "Writes a short guide into Claude Code's skills folder, so it knows what\n" +
1460
+ "CodeRook is and how to drive it. After that you ask for it in words:\n" +
1461
+ "'save this to CodeRook', 'what changed?' — or run it by name with\n" +
1462
+ "/coderook.\n" +
1463
+ "\n" +
1464
+ "Personal by default, so it is there in every project on this machine.\n" +
1465
+ "--project writes it into ./.claude instead, where it travels with the\n" +
1466
+ "repository for everybody who clones it.\n" +
1467
+ "\n" +
1468
+ "It teaches the command line rather than the MCP server, because that\n" +
1469
+ "needs no configuration at all. `coderook mcp` is still there when a\n" +
1470
+ "structured connection is wanted.\n",
1471
+ options: [
1472
+ {
1473
+ flags: "--project",
1474
+ description: "install into this project rather than for you",
1475
+ },
1476
+ ],
1477
+ examples: ["coderook skill", "coderook skill --project"],
1478
+ run: skill_command_js_1.commandSkill,
1479
+ },
1447
1480
  {
1448
1481
  /*
1449
1482
  The assistants speak one protocol between them, so this is one server
@@ -1475,7 +1508,7 @@ const SPECS = [
1475
1508
  "A project whose owner has turned off machine reading is refused, in\n" +
1476
1509
  "words rather than as a status code.\n",
1477
1510
  examples: ["claude mcp add coderook -- coderook mcp"],
1478
- run: () => (0, mcp_js_1.commandMcp)(),
1511
+ run: () => (0, mcp_js_1.commandMcp)(VERSION),
1479
1512
  },
1480
1513
  {
1481
1514
  name: "doctor",
@@ -33,6 +33,15 @@ const api_js_1 = require("./api.js");
33
33
  const config_js_1 = require("./config.js");
34
34
  /** What the protocol calls itself. Both clients accept this revision. */
35
35
  const PROTOCOL_VERSION = "2024-11-05";
36
+ /*
37
+ What this build calls itself, handed in rather than written down here.
38
+
39
+ The first version carried a literal, which the CLI already learned not to
40
+ do: the comment beside its own VERSION says a hardcoded copy had drifted
41
+ from what was published. Mine drifted within one release — the server
42
+ announced 0.13.0 to Claude Code while the package was 0.14.0.
43
+ */
44
+ let serverVersion = "0.0.0";
36
45
  /** Beyond this a file is described rather than pasted into a conversation. */
37
46
  const READ_LIMIT = 256 * 1024;
38
47
  function text(value) {
@@ -269,7 +278,7 @@ async function handle(request) {
269
278
  reply(id, {
270
279
  protocolVersion: PROTOCOL_VERSION,
271
280
  capabilities: { tools: {} },
272
- serverInfo: { name: "coderook", version: node_process_1.default.env.CODEROOK_CLI_VERSION ?? "0.13.0" },
281
+ serverInfo: { name: "coderook", version: serverVersion },
273
282
  });
274
283
  return;
275
284
  }
@@ -321,7 +330,8 @@ async function handle(request) {
321
330
  * Buffered by line rather than by chunk, because a chunk boundary falls
322
331
  * wherever the pipe decides and a half-read message parses as nothing.
323
332
  */
324
- async function commandMcp() {
333
+ async function commandMcp(version) {
334
+ serverVersion = version;
325
335
  node_process_1.default.stdin.setEncoding("utf8");
326
336
  let buffer = "";
327
337
  await new Promise((done) => {
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * Teaching an assistant about CodeRook, in one command.
4
+ *
5
+ * The other route in is a plugin marketplace, and marketplaces live in git
6
+ * repositories — which is a strange thing to require of people using a version
7
+ * host that is deliberately not git, and stranger still when the recommended
8
+ * host is the one this product exists as an alternative to.
9
+ *
10
+ * A skill is a file in a folder. The command line is already installed and
11
+ * already knows where that folder is, so it writes it: no marketplace, no
12
+ * clone, no second account. `coderook skill` and the assistant knows what
13
+ * CodeRook is and how to drive it from then on, in every project.
14
+ *
15
+ * The skill teaches it the command line rather than the MCP server. Both work,
16
+ * but the command line needs no configuration at all — the assistant already
17
+ * has a shell, and a thing that works with nothing to set up is the thing most
18
+ * people should be offered first.
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.commandSkill = commandSkill;
25
+ const promises_1 = require("node:fs/promises");
26
+ const node_os_1 = __importDefault(require("node:os"));
27
+ const node_path_1 = __importDefault(require("node:path"));
28
+ const node_process_1 = __importDefault(require("node:process"));
29
+ const dim = (value) => `[2m${value}[0m`;
30
+ const bold = (value) => `[1m${value}[0m`;
31
+ const red = (value) => `[31m${value}[0m`;
32
+ const green = (value) => `[32m${value}[0m`;
33
+ const accent = (value) => `[33m${value}[0m`;
34
+ /**
35
+ * The skill as it ships, found relative to this file.
36
+ *
37
+ * Not read from the working directory, because the command is run from
38
+ * somebody's project and the file lives wherever npm put the package.
39
+ */
40
+ async function shipped() {
41
+ /*
42
+ `__dirname` rather than `import.meta.url`: this package compiles to
43
+ CommonJS, where the latter is not available and the build refuses it.
44
+ */
45
+ const here = __dirname;
46
+ /*
47
+ Compiled to dist/cli/src, so the package root is three levels up. Tried in
48
+ order rather than assumed, so running from source works as well as running
49
+ from an install.
50
+ */
51
+ const candidates = [
52
+ node_path_1.default.resolve(here, "../../../skills/coderook/SKILL.md"),
53
+ node_path_1.default.resolve(here, "../../skills/coderook/SKILL.md"),
54
+ node_path_1.default.resolve(here, "../skills/coderook/SKILL.md"),
55
+ ];
56
+ for (const candidate of candidates) {
57
+ try {
58
+ return await (0, promises_1.readFile)(candidate, "utf8");
59
+ }
60
+ catch {
61
+ /* try the next shape */
62
+ }
63
+ }
64
+ throw new Error("The skill file is missing from this installation.");
65
+ }
66
+ /**
67
+ * Where the assistant looks.
68
+ *
69
+ * Personal by default — somebody who installs this wants it in every project,
70
+ * not only the one they happened to be standing in. `--project` writes it
71
+ * beside the code instead, which is what to do when it should travel with the
72
+ * repository for everybody who clones it.
73
+ */
74
+ function destination(project) {
75
+ const root = project
76
+ ? node_path_1.default.join(node_process_1.default.cwd(), ".claude")
77
+ : node_path_1.default.join(node_os_1.default.homedir(), ".claude");
78
+ return node_path_1.default.join(root, "skills", "coderook", "SKILL.md");
79
+ }
80
+ async function commandSkill(parsed) {
81
+ const project = parsed.flags.has("project");
82
+ const target = destination(project);
83
+ let body;
84
+ try {
85
+ body = await shipped();
86
+ }
87
+ catch (error) {
88
+ console.error(red(error instanceof Error ? error.message : String(error)));
89
+ return 1;
90
+ }
91
+ /*
92
+ Overwritten without asking, because the file is ours and the only reason it
93
+ differs is that it is an older copy. Anything a person wrote themselves
94
+ belongs under a different name.
95
+ */
96
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(target), { recursive: true });
97
+ await (0, promises_1.writeFile)(target, body, "utf8");
98
+ console.log(green("Installed the CodeRook skill."));
99
+ console.log(dim(" ") + target);
100
+ console.log("");
101
+ console.log(project
102
+ ? dim("Everyone who opens this project in Claude Code now has it.")
103
+ : dim("Claude Code has it in every project on this machine."));
104
+ console.log("");
105
+ console.log(dim("Ask for it in words — ") + accent("“save this to CodeRook”"));
106
+ console.log(dim("or run it by name — ") + accent("/coderook"));
107
+ console.log("");
108
+ console.log(dim("Signed in? ") +
109
+ bold("coderook whoami") +
110
+ dim(" · if not: ") +
111
+ bold("coderook sign-in"));
112
+ return 0;
113
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderook/cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "CodeRook from the command line, on any operating system",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "homepage": "https://coderook.com",
@@ -20,7 +20,8 @@
20
20
  "coderook": "dist/cli/src/cli.js"
21
21
  },
22
22
  "files": [
23
- "dist"
23
+ "dist",
24
+ "skills"
24
25
  ],
25
26
  "scripts": {
26
27
  "build": "tsc -p tsconfig.json",
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: coderook
3
+ description: Save, browse and restore versions of a project on CodeRook — a version host where every version is a complete snapshot and there is no git to learn. Use when asked to save or submit work to CodeRook, check what has changed, look at a project's versions or files, fetch a project, start or switch a line of work, or resolve a save that landed at the same time as somebody else's.
4
+ allowed-tools: Bash Read
5
+ ---
6
+
7
+ # CodeRook
8
+
9
+ CodeRook stores whole snapshots of a folder. A version names every file the
10
+ project had at that moment, so restoring one never depends on the versions
11
+ around it, and there is no staging area, no branches to rebase and no history
12
+ to rewrite.
13
+
14
+ Everything here is the `coderook` command line. Run it with Bash.
15
+
16
+ ## Before anything else
17
+
18
+ `coderook whoami` says who this machine is signed in as. If it refuses, the
19
+ person needs to run `coderook sign-in` themselves — it takes a personal access
20
+ token, so do not attempt it on their behalf.
21
+
22
+ ## Reading
23
+
24
+ ```bash
25
+ coderook status # what has changed in this folder since its last version
26
+ coderook projects # every project on the account
27
+ coderook versions [project] # what has been saved, newest first
28
+ coderook tracks [project] # the lines a project has, and any waiting on a decision
29
+ ```
30
+
31
+ `status` is the one to reach for when somebody asks what is uncommitted, what
32
+ changed, or whether anything needs saving. It reads the folder and changes
33
+ nothing.
34
+
35
+ ## Saving
36
+
37
+ ```bash
38
+ coderook submit -m "What changed, in a sentence"
39
+ ```
40
+
41
+ Send only what changed; the version still names every file. Write the message
42
+ yourself from the actual diff rather than asking for one — a message like
43
+ "update" helps nobody reading the history later.
44
+
45
+ **Ask before running this.** Saving is the one thing here that leaves a mark on
46
+ somebody's account, and a version saved by mistake is a version they have to
47
+ explain. Propose it, say what it would send, and let them agree.
48
+
49
+ `coderook submit -n` shows exactly what would be sent without sending it. Use
50
+ that freely; it is safe and it is the honest way to answer "what would this
51
+ upload?".
52
+
53
+ ## Fetching
54
+
55
+ ```bash
56
+ coderook get # bring this folder up to date
57
+ coderook clone <project> [dir] # fetch a project into a new folder
58
+ ```
59
+
60
+ `get` protects local edits by default. `coderook get --replace` discards them
61
+ to make an exact copy — only run it when the person has said so in those terms.
62
+
63
+ ## Lines of work
64
+
65
+ A project can have more than one line, so two people can save without one
66
+ landing on top of the other.
67
+
68
+ ```bash
69
+ coderook track # which line this folder saves to
70
+ coderook track spike --new # start a line and switch to it
71
+ coderook track main # switch back
72
+ coderook submit --track spike -m "…"
73
+ ```
74
+
75
+ Switching says where the next save goes and nothing else — no files move.
76
+ Run `coderook get` afterwards to bring that line's files in.
77
+
78
+ ## When two saves collide
79
+
80
+ If somebody saved while this folder was behind, the second save becomes a merge
81
+ waiting on a decision rather than overwriting anything.
82
+
83
+ ```bash
84
+ coderook merges # this folder's saves waiting on a decision
85
+ coderook merge <ref> # look at one, and decide
86
+ ```
87
+
88
+ Read the conflict out to the person and let them choose. Do not pick a side for
89
+ them: the whole reason it stopped is that the service could not tell which copy
90
+ was wanted.
91
+
92
+ ## What is worth leaving out
93
+
94
+ ```bash
95
+ coderook ignore --suggest # dependency directories, build output, virtual environments
96
+ coderook ignore --suggest --apply # add the confident ones to .gitignore
97
+ ```
98
+
99
+ Rules live in the project's own `.gitignore`, so CodeRook, git and the website
100
+ all read one file.
101
+
102
+ ## Bundles
103
+
104
+ ```bash
105
+ coderook bundle . project.cbx # the whole project, every version, as one file
106
+ coderook inspect project.cbx # what is inside, without unpacking
107
+ coderook unbundle project.cbx ./restored
108
+ ```
109
+
110
+ ## Things not to do
111
+
112
+ - Do not run `coderook delete` unless the person has asked for that project to
113
+ be deleted, by name, in this conversation.
114
+ - Do not run `coderook sign-out`. It costs them a token they have to fetch
115
+ again and gains nothing.
116
+ - Do not guess a project name. `coderook projects` lists them; a folder that is
117
+ already linked needs no name at all.
118
+
119
+ ## If something refuses
120
+
121
+ The commands explain themselves — pass the message on rather than rewording it.
122
+ A refusal that says a token was not accepted means signing in; one that says a
123
+ project does not allow machines means its owner turned that off deliberately,
124
+ and the answer is to say so, not to find another route in.