innernote 0.1.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 +241 -0
- package/dist/index.js +1969 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# innernote CLI
|
|
2
|
+
|
|
3
|
+
Write LinkedIn posts in your voice, from the terminal.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
innernote capture "the thing you just thought of"
|
|
7
|
+
innernote write "why most onboarding asks for too much upfront" --save
|
|
8
|
+
innernote week
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Needs [Node](https://nodejs.org) 20 or newer. Nothing else.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx innernote
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Run it without installing anything, or put it on your PATH for good:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g innernote
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then connect the machine to your account:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
innernote login
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
It asks for a pairing code, which you get from
|
|
32
|
+
[Settings](https://www.innernote.space/dashboard/settings). The key it saves
|
|
33
|
+
lasts 90 days and can be revoked from the same page.
|
|
34
|
+
|
|
35
|
+
### Working on it
|
|
36
|
+
|
|
37
|
+
The source is TypeScript and runs on [Bun](https://bun.sh):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run src/index.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`bun run build` produces the published bundle in `dist/`, which is what npm
|
|
44
|
+
ships and what `bun test` exercises in `dist.test.ts`. The published file runs
|
|
45
|
+
on node; the source does not.
|
|
46
|
+
|
|
47
|
+
## The session
|
|
48
|
+
|
|
49
|
+
Typing `innernote` on its own opens a session you stay in, the way `claude` or
|
|
50
|
+
`psql` do. Your week, then a prompt:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
▍ week
|
|
54
|
+
▍ write "hiring your first engineer" --save
|
|
55
|
+
▍ capture the thing that just came up
|
|
56
|
+
▍ exit
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Up arrow for history, tab to complete a command, `help` for what there is.
|
|
60
|
+
**Ctrl-C once cancels what you are typing; twice leaves.**
|
|
61
|
+
|
|
62
|
+
Piped or redirected it prints your week and exits instead, so it never hangs a
|
|
63
|
+
script waiting for input nobody is going to type.
|
|
64
|
+
|
|
65
|
+
## Connect
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
innernote login
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It prints a URL. Open it in a browser where you are already signed in, copy the
|
|
72
|
+
eight-character pairing code, and paste it back. The code works once and expires
|
|
73
|
+
in ten minutes.
|
|
74
|
+
|
|
75
|
+
The token it gives you is stored at `~/.innernote/config.json`, owner-read-only.
|
|
76
|
+
It is opaque, it is not your password, and you can revoke it from Settings at
|
|
77
|
+
any time.
|
|
78
|
+
|
|
79
|
+
## Commands
|
|
80
|
+
|
|
81
|
+
| Command | What it does |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `login [code]` | connect this machine |
|
|
84
|
+
| `logout` | forget the token stored here |
|
|
85
|
+
| `whoami` | show which account is connected |
|
|
86
|
+
| `capture <text>` | save an idea to your inbox |
|
|
87
|
+
| `write [topic]` | draft a post in your voice |
|
|
88
|
+
| `ideas [status]` | list what you have captured |
|
|
89
|
+
| `drafts [status]` | list your posts, with their ids |
|
|
90
|
+
| `week` | what is scheduled for the next seven days |
|
|
91
|
+
| `shape <shape...>` | push a post shorter, punchier, warmer (reads stdin) |
|
|
92
|
+
| `queue <post-id>` | schedule a post into your next open slot |
|
|
93
|
+
|
|
94
|
+
### write
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
innernote write # picks the pillar you have covered least
|
|
98
|
+
innernote write "hiring your first engineer"
|
|
99
|
+
innernote write --thought "$(cat notes/monday.md)"
|
|
100
|
+
innernote write "shipping fast" --format story --save
|
|
101
|
+
cat brief.md | innernote write
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Without `--save` the post is printed and nothing is stored, so you can pipe it:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
innernote write "onboarding" | pbcopy
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The draft comes from the same generation the app runs: same voice, same craft
|
|
111
|
+
rules, same check against what you have already published. It is not a lighter
|
|
112
|
+
version.
|
|
113
|
+
|
|
114
|
+
### shape
|
|
115
|
+
|
|
116
|
+
The same twelve moves the app's editor has. It reads the post from stdin, so it
|
|
117
|
+
composes:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pbpaste | innernote shape shorter punchier | pbcopy
|
|
121
|
+
innernote write "onboarding" --json | jq -r .content | innernote shape deslop
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Shapes: `hook` `example` `specific` `punchier` `shorter` `ending` `warmer`
|
|
125
|
+
`deslop` `mobile` `question` `takeaway` `jargon`
|
|
126
|
+
|
|
127
|
+
The names are the server's. The CLI never writes the instruction itself, so
|
|
128
|
+
"shorter" means the same thing here as it does in the editor and inside a chat.
|
|
129
|
+
|
|
130
|
+
### queue
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
innernote queue p17a1yk936ywnan10643efjtc58dhkah
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**A queued post goes live on its own** at your next cadence slot. Nobody presses
|
|
137
|
+
anything again. So it needs a connection you explicitly allowed to publish: tick
|
|
138
|
+
"Let it queue posts" in Settings when you generate the pairing code. Without it
|
|
139
|
+
you get a clear refusal, not a mystery.
|
|
140
|
+
|
|
141
|
+
innernote inside a chat can queue too, if you tick the same box for that
|
|
142
|
+
connection. It can only queue a post you already saved and read, and your chat
|
|
143
|
+
client asks you before it runs. Publish is in nobody's default grant, so every
|
|
144
|
+
connection that can schedule was one you deliberately allowed.
|
|
145
|
+
|
|
146
|
+
## Piping
|
|
147
|
+
|
|
148
|
+
Every command takes `--json` and prints the API's own payload, nothing else.
|
|
149
|
+
Human output and errors go to stderr, so stdout stays clean:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
innernote ideas --json | jq -r '.[].content'
|
|
153
|
+
innernote week --json | jq 'length'
|
|
154
|
+
pbpaste | innernote capture
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Exit codes
|
|
158
|
+
|
|
159
|
+
| Code | Meaning |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| 0 | it worked |
|
|
162
|
+
| 1 | it failed; the reason is on stderr |
|
|
163
|
+
| 2 | not connected, run `innernote login` |
|
|
164
|
+
| 3 | your account cannot do this right now |
|
|
165
|
+
|
|
166
|
+
Code 3 is separate on purpose. A scheduled job should be able to tell "innernote
|
|
167
|
+
is broken" from "your trial ended", because only one of those is worth waking
|
|
168
|
+
someone up for.
|
|
169
|
+
|
|
170
|
+
## Environment
|
|
171
|
+
|
|
172
|
+
| Variable | Effect |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| `INNERNOTE_TOKEN` | use this token, ignore the stored one |
|
|
175
|
+
| `INNERNOTE_API_URL` | talk to another host, for development |
|
|
176
|
+
| `NO_COLOR` | plain output |
|
|
177
|
+
|
|
178
|
+
Both token variables override the config file and are never written back, which
|
|
179
|
+
is what makes the CLI usable in CI without a second config format.
|
|
180
|
+
|
|
181
|
+
## How it works
|
|
182
|
+
|
|
183
|
+
The CLI is a thin client over the same HTTP API the web app uses. It holds no
|
|
184
|
+
database credentials and implements no product logic. Everything it can do is
|
|
185
|
+
something the API already lets your account do, so entitlement, limits and voice
|
|
186
|
+
all behave exactly as they do in the app, because the work happens server-side
|
|
187
|
+
in one place.
|
|
188
|
+
|
|
189
|
+
## The writer, here
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
▍ drafts
|
|
193
|
+
▍ open 3
|
|
194
|
+
▍ ask cut the second half and land it harder
|
|
195
|
+
▍ save
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`shape` covers the twelve named moves. `ask` covers everything else, in your own
|
|
199
|
+
words: it is the same assistant the app's composer runs, so it can change the
|
|
200
|
+
post, answer a question about it, or say it would rather not.
|
|
201
|
+
|
|
202
|
+
`show` reprints whatever you are holding, and the prompt says whether it is
|
|
203
|
+
saved, so you always know where you are. `drop` puts it down.
|
|
204
|
+
|
|
205
|
+
## Checking the whole flow
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
bun run cli/e2e.ts
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Runs the real user journey against a real server: connect, read pillars and
|
|
212
|
+
series, capture an idea, draft a post, reshape it, save it, then delete
|
|
213
|
+
everything it made. It reports what passed and cleans up after itself.
|
|
214
|
+
|
|
215
|
+
**It never publishes.** There is no queue step and there will not be one. A test
|
|
216
|
+
that can publish eventually will, on a real account, to real people. Queueing is
|
|
217
|
+
verified by asserting the refusal on a key that was not granted publish, which
|
|
218
|
+
proves the gate without touching it.
|
|
219
|
+
|
|
220
|
+
Point it anywhere:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
INNERNOTE_API_URL=http://localhost:3000 bun run cli/e2e.ts
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Development
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
bun run src/index.ts --help
|
|
230
|
+
bun test
|
|
231
|
+
bun run typecheck
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Point it at a local server:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
INNERNOTE_API_URL=http://localhost:3000 bun run src/index.ts whoami
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This package is deliberately outside the app's workspace and has no runtime
|
|
241
|
+
dependencies, so it cannot affect the web build.
|