@workjournal/cli 0.8.0 → 0.17.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 +11 -1
- package/dist/api-client.d.ts +26 -9
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +109 -57
- package/dist/api-client.js.map +1 -1
- package/dist/auth.d.ts +6 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +18 -0
- package/dist/auth.js.map +1 -1
- package/dist/cli-args.d.ts +19 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +50 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/commands/entries.d.ts +8 -1
- package/dist/commands/entries.d.ts.map +1 -1
- package/dist/commands/entries.js +74 -15
- package/dist/commands/entries.js.map +1 -1
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +2 -3
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/invites.d.ts.map +1 -1
- package/dist/commands/invites.js +6 -7
- package/dist/commands/invites.js.map +1 -1
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.d.ts.map +1 -1
- package/dist/commands/journals.js +20 -19
- package/dist/commands/journals.js.map +1 -1
- package/dist/commands/prompts.d.ts +9 -0
- package/dist/commands/prompts.d.ts.map +1 -0
- package/dist/commands/prompts.js +83 -0
- package/dist/commands/prompts.js.map +1 -0
- package/dist/commands/shares.d.ts.map +1 -1
- package/dist/commands/shares.js +11 -13
- package/dist/commands/shares.js.map +1 -1
- package/dist/commands/tags.d.ts +7 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +87 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/workspaces.d.ts.map +1 -1
- package/dist/commands/workspaces.js +4 -7
- package/dist/commands/workspaces.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/help/_dispatch.d.ts +29 -0
- package/dist/help/_dispatch.d.ts.map +1 -0
- package/dist/help/_dispatch.js +132 -0
- package/dist/help/_dispatch.js.map +1 -0
- package/dist/help/_registry.d.ts +18 -0
- package/dist/help/_registry.d.ts.map +1 -0
- package/dist/help/_registry.js +98 -0
- package/dist/help/_registry.js.map +1 -0
- package/dist/help/_renderer.d.ts +31 -0
- package/dist/help/_renderer.d.ts.map +1 -0
- package/dist/help/_renderer.js +99 -0
- package/dist/help/_renderer.js.map +1 -0
- package/dist/help/_types.d.ts +53 -0
- package/dist/help/_types.d.ts.map +1 -0
- package/dist/help/_types.js +15 -0
- package/dist/help/_types.js.map +1 -0
- package/dist/help/auth-login.json +12 -0
- package/dist/help/auth-logout.json +7 -0
- package/dist/help/auth-status.json +7 -0
- package/dist/help/auth-whoami.json +7 -0
- package/dist/help/config-show.json +7 -0
- package/dist/help/entries-delete.json +12 -0
- package/dist/help/entries-get.json +12 -0
- package/dist/help/entries-last.json +19 -0
- package/dist/help/entries-list.json +14 -0
- package/dist/help/entries-search.json +15 -0
- package/dist/help/entries-update.json +44 -0
- package/dist/help/entries-write.json +39 -0
- package/dist/help/export.json +29 -0
- package/dist/help/invites-delete.json +16 -0
- package/dist/help/invites-list.json +11 -0
- package/dist/help/invites-new.json +12 -0
- package/dist/help/journal.json +13 -0
- package/dist/help/journals-assign-prompt.json +12 -0
- package/dist/help/journals-delete.json +11 -0
- package/dist/help/journals-get.json +20 -0
- package/dist/help/journals-list.json +14 -0
- package/dist/help/journals-new.json +21 -0
- package/dist/help/journals-rename.json +12 -0
- package/dist/help/journals-select.json +11 -0
- package/dist/help/journals-set-slug.json +16 -0
- package/dist/help/journals-unassign-prompt.json +11 -0
- package/dist/help/prompts-delete.json +11 -0
- package/dist/help/prompts-get.json +11 -0
- package/dist/help/prompts-list.json +14 -0
- package/dist/help/prompts-new.json +23 -0
- package/dist/help/prompts-update.json +29 -0
- package/dist/help/shares-delete.json +16 -0
- package/dist/help/shares-list.json +11 -0
- package/dist/help/tags-delete.json +29 -0
- package/dist/help/tags-get.json +29 -0
- package/dist/help/tags-list.json +25 -0
- package/dist/help/tags-new.json +35 -0
- package/dist/help/tags-update.json +41 -0
- package/dist/index.js +312 -79
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"command": "tags new",
|
|
3
|
+
"description": "Create a new tag in a workspace (workspace-scope) or in a specific journal (journal-scope via --journal). Workspace-scope tags require a description; journal-scope tags allow an optional description. Plus+ tier; Free returns FEATURE_NOT_IN_TIER.",
|
|
4
|
+
"args": [
|
|
5
|
+
{
|
|
6
|
+
"name": "workspaceSlug",
|
|
7
|
+
"required": true,
|
|
8
|
+
"description": "Slug from `workspaces list`."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "name",
|
|
12
|
+
"required": true,
|
|
13
|
+
"description": "Tag name. Must be lowercase, hyphenated, alphanumeric (kebab-case). Max 50 chars."
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"flags": [
|
|
17
|
+
{
|
|
18
|
+
"short": "-d",
|
|
19
|
+
"long": "--description",
|
|
20
|
+
"value": "<text>",
|
|
21
|
+
"description": "Description (max 200 chars). Required at workspace scope; optional at journal scope."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"long": "--journal",
|
|
25
|
+
"value": "<journalSlug>",
|
|
26
|
+
"description": "Create as journal-scope. Omit for workspace-scope."
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"annotations": { "destructive": false, "idempotent": false },
|
|
30
|
+
"examples": [
|
|
31
|
+
"workjournal tags new acme decision -d \"Records a decision that future agents should know about\"",
|
|
32
|
+
"workjournal tags new acme planning -d \"Sprint planning notes\" --journal engineering"
|
|
33
|
+
],
|
|
34
|
+
"when_to_use": "Adding a new tag to the workspace vocabulary or journal-local set before referencing it from `entries write --tags`."
|
|
35
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"command": "tags update",
|
|
3
|
+
"description": "Rename a tag or replace its description. Renaming a workspace-scope tag cascades to every entry across the workspace; renaming a journal-scope tag cascades to entries in that journal. Not tier-gated — downgraded workspaces can still tidy up.",
|
|
4
|
+
"args": [
|
|
5
|
+
{
|
|
6
|
+
"name": "workspaceSlug",
|
|
7
|
+
"required": true,
|
|
8
|
+
"description": "Slug from `workspaces list`."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "tagName",
|
|
12
|
+
"required": true,
|
|
13
|
+
"description": "Current tag name."
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"flags": [
|
|
17
|
+
{
|
|
18
|
+
"short": "-n",
|
|
19
|
+
"long": "--name",
|
|
20
|
+
"value": "<newName>",
|
|
21
|
+
"description": "New name (kebab-case, max 50 chars). Cascades the rename to every entry in scope."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"short": "-d",
|
|
25
|
+
"long": "--description",
|
|
26
|
+
"value": "<text>",
|
|
27
|
+
"description": "New description (max 200 chars). Pass an empty value to clear (journal-scope only — workspace-scope requires a non-empty description)."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"long": "--journal",
|
|
31
|
+
"value": "<journalSlug>",
|
|
32
|
+
"description": "Target the journal-scope row of this name."
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"annotations": { "destructive": false, "idempotent": true },
|
|
36
|
+
"examples": [
|
|
37
|
+
"workjournal tags update acme decision -d \"Architecturally load-bearing decisions only\"",
|
|
38
|
+
"workjournal tags update acme bug -n incident"
|
|
39
|
+
],
|
|
40
|
+
"when_to_use": "Renaming a tag whose meaning shifted, or refining the description to better steer future tagging."
|
|
41
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import packageJson from '../package.json' with { type: 'json' };
|
|
3
|
+
import { API_PATHS, AuthRequiredError, apiGet } from './api-client.js';
|
|
4
|
+
import { loginFinish, loginInteractive, loginStart, revokeDeviceSession } from './auth.js';
|
|
5
|
+
import { parseGlobalFlags } from './cli-args.js';
|
|
6
|
+
import { createEntry, deleteEntry, getEntry, lastEntries, listEntries, searchEntries, updateEntry, } from './commands/entries.js';
|
|
5
7
|
import { exportJournal } from './commands/export.js';
|
|
6
8
|
import { deleteInvite, listInvites, newInvite } from './commands/invites.js';
|
|
7
9
|
import { createJournal, deleteJournal, getJournal, listJournals, renameJournal, selectJournal, setJournalSlug, } from './commands/journals.js';
|
|
10
|
+
import { assignJournalPrompt, createPrompt, deletePrompt, getPrompt, listPrompts, unassignJournalPrompt, updatePrompt, } from './commands/prompts.js';
|
|
8
11
|
import { deleteShare, listShares } from './commands/shares.js';
|
|
12
|
+
import { createTag, deleteTag, getTag, listTags, updateTag } from './commands/tags.js';
|
|
9
13
|
import { getWorkspace, listWorkspaces, selectWorkspace } from './commands/workspaces.js';
|
|
10
14
|
import { readConfig } from './config.js';
|
|
11
15
|
import { CONFIG_DIR, clearCredentials, clearLoginState, readCredentials } from './credentials.js';
|
|
16
|
+
import { printTopLevelHelp, tryHandleHelp } from './help/_dispatch.js';
|
|
17
|
+
import { FEEDBACK_FOOTER } from './help/_renderer.js';
|
|
12
18
|
import { findProjectConfig, getProjectConfigPath, rewriteProjectConfigAt, } from './project-config.js';
|
|
19
|
+
const FEEDBACK_URL = 'https://github.com/workjournal-pro/feedback/issues';
|
|
13
20
|
// ── Arg parsing ─────────────────────────────────────────────────────────────
|
|
14
21
|
const rawArgs = process.argv.slice(2);
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
// `parseGlobalFlags` strips `--json` / `--verbose`, preserves boolean flags
|
|
23
|
+
// (`--help` / `-h` / `--version` / `-V`) for the route handlers to see, and
|
|
24
|
+
// keeps `<flag> <value>` pairs intact so a literal `--json` body doesn't get
|
|
25
|
+
// silently swallowed. See `cli-args.ts` for the parser + its tests.
|
|
26
|
+
const { args, jsonOutput, verbose } = parseGlobalFlags(rawArgs);
|
|
17
27
|
/** Parse args into flags (single-dash short or double-dash long) and positional args. */
|
|
18
28
|
function parseFlags(argv) {
|
|
19
29
|
const flags = {};
|
|
@@ -33,6 +43,23 @@ function parseFlags(argv) {
|
|
|
33
43
|
}
|
|
34
44
|
return { flags, positional };
|
|
35
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse the `--tags a,b,c` flag value into a deduplicated string array.
|
|
48
|
+
* Returns `undefined` when the flag was not provided (so the caller can
|
|
49
|
+
* distinguish "omit tags from PATCH" from "replace with empty set").
|
|
50
|
+
* An explicit empty value (`--tags ""`) clears the tag set on PATCH.
|
|
51
|
+
*/
|
|
52
|
+
function parseTagsFlag(raw) {
|
|
53
|
+
if (raw === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
for (const part of raw.split(',')) {
|
|
57
|
+
const trimmed = part.trim();
|
|
58
|
+
if (trimmed.length > 0)
|
|
59
|
+
seen.add(trimmed);
|
|
60
|
+
}
|
|
61
|
+
return Array.from(seen);
|
|
62
|
+
}
|
|
36
63
|
/**
|
|
37
64
|
* Migrate a legacy `{ journal_id }` project config by walking workspaces and
|
|
38
65
|
* journals to find the entry whose `id` matches. Rewrites the file in place
|
|
@@ -40,10 +67,9 @@ function parseFlags(argv) {
|
|
|
40
67
|
* not authenticated).
|
|
41
68
|
*/
|
|
42
69
|
async function migrateLegacyProjectConfig(journalId, configPath) {
|
|
43
|
-
const token = await requireAuth();
|
|
44
70
|
let workspaces;
|
|
45
71
|
try {
|
|
46
|
-
const result = await apiGet(API_PATHS.workspaces
|
|
72
|
+
const result = await apiGet(API_PATHS.workspaces);
|
|
47
73
|
workspaces = result.data;
|
|
48
74
|
}
|
|
49
75
|
catch {
|
|
@@ -51,7 +77,7 @@ async function migrateLegacyProjectConfig(journalId, configPath) {
|
|
|
51
77
|
}
|
|
52
78
|
for (const ws of workspaces) {
|
|
53
79
|
try {
|
|
54
|
-
const journals = await apiGet(API_PATHS.journals(ws.slug)
|
|
80
|
+
const journals = await apiGet(API_PATHS.journals(ws.slug));
|
|
55
81
|
const match = journals.data.find((j) => j.id === journalId);
|
|
56
82
|
if (match) {
|
|
57
83
|
rewriteProjectConfigAt(configPath, ws.slug, match.slug);
|
|
@@ -97,6 +123,9 @@ async function resolveActiveSelection() {
|
|
|
97
123
|
// ── Routing ─────────────────────────────────────────────────────────────────
|
|
98
124
|
async function routeAuth(argv) {
|
|
99
125
|
const sub = argv[0];
|
|
126
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'auth' : `auth ${sub}`;
|
|
127
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
128
|
+
return;
|
|
100
129
|
switch (sub) {
|
|
101
130
|
case 'login': {
|
|
102
131
|
const loginSub = argv[1];
|
|
@@ -120,11 +149,16 @@ async function routeAuth(argv) {
|
|
|
120
149
|
}
|
|
121
150
|
break;
|
|
122
151
|
}
|
|
123
|
-
case 'logout':
|
|
152
|
+
case 'logout': {
|
|
153
|
+
const existing = readCredentials();
|
|
154
|
+
if (existing?.refresh_token) {
|
|
155
|
+
await revokeDeviceSession(existing.refresh_token);
|
|
156
|
+
}
|
|
124
157
|
clearCredentials();
|
|
125
158
|
clearLoginState();
|
|
126
159
|
process.stdout.write('Logged out. Credentials removed.\n');
|
|
127
160
|
break;
|
|
161
|
+
}
|
|
128
162
|
case 'whoami': {
|
|
129
163
|
const creds = readCredentials();
|
|
130
164
|
if (!creds) {
|
|
@@ -156,6 +190,9 @@ async function routeAuth(argv) {
|
|
|
156
190
|
}
|
|
157
191
|
async function routeWorkspaces(argv) {
|
|
158
192
|
const sub = argv[0];
|
|
193
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'workspaces' : `workspaces ${sub}`;
|
|
194
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
195
|
+
return;
|
|
159
196
|
switch (sub) {
|
|
160
197
|
case undefined:
|
|
161
198
|
case 'list':
|
|
@@ -187,10 +224,13 @@ async function routeWorkspaces(argv) {
|
|
|
187
224
|
}
|
|
188
225
|
async function routeJournals(argv) {
|
|
189
226
|
const sub = argv[0];
|
|
227
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'journals' : `journals ${sub}`;
|
|
228
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
229
|
+
return;
|
|
190
230
|
if (sub === undefined) {
|
|
191
231
|
// Shortcut: workjournal journals → show selected journal details
|
|
192
232
|
const sel = await resolveActiveSelection();
|
|
193
|
-
await getJournal(sel.workspaceSlug, sel.journalSlug, jsonOutput);
|
|
233
|
+
await getJournal(sel.workspaceSlug, sel.journalSlug, jsonOutput, verbose);
|
|
194
234
|
return;
|
|
195
235
|
}
|
|
196
236
|
switch (sub) {
|
|
@@ -212,7 +252,7 @@ async function routeJournals(argv) {
|
|
|
212
252
|
process.stderr.write('Usage: workjournal journals get <workspaceSlug> <journalSlug>\n');
|
|
213
253
|
process.exit(1);
|
|
214
254
|
}
|
|
215
|
-
await getJournal(ws, j, jsonOutput);
|
|
255
|
+
await getJournal(ws, j, jsonOutput, verbose);
|
|
216
256
|
return;
|
|
217
257
|
}
|
|
218
258
|
case 'new':
|
|
@@ -260,6 +300,27 @@ async function routeJournals(argv) {
|
|
|
260
300
|
await setJournalSlug(ws, j, newSlug, jsonOutput);
|
|
261
301
|
return;
|
|
262
302
|
}
|
|
303
|
+
case 'assign-prompt': {
|
|
304
|
+
const ws = argv[1];
|
|
305
|
+
const j = argv[2];
|
|
306
|
+
const promptSlug = argv[3];
|
|
307
|
+
if (!ws || !j || !promptSlug) {
|
|
308
|
+
process.stderr.write('Usage: workjournal journals assign-prompt <workspaceSlug> <journalSlug> <promptSlug>\n');
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
await assignJournalPrompt(ws, j, promptSlug, jsonOutput);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
case 'unassign-prompt': {
|
|
315
|
+
const ws = argv[1];
|
|
316
|
+
const j = argv[2];
|
|
317
|
+
if (!ws || !j) {
|
|
318
|
+
process.stderr.write('Usage: workjournal journals unassign-prompt <workspaceSlug> <journalSlug>\n');
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
await unassignJournalPrompt(ws, j, jsonOutput);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
263
324
|
case 'select': {
|
|
264
325
|
const ws = argv[1];
|
|
265
326
|
const j = argv[2];
|
|
@@ -272,12 +333,15 @@ async function routeJournals(argv) {
|
|
|
272
333
|
}
|
|
273
334
|
default:
|
|
274
335
|
process.stderr.write(`Unknown journals subcommand: ${sub}\n` +
|
|
275
|
-
'Usage: workjournal journals <list|get|new|delete|rename|set-slug|select>\n');
|
|
336
|
+
'Usage: workjournal journals <list|get|new|delete|rename|set-slug|assign-prompt|unassign-prompt|select>\n');
|
|
276
337
|
process.exit(1);
|
|
277
338
|
}
|
|
278
339
|
}
|
|
279
340
|
async function routeEntries(argv) {
|
|
280
341
|
const sub = argv[0];
|
|
342
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'entries' : `entries ${sub}`;
|
|
343
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
344
|
+
return;
|
|
281
345
|
switch (sub) {
|
|
282
346
|
case undefined:
|
|
283
347
|
case 'list': {
|
|
@@ -294,7 +358,7 @@ async function routeEntries(argv) {
|
|
|
294
358
|
const ws = argv[1];
|
|
295
359
|
const j = argv[2];
|
|
296
360
|
if (!ws || !j) {
|
|
297
|
-
process.stderr.write('Usage: workjournal entries write <workspaceSlug> <journalSlug> -t <title> -s <summary> -b <body
|
|
361
|
+
process.stderr.write('Usage: workjournal entries write <workspaceSlug> <journalSlug> -t <title> -s <summary> -b <body> [--tags <a,b,c>]\n');
|
|
298
362
|
process.exit(1);
|
|
299
363
|
}
|
|
300
364
|
const { flags } = parseFlags(argv.slice(3));
|
|
@@ -302,10 +366,12 @@ async function routeEntries(argv) {
|
|
|
302
366
|
const summary = flags['-s'] ?? flags['--summary'];
|
|
303
367
|
const body = flags['-b'] ?? flags['--body'];
|
|
304
368
|
if (!title || !summary || !body) {
|
|
305
|
-
process.stderr.write('Usage: workjournal entries write <workspaceSlug> <journalSlug> -t <title> -s <summary> -b <body
|
|
369
|
+
process.stderr.write('Usage: workjournal entries write <workspaceSlug> <journalSlug> -t <title> -s <summary> -b <body> [--tags <a,b,c>]\n');
|
|
306
370
|
process.exit(1);
|
|
307
371
|
}
|
|
308
|
-
|
|
372
|
+
const tagsRaw = flags['--tags'];
|
|
373
|
+
const tags = parseTagsFlag(tagsRaw);
|
|
374
|
+
await createEntry(ws, j, title, summary, body, tags, jsonOutput);
|
|
309
375
|
return;
|
|
310
376
|
}
|
|
311
377
|
case 'last': {
|
|
@@ -334,6 +400,28 @@ async function routeEntries(argv) {
|
|
|
334
400
|
await getEntry(ws, j, index, jsonOutput);
|
|
335
401
|
return;
|
|
336
402
|
}
|
|
403
|
+
case 'update': {
|
|
404
|
+
const ws = argv[1];
|
|
405
|
+
const j = argv[2];
|
|
406
|
+
const index = argv[3];
|
|
407
|
+
if (!ws || !j || !index) {
|
|
408
|
+
process.stderr.write('Usage: workjournal entries update <workspaceSlug> <journalSlug> <index> [-t <title>] [-s <summary>] [-b <file>|-] [--tags <a,b,c>]\n');
|
|
409
|
+
process.exit(1);
|
|
410
|
+
}
|
|
411
|
+
const { flags } = parseFlags(argv.slice(4));
|
|
412
|
+
const title = flags['-t'] ?? flags['--title'];
|
|
413
|
+
const summary = flags['-s'] ?? flags['--summary'];
|
|
414
|
+
const bodySource = flags['-b'] ?? flags['--body'];
|
|
415
|
+
const tagsRaw = flags['--tags'];
|
|
416
|
+
const tags = parseTagsFlag(tagsRaw);
|
|
417
|
+
await updateEntry(ws, j, index, {
|
|
418
|
+
...(title !== undefined ? { title } : {}),
|
|
419
|
+
...(summary !== undefined ? { summary } : {}),
|
|
420
|
+
...(bodySource !== undefined ? { bodySource } : {}),
|
|
421
|
+
...(tags !== undefined ? { tags } : {}),
|
|
422
|
+
}, jsonOutput);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
337
425
|
case 'delete': {
|
|
338
426
|
const ws = argv[1];
|
|
339
427
|
const j = argv[2];
|
|
@@ -358,12 +446,180 @@ async function routeEntries(argv) {
|
|
|
358
446
|
}
|
|
359
447
|
default:
|
|
360
448
|
process.stderr.write(`Unknown entries subcommand: ${sub}\n` +
|
|
361
|
-
'Usage: workjournal entries <list|write|last|get|delete|search>\n');
|
|
449
|
+
'Usage: workjournal entries <list|write|last|get|update|delete|search>\n');
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
async function routePrompts(argv) {
|
|
454
|
+
const sub = argv[0];
|
|
455
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'prompts' : `prompts ${sub}`;
|
|
456
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
457
|
+
return;
|
|
458
|
+
switch (sub) {
|
|
459
|
+
case undefined:
|
|
460
|
+
case 'list': {
|
|
461
|
+
const ws = argv[1] ?? readConfig().workspaceSlug;
|
|
462
|
+
if (!ws) {
|
|
463
|
+
process.stderr.write('Usage: workjournal prompts list <workspaceSlug>\n' +
|
|
464
|
+
'(or run `workjournal workspaces select <slug>` first)\n');
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
await listPrompts(ws, jsonOutput);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
case 'new':
|
|
471
|
+
case 'create': {
|
|
472
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
473
|
+
const ws = positional[0];
|
|
474
|
+
const name = positional[1];
|
|
475
|
+
if (!ws || !name) {
|
|
476
|
+
process.stderr.write('Usage: workjournal prompts new <workspaceSlug> <name> [-b <body>] [--slug <slug>]\n');
|
|
477
|
+
process.exit(1);
|
|
478
|
+
}
|
|
479
|
+
const body = flags['-b'] ?? flags['--body'] ?? '';
|
|
480
|
+
const slug = flags['--slug'];
|
|
481
|
+
await createPrompt(ws, name, body, slug, jsonOutput);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
case 'get': {
|
|
485
|
+
const ws = argv[1];
|
|
486
|
+
const slug = argv[2];
|
|
487
|
+
if (!ws || !slug) {
|
|
488
|
+
process.stderr.write('Usage: workjournal prompts get <workspaceSlug> <promptSlug>\n');
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
await getPrompt(ws, slug, jsonOutput);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
case 'update': {
|
|
495
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
496
|
+
const ws = positional[0];
|
|
497
|
+
const slug = positional[1];
|
|
498
|
+
if (!ws || !slug) {
|
|
499
|
+
process.stderr.write('Usage: workjournal prompts update <workspaceSlug> <promptSlug> [-n <name>] [-b <body>]\n');
|
|
500
|
+
process.exit(1);
|
|
501
|
+
}
|
|
502
|
+
const updates = {};
|
|
503
|
+
const name = flags['-n'] ?? flags['--name'];
|
|
504
|
+
const body = flags['-b'] ?? flags['--body'];
|
|
505
|
+
if (name !== undefined)
|
|
506
|
+
updates.name = name;
|
|
507
|
+
if (body !== undefined)
|
|
508
|
+
updates.body = body;
|
|
509
|
+
if (Object.keys(updates).length === 0) {
|
|
510
|
+
process.stderr.write('At least one of -n/--name or -b/--body is required.\n');
|
|
511
|
+
process.exit(1);
|
|
512
|
+
}
|
|
513
|
+
await updatePrompt(ws, slug, updates, jsonOutput);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
case 'delete': {
|
|
517
|
+
const ws = argv[1];
|
|
518
|
+
const slug = argv[2];
|
|
519
|
+
if (!ws || !slug) {
|
|
520
|
+
process.stderr.write('Usage: workjournal prompts delete <workspaceSlug> <promptSlug>\n');
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
await deletePrompt(ws, slug, jsonOutput);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
default:
|
|
527
|
+
process.stderr.write(`Unknown prompts subcommand: ${sub}\n` +
|
|
528
|
+
'Usage: workjournal prompts <list|new|get|update|delete>\n');
|
|
529
|
+
process.exit(1);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
async function routeTags(argv) {
|
|
533
|
+
const sub = argv[0];
|
|
534
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'tags' : `tags ${sub}`;
|
|
535
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
536
|
+
return;
|
|
537
|
+
switch (sub) {
|
|
538
|
+
case undefined:
|
|
539
|
+
case 'list': {
|
|
540
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
541
|
+
const ws = positional[0] ?? readConfig().workspaceSlug;
|
|
542
|
+
if (!ws) {
|
|
543
|
+
process.stderr.write('Usage: workjournal tags list <workspaceSlug> [--journal <journalSlug>]\n' +
|
|
544
|
+
'(or run `workjournal workspaces select <slug>` first)\n');
|
|
545
|
+
process.exit(1);
|
|
546
|
+
}
|
|
547
|
+
const journalSlug = flags['--journal'] ?? flags['-j'];
|
|
548
|
+
await listTags(ws, journalSlug, jsonOutput);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
case 'new':
|
|
552
|
+
case 'create': {
|
|
553
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
554
|
+
const ws = positional[0];
|
|
555
|
+
const name = positional[1];
|
|
556
|
+
if (!ws || !name) {
|
|
557
|
+
process.stderr.write('Usage: workjournal tags new <workspaceSlug> <name> [-d <description>] [--journal <journalSlug>]\n');
|
|
558
|
+
process.exit(1);
|
|
559
|
+
}
|
|
560
|
+
const description = flags['-d'] ?? flags['--description'];
|
|
561
|
+
const journalSlug = flags['--journal'] ?? flags['-j'];
|
|
562
|
+
await createTag(ws, name, description, journalSlug, jsonOutput);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
case 'get': {
|
|
566
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
567
|
+
const ws = positional[0];
|
|
568
|
+
const name = positional[1];
|
|
569
|
+
if (!ws || !name) {
|
|
570
|
+
process.stderr.write('Usage: workjournal tags get <workspaceSlug> <tagName> [--journal <journalSlug>]\n');
|
|
571
|
+
process.exit(1);
|
|
572
|
+
}
|
|
573
|
+
const journalSlug = flags['--journal'] ?? flags['-j'];
|
|
574
|
+
await getTag(ws, name, journalSlug, jsonOutput);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
case 'update': {
|
|
578
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
579
|
+
const ws = positional[0];
|
|
580
|
+
const name = positional[1];
|
|
581
|
+
if (!ws || !name) {
|
|
582
|
+
process.stderr.write('Usage: workjournal tags update <workspaceSlug> <tagName> [-n <newName>] [-d <description>] [--journal <journalSlug>]\n');
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
const updates = {};
|
|
586
|
+
const newName = flags['-n'] ?? flags['--name'];
|
|
587
|
+
const description = flags['-d'] ?? flags['--description'];
|
|
588
|
+
if (newName !== undefined)
|
|
589
|
+
updates.name = newName;
|
|
590
|
+
if (description !== undefined)
|
|
591
|
+
updates.description = description;
|
|
592
|
+
if (Object.keys(updates).length === 0) {
|
|
593
|
+
process.stderr.write('At least one of -n/--name or -d/--description is required.\n');
|
|
594
|
+
process.exit(1);
|
|
595
|
+
}
|
|
596
|
+
const journalSlug = flags['--journal'] ?? flags['-j'];
|
|
597
|
+
await updateTag(ws, name, updates, journalSlug, jsonOutput);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
case 'delete': {
|
|
601
|
+
const { flags, positional } = parseFlags(argv.slice(1));
|
|
602
|
+
const ws = positional[0];
|
|
603
|
+
const name = positional[1];
|
|
604
|
+
if (!ws || !name) {
|
|
605
|
+
process.stderr.write('Usage: workjournal tags delete <workspaceSlug> <tagName> [--journal <journalSlug>]\n');
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
const journalSlug = flags['--journal'] ?? flags['-j'];
|
|
609
|
+
await deleteTag(ws, name, journalSlug, jsonOutput);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
default:
|
|
613
|
+
process.stderr.write(`Unknown tags subcommand: ${sub}\n` +
|
|
614
|
+
'Usage: workjournal tags <list|new|get|update|delete>\n');
|
|
362
615
|
process.exit(1);
|
|
363
616
|
}
|
|
364
617
|
}
|
|
365
618
|
async function routeShares(argv) {
|
|
366
619
|
const sub = argv[0];
|
|
620
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'shares' : `shares ${sub}`;
|
|
621
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
622
|
+
return;
|
|
367
623
|
switch (sub) {
|
|
368
624
|
case undefined:
|
|
369
625
|
case 'list': {
|
|
@@ -394,6 +650,9 @@ async function routeShares(argv) {
|
|
|
394
650
|
}
|
|
395
651
|
async function routeInvites(argv) {
|
|
396
652
|
const sub = argv[0];
|
|
653
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'invites' : `invites ${sub}`;
|
|
654
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
655
|
+
return;
|
|
397
656
|
switch (sub) {
|
|
398
657
|
case undefined:
|
|
399
658
|
case 'list': {
|
|
@@ -435,10 +694,13 @@ async function routeInvites(argv) {
|
|
|
435
694
|
}
|
|
436
695
|
}
|
|
437
696
|
async function routeExport(argv) {
|
|
697
|
+
if (tryHandleHelp('export', argv, jsonOutput))
|
|
698
|
+
return;
|
|
438
699
|
const ws = argv[0];
|
|
439
700
|
const j = argv[1];
|
|
440
701
|
if (!ws || !j) {
|
|
441
|
-
process.stderr.write('Usage: workjournal export <workspaceSlug> <journalSlug> [-f json|md|csv] [-p <path>]\n'
|
|
702
|
+
process.stderr.write('Usage: workjournal export <workspaceSlug> <journalSlug> [-f json|md|csv] [-p <path>]\n' +
|
|
703
|
+
'Run `workjournal export --help` for details.\n');
|
|
442
704
|
process.exit(1);
|
|
443
705
|
}
|
|
444
706
|
const { flags } = parseFlags(argv.slice(2));
|
|
@@ -452,6 +714,9 @@ async function routeExport(argv) {
|
|
|
452
714
|
}
|
|
453
715
|
async function routeConfig(argv) {
|
|
454
716
|
const sub = argv[0];
|
|
717
|
+
const helpKey = !sub || sub === '--help' || sub === '-h' ? 'config show' : `config ${sub}`;
|
|
718
|
+
if (tryHandleHelp(helpKey, argv, jsonOutput))
|
|
719
|
+
return;
|
|
455
720
|
if (sub === 'show') {
|
|
456
721
|
const projectPath = getProjectConfigPath();
|
|
457
722
|
const stored = findProjectConfig();
|
|
@@ -490,71 +755,20 @@ async function routeConfig(argv) {
|
|
|
490
755
|
}
|
|
491
756
|
}
|
|
492
757
|
// ── Help ────────────────────────────────────────────────────────────────────
|
|
493
|
-
function
|
|
494
|
-
process.stdout.write(
|
|
495
|
-
|
|
496
|
-
Usage:
|
|
497
|
-
workjournal List entries in selected journal
|
|
498
|
-
|
|
499
|
-
Workspaces:
|
|
500
|
-
workjournal workspaces list List your workspaces
|
|
501
|
-
workjournal workspaces get <ws> Show workspace details
|
|
502
|
-
workjournal workspaces select <ws> Set active workspace
|
|
503
|
-
|
|
504
|
-
Journals:
|
|
505
|
-
workjournal journals list [<ws>] List journals in workspace
|
|
506
|
-
workjournal journals list shared-with-me List journals shared with you
|
|
507
|
-
workjournal journals get <ws> <j> Show journal details
|
|
508
|
-
workjournal journals new <ws> <name> [--slug <slug>] Create a new journal
|
|
509
|
-
workjournal journals delete <ws> <j> Delete a journal
|
|
510
|
-
workjournal journals rename <ws> <j> <newName> Rename a journal
|
|
511
|
-
workjournal journals set-slug <ws> <j> <newSlug> Change a journal's slug
|
|
512
|
-
workjournal journals select <ws> <j> Set active journal
|
|
513
|
-
workjournal journals Show selected journal details
|
|
514
|
-
|
|
515
|
-
Entries:
|
|
516
|
-
workjournal entries list <ws> <j> List entries
|
|
517
|
-
workjournal entries write <ws> <j> -t <title> -s <summary> -b <body>
|
|
518
|
-
Create a new entry
|
|
519
|
-
workjournal entries last <ws> <j> [count] Show most recent entries (full body)
|
|
520
|
-
workjournal entries get <ws> <j> <index> Show a single entry by index
|
|
521
|
-
workjournal entries delete <ws> <j> <index> Delete an entry by index
|
|
522
|
-
workjournal entries search <ws> <j> <query> Search entries
|
|
523
|
-
|
|
524
|
-
Shares (members):
|
|
525
|
-
workjournal shares list <ws> <j> List members
|
|
526
|
-
workjournal shares delete <ws> <j> <email> Remove a member
|
|
527
|
-
|
|
528
|
-
Invites:
|
|
529
|
-
workjournal invites list <ws> <j> List invitations
|
|
530
|
-
workjournal invites new <ws> <j> <email> Invite a collaborator
|
|
531
|
-
workjournal invites delete <ws> <j> <invitationId> Revoke an invitation
|
|
532
|
-
|
|
533
|
-
Export:
|
|
534
|
-
workjournal export <ws> <j> [-f json|md|csv] [-p <path>]
|
|
535
|
-
Export journal data
|
|
536
|
-
|
|
537
|
-
Auth:
|
|
538
|
-
workjournal auth login Interactive login
|
|
539
|
-
workjournal auth login start Print authorize URL (headless)
|
|
540
|
-
workjournal auth login finish <CODE> Exchange code for credentials
|
|
541
|
-
workjournal auth logout Remove stored credentials
|
|
542
|
-
workjournal auth whoami Show current auth status
|
|
543
|
-
workjournal auth status Show detailed auth status
|
|
544
|
-
|
|
545
|
-
Config:
|
|
546
|
-
workjournal config show Show resolved config
|
|
547
|
-
|
|
548
|
-
Flags:
|
|
549
|
-
--json Output raw JSON instead of tables
|
|
550
|
-
`);
|
|
758
|
+
function printVersion() {
|
|
759
|
+
process.stdout.write(`@workjournal/cli ${packageJson.version}\n`);
|
|
760
|
+
process.stdout.write(`${FEEDBACK_FOOTER}\n`);
|
|
551
761
|
}
|
|
552
762
|
// ── Main ────────────────────────────────────────────────────────────────────
|
|
553
763
|
async function run() {
|
|
554
764
|
try {
|
|
555
765
|
const command = args[0];
|
|
556
|
-
if (command === 'help' || command === '--help') {
|
|
557
|
-
|
|
766
|
+
if (command === 'help' || command === '--help' || command === '-h') {
|
|
767
|
+
printTopLevelHelp(jsonOutput);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
if (command === '--version' || command === '-V') {
|
|
771
|
+
printVersion();
|
|
558
772
|
return;
|
|
559
773
|
}
|
|
560
774
|
if (command === undefined) {
|
|
@@ -572,6 +786,8 @@ async function run() {
|
|
|
572
786
|
break;
|
|
573
787
|
case 'journal': {
|
|
574
788
|
// Shortcut: show selected journal details (matches docs/cli-commands.md)
|
|
789
|
+
if (tryHandleHelp('journal', args.slice(1), jsonOutput))
|
|
790
|
+
break;
|
|
575
791
|
const sel = await resolveActiveSelection();
|
|
576
792
|
if (args.length > 1) {
|
|
577
793
|
process.stderr.write('`workjournal journal` shows the selected journal. Use `workjournal entries`, ' +
|
|
@@ -579,7 +795,7 @@ async function run() {
|
|
|
579
795
|
'resource verbs.\n');
|
|
580
796
|
process.exit(1);
|
|
581
797
|
}
|
|
582
|
-
await getJournal(sel.workspaceSlug, sel.journalSlug, jsonOutput);
|
|
798
|
+
await getJournal(sel.workspaceSlug, sel.journalSlug, jsonOutput, verbose);
|
|
583
799
|
break;
|
|
584
800
|
}
|
|
585
801
|
case 'journals':
|
|
@@ -588,6 +804,12 @@ async function run() {
|
|
|
588
804
|
case 'entries':
|
|
589
805
|
await routeEntries(args.slice(1));
|
|
590
806
|
break;
|
|
807
|
+
case 'prompts':
|
|
808
|
+
await routePrompts(args.slice(1));
|
|
809
|
+
break;
|
|
810
|
+
case 'tags':
|
|
811
|
+
await routeTags(args.slice(1));
|
|
812
|
+
break;
|
|
591
813
|
case 'shares':
|
|
592
814
|
await routeShares(args.slice(1));
|
|
593
815
|
break;
|
|
@@ -601,12 +823,22 @@ async function run() {
|
|
|
601
823
|
await routeConfig(args.slice(1));
|
|
602
824
|
break;
|
|
603
825
|
default:
|
|
604
|
-
|
|
826
|
+
printTopLevelHelp(jsonOutput);
|
|
605
827
|
process.stderr.write(`\nUnknown command: ${command}\n`);
|
|
828
|
+
process.stderr.write(`If this is a bug, please report it: ${FEEDBACK_URL}\n`);
|
|
606
829
|
process.exit(1);
|
|
607
830
|
}
|
|
608
831
|
}
|
|
609
832
|
catch (err) {
|
|
833
|
+
if (err instanceof AuthRequiredError) {
|
|
834
|
+
if (err.reason === 'not-logged-in') {
|
|
835
|
+
process.stderr.write('Not logged in. Run `workjournal auth login` to authenticate.\n');
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
process.stderr.write('Authentication expired. Run `workjournal auth login` to re-authenticate.\n');
|
|
839
|
+
}
|
|
840
|
+
process.exit(1);
|
|
841
|
+
}
|
|
610
842
|
const message = err instanceof Error ? err.message : String(err);
|
|
611
843
|
if (message.includes('fetch') ||
|
|
612
844
|
message.includes('ECONNREFUSED') ||
|
|
@@ -616,6 +848,7 @@ async function run() {
|
|
|
616
848
|
else {
|
|
617
849
|
process.stderr.write(`Error: ${message}\n`);
|
|
618
850
|
}
|
|
851
|
+
process.stderr.write(`If this looks like a bug, please report it: ${FEEDBACK_URL}\n`);
|
|
619
852
|
process.exit(1);
|
|
620
853
|
}
|
|
621
854
|
}
|