bikeshed-now 0.4.1 → 0.6.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 +22 -0
- package/package.json +1 -1
- package/src/client.mjs +1 -1
- package/src/index.mjs +124 -3
package/README.md
CHANGED
|
@@ -30,6 +30,10 @@ bikeshed comments storage-migration
|
|
|
30
30
|
# Fix that sentence, publish the revision, and say what you changed.
|
|
31
31
|
bikeshed update storage-migration proposal.md
|
|
32
32
|
bikeshed reply storage-migration <thread> "Rewritten to describe the dual-write period."
|
|
33
|
+
|
|
34
|
+
# Given "Can suggest" rather than "Can edit"? Propose the change instead, for a
|
|
35
|
+
# person to accept or reject.
|
|
36
|
+
bikeshed suggest storage-migration "a single weekend" --with "two weekends"
|
|
33
37
|
```
|
|
34
38
|
|
|
35
39
|
Publishing identical bytes is a no-op: the bundle is hashed, and a matching hash
|
|
@@ -61,6 +65,24 @@ bikeshed comments 'https://bikeshed.now/d/build-estimate?k=…'
|
|
|
61
65
|
`bikeshed --help` lists the rest — listing documents, folders, and installing the
|
|
62
66
|
agent skills a deployment serves.
|
|
63
67
|
|
|
68
|
+
## Forking
|
|
69
|
+
|
|
70
|
+
To revise a document you can read but do not own, fork it. You get your own
|
|
71
|
+
private copy, at the version you name or the current one, and it remembers what
|
|
72
|
+
it was forked from.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
bikeshed fork 'https://bikeshed.now/d/build-estimate?k=…'
|
|
76
|
+
# forked build-estimate into build-estimate-x7k2p9 — https://bikeshed.now/d/build-estimate-x7k2p9
|
|
77
|
+
bikeshed lineage build-estimate-x7k2p9
|
|
78
|
+
# forked from build-estimate v3 Build estimate (changed since)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`lineage` shows each original you can open, nearest first, and whether the
|
|
82
|
+
nearest has changed since you forked it. On a document you own it also counts
|
|
83
|
+
its forks. The author of what you fork sees that it was forked — a count, never
|
|
84
|
+
who.
|
|
85
|
+
|
|
64
86
|
## Sharing is not automated
|
|
65
87
|
|
|
66
88
|
There is no command that shares a document, changes who can read it, or sets an
|
package/package.json
CHANGED
package/src/client.mjs
CHANGED
package/src/index.mjs
CHANGED
|
@@ -39,9 +39,15 @@ 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
|
|
47
|
+
bikeshed suggest <id> <text> --with <new text>
|
|
48
|
+
propose new text for a passage, for a
|
|
49
|
+
person to accept or reject (--delete to
|
|
50
|
+
propose removing it)
|
|
45
51
|
bikeshed open <id> open it in a browser
|
|
46
52
|
|
|
47
53
|
Where a command takes <id> it also takes the link you were sent. An unlisted
|
|
@@ -72,13 +78,19 @@ What you can publish
|
|
|
72
78
|
|
|
73
79
|
Options
|
|
74
80
|
--json machine-readable output
|
|
75
|
-
--title <text> title for publish
|
|
81
|
+
--title <text> title for publish or fork (fork default: the original's)
|
|
76
82
|
--id <id> with publish: the address, /d/<id> (default: from the title)
|
|
77
|
-
--folder <id> destination folder for publish
|
|
83
|
+
--folder <id> destination folder for publish or fork
|
|
84
|
+
--version <v> with fork: the version to copy (default: current)
|
|
78
85
|
--parent <id> parent folder for mkdir
|
|
79
86
|
--limit <n> with list: rows per page (default 20, max 50)
|
|
80
87
|
--cursor <id> with list: the page after the one that printed it
|
|
81
88
|
--all with list: every page; with comments: resolved too
|
|
89
|
+
--with <text> with suggest: what the passage should say instead
|
|
90
|
+
--delete with suggest: propose deleting the passage
|
|
91
|
+
--note <text> with suggest: why, for whoever decides
|
|
92
|
+
--prefix <text> with suggest: words just before a passage that repeats
|
|
93
|
+
--suffix <text> with suggest: words just after it
|
|
82
94
|
--watch with publish/update: republish on every save
|
|
83
95
|
--origin <url> the deployment (default: the one you logged in to)
|
|
84
96
|
--token <token> override the stored token
|
|
@@ -188,7 +200,8 @@ async function list(flags) {
|
|
|
188
200
|
}
|
|
189
201
|
for (const doc of result.documents) {
|
|
190
202
|
const marker = doc.visibility === "private" ? " " : doc.visibility === "public" ? "◉" : "◐";
|
|
191
|
-
|
|
203
|
+
// ⑂ marks a fork; where it came from is `bikeshed lineage`'s to say.
|
|
204
|
+
console.log(`${marker} ${doc.id.padEnd(34)} ${doc.version.padEnd(5)} ${doc.title}${doc.forked ? " ⑂" : ""}`);
|
|
192
205
|
}
|
|
193
206
|
if (result.nextCursor) console.log(`\n… more: --cursor ${result.nextCursor}`);
|
|
194
207
|
});
|
|
@@ -299,6 +312,12 @@ async function comments(flags, [ref]) {
|
|
|
299
312
|
// which passage to change without opening the document.
|
|
300
313
|
console.log(`\n── ${thread.threadId}${thread.section ? ` (${thread.section})` : ""}`);
|
|
301
314
|
if (thread.quote) console.log(` “${thread.quote}”`);
|
|
315
|
+
// A suggested edit says what the passage would become, and whether a
|
|
316
|
+
// person has decided it yet (SPEC §22).
|
|
317
|
+
if (thread.suggestion) {
|
|
318
|
+
const change = thread.suggestion.replacement === "" ? "(delete it)" : `“${thread.suggestion.replacement}”`;
|
|
319
|
+
console.log(` → ${change} [${thread.suggestion.state}]`);
|
|
320
|
+
}
|
|
302
321
|
for (const comment of thread.comments) {
|
|
303
322
|
const via = comment.via && comment.via !== "web" ? ` [via ${comment.via}]` : "";
|
|
304
323
|
console.log(` ${comment.author}${via}: ${comment.body}`);
|
|
@@ -320,6 +339,34 @@ async function reply(flags, [ref, threadId, ...rest]) {
|
|
|
320
339
|
out(flags.json, result, () => console.log(`replied in ${threadId}`));
|
|
321
340
|
}
|
|
322
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Propose new text for one passage of a document's current version. The
|
|
344
|
+
* passage is quoted as a reader sees it, which is how `comments` prints it, so
|
|
345
|
+
* a quote can go straight from one command to the other.
|
|
346
|
+
*/
|
|
347
|
+
async function suggest(flags, [ref, ...rest]) {
|
|
348
|
+
const exact = rest.join(" ");
|
|
349
|
+
const usage = "usage: bikeshed suggest <id> <text> (--with <new text> | --delete) [--note <why>]";
|
|
350
|
+
if (!ref || !exact) fail(usage);
|
|
351
|
+
const replacing = typeof flags.with === "string";
|
|
352
|
+
if (replacing === Boolean(flags.delete)) fail(usage);
|
|
353
|
+
// An empty --with is what an unset shell variable sends; deleting a passage
|
|
354
|
+
// has to be asked for by name.
|
|
355
|
+
if (replacing && flags.with === "") fail("an empty --with would delete the passage; say --delete if you mean that");
|
|
356
|
+
const { origin, token } = resolveAuth(flags);
|
|
357
|
+
const result = await callTool(origin, token, "suggest_edit", {
|
|
358
|
+
...docArgs(ref),
|
|
359
|
+
exact,
|
|
360
|
+
replacement: replacing ? flags.with : "",
|
|
361
|
+
...(typeof flags.note === "string" ? { note: flags.note } : {}),
|
|
362
|
+
...(typeof flags.prefix === "string" ? { prefix: flags.prefix } : {}),
|
|
363
|
+
...(typeof flags.suffix === "string" ? { suffix: flags.suffix } : {}),
|
|
364
|
+
});
|
|
365
|
+
out(flags.json, result, () =>
|
|
366
|
+
console.log(`suggested in ${result.threadId}; a person who can approve will accept or reject it`),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
323
370
|
async function folders(flags) {
|
|
324
371
|
const { origin, token } = resolveAuth(flags);
|
|
325
372
|
const result = await callTool(origin, token, "list_folders", {});
|
|
@@ -343,6 +390,71 @@ async function folders(flags) {
|
|
|
343
390
|
});
|
|
344
391
|
}
|
|
345
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Your own copy of a document you can read. The original's author sees that it
|
|
395
|
+
* was forked — a count, never who — and the fork records where it came from,
|
|
396
|
+
* which only people who can open the original are shown (SPEC §21).
|
|
397
|
+
*/
|
|
398
|
+
async function fork(flags, [ref]) {
|
|
399
|
+
if (!ref) fail("usage: bikeshed fork <id> [--version <v>] [--folder <id>] [--title <text>]");
|
|
400
|
+
const { origin, token } = resolveAuth(flags);
|
|
401
|
+
const args = docArgs(ref);
|
|
402
|
+
if (typeof flags.version === "string") args.version = flags.version;
|
|
403
|
+
if (typeof flags.folder === "string") args.folder = flags.folder;
|
|
404
|
+
if (typeof flags.title === "string") args.title = flags.title;
|
|
405
|
+
const result = await callTool(origin, token, "fork_document", args);
|
|
406
|
+
out(flags.json, { ...result, url: result.url ?? `${origin}/d/${result.docId}` }, () =>
|
|
407
|
+
console.log(`forked ${args.id} into ${result.docId} — ${result.url ?? `${origin}/d/${result.docId}`}`),
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Where a document came from, nearest first, as far as you can open, and — for
|
|
413
|
+
* its owner — what has been forked from it. The deployment decides what you may
|
|
414
|
+
* see; this only prints it (SPEC §21).
|
|
415
|
+
*/
|
|
416
|
+
async function lineage(flags, [ref]) {
|
|
417
|
+
if (!ref) fail("usage: bikeshed lineage <id>");
|
|
418
|
+
const { origin, token } = resolveAuth(flags);
|
|
419
|
+
const result = await callTool(origin, token, "get_lineage", docArgs(ref));
|
|
420
|
+
out(flags.json, result, () => console.log(describeLineage(result)));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** The human form of a get_lineage result. */
|
|
424
|
+
function describeLineage(result) {
|
|
425
|
+
const lines = [];
|
|
426
|
+
if (result.forked) {
|
|
427
|
+
if (result.forkedFrom.length === 0) {
|
|
428
|
+
lines.push("forked from a document you can't open");
|
|
429
|
+
}
|
|
430
|
+
result.forkedFrom.forEach((a, i) => {
|
|
431
|
+
const changed = a.changedSince ? " (changed since)" : "";
|
|
432
|
+
lines.push(`${i === 0 ? "forked from" : " which was"} ${a.id} ${a.version} ${a.title}${changed}`);
|
|
433
|
+
});
|
|
434
|
+
if (result.forkedFrom.length > 0 && result.moreYouCannotOpen) {
|
|
435
|
+
lines.push(" which was forked from a document you can't open");
|
|
436
|
+
}
|
|
437
|
+
} else if (!result.forks) {
|
|
438
|
+
lines.push(`${result.id} is not a fork.`);
|
|
439
|
+
}
|
|
440
|
+
if (result.forks) {
|
|
441
|
+
const { total, youCannotOpen, listed } = result.forks;
|
|
442
|
+
if (lines.length) lines.push("");
|
|
443
|
+
if (total === 0) {
|
|
444
|
+
lines.push("Nobody has forked it yet.");
|
|
445
|
+
} else {
|
|
446
|
+
const times = total === 1 ? "once" : `${total} times`;
|
|
447
|
+
lines.push(youCannotOpen ? `forked ${times}; ${youCannotOpen} you can't open` : `forked ${times}`);
|
|
448
|
+
for (const f of listed) {
|
|
449
|
+
const when = f.forkedAt ? f.forkedAt.slice(0, 10) : "";
|
|
450
|
+
const owner = f.owner ? ` ${f.owner}` : "";
|
|
451
|
+
lines.push(` ${f.id.padEnd(34)} ${f.visibility.padEnd(8)} ${when.padEnd(10)} ${f.title}${owner}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return lines.join("\n");
|
|
456
|
+
}
|
|
457
|
+
|
|
346
458
|
async function mkdir(flags, rest) {
|
|
347
459
|
const name = rest.join(" ");
|
|
348
460
|
if (!name) fail("usage: bikeshed mkdir <name> [--parent <id>]");
|
|
@@ -454,9 +566,12 @@ const COMMANDS = {
|
|
|
454
566
|
list,
|
|
455
567
|
publish,
|
|
456
568
|
update,
|
|
569
|
+
fork,
|
|
570
|
+
lineage,
|
|
457
571
|
get,
|
|
458
572
|
comments,
|
|
459
573
|
reply,
|
|
574
|
+
suggest,
|
|
460
575
|
open,
|
|
461
576
|
folders,
|
|
462
577
|
mkdir,
|
|
@@ -480,11 +595,17 @@ async function main() {
|
|
|
480
595
|
title: { type: "string" },
|
|
481
596
|
id: { type: "string" },
|
|
482
597
|
folder: { type: "string" },
|
|
598
|
+
version: { type: "string" },
|
|
483
599
|
parent: { type: "string" },
|
|
484
600
|
origin: { type: "string" },
|
|
485
601
|
token: { type: "string" },
|
|
486
602
|
limit: { type: "string" },
|
|
487
603
|
cursor: { type: "string" },
|
|
604
|
+
with: { type: "string" },
|
|
605
|
+
delete: { type: "boolean", default: false },
|
|
606
|
+
note: { type: "string" },
|
|
607
|
+
prefix: { type: "string" },
|
|
608
|
+
suffix: { type: "string" },
|
|
488
609
|
},
|
|
489
610
|
});
|
|
490
611
|
|