@coderook/cli 0.25.0 → 0.25.1

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.25.0",
5
+ "version": "0.25.1",
6
6
  "author": {
7
7
  "name": "ACCA Gaming Productions",
8
8
  "url": "https://coderook.com"
package/README.md CHANGED
@@ -282,12 +282,14 @@ a half-written tree.
282
282
 
283
283
  ## Claude Code
284
284
 
285
- ```
285
+ Run this **in a terminal**, not inside Claude Code:
286
+
287
+ ```bash
286
288
  cbx skill
287
289
  ```
288
290
 
289
- That is the whole setup. It writes a short guide into Claude Code's skills
290
- folder, and from then on you ask for what you want in ordinary words:
291
+ That is the whole setup. It writes `~/.claude/skills/coderook/SKILL.md`, and
292
+ from then on you ask for what you want in ordinary words:
291
293
 
292
294
  > save this to CodeRook
293
295
 
@@ -298,6 +300,12 @@ folder, and from then on you ask for what you want in ordinary words:
298
300
  Claude works out which commands to run. You can also call it by name with
299
301
  `/coderook`.
300
302
 
303
+ **The skill is called `coderook`, not `cbx`.** `cbx` is the command line, run
304
+ in a terminal; the skill is the file that teaches Claude how to use it. Typing
305
+ `cbx skill` *into* Claude Code asks it for a skill by that name and it will
306
+ tell you there is not one — which is correct, and is why the line above says
307
+ where to run it.
308
+
301
309
  `cbx skill --project` writes it into `./.claude` instead of your home
302
310
  folder, so it travels with the repository and everybody who clones it has it
303
311
  too.
@@ -44,25 +44,13 @@ const api_js_2 = require("./api.js");
44
44
  const import_command_js_1 = require("./import_command.js");
45
45
  const runner_js_1 = require("./runner.js");
46
46
  const config_js_1 = require("./config.js");
47
- /*
48
- Read from the package rather than written twice. A hardcoded copy had
49
- already drifted from the published version, which makes `cbx doctor`
50
- worse than useless when working out what somebody is actually running.
51
- */
52
- const VERSION = (() => {
53
- try {
54
- return (require("../../../package.json").version ?? "0.0.0");
55
- }
56
- catch {
57
- return "0.0.0";
58
- }
59
- })();
47
+ const version_js_1 = require("./version.js");
60
48
  /*
61
49
  Said once, before anything reaches the service. The version comes from the
62
50
  package rather than a constant, so it cannot drift from what was published
63
51
  and claim a behaviour this build does not have.
64
52
  */
65
- (0, identify_js_1.declareClient)("cli", VERSION);
53
+ (0, identify_js_1.declareClient)("cli", version_js_1.VERSION);
66
54
  // ── presentation ────────────────────────────────────────────────────────────
67
55
  const colour = node_process_1.default.stdout.isTTY && !node_process_1.default.env.NO_COLOR;
68
56
  const dim = (text) => (colour ? `${text}` : text);
@@ -1205,7 +1193,7 @@ async function commandInspect(parsed) {
1205
1193
  }
1206
1194
  async function commandDoctor() {
1207
1195
  const service = await (0, api_js_2.health)().catch(() => null);
1208
- console.log(`cbx ${VERSION} · Node ${node_process_1.default.versions.node} · ${node_process_1.default.platform}`);
1196
+ console.log(`cbx ${version_js_1.VERSION} · Node ${node_process_1.default.versions.node} · ${node_process_1.default.platform}`);
1209
1197
  console.log(`Config: ${(0, config_js_1.configDirectory)()}`);
1210
1198
  console.log(service
1211
1199
  ? `Service: ${service.status} · schema ${service.schemaVersion}` +
@@ -1417,7 +1405,7 @@ async function commandRunner(parsed) {
1417
1405
  for (;;) {
1418
1406
  let job = null;
1419
1407
  try {
1420
- job = await (0, runner_js_1.claim)(project.id, name, VERSION, answersTo);
1408
+ job = await (0, runner_js_1.claim)(project.id, name, version_js_1.VERSION, answersTo);
1421
1409
  }
1422
1410
  catch (error) {
1423
1411
  /*
@@ -2040,7 +2028,7 @@ const SPECS = [
2040
2028
  "A project whose owner has turned off machine reading is refused, in\n" +
2041
2029
  "words rather than as a status code.\n",
2042
2030
  examples: ["claude mcp add coderook -- cbx mcp"],
2043
- run: () => (0, mcp_js_1.commandMcp)(VERSION),
2031
+ run: () => (0, mcp_js_1.commandMcp)(version_js_1.VERSION),
2044
2032
  },
2045
2033
  {
2046
2034
  name: "doctor",
@@ -2054,11 +2042,11 @@ const REGISTRY = (0, registry_js_1.buildRegistry)(SPECS);
2054
2042
  async function main(argv) {
2055
2043
  const [name, ...rest] = argv;
2056
2044
  if (!name || name === "--help" || name === "-h") {
2057
- console.log((0, help_js_1.renderHelp)(REGISTRY, VERSION));
2045
+ console.log((0, help_js_1.renderHelp)(REGISTRY, version_js_1.VERSION));
2058
2046
  return 0;
2059
2047
  }
2060
2048
  if (name === "--version" || name === "-v" || name === "version") {
2061
- console.log(VERSION);
2049
+ console.log(version_js_1.VERSION);
2062
2050
  return 0;
2063
2051
  }
2064
2052
  /*
@@ -2069,7 +2057,7 @@ async function main(argv) {
2069
2057
  if (name === "help") {
2070
2058
  const wanted = rest[0];
2071
2059
  if (!wanted) {
2072
- console.log((0, help_js_1.renderHelp)(REGISTRY, VERSION));
2060
+ console.log((0, help_js_1.renderHelp)(REGISTRY, version_js_1.VERSION));
2073
2061
  return 0;
2074
2062
  }
2075
2063
  const spec = REGISTRY.lookup.get(wanted);
@@ -10,7 +10,7 @@
10
10
  * is why this file exists at all.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.TRAILER = exports.EMPTY_TREE = void 0;
13
+ exports.MESSAGE_LIMIT = exports.TRAILER = exports.EMPTY_TREE = void 0;
14
14
  exports.parseRemoteUrl = parseRemoteUrl;
15
15
  exports.commitFromMessage = commitFromMessage;
16
16
  exports.messageWithCommit = messageWithCommit;
@@ -75,10 +75,47 @@ function commitFromMessage(message) {
75
75
  ];
76
76
  return all.length ? all[all.length - 1][1] : null;
77
77
  }
78
- /** Attach the marker to a commit message without disturbing what it says. */
78
+ /**
79
+ * What a version message may hold, matching the service.
80
+ *
81
+ * Not a guess and not a safety margin: the publish endpoint trims and then
82
+ * refuses anything longer, so exceeding it fails the whole push rather than
83
+ * being quietly shortened somewhere along the way.
84
+ */
85
+ exports.MESSAGE_LIMIT = 240;
86
+ /**
87
+ * Attach the marker to a commit message, within what the service will accept.
88
+ *
89
+ * The marker is not decoration — it is how a version is tied back to the
90
+ * commit it came from, and losing it means a later push republishes history
91
+ * the project already holds. So when the two together are too long, the
92
+ * message gives way and the marker survives.
93
+ *
94
+ * Git's own convention decides how: the first line is the summary and the rest
95
+ * is detail, so as much as fits is kept and the remainder is cut on a word
96
+ * boundary. A repository with a two-paragraph commit message would otherwise
97
+ * fail the push outright — which is what it did, on a real transfer, with an
98
+ * error naming a limit the person had never heard of.
99
+ */
79
100
  function messageWithCommit(message, sha) {
101
+ const trailer = `\n\n${exports.TRAILER} ${sha}`;
102
+ const room = exports.MESSAGE_LIMIT - trailer.length;
80
103
  const body = message.replace(/\s+$/, "");
81
- return `${body}\n\n${exports.TRAILER} ${sha}`;
104
+ if (body.length <= room)
105
+ return `${body}${trailer}`;
106
+ /*
107
+ Cut on a word boundary when one is reasonably near the end, so the result
108
+ reads as a shortened sentence rather than a severed one. The ellipsis is
109
+ what tells a reader there was more.
110
+ */
111
+ const kept = body.slice(0, room - 1);
112
+ const tidy = kept.replace(/\s+\S*$/, "");
113
+ const shortened = (tidy.length > room / 2 ? tidy : kept).trimEnd();
114
+ /*
115
+ A message of nothing but whitespace would leave an empty string, which the
116
+ service refuses for its own reason: it requires at least one character.
117
+ */
118
+ return `${shortened || sha.slice(0, 8)}…${trailer}`;
82
119
  }
83
120
  /**
84
121
  * The message as a person wrote it, with our bookkeeping taken back out.
@@ -106,6 +106,7 @@ const upload_js_1 = require("../../desktop-app/src/main/upload.js");
106
106
  const tracks_js_1 = require("../../desktop-app/src/main/tracks.js");
107
107
  const identify_js_1 = require("../../desktop-app/src/main/identify.js");
108
108
  const config_js_1 = require("./config.js");
109
+ const version_js_1 = require("./version.js");
109
110
  const publish_js_1 = require("./publish.js");
110
111
  const git_history_js_1 = require("./git_history.js");
111
112
  const api_js_1 = require("./api.js");
@@ -1080,7 +1081,14 @@ async function* lines() {
1080
1081
  }
1081
1082
  async function main(argv) {
1082
1083
  const url = argv[1] ?? argv[0] ?? "";
1083
- (0, identify_js_1.declareClient)("cli", "git-remote");
1084
+ /*
1085
+ The real version, not the word "git-remote". This passed its own name
1086
+ where the version belongs, so the service applied its version floor and
1087
+ refused to serve files — `git clone` failed with a demand to update to a
1088
+ release older than the one running. Push was unaffected, which is why it
1089
+ went unnoticed until a clone.
1090
+ */
1091
+ (0, identify_js_1.declareClient)("cli", version_js_1.VERSION);
1084
1092
  const pending = [];
1085
1093
  const importing = [];
1086
1094
  for await (const line of lines()) {
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.VERSION = void 0;
7
+ /**
8
+ * What this build calls itself to the service.
9
+ *
10
+ * Read from the package rather than written down, because a hardcoded copy had
11
+ * already drifted from the published version once — and the version is not
12
+ * cosmetic. The service refuses operations it knows an older client cannot do
13
+ * safely, so a build that misstates its version is refused as though it were
14
+ * ancient.
15
+ *
16
+ * Which is exactly what happened: the git remote helper announced itself as
17
+ * `cli/git-remote`, having passed its own name where the version belongs. The
18
+ * service could make nothing of it, applied the floor, and told people to
19
+ * update to a version far older than the one they were running. Pushing was
20
+ * unaffected and cloning was refused, so it surfaced only on the way back.
21
+ */
22
+ const node_fs_1 = require("node:fs");
23
+ const node_path_1 = __importDefault(require("node:path"));
24
+ /**
25
+ * Search upwards for this package's own manifest.
26
+ *
27
+ * A fixed number of `..` segments only holds for one directory layout. The
28
+ * compiled file sits three deep under `dist`, the source two deep under `src`,
29
+ * and a bundler may put it somewhere else again — so a fixed path silently
30
+ * resolved to a different package's manifest, or to none, and fell back to
31
+ * `0.0.0`. Walking up and checking the name finds the right file wherever
32
+ * this ends up.
33
+ */
34
+ function readVersion() {
35
+ /*
36
+ `__dirname` in the build, which compiles to CommonJS and is what ships.
37
+ Running the source directly for a test loads it as a module where that name
38
+ does not exist, so the check is on `typeof` — which is safe for a name that
39
+ was never declared — and the working directory stands in.
40
+ */
41
+ let here = typeof __dirname === "string" ? __dirname : process.cwd();
42
+ for (let up = 0; up < 6; up += 1) {
43
+ try {
44
+ const manifest = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(here, "package.json"), "utf8"));
45
+ if (manifest.name === "@coderook/cli" && manifest.version) {
46
+ return manifest.version;
47
+ }
48
+ }
49
+ catch {
50
+ // Not here, or not readable. Keep walking.
51
+ }
52
+ const parent = node_path_1.default.dirname(here);
53
+ if (parent === here)
54
+ break;
55
+ here = parent;
56
+ }
57
+ return "0.0.0";
58
+ }
59
+ exports.VERSION = readVersion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderook/cli",
3
- "version": "0.25.0",
3
+ "version": "0.25.1",
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",