innernote 0.3.2 → 0.3.4
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 +1 -0
- package/dist/index.js +139 -51
- package/package.json +22 -1
package/README.md
CHANGED
|
@@ -100,6 +100,7 @@ from it fails the suite, so what you read here is what the binary has.
|
|
|
100
100
|
| `week` | what is scheduled for the next seven days |
|
|
101
101
|
| `queue <post-id>` | schedule a post into your next open slot |
|
|
102
102
|
| `unqueue <post-id>` | pull it back out before it goes live |
|
|
103
|
+
| `skill [--install]` | print the agent skill, or register it for Claude Code |
|
|
103
104
|
|
|
104
105
|
### write
|
|
105
106
|
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,9 @@ class ApiError extends Error {
|
|
|
83
83
|
get isRefusal() {
|
|
84
84
|
return this.status === 402 || this.status === 429;
|
|
85
85
|
}
|
|
86
|
+
get isNotConnected() {
|
|
87
|
+
return this.status === 401;
|
|
88
|
+
}
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
class NotLoggedIn extends Error {
|
|
@@ -497,13 +500,41 @@ function resolveRef(ref) {
|
|
|
497
500
|
return /^[a-z0-9]{20,}$/.test(ref) ? { id: ref, title: ref } : null;
|
|
498
501
|
}
|
|
499
502
|
|
|
500
|
-
// src/
|
|
501
|
-
function parseFlags(args) {
|
|
503
|
+
// src/flags.ts
|
|
504
|
+
function parseFlags(args, valueFlags = []) {
|
|
505
|
+
const values = new Map;
|
|
506
|
+
const present = new Set;
|
|
507
|
+
const rest = [];
|
|
508
|
+
for (let i = 0;i < args.length; i++) {
|
|
509
|
+
const arg = args[i];
|
|
510
|
+
if (!arg.startsWith("--")) {
|
|
511
|
+
rest.push(arg);
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
const eq = arg.indexOf("=");
|
|
515
|
+
const name = eq === -1 ? arg.slice(2) : arg.slice(2, eq);
|
|
516
|
+
present.add(name);
|
|
517
|
+
if (!valueFlags.includes(name))
|
|
518
|
+
continue;
|
|
519
|
+
if (eq !== -1) {
|
|
520
|
+
values.set(name, arg.slice(eq + 1));
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
const next = args[i + 1];
|
|
524
|
+
if (next !== undefined && !next.startsWith("--")) {
|
|
525
|
+
values.set(name, next);
|
|
526
|
+
i++;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
502
529
|
return {
|
|
503
|
-
json:
|
|
504
|
-
rest
|
|
530
|
+
json: present.has("json"),
|
|
531
|
+
rest,
|
|
532
|
+
value: (name) => values.get(name),
|
|
533
|
+
has: (name) => present.has(name)
|
|
505
534
|
};
|
|
506
535
|
}
|
|
536
|
+
|
|
537
|
+
// src/commands/read.ts
|
|
507
538
|
function powers(scopes) {
|
|
508
539
|
if (!scopes || scopes.length === 0)
|
|
509
540
|
return "full access";
|
|
@@ -654,14 +685,6 @@ async function context(args) {
|
|
|
654
685
|
return 0;
|
|
655
686
|
}
|
|
656
687
|
|
|
657
|
-
// src/commands/read.ts
|
|
658
|
-
function parseFlags2(args) {
|
|
659
|
-
return {
|
|
660
|
-
json: args.includes("--json"),
|
|
661
|
-
rest: args.filter((a) => !a.startsWith("--"))
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
|
|
665
688
|
// src/progress.ts
|
|
666
689
|
var DRAFTING = [
|
|
667
690
|
{ at: 0, text: "reading your voice..." },
|
|
@@ -831,9 +854,10 @@ async function whileThinking(phases, run) {
|
|
|
831
854
|
|
|
832
855
|
// src/commands/write.ts
|
|
833
856
|
async function capture(args) {
|
|
834
|
-
const { json, rest } =
|
|
835
|
-
const
|
|
836
|
-
const
|
|
857
|
+
const { json, rest } = parseFlags(args);
|
|
858
|
+
const typed = rest.join(" ").trim();
|
|
859
|
+
const piped = typed ? null : await readStdin();
|
|
860
|
+
const content = (typed || piped || "").trim();
|
|
837
861
|
if (!content) {
|
|
838
862
|
fail("Nothing to capture.");
|
|
839
863
|
note(dim2('Try: innernote capture "the thing you just thought of"'));
|
|
@@ -853,21 +877,14 @@ async function capture(args) {
|
|
|
853
877
|
return 0;
|
|
854
878
|
}
|
|
855
879
|
async function write(args) {
|
|
856
|
-
const { json, rest } =
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
};
|
|
865
|
-
const piped = await readStdin();
|
|
866
|
-
const thought = flagValue("thought") ?? (piped ?? undefined);
|
|
867
|
-
const topic = rest.filter((a) => a !== thought).join(" ").trim();
|
|
868
|
-
const format = flagValue("format");
|
|
869
|
-
const series = flagValue("series");
|
|
870
|
-
const save = args.includes("--save");
|
|
880
|
+
const { json, rest, value, has } = parseFlags(args, ["thought", "format", "series"]);
|
|
881
|
+
const topic = rest.join(" ").trim();
|
|
882
|
+
const thoughtFlag = value("thought");
|
|
883
|
+
const piped = thoughtFlag || topic ? null : await readStdin();
|
|
884
|
+
const thought = thoughtFlag ?? (piped ?? undefined);
|
|
885
|
+
const format = value("format");
|
|
886
|
+
const series = value("series");
|
|
887
|
+
const save = has("save");
|
|
871
888
|
const call = () => request("/api/content/generate", {
|
|
872
889
|
method: "POST",
|
|
873
890
|
body: {
|
|
@@ -934,11 +951,11 @@ var SHAPES = [
|
|
|
934
951
|
"jargon"
|
|
935
952
|
];
|
|
936
953
|
async function shape(args) {
|
|
937
|
-
const { json, rest } =
|
|
938
|
-
const
|
|
954
|
+
const { json, rest } = parseFlags(args);
|
|
955
|
+
const held = getDraft();
|
|
956
|
+
const piped = held ? null : await readStdin();
|
|
939
957
|
const chosen = rest.filter((a) => SHAPES.includes(a));
|
|
940
958
|
const freeText = rest.filter((a) => !SHAPES.includes(a)).join(" ").trim();
|
|
941
|
-
const held = getDraft();
|
|
942
959
|
const content = (piped ?? held?.content ?? "").trim();
|
|
943
960
|
if (!content) {
|
|
944
961
|
fail("Nothing to reshape.");
|
|
@@ -977,14 +994,15 @@ async function shape(args) {
|
|
|
977
994
|
return 0;
|
|
978
995
|
}
|
|
979
996
|
async function queue(args) {
|
|
980
|
-
const { json, rest } =
|
|
981
|
-
const
|
|
982
|
-
if (!
|
|
997
|
+
const { json, rest } = parseFlags(args);
|
|
998
|
+
const ref = rest[0] ? resolveRef(rest[0]) : null;
|
|
999
|
+
if (!ref) {
|
|
983
1000
|
fail("Which post?");
|
|
984
|
-
note(dim2(`${CMD}
|
|
1001
|
+
note(dim2(`${CMD} drafts then ${CMD} queue 3`));
|
|
1002
|
+
note(dim2(`Or pass the id: ${CMD} queue <post-id>`));
|
|
985
1003
|
return 1;
|
|
986
1004
|
}
|
|
987
|
-
const result = await request(`/api/posts/${encodeURIComponent(id)}/queue`, { method: "POST", timeoutMs: 60000 });
|
|
1005
|
+
const result = await request(`/api/posts/${encodeURIComponent(ref.id)}/queue`, { method: "POST", timeoutMs: 60000 });
|
|
988
1006
|
if (json) {
|
|
989
1007
|
out(JSON.stringify(result, null, 2));
|
|
990
1008
|
return 0;
|
|
@@ -999,7 +1017,7 @@ async function queue(args) {
|
|
|
999
1017
|
return 0;
|
|
1000
1018
|
}
|
|
1001
1019
|
async function save(args) {
|
|
1002
|
-
const { json } =
|
|
1020
|
+
const { json } = parseFlags(args);
|
|
1003
1021
|
const held = getDraft();
|
|
1004
1022
|
if (!held?.content) {
|
|
1005
1023
|
fail("Nothing to save.");
|
|
@@ -1026,7 +1044,7 @@ async function save(args) {
|
|
|
1026
1044
|
return 0;
|
|
1027
1045
|
}
|
|
1028
1046
|
async function open(args) {
|
|
1029
|
-
const { json, rest } =
|
|
1047
|
+
const { json, rest } = parseFlags(args);
|
|
1030
1048
|
const ref = rest[0];
|
|
1031
1049
|
if (!ref) {
|
|
1032
1050
|
fail("Open which one?");
|
|
@@ -1058,7 +1076,7 @@ async function open(args) {
|
|
|
1058
1076
|
return 0;
|
|
1059
1077
|
}
|
|
1060
1078
|
async function ask(args) {
|
|
1061
|
-
const { json, rest } =
|
|
1079
|
+
const { json, rest } = parseFlags(args);
|
|
1062
1080
|
const message = rest.join(" ").trim();
|
|
1063
1081
|
const held = getDraft();
|
|
1064
1082
|
if (!message) {
|
|
@@ -1112,7 +1130,7 @@ async function ask(args) {
|
|
|
1112
1130
|
return 0;
|
|
1113
1131
|
}
|
|
1114
1132
|
async function show(args) {
|
|
1115
|
-
const { json } =
|
|
1133
|
+
const { json } = parseFlags(args);
|
|
1116
1134
|
const held = getDraft();
|
|
1117
1135
|
if (!held?.content) {
|
|
1118
1136
|
note("Nothing in hand.");
|
|
@@ -1150,7 +1168,7 @@ async function drop() {
|
|
|
1150
1168
|
return 0;
|
|
1151
1169
|
}
|
|
1152
1170
|
async function unqueue(args) {
|
|
1153
|
-
const { json, rest } =
|
|
1171
|
+
const { json, rest } = parseFlags(args);
|
|
1154
1172
|
const ref = rest[0] ? resolveRef(rest[0]) : null;
|
|
1155
1173
|
if (!ref) {
|
|
1156
1174
|
fail("Which post?");
|
|
@@ -1410,6 +1428,12 @@ var COMMANDS = {
|
|
|
1410
1428
|
detail: "The undo for queue, while there is still time. The post returns to your drafts and nothing goes live. Once it has been published this refuses, because a live post cannot be unsent this way.",
|
|
1411
1429
|
examples: ["innernote unqueue p17abc...", "innernote unqueue 3"]
|
|
1412
1430
|
},
|
|
1431
|
+
skill: {
|
|
1432
|
+
summary: "print the agent skill, or install it for Claude Code",
|
|
1433
|
+
usage: "innernote skill [--install]",
|
|
1434
|
+
detail: "The playbook an agent should read before driving this CLI: the loop, the read-before-write rule, what the exit codes mean, and the one rule that protects real people. Prints to stdout so any agent can take it. --install also registers it in ~/.claude/skills so Claude Code knows it in every future session.",
|
|
1435
|
+
examples: ["innernote skill", "innernote skill --install"]
|
|
1436
|
+
},
|
|
1413
1437
|
context: {
|
|
1414
1438
|
summary: "what you post about: your pillars and your series",
|
|
1415
1439
|
usage: "innernote context",
|
|
@@ -1419,8 +1443,8 @@ var COMMANDS = {
|
|
|
1419
1443
|
queue: {
|
|
1420
1444
|
summary: "schedule a post into your next open slot",
|
|
1421
1445
|
usage: "innernote queue <post-id>",
|
|
1422
|
-
detail: "A queued post GOES LIVE on LinkedIn on its own at your next cadence slot. Nobody presses anything again. Needs a connection you allowed to publish: tick that box in Settings when you generate the code.",
|
|
1423
|
-
examples: ["innernote drafts", "innernote queue p17a1yk936ywnan10643efjtc58dhkah"]
|
|
1446
|
+
detail: "A queued post GOES LIVE on LinkedIn on its own at your next cadence slot. Nobody presses anything again. Needs a connection you allowed to publish: tick that box in Settings when you generate the code. Takes a number from the last list, or a full id. It never assumes the draft in hand: this is the one command that makes you say which post.",
|
|
1447
|
+
examples: ["innernote drafts", "innernote queue 3", "innernote queue p17a1yk936ywnan10643efjtc58dhkah"]
|
|
1424
1448
|
}
|
|
1425
1449
|
};
|
|
1426
1450
|
function commandHelp(name) {
|
|
@@ -1533,8 +1557,29 @@ function suggest(state) {
|
|
|
1533
1557
|
// package.json
|
|
1534
1558
|
var package_default = {
|
|
1535
1559
|
name: "innernote",
|
|
1536
|
-
version: "0.3.
|
|
1560
|
+
version: "0.3.4",
|
|
1537
1561
|
description: "Write LinkedIn posts in your voice, from the terminal.",
|
|
1562
|
+
keywords: [
|
|
1563
|
+
"linkedin",
|
|
1564
|
+
"mcp",
|
|
1565
|
+
"mcp-server",
|
|
1566
|
+
"model-context-protocol",
|
|
1567
|
+
"ai-agent",
|
|
1568
|
+
"claude",
|
|
1569
|
+
"claude-code",
|
|
1570
|
+
"cursor",
|
|
1571
|
+
"agent-skill",
|
|
1572
|
+
"writing",
|
|
1573
|
+
"content",
|
|
1574
|
+
"personal-branding",
|
|
1575
|
+
"ghostwriting",
|
|
1576
|
+
"cli"
|
|
1577
|
+
],
|
|
1578
|
+
homepage: "https://www.innernote.space/cli",
|
|
1579
|
+
license: "UNLICENSED",
|
|
1580
|
+
bugs: {
|
|
1581
|
+
url: "https://www.innernote.space/cli"
|
|
1582
|
+
},
|
|
1538
1583
|
type: "module",
|
|
1539
1584
|
bin: {
|
|
1540
1585
|
innernote: "dist/index.js"
|
|
@@ -1616,6 +1661,42 @@ async function home(inSession = false) {
|
|
|
1616
1661
|
return 0;
|
|
1617
1662
|
}
|
|
1618
1663
|
|
|
1664
|
+
// src/commands/skill.ts
|
|
1665
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
1666
|
+
import { homedir as homedir2 } from "node:os";
|
|
1667
|
+
import { dirname, join as join2 } from "node:path";
|
|
1668
|
+
import { fileURLToPath } from "node:url";
|
|
1669
|
+
async function readSkill() {
|
|
1670
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
1671
|
+
for (const rel of ["../../skills/innernote-cli/SKILL.md", "../skills/innernote-cli/SKILL.md"]) {
|
|
1672
|
+
try {
|
|
1673
|
+
return await readFile2(join2(here, rel), "utf8");
|
|
1674
|
+
} catch {}
|
|
1675
|
+
}
|
|
1676
|
+
return null;
|
|
1677
|
+
}
|
|
1678
|
+
async function skill(args) {
|
|
1679
|
+
const install = args.includes("--install");
|
|
1680
|
+
const text = await readSkill();
|
|
1681
|
+
if (!text) {
|
|
1682
|
+
fail("The skill file is missing from this install.");
|
|
1683
|
+
note(dim2("Reinstall with `npm i -g innernote`, or read it on any machine with the package."));
|
|
1684
|
+
return 1;
|
|
1685
|
+
}
|
|
1686
|
+
if (install) {
|
|
1687
|
+
const dir = join2(homedir2(), ".claude", "skills", "innernote-cli");
|
|
1688
|
+
await mkdir2(dir, { recursive: true });
|
|
1689
|
+
const target = join2(dir, "SKILL.md");
|
|
1690
|
+
await writeFile2(target, text);
|
|
1691
|
+
await chmod2(target, 420);
|
|
1692
|
+
ok(`Installed for Claude Code at ${target}`);
|
|
1693
|
+
note(dim2("It loads in future sessions on its own. Here it is for this one:"));
|
|
1694
|
+
note("");
|
|
1695
|
+
}
|
|
1696
|
+
out(text);
|
|
1697
|
+
return 0;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1619
1700
|
// src/session.ts
|
|
1620
1701
|
import { createInterface } from "node:readline";
|
|
1621
1702
|
|
|
@@ -1761,6 +1842,12 @@ var COMMANDS2 = {
|
|
|
1761
1842
|
detail: "The undo for queue, while there is still time. The post returns to your drafts and nothing goes live. Once it has been published this refuses, because a live post cannot be unsent this way.",
|
|
1762
1843
|
examples: ["innernote unqueue p17abc...", "innernote unqueue 3"]
|
|
1763
1844
|
},
|
|
1845
|
+
skill: {
|
|
1846
|
+
summary: "print the agent skill, or install it for Claude Code",
|
|
1847
|
+
usage: "innernote skill [--install]",
|
|
1848
|
+
detail: "The playbook an agent should read before driving this CLI: the loop, the read-before-write rule, what the exit codes mean, and the one rule that protects real people. Prints to stdout so any agent can take it. --install also registers it in ~/.claude/skills so Claude Code knows it in every future session.",
|
|
1849
|
+
examples: ["innernote skill", "innernote skill --install"]
|
|
1850
|
+
},
|
|
1764
1851
|
context: {
|
|
1765
1852
|
summary: "what you post about: your pillars and your series",
|
|
1766
1853
|
usage: "innernote context",
|
|
@@ -1770,8 +1857,8 @@ var COMMANDS2 = {
|
|
|
1770
1857
|
queue: {
|
|
1771
1858
|
summary: "schedule a post into your next open slot",
|
|
1772
1859
|
usage: "innernote queue <post-id>",
|
|
1773
|
-
detail: "A queued post GOES LIVE on LinkedIn on its own at your next cadence slot. Nobody presses anything again. Needs a connection you allowed to publish: tick that box in Settings when you generate the code.",
|
|
1774
|
-
examples: ["innernote drafts", "innernote queue p17a1yk936ywnan10643efjtc58dhkah"]
|
|
1860
|
+
detail: "A queued post GOES LIVE on LinkedIn on its own at your next cadence slot. Nobody presses anything again. Needs a connection you allowed to publish: tick that box in Settings when you generate the code. Takes a number from the last list, or a full id. It never assumes the draft in hand: this is the one command that makes you say which post.",
|
|
1861
|
+
examples: ["innernote drafts", "innernote queue 3", "innernote queue p17a1yk936ywnan10643efjtc58dhkah"]
|
|
1775
1862
|
}
|
|
1776
1863
|
};
|
|
1777
1864
|
function commandHelp2(name) {
|
|
@@ -2029,7 +2116,7 @@ function whatThereIs() {
|
|
|
2029
2116
|
["Writing", ["write", "shape", "ask", "save", "capture"]],
|
|
2030
2117
|
["Looking", ["show", "ideas", "drafts", "open", "week", "context", "whoami"]],
|
|
2031
2118
|
["Shipping", ["queue", "unqueue"]],
|
|
2032
|
-
["Connection", ["login", "logout"]]
|
|
2119
|
+
["Connection", ["login", "logout", "skill"]]
|
|
2033
2120
|
];
|
|
2034
2121
|
for (const [title, cmds] of groups) {
|
|
2035
2122
|
lines.push(` ${bold2(title)}`);
|
|
@@ -2055,7 +2142,7 @@ var VERSION2 = package_default.version;
|
|
|
2055
2142
|
// src/index.ts
|
|
2056
2143
|
function commandList() {
|
|
2057
2144
|
const groups = [
|
|
2058
|
-
["Getting connected", ["login", "logout", "whoami"]],
|
|
2145
|
+
["Getting connected", ["login", "logout", "whoami", "skill"]],
|
|
2059
2146
|
["Writing", ["write", "shape", "ask", "save", "capture"]],
|
|
2060
2147
|
["Looking", ["show", "ideas", "drafts", "open", "week", "context"]],
|
|
2061
2148
|
["Shipping", ["queue", "unqueue"]]
|
|
@@ -2084,6 +2171,7 @@ var HELP = () => [
|
|
|
2084
2171
|
`);
|
|
2085
2172
|
var COMMANDS3 = {
|
|
2086
2173
|
context,
|
|
2174
|
+
skill,
|
|
2087
2175
|
login,
|
|
2088
2176
|
logout: () => logout(),
|
|
2089
2177
|
whoami,
|
|
@@ -2156,7 +2244,7 @@ main().then((code) => {
|
|
|
2156
2244
|
}
|
|
2157
2245
|
if (isApiError(err)) {
|
|
2158
2246
|
fail2(err.message);
|
|
2159
|
-
process.exitCode = err.isRefusal ? 3 : 1;
|
|
2247
|
+
process.exitCode = err.isNotConnected ? 2 : err.isRefusal ? 3 : 1;
|
|
2160
2248
|
return;
|
|
2161
2249
|
}
|
|
2162
2250
|
fail2(err instanceof Error ? err.message : String(err));
|
package/package.json
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "innernote",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Write LinkedIn posts in your voice, from the terminal.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"linkedin",
|
|
7
|
+
"mcp",
|
|
8
|
+
"mcp-server",
|
|
9
|
+
"model-context-protocol",
|
|
10
|
+
"ai-agent",
|
|
11
|
+
"claude",
|
|
12
|
+
"claude-code",
|
|
13
|
+
"cursor",
|
|
14
|
+
"agent-skill",
|
|
15
|
+
"writing",
|
|
16
|
+
"content",
|
|
17
|
+
"personal-branding",
|
|
18
|
+
"ghostwriting",
|
|
19
|
+
"cli"
|
|
20
|
+
],
|
|
21
|
+
"homepage": "https://www.innernote.space/cli",
|
|
22
|
+
"license": "UNLICENSED",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://www.innernote.space/cli"
|
|
25
|
+
},
|
|
5
26
|
"type": "module",
|
|
6
27
|
"bin": {
|
|
7
28
|
"innernote": "dist/index.js"
|