@workjournal/cli 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 +47 -56
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +8 -8
- package/dist/auth.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,93 +1,84 @@
|
|
|
1
1
|
# @workjournal/cli
|
|
2
2
|
|
|
3
|
-
Command-line tool for
|
|
3
|
+
Command-line tool for [Workjournal](https://workjournal.pro) — manage journals, entries, and collaborators from your terminal.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
Run on demand without installing:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @workjournal/cli
|
|
10
|
+
npx @workjournal/cli <command>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Or install globally:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install -g @workjournal/cli
|
|
17
|
-
workjournal
|
|
17
|
+
workjournal <command>
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
| Command | Description |
|
|
23
|
-
|---------|-------------|
|
|
24
|
-
| `workjournal login` | Interactive paste-back login (terminal only) |
|
|
25
|
-
| `workjournal login start` | Print authorize URL and store PKCE state |
|
|
26
|
-
| `workjournal login finish <CODE>` | Exchange the pasted code for credentials |
|
|
27
|
-
| `workjournal logout` | Remove stored credentials |
|
|
28
|
-
| `workjournal whoami` | Check if authenticated |
|
|
29
|
-
| `workjournal status` | Show token expiry details |
|
|
30
|
-
|
|
31
|
-
## How login works
|
|
32
|
-
|
|
33
|
-
The CLI uses OAuth out-of-band redirect (`urn:ietf:wg:oauth:2.0:oob`) with PKCE. There is no port binding, no auto-opened browser, and no callback server. The flow works equally well in local terminals, SSH sessions, dev containers, and CI.
|
|
34
|
-
|
|
35
|
-
### Interactive (terminal)
|
|
20
|
+
## First-time setup
|
|
36
21
|
|
|
37
22
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
https://app.workjournal.pro/authorize?...
|
|
42
|
-
|
|
43
|
-
Code: ABC123DE
|
|
44
|
-
Authenticated successfully!
|
|
45
|
-
Credentials saved to ~/.workjournal/credentials.json
|
|
23
|
+
workjournal auth login # authenticate
|
|
24
|
+
workjournal journals list # find your journal ID
|
|
25
|
+
workjournal journals select <id> # set it as the active journal
|
|
46
26
|
```
|
|
47
27
|
|
|
48
|
-
|
|
28
|
+
Once a journal is selected, `workjournal journal ...` acts on it without repeating the ID.
|
|
49
29
|
|
|
50
|
-
|
|
30
|
+
## Commands
|
|
51
31
|
|
|
52
|
-
|
|
32
|
+
| Command | Description |
|
|
33
|
+
|---------|-------------|
|
|
34
|
+
| `workjournal journal entries` | List entries |
|
|
35
|
+
| `workjournal journal entries write -s <summary> -b <body>` | Create an entry |
|
|
36
|
+
| `workjournal journal entries last [count]` | Show the most recent entries |
|
|
37
|
+
| `workjournal journal entries search <query>` | Search entries |
|
|
38
|
+
| `workjournal journal invites new <email>` | Invite a collaborator |
|
|
39
|
+
| `workjournal journal shares` | List members |
|
|
40
|
+
| `workjournal journal export [-f json\|md\|csv] [-p <path>]` | Export journal data |
|
|
41
|
+
| `workjournal journals list` | List journals you have access to |
|
|
42
|
+
| `workjournal journals new <name>` | Create a new journal |
|
|
43
|
+
| `workjournal journals select <id>` | Set the active journal |
|
|
44
|
+
| `workjournal auth login` | Interactive login (works over SSH too) |
|
|
45
|
+
| `workjournal auth logout` | Remove stored credentials |
|
|
46
|
+
| `workjournal auth whoami` | Show current auth status |
|
|
47
|
+
| `workjournal --json <command>` | Output raw JSON instead of tables |
|
|
48
|
+
| `workjournal help` | Full command reference |
|
|
49
|
+
|
|
50
|
+
For the complete command reference, see **[workjournal.pro/docs/commands](https://workjournal.pro/docs/commands)**.
|
|
51
|
+
|
|
52
|
+
## Typical workflows
|
|
53
|
+
|
|
54
|
+
Add a new entry to the selected journal:
|
|
53
55
|
|
|
54
56
|
```bash
|
|
55
|
-
workjournal
|
|
56
|
-
# user opens URL, approves, copies the displayed code
|
|
57
|
-
workjournal login finish ABC123DE # reads state, exchanges code, writes credentials
|
|
57
|
+
workjournal journal entries write -s "Shipped v2 API" -b "Migrated /v1 callers and flipped the flag."
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
## Credential storage
|
|
60
|
+
Invite a collaborator:
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
~/.workjournal/
|
|
68
|
-
├── credentials.json # { access_token, refresh_token, expires_at }
|
|
69
|
-
└── cli-login-state.json # ephemeral PKCE state, deleted after `login finish`
|
|
62
|
+
```bash
|
|
63
|
+
workjournal journal invites new alice@example.com
|
|
70
64
|
```
|
|
71
65
|
|
|
72
|
-
|
|
66
|
+
Export a journal to Markdown:
|
|
73
67
|
|
|
74
|
-
|
|
68
|
+
```bash
|
|
69
|
+
workjournal journal export -f md -p ./journal.md
|
|
70
|
+
```
|
|
75
71
|
|
|
76
|
-
|
|
72
|
+
## Credentials
|
|
77
73
|
|
|
78
|
-
|
|
74
|
+
The CLI stores credentials at `~/.workjournal/credentials.json` with user-only file permissions. Remove them with `workjournal auth logout`.
|
|
79
75
|
|
|
80
|
-
##
|
|
76
|
+
## Headless environments
|
|
81
77
|
|
|
82
|
-
|
|
83
|
-
- **Codes are single-use** and expire 5 minutes after `login start`.
|
|
84
|
-
- **No tokens in URLs** — the access token never appears in any redirect.
|
|
85
|
-
- **Constant-time comparison** of the PKCE verifier on the API side prevents timing attacks.
|
|
86
|
-
- **No long-lived listener** on the user's machine — the CLI binds no sockets.
|
|
78
|
+
`workjournal auth login` works in SSH sessions, dev containers, and CI — it binds no ports and does not require a browser on the same machine. You only need a browser somewhere (laptop, phone) to open the authorize URL.
|
|
87
79
|
|
|
88
80
|
## Links
|
|
89
81
|
|
|
90
82
|
- [Workjournal](https://workjournal.pro)
|
|
91
|
-
- [Get
|
|
92
|
-
- [
|
|
93
|
-
- [CLI auth workflow reference](https://github.com/workjournal-pro/workjournal/blob/main/docs/cli-tool-auth-workflow.md)
|
|
83
|
+
- [Get started](https://workjournal.pro/docs/get-started)
|
|
84
|
+
- [Full command reference](https://workjournal.pro/docs/commands)
|
package/dist/auth.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The state file holds the verifier between this command and `loginFinish`. The
|
|
5
5
|
* assistant (or the user) is expected to open the URL, approve the request, and
|
|
6
|
-
* paste the displayed code back into a `workjournal login finish <CODE>` call.
|
|
6
|
+
* paste the displayed code back into a `workjournal auth login finish <CODE>` call.
|
|
7
7
|
*/
|
|
8
8
|
export declare function loginStart(): Promise<void>;
|
|
9
9
|
/**
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBhD;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBhD;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA2CtD"}
|
package/dist/auth.js
CHANGED
|
@@ -7,7 +7,7 @@ import { warnIfWsl } from './wsl.js';
|
|
|
7
7
|
*
|
|
8
8
|
* The state file holds the verifier between this command and `loginFinish`. The
|
|
9
9
|
* assistant (or the user) is expected to open the URL, approve the request, and
|
|
10
|
-
* paste the displayed code back into a `workjournal login finish <CODE>` call.
|
|
10
|
+
* paste the displayed code back into a `workjournal auth login finish <CODE>` call.
|
|
11
11
|
*/
|
|
12
12
|
export async function loginStart() {
|
|
13
13
|
await warnIfWsl({ interactive: false });
|
|
@@ -22,7 +22,7 @@ export async function loginStart() {
|
|
|
22
22
|
process.stdout.write('Open this URL in any browser:\n\n');
|
|
23
23
|
process.stdout.write(` ${url}\n\n`);
|
|
24
24
|
process.stdout.write('After approving, run:\n\n');
|
|
25
|
-
process.stdout.write(' workjournal login finish <CODE>\n');
|
|
25
|
+
process.stdout.write(' workjournal auth login finish <CODE>\n');
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* Phase 2: read the verifier from the state file, exchange the pasted code for
|
|
@@ -35,17 +35,17 @@ export async function loginStart() {
|
|
|
35
35
|
export async function loginFinish(rawCode) {
|
|
36
36
|
const code = rawCode.trim().toUpperCase();
|
|
37
37
|
if (!code) {
|
|
38
|
-
process.stderr.write('Error: missing code argument.\nUsage: workjournal login finish <CODE>\n');
|
|
38
|
+
process.stderr.write('Error: missing code argument.\nUsage: workjournal auth login finish <CODE>\n');
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
41
41
|
const state = readLoginState();
|
|
42
42
|
if (!state) {
|
|
43
|
-
process.stderr.write('Error: no login in progress. Run `workjournal login start` first.\n');
|
|
43
|
+
process.stderr.write('Error: no login in progress. Run `workjournal auth login start` first.\n');
|
|
44
44
|
process.exit(1);
|
|
45
45
|
}
|
|
46
46
|
if (isLoginStateExpired(state)) {
|
|
47
47
|
clearLoginState();
|
|
48
|
-
process.stderr.write('Error: login state expired. Run `workjournal login start` again.\n');
|
|
48
|
+
process.stderr.write('Error: login state expired. Run `workjournal auth login start` again.\n');
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
await exchangeAndPersist(code, state.verifier);
|
|
@@ -62,10 +62,10 @@ export async function loginFinish(rawCode) {
|
|
|
62
62
|
*/
|
|
63
63
|
export async function loginInteractive() {
|
|
64
64
|
if (!process.stdin.isTTY) {
|
|
65
|
-
process.stderr.write('Error: `workjournal login` with no subcommand requires an interactive terminal.\n' +
|
|
65
|
+
process.stderr.write('Error: `workjournal auth login` with no subcommand requires an interactive terminal.\n' +
|
|
66
66
|
'For non-interactive use, run:\n' +
|
|
67
|
-
' workjournal login start\n' +
|
|
68
|
-
' workjournal login finish <CODE>\n');
|
|
67
|
+
' workjournal auth login start\n' +
|
|
68
|
+
' workjournal auth login finish <CODE>\n');
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
await warnIfWsl({ interactive: true });
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EACN,UAAU,EACV,eAAe,EACf,mBAAmB,EAEnB,cAAc,EAEd,gBAAgB,EAChB,eAAe,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC/B,MAAM,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IAExC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAe;QACzB,QAAQ;QACR,SAAS;QACT,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,eAAe,CAAC,KAAK,CAAC,CAAC;IAEvB,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workjournal/cli",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Command-line tool for
|
|
3
|
+
"version": "0.3.4",
|
|
4
|
+
"description": "Command-line tool for Workjournal — manage journals, entries, and collaborators from your terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|