@coderook/cli 0.31.9 → 0.31.10
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 +58 -4
- package/dist/cli/src/cli.js +32 -0
- package/dist/cli/src/config.js +21 -0
- package/dist/cli/src/project_commands.js +206 -0
- package/package.json +1 -1
- package/skills/coderook/SKILL.md +12 -0
|
@@ -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.10",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ACCA Gaming Productions",
|
|
8
8
|
"url": "https://coderook.com"
|
package/README.md
CHANGED
|
@@ -118,6 +118,50 @@ on a decision. `cbx merges` lists them and `cbx merge <ref>` walks
|
|
|
118
118
|
through it; `cbx tracks` shows them beside the ordinary lines, because
|
|
119
119
|
somebody looking for where they can save needs to see the one they cannot.
|
|
120
120
|
|
|
121
|
+
## Proposals
|
|
122
|
+
|
|
123
|
+
A line gets back to main by being proposed. The proposal is checked and
|
|
124
|
+
reviewed before it lands, and it follows the line: saving onto it afterwards
|
|
125
|
+
changes what is proposed rather than needing a second one.
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
cbx propose -m "Faster encoder" offer this folder's line to main
|
|
129
|
+
cbx proposals what is open (--all for the rest)
|
|
130
|
+
cbx merge M-3 look at one: reviews, checks, decisions
|
|
131
|
+
cbx merge M-3 --ask sam,priya ask people to review it
|
|
132
|
+
cbx merge M-3 --apply land it, once nothing is in the way
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`--into` proposes into a line other than main, and `--from` proposes a line
|
|
136
|
+
other than the one this folder is on. "Fixes #12" in the title or body closes
|
|
137
|
+
issue 12 when it lands. The same proposals are on the website's Merges page
|
|
138
|
+
and behind **propose** in the desktop application.
|
|
139
|
+
|
|
140
|
+
A line can require approvals, and an approval from whoever proposed it does
|
|
141
|
+
not count. Checks come from actions: `cbx actions --on-proposal Tests` runs
|
|
142
|
+
Tests whenever a line is proposed or saved onto, and its result is a required
|
|
143
|
+
check. `--on-save` runs an action on every save, and `--by-hand` only when
|
|
144
|
+
somebody starts it.
|
|
145
|
+
|
|
146
|
+
A **protected** line refuses saves made straight onto it — from `cbx submit`,
|
|
147
|
+
the desktop application and `git push` alike — so the way in is a line of your
|
|
148
|
+
own and a proposal. It also cannot be put back on an earlier save, and a merge
|
|
149
|
+
cannot land on it over a conflict or a failing check.
|
|
150
|
+
|
|
151
|
+
## Who can reach a project
|
|
152
|
+
|
|
153
|
+
cbx visibility # what it is now, and what each level means
|
|
154
|
+
cbx visibility public # list it on your profile
|
|
155
|
+
cbx visibility unlisted my-project # link only: kept off your profile and out of search
|
|
156
|
+
cbx visibility private # back to you and the people you invite
|
|
157
|
+
|
|
158
|
+
Making a project public or unlisted asks first and says what becomes readable.
|
|
159
|
+
In a script there is nobody to ask, so pass `--yes` (or `-y`); without it the
|
|
160
|
+
command refuses rather than waiting. Going private never asks.
|
|
161
|
+
|
|
162
|
+
A public project's page offers only its named versions that have not been
|
|
163
|
+
hidden (see `cbx promote` and `cbx mark --hide`).
|
|
164
|
+
|
|
121
165
|
## Ignore rules
|
|
122
166
|
|
|
123
167
|
```
|
|
@@ -141,6 +185,11 @@ and the desktop application all read one file. A `!` line puts something back.
|
|
|
141
185
|
Personal exclusions that should not reach a collaborator belong in
|
|
142
186
|
`.git/info/exclude`.
|
|
143
187
|
|
|
188
|
+
In a git repository, a file git already tracks is sent even if a rule matches
|
|
189
|
+
it — the same exception git makes, so a broad rule written after the fact does
|
|
190
|
+
not quietly drop committed source. Git's own `.git` directory is never sent,
|
|
191
|
+
and the service refuses a save with any path inside one.
|
|
192
|
+
|
|
144
193
|
## Moving a repository here
|
|
145
194
|
|
|
146
195
|
`cbx import` takes a snapshot — the files as they are now, one version, no
|
|
@@ -167,7 +216,7 @@ exists.
|
|
|
167
216
|
|
|
168
217
|
The project is created **private** whatever the source was — publishing
|
|
169
218
|
somebody's code as a side effect of moving it is not recoverable. Pass
|
|
170
|
-
`--visibility same` to mirror the source, or `--public`.
|
|
219
|
+
`--visibility same` to mirror the source, or `--visibility public`.
|
|
171
220
|
|
|
172
221
|
A private repository needs a read token in the environment — `GITHUB_TOKEN`,
|
|
173
222
|
`GITLAB_TOKEN` or `FORGE_TOKEN`. It is never taken as a flag, never stored,
|
|
@@ -254,7 +303,8 @@ second implementation of them that happens to agree.
|
|
|
254
303
|
|
|
255
304
|
**What does not appear on that list**, because git has no such idea and
|
|
256
305
|
inventing one would be pretending: `projects`, `delete`, `people`, `watch`,
|
|
257
|
-
`issues`, `
|
|
306
|
+
`issues`, `propose`, `proposals`, `actions`, `runs`, `logs`, `runner`,
|
|
307
|
+
`tokens`, `licence`, `ai`. Use
|
|
258
308
|
them by name; nothing about them changes when a version arrives through git.
|
|
259
309
|
|
|
260
310
|
`git commit` has no CodeRook equivalent either, and should not: it is local to
|
|
@@ -278,9 +328,13 @@ deliberately *not* used, since nobody wrote it about the release.
|
|
|
278
328
|
|
|
279
329
|
Cloning reverses it: every release comes back as a tag on the right commit.
|
|
280
330
|
|
|
331
|
+
From the command line, `cbx release v1.0` names the newest save the same way,
|
|
332
|
+
and `cbx notes 41 --edit` writes its release notes.
|
|
333
|
+
|
|
281
334
|
Assets are separate and unaffected. They attach to a version from a run's
|
|
282
|
-
artifacts
|
|
283
|
-
adds them — which is what a release without a
|
|
335
|
+
artifacts or with `cbx attach <file>`, so a release made by pushing a tag
|
|
336
|
+
simply has none until something adds them — which is what a release without a
|
|
337
|
+
build has always looked like.
|
|
284
338
|
|
|
285
339
|
## Bundles
|
|
286
340
|
|
package/dist/cli/src/cli.js
CHANGED
|
@@ -2267,6 +2267,36 @@ const SPECS = [
|
|
|
2267
2267
|
],
|
|
2268
2268
|
run: project_commands_js_1.commandAi,
|
|
2269
2269
|
},
|
|
2270
|
+
{
|
|
2271
|
+
/*
|
|
2272
|
+
Not `publish`, which already reaches `submit` and would read as a
|
|
2273
|
+
release. This is who can reach the project, and it is named for that.
|
|
2274
|
+
*/
|
|
2275
|
+
name: "visibility",
|
|
2276
|
+
group: "Your projects",
|
|
2277
|
+
summary: "who can reach a project: private, link only or public",
|
|
2278
|
+
usage: "visibility [level] [project]",
|
|
2279
|
+
detail: "The level is public, unlisted or private. With none, says what the\n" +
|
|
2280
|
+
"project is set to now.\n\n" +
|
|
2281
|
+
"Private is you and the people you invite. Unlisted, which the website\n" +
|
|
2282
|
+
"calls link only, keeps it off your profile and out of search. Public\n" +
|
|
2283
|
+
"lists it on your profile, and its page offers the saves somebody named\n" +
|
|
2284
|
+
"and did not hide.\n\n" +
|
|
2285
|
+
"Opening a project up asks first and says what becomes readable: any\n" +
|
|
2286
|
+
"account signed in to CodeRook that has its link can open every save\n" +
|
|
2287
|
+
"through the API, not only the named versions. Going private asks\n" +
|
|
2288
|
+
"nothing.",
|
|
2289
|
+
options: [
|
|
2290
|
+
{ flags: "-y, --yes", description: "open it up without asking, for scripts" },
|
|
2291
|
+
],
|
|
2292
|
+
examples: [
|
|
2293
|
+
"cbx visibility",
|
|
2294
|
+
"cbx visibility public",
|
|
2295
|
+
"cbx visibility unlisted my-project --yes",
|
|
2296
|
+
"cbx visibility private my-project",
|
|
2297
|
+
],
|
|
2298
|
+
run: project_commands_js_1.commandVisibility,
|
|
2299
|
+
},
|
|
2270
2300
|
{
|
|
2271
2301
|
name: "issues",
|
|
2272
2302
|
group: "Your projects",
|
|
@@ -2715,6 +2745,8 @@ const SPECS = [
|
|
|
2715
2745
|
{ flags: "--theirs", description: "keep theirs" },
|
|
2716
2746
|
{ flags: "--both", description: "keep both" },
|
|
2717
2747
|
{ flags: "--drop", description: "abandon the upload" },
|
|
2748
|
+
{ flags: "--path <file>", description: "decide one file rather than every one outstanding" },
|
|
2749
|
+
{ flags: "--cancel", description: "call the merge off; your upload stays stored" },
|
|
2718
2750
|
{ flags: "--ask <usernames>", description: "ask people to review it, comma separated" },
|
|
2719
2751
|
],
|
|
2720
2752
|
run: commandMerge,
|
package/dist/cli/src/config.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DamagedLinkError = exports.credentials = exports.DEFAULT_API = void 0;
|
|
7
7
|
exports.apiOrigin = apiOrigin;
|
|
8
|
+
exports.siteOrigin = siteOrigin;
|
|
8
9
|
exports.configDirectory = configDirectory;
|
|
9
10
|
exports.storeToken = storeToken;
|
|
10
11
|
exports.loadToken = loadToken;
|
|
@@ -33,6 +34,26 @@ exports.DEFAULT_API = "https://api.coderook.com";
|
|
|
33
34
|
function apiOrigin() {
|
|
34
35
|
return (process.env.CODEROOK_API_URL || exports.DEFAULT_API).replace(/\/+$/, "");
|
|
35
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The website that goes with the service, for a link somebody can open.
|
|
39
|
+
*
|
|
40
|
+
* Derived rather than configured: the service answers on `api.` in front of
|
|
41
|
+
* the site's own host, so taking that off gives the address people use. A
|
|
42
|
+
* service anywhere else — a local one on a port — has no site this can name,
|
|
43
|
+
* and null says so rather than printing a link that goes nowhere.
|
|
44
|
+
*/
|
|
45
|
+
function siteOrigin(api = apiOrigin()) {
|
|
46
|
+
try {
|
|
47
|
+
const url = new URL(api);
|
|
48
|
+
if (!url.hostname.startsWith("api."))
|
|
49
|
+
return null;
|
|
50
|
+
url.hostname = url.hostname.slice("api.".length);
|
|
51
|
+
return url.origin;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
36
57
|
/** The per-user configuration directory, per platform convention. */
|
|
37
58
|
function configDirectory() {
|
|
38
59
|
if (process.env.CODEROOK_CONFIG_DIR)
|
|
@@ -14,8 +14,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.resolveProject = resolveProject;
|
|
16
16
|
exports.commandAi = commandAi;
|
|
17
|
+
exports.readLevel = readLevel;
|
|
18
|
+
exports.splitVisibility = splitVisibility;
|
|
19
|
+
exports.offeredPublicly = offeredPublicly;
|
|
20
|
+
exports.commandVisibility = commandVisibility;
|
|
17
21
|
exports.commandVersions = commandVersions;
|
|
18
22
|
const node_process_1 = __importDefault(require("node:process"));
|
|
23
|
+
const promises_1 = require("node:readline/promises");
|
|
19
24
|
const api_js_1 = require("./api.js");
|
|
20
25
|
const config_js_1 = require("./config.js");
|
|
21
26
|
const dim = (value) => `[2m${value}[0m`;
|
|
@@ -121,6 +126,207 @@ async function commandAi(parsed) {
|
|
|
121
126
|
console.log(dim("one that refuses model training."));
|
|
122
127
|
return 0;
|
|
123
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Who can reach a project, in the order the site shows them.
|
|
131
|
+
*
|
|
132
|
+
* The service calls the middle one `unlisted` and the website calls it "Link
|
|
133
|
+
* only"; both are accepted, and the prose uses the website's words.
|
|
134
|
+
*/
|
|
135
|
+
const LEVELS = [
|
|
136
|
+
["private", "private", "you and the people you invite"],
|
|
137
|
+
[
|
|
138
|
+
"unlisted",
|
|
139
|
+
"link only",
|
|
140
|
+
"not listed anywhere; any account signed in with its link can read it",
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
"public",
|
|
144
|
+
"public",
|
|
145
|
+
"listed on your profile and in search; its page offers the named versions",
|
|
146
|
+
],
|
|
147
|
+
];
|
|
148
|
+
const wordFor = (level) => LEVELS.find(([name]) => name === level)?.[1] ?? level;
|
|
149
|
+
/** A typed word as a level, or null when it is not one. */
|
|
150
|
+
function readLevel(word) {
|
|
151
|
+
const text = (word ?? "").trim().toLowerCase();
|
|
152
|
+
if (text === "link" || text === "link-only")
|
|
153
|
+
return "unlisted";
|
|
154
|
+
const found = LEVELS.find(([name]) => name === text);
|
|
155
|
+
return found ? found[0] : null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* `[level] [project]`, both optional.
|
|
159
|
+
*
|
|
160
|
+
* The level is recognised by being one, so `cbx visibility my-project` asks
|
|
161
|
+
* and `cbx visibility public` changes. Two words where the first is not a
|
|
162
|
+
* level is a mistyped level rather than a project, and is said so — reading
|
|
163
|
+
* it as a project would answer "no project matching" to somebody who typed
|
|
164
|
+
* "pubic".
|
|
165
|
+
*/
|
|
166
|
+
function splitVisibility(positional) {
|
|
167
|
+
const [first, second] = positional;
|
|
168
|
+
const level = readLevel(first);
|
|
169
|
+
if (level)
|
|
170
|
+
return { level, project: second };
|
|
171
|
+
if (second !== undefined) {
|
|
172
|
+
return {
|
|
173
|
+
error: `"${first}" is not a visibility. Pick public, unlisted or private.`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
return { project: first };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The versions a public page offers, by the service's own rule.
|
|
180
|
+
*
|
|
181
|
+
* Named, not hidden, finished arriving and not taken down — the four things
|
|
182
|
+
* `public_rule.ts` asks. Counted here so the question before a project goes
|
|
183
|
+
* public can say what the page will show rather than describe it.
|
|
184
|
+
*/
|
|
185
|
+
function offeredPublicly(saved) {
|
|
186
|
+
return saved.filter((one) => Boolean(one.name) &&
|
|
187
|
+
one.visibility === "public" &&
|
|
188
|
+
one.state === "verified" &&
|
|
189
|
+
!one.removedAt);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The public page's address, once it answers.
|
|
193
|
+
*
|
|
194
|
+
* Asked of the service rather than assembled, because the page lives under
|
|
195
|
+
* the owner's name and the owner is not always the person running this — a
|
|
196
|
+
* collaborator can open up somebody else's project. A link is printed only
|
|
197
|
+
* when the public side has confirmed it is the same project.
|
|
198
|
+
*/
|
|
199
|
+
async function publicAddress(project) {
|
|
200
|
+
const site = (0, config_js_1.siteOrigin)();
|
|
201
|
+
if (!site)
|
|
202
|
+
return null;
|
|
203
|
+
const me = await (0, api_js_1.whoami)().catch(() => null);
|
|
204
|
+
if (!me?.username)
|
|
205
|
+
return null;
|
|
206
|
+
const found = await (0, api_js_1.findPublicProject)(me.username, project.slug);
|
|
207
|
+
if (found?.id !== project.id)
|
|
208
|
+
return null;
|
|
209
|
+
return `${site}/${encodeURIComponent(me.username)}/${encodeURIComponent(project.slug)}`;
|
|
210
|
+
}
|
|
211
|
+
/** A plain yes or no, where anything but yes is no. */
|
|
212
|
+
async function agreed(question) {
|
|
213
|
+
const prompt = (0, promises_1.createInterface)({
|
|
214
|
+
input: node_process_1.default.stdin,
|
|
215
|
+
output: node_process_1.default.stdout,
|
|
216
|
+
});
|
|
217
|
+
const typed = await prompt.question(question);
|
|
218
|
+
prompt.close();
|
|
219
|
+
return /^y(es)?$/i.test(typed.trim());
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Show or change who can reach a project.
|
|
223
|
+
*
|
|
224
|
+
* Opening one up asks first and says what becomes readable, because that is
|
|
225
|
+
* the step that cannot be taken back — somebody may already have read it by
|
|
226
|
+
* the time it is private again. Closing one asks nothing: it takes nothing
|
|
227
|
+
* from anybody who should have it.
|
|
228
|
+
*/
|
|
229
|
+
async function commandVisibility(parsed) {
|
|
230
|
+
const asked = splitVisibility(parsed.positional);
|
|
231
|
+
if (asked.error) {
|
|
232
|
+
console.error(red(asked.error));
|
|
233
|
+
return 1;
|
|
234
|
+
}
|
|
235
|
+
const project = await resolveProject(asked.project);
|
|
236
|
+
if (!project)
|
|
237
|
+
return 1;
|
|
238
|
+
const current = readLevel(project.visibility) ?? "private";
|
|
239
|
+
if (!asked.level) {
|
|
240
|
+
console.log(`${bold(project.name)} is ${accent(wordFor(current))}.`);
|
|
241
|
+
for (const [level, , meaning] of LEVELS) {
|
|
242
|
+
const mark = level === current ? accent("›") : " ";
|
|
243
|
+
console.log(` ${mark} ${level.padEnd(9)} ${dim(meaning)}`);
|
|
244
|
+
}
|
|
245
|
+
if (current === "public") {
|
|
246
|
+
const address = await publicAddress(project);
|
|
247
|
+
if (address)
|
|
248
|
+
console.log(`\n ${address}`);
|
|
249
|
+
}
|
|
250
|
+
console.log("");
|
|
251
|
+
console.log(dim(`Change it with: cbx visibility <level>` +
|
|
252
|
+
(asked.project ? ` ${asked.project}` : "")));
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
255
|
+
const target = asked.level;
|
|
256
|
+
if (target === current) {
|
|
257
|
+
const address = target === "public" ? await publicAddress(project) : null;
|
|
258
|
+
console.log(`${project.name} is already ${wordFor(target)}` +
|
|
259
|
+
(address ? `: ${address}` : "."));
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
const sure = parsed.flags.get("yes") === true || parsed.flags.get("y") === true;
|
|
263
|
+
const asking = target !== "private" && !sure;
|
|
264
|
+
/*
|
|
265
|
+
Refused rather than asked when nobody can answer. A prompt on a pipe
|
|
266
|
+
either hangs a script for ever or reads an empty line as no, and neither
|
|
267
|
+
tells whoever wrote the script what to do about it.
|
|
268
|
+
*/
|
|
269
|
+
if (asking && !node_process_1.default.stdin.isTTY) {
|
|
270
|
+
console.error(red(`Making ${project.name} ${wordFor(target)} needs a yes, and nobody is here to give one.`));
|
|
271
|
+
console.error(dim(" Run it in a terminal to be asked, or add --yes."));
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
const offered = target === "public" ? offeredPublicly(await (0, api_js_1.versions)(project.id)) : [];
|
|
275
|
+
if (asking) {
|
|
276
|
+
if (target === "public") {
|
|
277
|
+
console.log(`Making ${bold(project.name)} public lists it on your profile and in search.`);
|
|
278
|
+
if (offered.length) {
|
|
279
|
+
const names = offered.slice(0, 5).map((one) => one.name).join(", ");
|
|
280
|
+
const more = offered.length > 5 ? ` and ${offered.length - 5} more` : "";
|
|
281
|
+
console.log(` Its page offers ${offered.length} named version${offered.length === 1 ? "" : "s"}: ${names}${more}.`);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
console.log(" Its page will be empty until a save is named — cbx promote does that.");
|
|
285
|
+
}
|
|
286
|
+
console.log(dim(" Saves nobody named, and versions you hid, are not on the page."));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
console.log(`Making ${bold(project.name)} link only keeps it off your profile and out of search.`);
|
|
290
|
+
}
|
|
291
|
+
/*
|
|
292
|
+
Said because it is true today, not because it is the design. The public
|
|
293
|
+
page follows the named-versions rule; the signed-in routes let any
|
|
294
|
+
account read an unlisted or public project whole, commits and hidden
|
|
295
|
+
versions included. Somebody deciding whether to open a project up
|
|
296
|
+
should be deciding about that.
|
|
297
|
+
*/
|
|
298
|
+
console.log(dim(" Any account signed in to CodeRook that has its link can open every save\n" +
|
|
299
|
+
" through the API, not only the named versions. Check the history holds\n" +
|
|
300
|
+
" nothing you would not share."));
|
|
301
|
+
if (!(await agreed(`Make ${project.name} ${wordFor(target)}? [y/N] `))) {
|
|
302
|
+
console.log(dim(`Nothing changed. ${project.name} is still ${wordFor(current)}.`));
|
|
303
|
+
return 1;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
await (0, api_js_1.updateProject)(project.id, { visibility: target });
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
console.error(red(error instanceof Error ? error.message : String(error)));
|
|
311
|
+
return 1;
|
|
312
|
+
}
|
|
313
|
+
if (target === "public") {
|
|
314
|
+
const address = await publicAddress(project);
|
|
315
|
+
console.log(green(`${project.name} is now public`) + (address ? `: ${address}` : "."));
|
|
316
|
+
console.log(dim(offered.length
|
|
317
|
+
? ` Its page offers ${offered.length} named version${offered.length === 1 ? "" : "s"}.`
|
|
318
|
+
: " Its page is empty until a save is named — cbx promote does that."));
|
|
319
|
+
}
|
|
320
|
+
else if (target === "unlisted") {
|
|
321
|
+
console.log(green(`${project.name} is now link only.`));
|
|
322
|
+
console.log(dim(" It is not listed anywhere; any account signed in with its link can read it."));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
console.log(green(`${project.name} is now private.`));
|
|
326
|
+
console.log(dim(" Only you and the people you invite can reach it."));
|
|
327
|
+
}
|
|
328
|
+
return 0;
|
|
329
|
+
}
|
|
124
330
|
/** Every saved version of a project, newest first. */
|
|
125
331
|
async function commandVersions(parsed) {
|
|
126
332
|
const project = await resolveProject(parsed.positional[0]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderook/cli",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.10",
|
|
4
4
|
"description": "The command line for CodeRook (coderook.com): version control and project hosting for projects of any size. Every save is a compressed snapshot, private or public, never used to train AI.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"homepage": "https://coderook.com",
|
package/skills/coderook/SKILL.md
CHANGED
|
@@ -103,6 +103,18 @@ project standing on it, so the next person to pull still lands on the mistake.
|
|
|
103
103
|
**Ask before `undo`, `promote` and `take-down`.** They change what other
|
|
104
104
|
people see. `cbx versions` first, so the person can say which save they mean.
|
|
105
105
|
|
|
106
|
+
## Who can reach a project
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cbx visibility # what it is now: private, unlisted or public
|
|
110
|
+
cbx visibility public --yes # list it on the owner's profile
|
|
111
|
+
cbx visibility private # back to the people invited
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Never make a project public or unlisted unless the person has asked for
|
|
115
|
+
exactly that.** `--yes` skips the question the command would otherwise ask
|
|
116
|
+
them, so only pass it once they have answered it. Going private is always safe.
|
|
117
|
+
|
|
106
118
|
## When two saves collide
|
|
107
119
|
|
|
108
120
|
If somebody saved while this folder was behind, the second save becomes a merge
|