innernote 0.1.1 → 0.2.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/dist/index.js +165 -96
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -286,44 +286,44 @@ function wordmark(name, gap = 1) {
|
|
|
286
286
|
function widest(rows) {
|
|
287
287
|
return Math.max(...rows.map((r) => r.length));
|
|
288
288
|
}
|
|
289
|
-
function lockup(name = "innernote",
|
|
290
|
-
const room = (process.stdout.columns
|
|
291
|
-
const
|
|
292
|
-
const
|
|
289
|
+
function lockup(name = "innernote", sub) {
|
|
290
|
+
const room = (process.stdout.columns || 80) - 5;
|
|
291
|
+
const subs = sub == null ? [] : Array.isArray(sub) ? sub : [sub];
|
|
292
|
+
const mark = logo(2).map((r) => r.trimEnd());
|
|
293
|
+
const ink = widest(mark);
|
|
293
294
|
const word = wordmark(name);
|
|
294
295
|
if (word) {
|
|
295
|
-
const
|
|
296
|
-
|
|
296
|
+
const gap = 2;
|
|
297
|
+
const wide = Math.max(widest(word), ...subs.map((s) => width(s)));
|
|
298
|
+
if (ink + gap + wide <= room) {
|
|
297
299
|
const rows2 = mark.map((r, i) => {
|
|
298
300
|
const right = word[i] ?? "";
|
|
299
|
-
return right ? `${caramel(r.padEnd(
|
|
301
|
+
return right ? `${caramel(r.padEnd(ink))}${" ".repeat(gap)}${bold2(caramel(right))}` : caramel(r);
|
|
300
302
|
});
|
|
301
|
-
|
|
302
|
-
|
|
303
|
+
const indent = " ".repeat(ink + gap);
|
|
304
|
+
for (const line of subs)
|
|
305
|
+
rows2.push(`${indent}${line}`);
|
|
303
306
|
return rows2;
|
|
304
307
|
}
|
|
305
308
|
}
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (
|
|
315
|
-
return left +
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
rows
|
|
321
|
-
if (tagline)
|
|
322
|
-
rows.push(dim2(tagline));
|
|
323
|
-
return rows;
|
|
309
|
+
const mid = Math.floor(mark.length / 2);
|
|
310
|
+
const below = [];
|
|
311
|
+
const rows = mark.map((r, i) => {
|
|
312
|
+
const left = caramel(r.padEnd(ink)) + " ";
|
|
313
|
+
if (i === mid)
|
|
314
|
+
return left + bold2(caramel(name));
|
|
315
|
+
const sub2 = subs[i - mid - 1];
|
|
316
|
+
if (i > mid && sub2 !== undefined) {
|
|
317
|
+
if (ink + 3 + width(sub2) <= room)
|
|
318
|
+
return left + sub2;
|
|
319
|
+
below.push(sub2);
|
|
320
|
+
}
|
|
321
|
+
return caramel(r);
|
|
322
|
+
});
|
|
323
|
+
return [...rows, ...below];
|
|
324
324
|
}
|
|
325
325
|
function banner(tagline = "your voice, from the terminal") {
|
|
326
|
-
return lockup("innernote", tagline).map((r) => " " + r).join(`
|
|
326
|
+
return lockup("innernote", dim2(tagline)).map((r) => " " + r).join(`
|
|
327
327
|
`);
|
|
328
328
|
}
|
|
329
329
|
function bar(score, width2 = 10) {
|
|
@@ -344,6 +344,7 @@ async function login(args) {
|
|
|
344
344
|
let code = args.find((a) => !a.startsWith("-"))?.trim();
|
|
345
345
|
if (!code) {
|
|
346
346
|
out(`Open ${bold2(config.apiUrl + PAIR_PAGE)} and copy your pairing code.`);
|
|
347
|
+
out(dim2(`New here? Sign in at ${config.apiUrl.replace(/^https?:\/\//, "")} first.`));
|
|
347
348
|
out();
|
|
348
349
|
if (!process.stdin.isTTY) {
|
|
349
350
|
fail("No pairing code given, and there is no terminal to ask on.");
|
|
@@ -1121,6 +1122,9 @@ var dim4 = sgr2("2");
|
|
|
1121
1122
|
var green4 = sgr2("32");
|
|
1122
1123
|
var yellow4 = sgr2("33");
|
|
1123
1124
|
var red4 = sgr2("31");
|
|
1125
|
+
function width2(s) {
|
|
1126
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
1127
|
+
}
|
|
1124
1128
|
var canAnimate2 = isTTY2 && process.env.TERM !== "dumb" && !process.env.CI;
|
|
1125
1129
|
var MARK_GRID2 = [
|
|
1126
1130
|
"....#....",
|
|
@@ -1159,44 +1163,44 @@ function wordmark2(name, gap = 1) {
|
|
|
1159
1163
|
function widest2(rows) {
|
|
1160
1164
|
return Math.max(...rows.map((r) => r.length));
|
|
1161
1165
|
}
|
|
1162
|
-
function lockup2(name = "innernote",
|
|
1163
|
-
const room = (process.stdout.columns
|
|
1164
|
-
const
|
|
1165
|
-
const
|
|
1166
|
+
function lockup2(name = "innernote", sub) {
|
|
1167
|
+
const room = (process.stdout.columns || 80) - 5;
|
|
1168
|
+
const subs = sub == null ? [] : Array.isArray(sub) ? sub : [sub];
|
|
1169
|
+
const mark = logo2(2).map((r) => r.trimEnd());
|
|
1170
|
+
const ink = widest2(mark);
|
|
1166
1171
|
const word = wordmark2(name);
|
|
1167
1172
|
if (word) {
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1173
|
+
const gap = 2;
|
|
1174
|
+
const wide = Math.max(widest2(word), ...subs.map((s) => width2(s)));
|
|
1175
|
+
if (ink + gap + wide <= room) {
|
|
1170
1176
|
const rows2 = mark.map((r, i) => {
|
|
1171
1177
|
const right = word[i] ?? "";
|
|
1172
|
-
return right ? `${caramel2(r.padEnd(
|
|
1178
|
+
return right ? `${caramel2(r.padEnd(ink))}${" ".repeat(gap)}${bold4(caramel2(right))}` : caramel2(r);
|
|
1173
1179
|
});
|
|
1174
|
-
|
|
1175
|
-
|
|
1180
|
+
const indent = " ".repeat(ink + gap);
|
|
1181
|
+
for (const line of subs)
|
|
1182
|
+
rows2.push(`${indent}${line}`);
|
|
1176
1183
|
return rows2;
|
|
1177
1184
|
}
|
|
1178
1185
|
}
|
|
1179
|
-
const
|
|
1180
|
-
const
|
|
1181
|
-
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
if (
|
|
1188
|
-
return left +
|
|
1189
|
-
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
rows
|
|
1194
|
-
if (tagline)
|
|
1195
|
-
rows.push(dim4(tagline));
|
|
1196
|
-
return rows;
|
|
1186
|
+
const mid = Math.floor(mark.length / 2);
|
|
1187
|
+
const below = [];
|
|
1188
|
+
const rows = mark.map((r, i) => {
|
|
1189
|
+
const left = caramel2(r.padEnd(ink)) + " ";
|
|
1190
|
+
if (i === mid)
|
|
1191
|
+
return left + bold4(caramel2(name));
|
|
1192
|
+
const sub2 = subs[i - mid - 1];
|
|
1193
|
+
if (i > mid && sub2 !== undefined) {
|
|
1194
|
+
if (ink + 3 + width2(sub2) <= room)
|
|
1195
|
+
return left + sub2;
|
|
1196
|
+
below.push(sub2);
|
|
1197
|
+
}
|
|
1198
|
+
return caramel2(r);
|
|
1199
|
+
});
|
|
1200
|
+
return [...rows, ...below];
|
|
1197
1201
|
}
|
|
1198
1202
|
function banner2(tagline = "your voice, from the terminal") {
|
|
1199
|
-
return lockup2("innernote", tagline).map((r) => " " + r).join(`
|
|
1203
|
+
return lockup2("innernote", dim4(tagline)).map((r) => " " + r).join(`
|
|
1200
1204
|
`);
|
|
1201
1205
|
}
|
|
1202
1206
|
|
|
@@ -1341,12 +1345,12 @@ function commandHelp(name) {
|
|
|
1341
1345
|
return lines.join(`
|
|
1342
1346
|
`);
|
|
1343
1347
|
}
|
|
1344
|
-
function wrap3(text,
|
|
1348
|
+
function wrap3(text, width3, indent) {
|
|
1345
1349
|
const words = text.split(/\s+/);
|
|
1346
1350
|
const lines = [];
|
|
1347
1351
|
let line = "";
|
|
1348
1352
|
for (const w of words) {
|
|
1349
|
-
if ((line + " " + w).trim().length >
|
|
1353
|
+
if ((line + " " + w).trim().length > width3) {
|
|
1350
1354
|
lines.push(indent + line.trim());
|
|
1351
1355
|
line = w;
|
|
1352
1356
|
} else {
|
|
@@ -1368,65 +1372,68 @@ function margin(rows) {
|
|
|
1368
1372
|
`);
|
|
1369
1373
|
}
|
|
1370
1374
|
function landing(state) {
|
|
1371
|
-
const
|
|
1372
|
-
if (state.
|
|
1373
|
-
|
|
1374
|
-
}
|
|
1375
|
-
const sub = [];
|
|
1375
|
+
const small = [];
|
|
1376
|
+
if (state.plan)
|
|
1377
|
+
small.push(state.plan);
|
|
1376
1378
|
if (state.powers)
|
|
1377
|
-
|
|
1378
|
-
if (typeof state.expiresInDays === "number" && state.expiresInDays <= 14) {
|
|
1379
|
-
sub.push(`key expires in ${state.expiresInDays} ${state.expiresInDays === 1 ? "day" : "days"}`);
|
|
1380
|
-
}
|
|
1379
|
+
small.push(state.powers);
|
|
1381
1380
|
if (state.version)
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1381
|
+
small.push(`v${state.version}`);
|
|
1382
|
+
const sub = [];
|
|
1383
|
+
if (state.name)
|
|
1384
|
+
sub.push(`${bold2(state.name)} ${dim2(small.join(" "))}`);
|
|
1385
|
+
else if (small.length)
|
|
1386
|
+
sub.push(dim2(small.join(" ")));
|
|
1387
|
+
if (typeof state.expiresInDays === "number" && state.expiresInDays <= 14) {
|
|
1388
|
+
sub.push(yellow2(`key expires in ${state.expiresInDays} ${state.expiresInDays === 1 ? "day" : "days"}`));
|
|
1387
1389
|
}
|
|
1390
|
+
const rows = ["", ...lockup("innernote", sub), ""];
|
|
1391
|
+
if (state.week?.length)
|
|
1392
|
+
rows.push(...state.week, "");
|
|
1388
1393
|
const counts = [];
|
|
1389
1394
|
if (state.ideas)
|
|
1390
1395
|
counts.push(`${state.ideas} ${state.ideas === 1 ? "idea" : "ideas"} waiting`);
|
|
1391
1396
|
if (state.drafts)
|
|
1392
|
-
counts.push(`${state.drafts} drafts`);
|
|
1397
|
+
counts.push(`${state.drafts} ${state.drafts === 1 ? "draft" : "drafts"}`);
|
|
1393
1398
|
if (counts.length)
|
|
1394
|
-
rows.push(
|
|
1399
|
+
rows.push(dim2(counts.join(" ")));
|
|
1395
1400
|
if (state.next) {
|
|
1396
|
-
rows.push(
|
|
1401
|
+
rows.push(`${caramel(state.next.command)} ${dim2(state.next.why)}`);
|
|
1397
1402
|
}
|
|
1398
1403
|
rows.push("");
|
|
1399
1404
|
return margin(rows);
|
|
1400
1405
|
}
|
|
1401
1406
|
function landingDisconnected(apiUrl, version) {
|
|
1407
|
+
const host = apiUrl.replace(/^https?:\/\//, "");
|
|
1408
|
+
const sub = [dim2("LinkedIn posts in your voice, from the terminal")];
|
|
1409
|
+
if (version)
|
|
1410
|
+
sub.push(dim2(`v${version}`));
|
|
1402
1411
|
return margin([
|
|
1403
1412
|
"",
|
|
1404
|
-
...lockup("innernote",
|
|
1405
|
-
...version ? [` ${dim2(`v${version}`)}`] : [],
|
|
1413
|
+
...lockup("innernote", sub),
|
|
1406
1414
|
"",
|
|
1407
|
-
dim2("
|
|
1408
|
-
|
|
1409
|
-
`${
|
|
1410
|
-
dim2(`Get a code at ${apiUrl.replace(/^https?:\/\//, "")}/dashboard/settings`),
|
|
1415
|
+
`${caramel(`${CMD} login`)} ${dim2("connect this machine")}`,
|
|
1416
|
+
dim2(`Get a code at ${host}/dashboard/settings`),
|
|
1417
|
+
`${dim2("No account yet?")} ${caramel(host)}`,
|
|
1411
1418
|
""
|
|
1412
1419
|
]);
|
|
1413
1420
|
}
|
|
1414
1421
|
function suggest(state) {
|
|
1415
1422
|
if (state.scheduled === 0 && state.ideas > 0) {
|
|
1416
|
-
return { command:
|
|
1423
|
+
return { command: "ideas", why: "nothing scheduled, and you have things saved" };
|
|
1417
1424
|
}
|
|
1418
1425
|
if (state.scheduled === 0) {
|
|
1419
|
-
return { command:
|
|
1426
|
+
return { command: "write", why: "the week is empty" };
|
|
1420
1427
|
}
|
|
1421
1428
|
if (state.ideas >= 5) {
|
|
1422
|
-
return { command:
|
|
1429
|
+
return { command: "ideas", why: "your inbox is filling up" };
|
|
1423
1430
|
}
|
|
1424
|
-
return { command:
|
|
1431
|
+
return { command: "write", why: "start something" };
|
|
1425
1432
|
}
|
|
1426
1433
|
// package.json
|
|
1427
1434
|
var package_default = {
|
|
1428
1435
|
name: "innernote",
|
|
1429
|
-
version: "0.
|
|
1436
|
+
version: "0.2.0",
|
|
1430
1437
|
description: "Write LinkedIn posts in your voice, from the terminal.",
|
|
1431
1438
|
type: "module",
|
|
1432
1439
|
bin: {
|
|
@@ -1463,7 +1470,7 @@ function powers2(scopes) {
|
|
|
1463
1470
|
return scopes[0];
|
|
1464
1471
|
return `${scopes.slice(0, -1).join(", ")} and ${scopes[scopes.length - 1]}`;
|
|
1465
1472
|
}
|
|
1466
|
-
async function home() {
|
|
1473
|
+
async function home(inSession = false) {
|
|
1467
1474
|
const config = await loadConfig();
|
|
1468
1475
|
if (!config.token) {
|
|
1469
1476
|
out();
|
|
@@ -1495,11 +1502,14 @@ async function home() {
|
|
|
1495
1502
|
`).map((l) => l.replace(/^ {2}/, "")) : null,
|
|
1496
1503
|
ideas: ideas2?.ideas.length,
|
|
1497
1504
|
drafts: drafts2?.posts.length,
|
|
1498
|
-
next:
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1505
|
+
next: (() => {
|
|
1506
|
+
const n = suggest({
|
|
1507
|
+
scheduled,
|
|
1508
|
+
ideas: ideas2?.ideas.length ?? 0,
|
|
1509
|
+
drafts: drafts2?.posts.length ?? 0
|
|
1510
|
+
});
|
|
1511
|
+
return inSession ? n : { ...n, command: `${CMD} ${n.command}` };
|
|
1512
|
+
})()
|
|
1503
1513
|
}));
|
|
1504
1514
|
out();
|
|
1505
1515
|
return 0;
|
|
@@ -1508,6 +1518,30 @@ async function home() {
|
|
|
1508
1518
|
// src/session.ts
|
|
1509
1519
|
import { createInterface } from "node:readline";
|
|
1510
1520
|
|
|
1521
|
+
// src/ghost.ts
|
|
1522
|
+
function ghostFor(line2, cursor, history, names) {
|
|
1523
|
+
if (!line2 || cursor !== line2.length)
|
|
1524
|
+
return null;
|
|
1525
|
+
if (line2.startsWith(" "))
|
|
1526
|
+
return null;
|
|
1527
|
+
const fromHistory = history.find((h) => h.startsWith(line2) && h.length > line2.length);
|
|
1528
|
+
if (fromHistory)
|
|
1529
|
+
return fromHistory.slice(line2.length);
|
|
1530
|
+
if (!line2.includes(" ")) {
|
|
1531
|
+
const name = names.find((n) => n.startsWith(line2) && n.length > line2.length);
|
|
1532
|
+
return name ? name.slice(line2.length) : null;
|
|
1533
|
+
}
|
|
1534
|
+
if (line2.startsWith("help ")) {
|
|
1535
|
+
const arg = line2.slice(5);
|
|
1536
|
+
if (arg && !arg.includes(" ")) {
|
|
1537
|
+
const name = names.find((n) => n.startsWith(arg) && n.length > arg.length);
|
|
1538
|
+
if (name)
|
|
1539
|
+
return name.slice(arg.length);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1511
1545
|
// src/help.ts
|
|
1512
1546
|
var COMMANDS2 = {
|
|
1513
1547
|
login: {
|
|
@@ -1649,12 +1683,12 @@ function commandHelp2(name) {
|
|
|
1649
1683
|
return lines.join(`
|
|
1650
1684
|
`);
|
|
1651
1685
|
}
|
|
1652
|
-
function wrap4(text,
|
|
1686
|
+
function wrap4(text, width3, indent) {
|
|
1653
1687
|
const words = text.split(/\s+/);
|
|
1654
1688
|
const lines = [];
|
|
1655
1689
|
let line2 = "";
|
|
1656
1690
|
for (const w of words) {
|
|
1657
|
-
if ((line2 + " " + w).trim().length >
|
|
1691
|
+
if ((line2 + " " + w).trim().length > width3) {
|
|
1658
1692
|
lines.push(indent + line2.trim());
|
|
1659
1693
|
line2 = w;
|
|
1660
1694
|
} else {
|
|
@@ -1726,6 +1760,40 @@ function indented(run) {
|
|
|
1726
1760
|
};
|
|
1727
1761
|
return run().finally(restore);
|
|
1728
1762
|
}
|
|
1763
|
+
function armGhost(rl, names, promptWidth) {
|
|
1764
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
1765
|
+
return;
|
|
1766
|
+
if (dim2("x") === "x")
|
|
1767
|
+
return;
|
|
1768
|
+
const inner = rl;
|
|
1769
|
+
let shown = null;
|
|
1770
|
+
const clear = () => {
|
|
1771
|
+
if (shown == null)
|
|
1772
|
+
return;
|
|
1773
|
+
process.stdout.write("\x1B[K");
|
|
1774
|
+
shown = null;
|
|
1775
|
+
};
|
|
1776
|
+
const draw = () => {
|
|
1777
|
+
if (process.stdin.isPaused())
|
|
1778
|
+
return;
|
|
1779
|
+
const rest = ghostFor(inner.line ?? "", inner.cursor ?? 0, inner.history ?? [], names);
|
|
1780
|
+
if (!rest)
|
|
1781
|
+
return;
|
|
1782
|
+
const cols = process.stdout.columns || 80;
|
|
1783
|
+
if (promptWidth() + (inner.line?.length ?? 0) + rest.length >= cols - 1)
|
|
1784
|
+
return;
|
|
1785
|
+
process.stdout.write(`${dim2(rest)}\x1B[${rest.length}D`);
|
|
1786
|
+
shown = rest;
|
|
1787
|
+
};
|
|
1788
|
+
process.stdin.prependListener("keypress", (_ch, key) => {
|
|
1789
|
+
const offered = shown;
|
|
1790
|
+
clear();
|
|
1791
|
+
if (key?.name === "right" && offered && inner.cursor === inner.line.length) {
|
|
1792
|
+
rl.write(offered);
|
|
1793
|
+
}
|
|
1794
|
+
setImmediate(draw);
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1729
1797
|
async function session(opts) {
|
|
1730
1798
|
await opts.intro();
|
|
1731
1799
|
const names = [...Object.keys(COMMANDS2), ...BUILTINS];
|
|
@@ -1743,7 +1811,8 @@ async function session(opts) {
|
|
|
1743
1811
|
return [hits.length ? hits : names, line2];
|
|
1744
1812
|
}
|
|
1745
1813
|
});
|
|
1746
|
-
|
|
1814
|
+
armGhost(rl, names, () => width(promptFor()));
|
|
1815
|
+
console.log(` ${dim2("Type a command, or")} ${caramel("help")}${dim2(". Right arrow takes the hint. Ctrl-C twice to leave.")}
|
|
1747
1816
|
`);
|
|
1748
1817
|
rl.prompt();
|
|
1749
1818
|
return new Promise((resolve) => {
|
|
@@ -1924,7 +1993,7 @@ async function main() {
|
|
|
1924
1993
|
return home();
|
|
1925
1994
|
return session({
|
|
1926
1995
|
intro: async () => {
|
|
1927
|
-
await home();
|
|
1996
|
+
await home(true);
|
|
1928
1997
|
},
|
|
1929
1998
|
status: () => {
|
|
1930
1999
|
const d = getDraft2();
|