bikeshed-now 0.4.1 → 0.5.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
@@ -61,6 +61,24 @@ bikeshed comments 'https://bikeshed.now/d/build-estimate?k=…'
61
61
  `bikeshed --help` lists the rest — listing documents, folders, and installing the
62
62
  agent skills a deployment serves.
63
63
 
64
+ ## Forking
65
+
66
+ To revise a document you can read but do not own, fork it. You get your own
67
+ private copy, at the version you name or the current one, and it remembers what
68
+ it was forked from.
69
+
70
+ ```bash
71
+ bikeshed fork 'https://bikeshed.now/d/build-estimate?k=…'
72
+ # forked build-estimate into build-estimate-x7k2p9 — https://bikeshed.now/d/build-estimate-x7k2p9
73
+ bikeshed lineage build-estimate-x7k2p9
74
+ # forked from build-estimate v3 Build estimate (changed since)
75
+ ```
76
+
77
+ `lineage` shows each original you can open, nearest first, and whether the
78
+ nearest has changed since you forked it. On a document you own it also counts
79
+ its forks. The author of what you fork sees that it was forked — a count, never
80
+ who.
81
+
64
82
  ## Sharing is not automated
65
83
 
66
84
  There is no command that shares a document, changes who can read it, or sets an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bikeshed-now",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "Publish and revise documents on a Bikeshed deployment from the terminal.",
package/src/client.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  import { readFileSync } from "node:fs";
5
5
  import { basename } from "node:path";
6
6
 
7
- export const CLIENT_NAME = "bikeshed-cli/0.4.1";
7
+ export const CLIENT_NAME = "bikeshed-cli/0.5.0";
8
8
 
9
9
  /**
10
10
  * Three surfaces, and the split is deliberate rather than untidy.
package/src/index.mjs CHANGED
@@ -39,6 +39,8 @@ const USAGE = `bikeshed — publish and revise documents
39
39
  bikeshed list documents you can read
40
40
  bikeshed publish <file> create a new document
41
41
  bikeshed update <id> <file> publish a new version
42
+ bikeshed fork <id> your own copy, which remembers its original
43
+ bikeshed lineage <id> what it was forked from; for its owner, its forks
42
44
  bikeshed get <id> print a document's source
43
45
  bikeshed comments <id> unresolved feedback, with its anchored text
44
46
  bikeshed reply <id> <thread> <text> reply in a thread
@@ -72,9 +74,10 @@ What you can publish
72
74
 
73
75
  Options
74
76
  --json machine-readable output
75
- --title <text> title for publish
77
+ --title <text> title for publish or fork (fork default: the original's)
76
78
  --id <id> with publish: the address, /d/<id> (default: from the title)
77
- --folder <id> destination folder for publish
79
+ --folder <id> destination folder for publish or fork
80
+ --version <v> with fork: the version to copy (default: current)
78
81
  --parent <id> parent folder for mkdir
79
82
  --limit <n> with list: rows per page (default 20, max 50)
80
83
  --cursor <id> with list: the page after the one that printed it
@@ -188,7 +191,8 @@ async function list(flags) {
188
191
  }
189
192
  for (const doc of result.documents) {
190
193
  const marker = doc.visibility === "private" ? " " : doc.visibility === "public" ? "◉" : "◐";
191
- console.log(`${marker} ${doc.id.padEnd(34)} ${doc.version.padEnd(5)} ${doc.title}`);
194
+ // ⑂ marks a fork; where it came from is `bikeshed lineage`'s to say.
195
+ console.log(`${marker} ${doc.id.padEnd(34)} ${doc.version.padEnd(5)} ${doc.title}${doc.forked ? " ⑂" : ""}`);
192
196
  }
193
197
  if (result.nextCursor) console.log(`\n… more: --cursor ${result.nextCursor}`);
194
198
  });
@@ -343,6 +347,71 @@ async function folders(flags) {
343
347
  });
344
348
  }
345
349
 
350
+ /**
351
+ * Your own copy of a document you can read. The original's author sees that it
352
+ * was forked — a count, never who — and the fork records where it came from,
353
+ * which only people who can open the original are shown (SPEC §21).
354
+ */
355
+ async function fork(flags, [ref]) {
356
+ if (!ref) fail("usage: bikeshed fork <id> [--version <v>] [--folder <id>] [--title <text>]");
357
+ const { origin, token } = resolveAuth(flags);
358
+ const args = docArgs(ref);
359
+ if (typeof flags.version === "string") args.version = flags.version;
360
+ if (typeof flags.folder === "string") args.folder = flags.folder;
361
+ if (typeof flags.title === "string") args.title = flags.title;
362
+ const result = await callTool(origin, token, "fork_document", args);
363
+ out(flags.json, { ...result, url: result.url ?? `${origin}/d/${result.docId}` }, () =>
364
+ console.log(`forked ${args.id} into ${result.docId} — ${result.url ?? `${origin}/d/${result.docId}`}`),
365
+ );
366
+ }
367
+
368
+ /**
369
+ * Where a document came from, nearest first, as far as you can open, and — for
370
+ * its owner — what has been forked from it. The deployment decides what you may
371
+ * see; this only prints it (SPEC §21).
372
+ */
373
+ async function lineage(flags, [ref]) {
374
+ if (!ref) fail("usage: bikeshed lineage <id>");
375
+ const { origin, token } = resolveAuth(flags);
376
+ const result = await callTool(origin, token, "get_lineage", docArgs(ref));
377
+ out(flags.json, result, () => console.log(describeLineage(result)));
378
+ }
379
+
380
+ /** The human form of a get_lineage result. */
381
+ function describeLineage(result) {
382
+ const lines = [];
383
+ if (result.forked) {
384
+ if (result.forkedFrom.length === 0) {
385
+ lines.push("forked from a document you can't open");
386
+ }
387
+ result.forkedFrom.forEach((a, i) => {
388
+ const changed = a.changedSince ? " (changed since)" : "";
389
+ lines.push(`${i === 0 ? "forked from" : " which was"} ${a.id} ${a.version} ${a.title}${changed}`);
390
+ });
391
+ if (result.forkedFrom.length > 0 && result.moreYouCannotOpen) {
392
+ lines.push(" which was forked from a document you can't open");
393
+ }
394
+ } else if (!result.forks) {
395
+ lines.push(`${result.id} is not a fork.`);
396
+ }
397
+ if (result.forks) {
398
+ const { total, youCannotOpen, listed } = result.forks;
399
+ if (lines.length) lines.push("");
400
+ if (total === 0) {
401
+ lines.push("Nobody has forked it yet.");
402
+ } else {
403
+ const times = total === 1 ? "once" : `${total} times`;
404
+ lines.push(youCannotOpen ? `forked ${times}; ${youCannotOpen} you can't open` : `forked ${times}`);
405
+ for (const f of listed) {
406
+ const when = f.forkedAt ? f.forkedAt.slice(0, 10) : "";
407
+ const owner = f.owner ? ` ${f.owner}` : "";
408
+ lines.push(` ${f.id.padEnd(34)} ${f.visibility.padEnd(8)} ${when.padEnd(10)} ${f.title}${owner}`);
409
+ }
410
+ }
411
+ }
412
+ return lines.join("\n");
413
+ }
414
+
346
415
  async function mkdir(flags, rest) {
347
416
  const name = rest.join(" ");
348
417
  if (!name) fail("usage: bikeshed mkdir <name> [--parent <id>]");
@@ -454,6 +523,8 @@ const COMMANDS = {
454
523
  list,
455
524
  publish,
456
525
  update,
526
+ fork,
527
+ lineage,
457
528
  get,
458
529
  comments,
459
530
  reply,
@@ -480,6 +551,7 @@ async function main() {
480
551
  title: { type: "string" },
481
552
  id: { type: "string" },
482
553
  folder: { type: "string" },
554
+ version: { type: "string" },
483
555
  parent: { type: "string" },
484
556
  origin: { type: "string" },
485
557
  token: { type: "string" },