@kiipu/cli 0.0.8 → 0.0.9
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 +22 -22
- package/dist/commands/ask.js +1 -6
- package/dist/commands/auth.js +1 -1
- package/dist/commands/doctor.js +9 -3
- package/dist/commands/help.js +50 -50
- package/dist/commands/{post.js → note.js} +68 -64
- package/dist/config/load-env.js +4 -1
- package/dist/index.js +3 -3
- package/dist/lib/ask-client.js +6 -4
- package/dist/lib/ask-formatters.js +1 -1
- package/dist/lib/kiipu-integration-client.js +26 -20
- package/dist/lib/kiipu-user-client.js +14 -14
- package/dist/lib/{post-actions.js → note-actions.js} +19 -19
- package/dist/lib/{post-formatters.js → note-formatters.js} +26 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Kiipu CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create Kiipu notes from your terminal.
|
|
4
4
|
|
|
5
|
-
`@kiipu/cli` is the official command line interface for Kiipu. It is the best place to start if you want to authenticate locally and
|
|
5
|
+
`@kiipu/cli` is the official command line interface for Kiipu. It is the best place to start if you want to authenticate locally and note directly from the command line.
|
|
6
6
|
|
|
7
7
|
Use it to:
|
|
8
8
|
|
|
9
9
|
- sign in on the current device
|
|
10
|
-
- ask questions over your saved
|
|
11
|
-
-
|
|
12
|
-
- delete, restore, or permanently remove
|
|
10
|
+
- ask questions over your saved notes
|
|
11
|
+
- create notes from the command line
|
|
12
|
+
- delete, restore, or permanently remove notes by id
|
|
13
13
|
- verify local authentication and API access with `kiipu doctor`
|
|
14
14
|
|
|
15
15
|
If you want Claude Code integration on top of the CLI, use `@kiipu/claude-plugin`.
|
|
@@ -28,10 +28,10 @@ npm install -g @kiipu/cli
|
|
|
28
28
|
kiipu auth login
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
2.
|
|
31
|
+
2. Create a note:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
kiipu
|
|
34
|
+
kiipu note create "Hello Kiipu"
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
3. Confirm local setup:
|
|
@@ -40,7 +40,7 @@ kiipu post create "Hello Kiipu"
|
|
|
40
40
|
kiipu doctor
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
4. Ask over your saved
|
|
43
|
+
4. Ask over your saved notes:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
kiipu ask "What did I save about the roadmap?"
|
|
@@ -51,7 +51,7 @@ kiipu ask "What did I save about the roadmap?"
|
|
|
51
51
|
```bash
|
|
52
52
|
kiipu auth login
|
|
53
53
|
kiipu ask "What should I follow up on?"
|
|
54
|
-
kiipu
|
|
54
|
+
kiipu note create "Ship the beta today"
|
|
55
55
|
kiipu auth status
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -73,21 +73,21 @@ kiipu auth status
|
|
|
73
73
|
kiipu auth logout
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## Noteing
|
|
77
77
|
|
|
78
|
-
Create a
|
|
78
|
+
Create a note:
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
kiipu
|
|
82
|
-
kiipu
|
|
81
|
+
kiipu note create "Ship the beta today"
|
|
82
|
+
kiipu note create --content "Ship the beta today"
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
Delete, restore, or permanently remove a
|
|
85
|
+
Delete, restore, or permanently remove a note by id:
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
kiipu
|
|
89
|
-
kiipu
|
|
90
|
-
kiipu
|
|
88
|
+
kiipu note delete --id note_123
|
|
89
|
+
kiipu note restore --id note_123
|
|
90
|
+
kiipu note purge --id note_123
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
## Ask
|
|
@@ -118,10 +118,10 @@ kiipu ask "What did I save about the roadmap?"
|
|
|
118
118
|
kiipu ask history --limit 10
|
|
119
119
|
kiipu ask show --id conv_123
|
|
120
120
|
|
|
121
|
-
kiipu
|
|
122
|
-
kiipu
|
|
123
|
-
kiipu
|
|
124
|
-
kiipu
|
|
121
|
+
kiipu note create "Hello Kiipu"
|
|
122
|
+
kiipu note delete --id note_123
|
|
123
|
+
kiipu note restore --id note_123
|
|
124
|
+
kiipu note purge --id note_123
|
|
125
125
|
|
|
126
126
|
kiipu doctor
|
|
127
127
|
kiipu --help
|
|
@@ -152,5 +152,5 @@ See the full command reference in the terminal:
|
|
|
152
152
|
kiipu --help
|
|
153
153
|
kiipu auth --help
|
|
154
154
|
kiipu ask --help
|
|
155
|
-
kiipu
|
|
155
|
+
kiipu note --help
|
|
156
156
|
```
|
package/dist/commands/ask.js
CHANGED
|
@@ -90,12 +90,7 @@ function readQuestion(args) {
|
|
|
90
90
|
if (explicit) {
|
|
91
91
|
return explicit;
|
|
92
92
|
}
|
|
93
|
-
return stripKnownFlags(args, [
|
|
94
|
-
'--question',
|
|
95
|
-
'--conversation-id',
|
|
96
|
-
'--top-k',
|
|
97
|
-
'--source-mode',
|
|
98
|
-
])
|
|
93
|
+
return stripKnownFlags(args, ['--question', '--conversation-id', '--top-k', '--source-mode'])
|
|
99
94
|
.join(' ')
|
|
100
95
|
.trim();
|
|
101
96
|
}
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { saveKiipuConfig } from '../config/config.js';
|
|
2
|
-
import { createAuthState, createLoopbackServer, createPkcePair, getDefaultDeviceName, openBrowser, waitForEnterBeforeOpeningBrowser } from '../lib/browser-auth.js';
|
|
2
|
+
import { createAuthState, createLoopbackServer, createPkcePair, getDefaultDeviceName, openBrowser, waitForEnterBeforeOpeningBrowser, } from '../lib/browser-auth.js';
|
|
3
3
|
import { KiipuUserApiClient } from '../lib/kiipu-user-client.js';
|
|
4
4
|
import { logCliEvent } from '../logger/cli-logger.js';
|
|
5
5
|
async function storeAuthenticatedConfig(config, payload) {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -14,11 +14,15 @@ export async function runDoctorCommand(config) {
|
|
|
14
14
|
const checks = [];
|
|
15
15
|
let ok = true;
|
|
16
16
|
const apiBaseUrlConfig = getConfiguredApiBaseUrl();
|
|
17
|
-
checks.push(config.apiKey
|
|
17
|
+
checks.push(config.apiKey
|
|
18
|
+
? `OK API key: ${config.keyPrefix ?? 'configured'}`
|
|
19
|
+
: 'Missing API key. Run `kiipu auth login`.');
|
|
18
20
|
if (!(config.apiKey || process.env.KIIPU_API_KEY)) {
|
|
19
21
|
ok = false;
|
|
20
22
|
}
|
|
21
|
-
checks.push(config.apiKey || process.env.KIIPU_API_KEY
|
|
23
|
+
checks.push(config.apiKey || process.env.KIIPU_API_KEY
|
|
24
|
+
? 'OK note API auth: configured'
|
|
25
|
+
: 'Missing API key for note requests.');
|
|
22
26
|
checks.push(apiBaseUrlConfig.source === 'env'
|
|
23
27
|
? `WARN API base URL override: ${config.apiBaseUrl}`
|
|
24
28
|
: `OK API base URL: ${config.apiBaseUrl}`);
|
|
@@ -42,7 +46,9 @@ export async function runDoctorCommand(config) {
|
|
|
42
46
|
if (!authStatus.ok) {
|
|
43
47
|
ok = false;
|
|
44
48
|
}
|
|
45
|
-
checks.push(authStatus.ok
|
|
49
|
+
checks.push(authStatus.ok
|
|
50
|
+
? `OK API key auth: ${authStatus.data.username}`
|
|
51
|
+
: `API key auth failed: ${authStatus.error.message}`);
|
|
46
52
|
}
|
|
47
53
|
try {
|
|
48
54
|
await access(configPath);
|
package/dist/commands/help.js
CHANGED
|
@@ -16,7 +16,7 @@ export function getHelpResult(command) {
|
|
|
16
16
|
' kiipu ask show --id <conversationId>',
|
|
17
17
|
'',
|
|
18
18
|
'Description:',
|
|
19
|
-
' Ask questions over your Kiipu
|
|
19
|
+
' Ask questions over your Kiipu notes using the same conversation-aware Ask surface as the web app.',
|
|
20
20
|
'',
|
|
21
21
|
'Options:',
|
|
22
22
|
' --question "<text>" Question to ask when not using a positional argument',
|
|
@@ -36,64 +36,64 @@ export function getHelpResult(command) {
|
|
|
36
36
|
]),
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
-
if (command === '
|
|
39
|
+
if (command === 'note') {
|
|
40
40
|
return {
|
|
41
41
|
ok: true,
|
|
42
42
|
message: block([
|
|
43
43
|
'Kiipu CLI',
|
|
44
44
|
'',
|
|
45
45
|
'Usage:',
|
|
46
|
-
' kiipu
|
|
47
|
-
' kiipu
|
|
48
|
-
' kiipu
|
|
49
|
-
' kiipu
|
|
50
|
-
' kiipu
|
|
51
|
-
' kiipu
|
|
52
|
-
' kiipu
|
|
53
|
-
' kiipu
|
|
54
|
-
' kiipu
|
|
55
|
-
' kiipu
|
|
56
|
-
' kiipu
|
|
57
|
-
' kiipu
|
|
46
|
+
' kiipu note create --content "<text>"',
|
|
47
|
+
' kiipu note create "<text>"',
|
|
48
|
+
' kiipu note list [--tag <tag>] [--sort <updatedAt|createdAt|title>] [--starred] [--deleted]',
|
|
49
|
+
' kiipu note search <query>',
|
|
50
|
+
' kiipu note search --query "<query>"',
|
|
51
|
+
' kiipu note show --id <noteId>',
|
|
52
|
+
' kiipu note update --id <noteId> --content "<text>" [--title "<title>"] [--visibility public|private] [--tags <a,b,c>]',
|
|
53
|
+
' kiipu note star --id <noteId>',
|
|
54
|
+
' kiipu note pin --id <noteId>',
|
|
55
|
+
' kiipu note delete --id <noteId>',
|
|
56
|
+
' kiipu note restore --id <noteId>',
|
|
57
|
+
' kiipu note purge --id <noteId>',
|
|
58
58
|
'',
|
|
59
59
|
'Description:',
|
|
60
|
-
' Run direct Kiipu
|
|
60
|
+
' Run direct Kiipu note actions from the local CLI.',
|
|
61
61
|
'',
|
|
62
62
|
'Actions:',
|
|
63
|
-
' create Create a new
|
|
64
|
-
' list List your
|
|
65
|
-
' search Search your
|
|
66
|
-
' show Show one
|
|
67
|
-
' update Update
|
|
68
|
-
' star Toggle a
|
|
69
|
-
' pin Toggle a
|
|
70
|
-
' delete Soft-delete an existing
|
|
71
|
-
' restore Restore a deleted
|
|
72
|
-
' purge Permanently delete a
|
|
63
|
+
' create Create a new note',
|
|
64
|
+
' list List your active, starred, or deleted notes',
|
|
65
|
+
' search Search your active notes',
|
|
66
|
+
' show Show one note with full metadata',
|
|
67
|
+
' update Update note content and metadata',
|
|
68
|
+
' star Toggle a note star',
|
|
69
|
+
' pin Toggle a note pin',
|
|
70
|
+
' delete Soft-delete an existing note by explicit id',
|
|
71
|
+
' restore Restore a deleted note by explicit id',
|
|
72
|
+
' purge Permanently delete a note by explicit id',
|
|
73
73
|
'',
|
|
74
74
|
'Options:',
|
|
75
|
-
' --content "<text>"
|
|
76
|
-
' --id <
|
|
77
|
-
' --query "<query>" Search query for
|
|
78
|
-
' --tag <tag> Filter
|
|
75
|
+
' --content "<text>" Note content for create',
|
|
76
|
+
' --id <noteId> Required for show, update, star, pin, delete, restore, and purge',
|
|
77
|
+
' --query "<query>" Search query for note search',
|
|
78
|
+
' --tag <tag> Filter note list results by tag',
|
|
79
79
|
' --sort <field> One of updatedAt, createdAt, or title',
|
|
80
|
-
' --starred List only starred
|
|
81
|
-
' --deleted List only deleted
|
|
82
|
-
' --title "<title>" Optional title for
|
|
83
|
-
' --visibility <value> Optional visibility for
|
|
84
|
-
' --tags <a,b,c> Optional comma-separated tags for
|
|
80
|
+
' --starred List only starred notes',
|
|
81
|
+
' --deleted List only deleted notes',
|
|
82
|
+
' --title "<title>" Optional title for note update',
|
|
83
|
+
' --visibility <value> Optional visibility for note update',
|
|
84
|
+
' --tags <a,b,c> Optional comma-separated tags for note update',
|
|
85
85
|
'',
|
|
86
86
|
'Examples:',
|
|
87
|
-
' kiipu
|
|
88
|
-
' kiipu
|
|
89
|
-
' kiipu
|
|
90
|
-
' kiipu
|
|
91
|
-
' kiipu
|
|
92
|
-
' kiipu
|
|
93
|
-
' kiipu
|
|
94
|
-
' kiipu
|
|
95
|
-
' kiipu
|
|
96
|
-
' kiipu
|
|
87
|
+
' kiipu note create "Hello Kiipu"',
|
|
88
|
+
' kiipu note list --sort updatedAt',
|
|
89
|
+
' kiipu note search "roadmap"',
|
|
90
|
+
' kiipu note show --id 123',
|
|
91
|
+
' kiipu note update --id 123 --content "Updated text" --tags work,#notes',
|
|
92
|
+
' kiipu note star --id 123',
|
|
93
|
+
' kiipu note pin --id 123',
|
|
94
|
+
' kiipu note create --content "Hello Kiipu"',
|
|
95
|
+
' kiipu note delete --id 123',
|
|
96
|
+
' kiipu note restore --id 123',
|
|
97
97
|
]),
|
|
98
98
|
};
|
|
99
99
|
}
|
|
@@ -173,8 +173,8 @@ export function getHelpResult(command) {
|
|
|
173
173
|
' kiipu <command> [options]',
|
|
174
174
|
'',
|
|
175
175
|
'Core commands:',
|
|
176
|
-
' ask Ask questions over your Kiipu
|
|
177
|
-
'
|
|
176
|
+
' ask Ask questions over your Kiipu notes and browse Ask conversations',
|
|
177
|
+
' note Create, browse, update, and delete notes with direct CLI arguments',
|
|
178
178
|
' auth Manage local API key authentication',
|
|
179
179
|
' doctor Check local setup, API access, and wrapper readiness',
|
|
180
180
|
' skills Show where the Claude Code plugin package lives',
|
|
@@ -182,10 +182,10 @@ export function getHelpResult(command) {
|
|
|
182
182
|
'Core examples:',
|
|
183
183
|
' kiipu ask "What changed in my roadmap notes?"',
|
|
184
184
|
' kiipu ask history --limit 10',
|
|
185
|
-
' kiipu
|
|
186
|
-
' kiipu
|
|
187
|
-
' kiipu
|
|
188
|
-
' kiipu
|
|
185
|
+
' kiipu note create "Hello Kiipu"',
|
|
186
|
+
' kiipu note list --starred',
|
|
187
|
+
' kiipu note search "Hello"',
|
|
188
|
+
' kiipu note delete --id 123',
|
|
189
189
|
' kiipu auth login',
|
|
190
190
|
' kiipu doctor',
|
|
191
191
|
' claude --plugin-dir ./packages/claude-plugin',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatNoteCollection, formatNoteDetail } from '../lib/note-formatters.js';
|
|
2
2
|
import { KiipuUserApiClient } from '../lib/kiipu-user-client.js';
|
|
3
|
-
import {
|
|
3
|
+
import { executeNoteAction } from '../lib/note-actions.js';
|
|
4
4
|
import { hasFlag, readFlag } from '../utils/args.js';
|
|
5
5
|
const actions = new Set([
|
|
6
6
|
'create',
|
|
@@ -18,21 +18,21 @@ const sortValues = new Set(['updatedAt', 'createdAt', 'title']);
|
|
|
18
18
|
function usage(action) {
|
|
19
19
|
switch (action) {
|
|
20
20
|
case 'create':
|
|
21
|
-
return 'Usage: kiipu
|
|
21
|
+
return 'Usage: kiipu note create --content "<text>"\n or: kiipu note create "<text>"';
|
|
22
22
|
case 'list':
|
|
23
|
-
return 'Usage: kiipu
|
|
23
|
+
return 'Usage: kiipu note list [--tag <tag>] [--sort <updatedAt|createdAt|title>] [--starred] [--deleted]';
|
|
24
24
|
case 'search':
|
|
25
|
-
return 'Usage: kiipu
|
|
25
|
+
return 'Usage: kiipu note search <query>\n or: kiipu note search --query "<query>"';
|
|
26
26
|
case 'show':
|
|
27
|
-
return 'Usage: kiipu
|
|
27
|
+
return 'Usage: kiipu note show --id <noteId>';
|
|
28
28
|
case 'update':
|
|
29
|
-
return 'Usage: kiipu
|
|
29
|
+
return 'Usage: kiipu note update --id <noteId> --content "<text>" [--title "<title>"] [--visibility public|private] [--tags <a,b,c>]';
|
|
30
30
|
case 'star':
|
|
31
|
-
return 'Usage: kiipu
|
|
31
|
+
return 'Usage: kiipu note star --id <noteId>';
|
|
32
32
|
case 'pin':
|
|
33
|
-
return 'Usage: kiipu
|
|
33
|
+
return 'Usage: kiipu note pin --id <noteId>';
|
|
34
34
|
default:
|
|
35
|
-
return `Usage: kiipu
|
|
35
|
+
return `Usage: kiipu note ${action} --id <noteId>`;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
function error(message) {
|
|
@@ -81,9 +81,9 @@ function validateSort(sort) {
|
|
|
81
81
|
}
|
|
82
82
|
return sortValues.has(sort) ? sort : null;
|
|
83
83
|
}
|
|
84
|
-
function
|
|
85
|
-
const
|
|
86
|
-
return
|
|
84
|
+
function parseNoteId(args, action) {
|
|
85
|
+
const noteId = readFlag(args, '--id')?.trim();
|
|
86
|
+
return noteId ? noteId : error(usage(action));
|
|
87
87
|
}
|
|
88
88
|
function parseTags(input) {
|
|
89
89
|
if (!input) {
|
|
@@ -105,19 +105,19 @@ function parseTags(input) {
|
|
|
105
105
|
}
|
|
106
106
|
return Array.from(unique.values());
|
|
107
107
|
}
|
|
108
|
-
function
|
|
108
|
+
function toCliNote(note) {
|
|
109
109
|
return {
|
|
110
|
-
id:
|
|
111
|
-
title:
|
|
112
|
-
rawText:
|
|
113
|
-
finalText:
|
|
114
|
-
visibility:
|
|
115
|
-
tags:
|
|
116
|
-
folder:
|
|
117
|
-
isPinned:
|
|
118
|
-
isStarred:
|
|
119
|
-
createdAt:
|
|
120
|
-
updatedAt:
|
|
110
|
+
id: note.id,
|
|
111
|
+
title: note.title,
|
|
112
|
+
rawText: note.rawText,
|
|
113
|
+
finalText: note.finalText,
|
|
114
|
+
visibility: note.visibility,
|
|
115
|
+
tags: note.tags,
|
|
116
|
+
folder: note.folder ?? null,
|
|
117
|
+
isPinned: note.isPinned,
|
|
118
|
+
isStarred: note.isStarred,
|
|
119
|
+
createdAt: note.createdAt,
|
|
120
|
+
updatedAt: note.updatedAt,
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
123
|
async function handleMutationAction(config, action, args) {
|
|
@@ -126,13 +126,13 @@ async function handleMutationAction(config, action, args) {
|
|
|
126
126
|
if (!content) {
|
|
127
127
|
return error(usage('create'));
|
|
128
128
|
}
|
|
129
|
-
return
|
|
129
|
+
return executeNoteAction(config, { action: 'create', content });
|
|
130
130
|
}
|
|
131
|
-
const
|
|
132
|
-
if (typeof
|
|
133
|
-
return
|
|
131
|
+
const noteId = parseNoteId(args, action);
|
|
132
|
+
if (typeof noteId !== 'string') {
|
|
133
|
+
return noteId;
|
|
134
134
|
}
|
|
135
|
-
return
|
|
135
|
+
return executeNoteAction(config, { action, noteId });
|
|
136
136
|
}
|
|
137
137
|
async function handleList(config, args) {
|
|
138
138
|
const { client, error: clientError } = requireUserClient(config);
|
|
@@ -149,36 +149,36 @@ async function handleList(config, args) {
|
|
|
149
149
|
return error(`--starred and --deleted cannot be used together.\n${usage('list')}`);
|
|
150
150
|
}
|
|
151
151
|
const tag = readFlag(args, '--tag');
|
|
152
|
-
let
|
|
152
|
+
let notes;
|
|
153
153
|
let responseData;
|
|
154
154
|
if (starred) {
|
|
155
|
-
const response = await client.
|
|
155
|
+
const response = await client.listStarredNotes({ tag, sort });
|
|
156
156
|
if (!response.ok) {
|
|
157
157
|
return error(response.error.message);
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
notes = response.data.map((entry) => toCliNote(entry.note));
|
|
160
160
|
responseData = response.data;
|
|
161
161
|
}
|
|
162
162
|
else if (deleted) {
|
|
163
|
-
const response = await client.
|
|
163
|
+
const response = await client.listDeletedNotes({ sort });
|
|
164
164
|
if (!response.ok) {
|
|
165
165
|
return error(response.error.message);
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
notes = response.data.map(toCliNote);
|
|
168
168
|
responseData = response.data;
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
|
-
const response = await client.
|
|
171
|
+
const response = await client.listNotes({ tag, sort });
|
|
172
172
|
if (!response.ok) {
|
|
173
173
|
return error(response.error.message);
|
|
174
174
|
}
|
|
175
|
-
|
|
175
|
+
notes = response.data.map(toCliNote);
|
|
176
176
|
responseData = response.data;
|
|
177
177
|
}
|
|
178
|
-
const title = starred ? 'Starred
|
|
178
|
+
const title = starred ? 'Starred notes' : deleted ? 'Deleted notes' : 'Notes';
|
|
179
179
|
return {
|
|
180
180
|
ok: true,
|
|
181
|
-
message:
|
|
181
|
+
message: formatNoteCollection(title, notes),
|
|
182
182
|
data: responseData,
|
|
183
183
|
};
|
|
184
184
|
}
|
|
@@ -191,13 +191,13 @@ async function handleSearch(config, args) {
|
|
|
191
191
|
if (!query) {
|
|
192
192
|
return error(usage('search'));
|
|
193
193
|
}
|
|
194
|
-
const response = await client.
|
|
194
|
+
const response = await client.searchNotes(query);
|
|
195
195
|
if (!response.ok) {
|
|
196
196
|
return error(response.error.message);
|
|
197
197
|
}
|
|
198
198
|
return {
|
|
199
199
|
ok: true,
|
|
200
|
-
message:
|
|
200
|
+
message: formatNoteCollection(`Search results for "${query}"`, response.data.map(toCliNote)),
|
|
201
201
|
data: response.data,
|
|
202
202
|
};
|
|
203
203
|
}
|
|
@@ -206,17 +206,17 @@ async function handleShow(config, args) {
|
|
|
206
206
|
if (!client) {
|
|
207
207
|
return clientError;
|
|
208
208
|
}
|
|
209
|
-
const
|
|
210
|
-
if (typeof
|
|
211
|
-
return
|
|
209
|
+
const noteId = parseNoteId(args, 'show');
|
|
210
|
+
if (typeof noteId !== 'string') {
|
|
211
|
+
return noteId;
|
|
212
212
|
}
|
|
213
|
-
const response = await client.
|
|
213
|
+
const response = await client.getNote(noteId);
|
|
214
214
|
if (!response.ok) {
|
|
215
215
|
return error(response.error.message);
|
|
216
216
|
}
|
|
217
217
|
return {
|
|
218
218
|
ok: true,
|
|
219
|
-
message:
|
|
219
|
+
message: formatNoteDetail(toCliNote(response.data)),
|
|
220
220
|
data: response.data,
|
|
221
221
|
};
|
|
222
222
|
}
|
|
@@ -225,9 +225,9 @@ async function handleUpdate(config, args) {
|
|
|
225
225
|
if (!client) {
|
|
226
226
|
return clientError;
|
|
227
227
|
}
|
|
228
|
-
const
|
|
229
|
-
if (typeof
|
|
230
|
-
return
|
|
228
|
+
const noteId = parseNoteId(args, 'update');
|
|
229
|
+
if (typeof noteId !== 'string') {
|
|
230
|
+
return noteId;
|
|
231
231
|
}
|
|
232
232
|
const content = readFlag(args, '--content')?.trim();
|
|
233
233
|
if (!content) {
|
|
@@ -239,7 +239,7 @@ async function handleUpdate(config, args) {
|
|
|
239
239
|
}
|
|
240
240
|
const title = readFlag(args, '--title');
|
|
241
241
|
const tags = readFlag(args, '--tags');
|
|
242
|
-
const response = await client.
|
|
242
|
+
const response = await client.updateNote(noteId, {
|
|
243
243
|
rawText: content,
|
|
244
244
|
...(title !== undefined ? { title: title || null } : {}),
|
|
245
245
|
...(visibility === 'public' || visibility === 'private' ? { visibility } : {}),
|
|
@@ -250,7 +250,7 @@ async function handleUpdate(config, args) {
|
|
|
250
250
|
}
|
|
251
251
|
return {
|
|
252
252
|
ok: true,
|
|
253
|
-
message: `
|
|
253
|
+
message: `Note updated.\n\n${formatNoteDetail(toCliNote(response.data))}`,
|
|
254
254
|
data: response.data,
|
|
255
255
|
};
|
|
256
256
|
}
|
|
@@ -259,17 +259,19 @@ async function handleStar(config, args) {
|
|
|
259
259
|
if (!client) {
|
|
260
260
|
return clientError;
|
|
261
261
|
}
|
|
262
|
-
const
|
|
263
|
-
if (typeof
|
|
264
|
-
return
|
|
262
|
+
const noteId = parseNoteId(args, 'star');
|
|
263
|
+
if (typeof noteId !== 'string') {
|
|
264
|
+
return noteId;
|
|
265
265
|
}
|
|
266
|
-
const response = await client.toggleStar(
|
|
266
|
+
const response = await client.toggleStar(noteId);
|
|
267
267
|
if (!response.ok) {
|
|
268
268
|
return error(response.error.message);
|
|
269
269
|
}
|
|
270
270
|
return {
|
|
271
271
|
ok: true,
|
|
272
|
-
message: response.data.isStarred
|
|
272
|
+
message: response.data.isStarred
|
|
273
|
+
? `Note starred. ${response.data.id}`
|
|
274
|
+
: `Note unstarred. ${response.data.id}`,
|
|
273
275
|
data: response.data,
|
|
274
276
|
};
|
|
275
277
|
}
|
|
@@ -278,24 +280,26 @@ async function handlePin(config, args) {
|
|
|
278
280
|
if (!client) {
|
|
279
281
|
return clientError;
|
|
280
282
|
}
|
|
281
|
-
const
|
|
282
|
-
if (typeof
|
|
283
|
-
return
|
|
283
|
+
const noteId = parseNoteId(args, 'pin');
|
|
284
|
+
if (typeof noteId !== 'string') {
|
|
285
|
+
return noteId;
|
|
284
286
|
}
|
|
285
|
-
const response = await client.togglePin(
|
|
287
|
+
const response = await client.togglePin(noteId);
|
|
286
288
|
if (!response.ok) {
|
|
287
289
|
return error(response.error.message);
|
|
288
290
|
}
|
|
289
291
|
return {
|
|
290
292
|
ok: true,
|
|
291
|
-
message: response.data.isPinned
|
|
293
|
+
message: response.data.isPinned
|
|
294
|
+
? `Note pinned. ${response.data.id}`
|
|
295
|
+
: `Note unpinned. ${response.data.id}`,
|
|
292
296
|
data: response.data,
|
|
293
297
|
};
|
|
294
298
|
}
|
|
295
|
-
export async function
|
|
299
|
+
export async function runNoteCommand(config, args) {
|
|
296
300
|
const action = args[1];
|
|
297
301
|
if (!action || !actions.has(action)) {
|
|
298
|
-
return error('Usage: kiipu
|
|
302
|
+
return error('Usage: kiipu note <create|delete|restore|purge|list|search|show|update|star|pin> [options]');
|
|
299
303
|
}
|
|
300
304
|
const actionArgs = args.slice(2);
|
|
301
305
|
switch (action) {
|
|
@@ -317,5 +321,5 @@ export async function runPostCommand(config, args) {
|
|
|
317
321
|
case 'pin':
|
|
318
322
|
return handlePin(config, actionArgs);
|
|
319
323
|
}
|
|
320
|
-
return error('Unsupported
|
|
324
|
+
return error('Unsupported note action.');
|
|
321
325
|
}
|
package/dist/config/load-env.js
CHANGED
|
@@ -13,7 +13,10 @@ function parseEnvFile(content) {
|
|
|
13
13
|
if (!key || process.env[key] !== undefined) {
|
|
14
14
|
continue;
|
|
15
15
|
}
|
|
16
|
-
const value = line
|
|
16
|
+
const value = line
|
|
17
|
+
.slice(separatorIndex + 1)
|
|
18
|
+
.trim()
|
|
19
|
+
.replace(/^['"]|['"]$/g, '');
|
|
17
20
|
process.env[key] = value;
|
|
18
21
|
}
|
|
19
22
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { runAskCommand } from './commands/ask.js';
|
|
|
5
5
|
import { runAuthCommand } from './commands/auth.js';
|
|
6
6
|
import { runDoctorCommand } from './commands/doctor.js';
|
|
7
7
|
import { getHelpResult } from './commands/help.js';
|
|
8
|
-
import {
|
|
8
|
+
import { runNoteCommand } from './commands/note.js';
|
|
9
9
|
import { runSkillsCommand } from './commands/skills.js';
|
|
10
10
|
import { readFlag, hasFlag } from './utils/args.js';
|
|
11
11
|
import { CLI_VERSION } from './version.js';
|
|
@@ -86,8 +86,8 @@ async function main() {
|
|
|
86
86
|
result = await runDoctorCommand(await loadKiipuConfig());
|
|
87
87
|
return printResult(result, asJson);
|
|
88
88
|
}
|
|
89
|
-
if (command === '
|
|
90
|
-
result = await
|
|
89
|
+
if (command === 'note') {
|
|
90
|
+
result = await runNoteCommand(config, commandArgs);
|
|
91
91
|
return printResult(result, asJson);
|
|
92
92
|
}
|
|
93
93
|
if (command === 'ask') {
|
package/dist/lib/ask-client.js
CHANGED
|
@@ -45,14 +45,14 @@ function parseSource(input) {
|
|
|
45
45
|
if (!isRecord(input)) {
|
|
46
46
|
return null;
|
|
47
47
|
}
|
|
48
|
-
const
|
|
48
|
+
const noteId = typeof input.noteId === 'string' ? input.noteId : '';
|
|
49
49
|
const snippet = typeof input.snippet === 'string' ? input.snippet : '';
|
|
50
|
-
if (!
|
|
50
|
+
if (!noteId || !snippet) {
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
return {
|
|
54
54
|
index: typeof input.index === 'number' ? input.index : 0,
|
|
55
|
-
|
|
55
|
+
noteId,
|
|
56
56
|
title: typeof input.title === 'string' ? input.title : null,
|
|
57
57
|
snippet,
|
|
58
58
|
score: typeof input.score === 'number' ? input.score : 0,
|
|
@@ -60,7 +60,9 @@ function parseSource(input) {
|
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
function parseSources(input) {
|
|
63
|
-
return Array.isArray(input)
|
|
63
|
+
return Array.isArray(input)
|
|
64
|
+
? input.map(parseSource).filter((source) => Boolean(source))
|
|
65
|
+
: [];
|
|
64
66
|
}
|
|
65
67
|
function parseAskEvent(input) {
|
|
66
68
|
if (!isRecord(input) || typeof input.type !== 'string') {
|
|
@@ -24,7 +24,7 @@ function truncate(value, maxLength) {
|
|
|
24
24
|
function formatSourceLine(source) {
|
|
25
25
|
const title = source.title?.trim() || '(untitled)';
|
|
26
26
|
const score = Number.isFinite(source.score) ? ` score ${source.score.toFixed(3)}` : '';
|
|
27
|
-
return `[${source.index}] ${title} (${source.
|
|
27
|
+
return `[${source.index}] ${title} (${source.noteId})${score}`;
|
|
28
28
|
}
|
|
29
29
|
export function formatAskFooter(input) {
|
|
30
30
|
const lines = ['', 'Sources:'];
|
|
@@ -9,40 +9,46 @@ function buildError(requestId, message, code = 'request_failed') {
|
|
|
9
9
|
},
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function parseCreateNoteRequest(input) {
|
|
13
13
|
const requestId = typeof input.requestId === 'string' ? input.requestId : randomUUID();
|
|
14
14
|
const rawText = typeof input.rawText === 'string' ? input.rawText.trim() : '';
|
|
15
15
|
if (!rawText) {
|
|
16
16
|
throw new Error('rawText is required.');
|
|
17
17
|
}
|
|
18
18
|
const visibility = input.visibility;
|
|
19
|
-
const tags = Array.isArray(input.tags)
|
|
19
|
+
const tags = Array.isArray(input.tags)
|
|
20
|
+
? input.tags.filter((tag) => typeof tag === 'string')
|
|
21
|
+
: [];
|
|
20
22
|
return {
|
|
21
23
|
requestId,
|
|
22
24
|
requestedAt: typeof input.requestedAt === 'string' ? input.requestedAt : undefined,
|
|
23
25
|
traceId: typeof input.traceId === 'string' ? input.traceId : undefined,
|
|
24
26
|
rawText,
|
|
25
|
-
sourceType: input.sourceType === 'manual' ||
|
|
27
|
+
sourceType: input.sourceType === 'manual' ||
|
|
28
|
+
input.sourceType === 'imported' ||
|
|
29
|
+
input.sourceType === 'skill_command'
|
|
26
30
|
? input.sourceType
|
|
27
31
|
: 'skill_command',
|
|
28
32
|
finalText: typeof input.finalText === 'string' ? input.finalText : undefined,
|
|
29
|
-
visibility: visibility === 'unlisted' || visibility === 'private' || visibility === 'public'
|
|
33
|
+
visibility: visibility === 'unlisted' || visibility === 'private' || visibility === 'public'
|
|
34
|
+
? visibility
|
|
35
|
+
: 'public',
|
|
30
36
|
sourceMessageId: typeof input.sourceMessageId === 'string' ? input.sourceMessageId : undefined,
|
|
31
37
|
title: typeof input.title === 'string' ? input.title : input.title === null ? null : undefined,
|
|
32
38
|
tags,
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
|
-
function
|
|
41
|
+
function parseNoteMutationRequest(input) {
|
|
36
42
|
const requestId = typeof input.requestId === 'string' ? input.requestId : randomUUID();
|
|
37
|
-
const
|
|
38
|
-
if (!
|
|
39
|
-
throw new Error('
|
|
43
|
+
const noteId = typeof input.noteId === 'string' ? input.noteId.trim() : '';
|
|
44
|
+
if (!noteId) {
|
|
45
|
+
throw new Error('noteId is required.');
|
|
40
46
|
}
|
|
41
47
|
return {
|
|
42
48
|
requestId,
|
|
43
49
|
requestedAt: typeof input.requestedAt === 'string' ? input.requestedAt : undefined,
|
|
44
50
|
traceId: typeof input.traceId === 'string' ? input.traceId : undefined,
|
|
45
|
-
|
|
51
|
+
noteId,
|
|
46
52
|
};
|
|
47
53
|
}
|
|
48
54
|
export class KiipuIntegrationApiClient {
|
|
@@ -87,19 +93,19 @@ export class KiipuIntegrationApiClient {
|
|
|
87
93
|
? payload.code
|
|
88
94
|
: 'request_failed');
|
|
89
95
|
}
|
|
90
|
-
|
|
91
|
-
return this.request('/integrations/
|
|
96
|
+
createNote(input) {
|
|
97
|
+
return this.request('/integrations/notes', 'POST', parseCreateNoteRequest(input));
|
|
92
98
|
}
|
|
93
|
-
|
|
94
|
-
const body =
|
|
95
|
-
return this.request(`/integrations/
|
|
99
|
+
deleteNote(input) {
|
|
100
|
+
const body = parseNoteMutationRequest(input);
|
|
101
|
+
return this.request(`/integrations/notes/${body.noteId}/delete`, 'POST', body);
|
|
96
102
|
}
|
|
97
|
-
|
|
98
|
-
const body =
|
|
99
|
-
return this.request(`/integrations/
|
|
103
|
+
restoreNote(input) {
|
|
104
|
+
const body = parseNoteMutationRequest(input);
|
|
105
|
+
return this.request(`/integrations/notes/${body.noteId}/restore`, 'POST', body);
|
|
100
106
|
}
|
|
101
|
-
|
|
102
|
-
const body =
|
|
103
|
-
return this.request(`/integrations/
|
|
107
|
+
permanentDeleteNote(input) {
|
|
108
|
+
const body = parseNoteMutationRequest(input);
|
|
109
|
+
return this.request(`/integrations/notes/${body.noteId}/permanent-delete`, 'POST', body);
|
|
104
110
|
}
|
|
105
111
|
}
|
|
@@ -72,34 +72,34 @@ export class KiipuUserApiClient {
|
|
|
72
72
|
body: JSON.stringify(input),
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
return this.request(this.buildPath('/
|
|
75
|
+
listNotes(input) {
|
|
76
|
+
return this.request(this.buildPath('/notes/me', input));
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
return this.request(this.buildPath('/
|
|
78
|
+
searchNotes(query) {
|
|
79
|
+
return this.request(this.buildPath('/notes/me/search', { q: query }));
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
return this.request(this.buildPath('/
|
|
81
|
+
listStarredNotes(input) {
|
|
82
|
+
return this.request(this.buildPath('/notes/me/starred', input));
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
return this.request(this.buildPath('/
|
|
84
|
+
listDeletedNotes(input) {
|
|
85
|
+
return this.request(this.buildPath('/notes/me/deleted', input));
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
return this.request(`/
|
|
87
|
+
getNote(id) {
|
|
88
|
+
return this.request(`/notes/${id}`);
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
return this.request(`/
|
|
90
|
+
updateNote(id, input) {
|
|
91
|
+
return this.request(`/notes/${id}/content`, {
|
|
92
92
|
method: 'PATCH',
|
|
93
93
|
body: JSON.stringify(input),
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
toggleStar(id) {
|
|
97
|
-
return this.request(`/
|
|
97
|
+
return this.request(`/notes/${id}/star`, {
|
|
98
98
|
method: 'PATCH',
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
togglePin(id) {
|
|
102
|
-
return this.request(`/
|
|
102
|
+
return this.request(`/notes/${id}/pin`, {
|
|
103
103
|
method: 'PATCH',
|
|
104
104
|
});
|
|
105
105
|
}
|
|
@@ -3,7 +3,7 @@ import { KiipuIntegrationApiClient } from './kiipu-integration-client.js';
|
|
|
3
3
|
function formatRequestFailed(message, code) {
|
|
4
4
|
return `Request failed: ${message} (${code}).`;
|
|
5
5
|
}
|
|
6
|
-
function
|
|
6
|
+
function getNoteApiClient(config) {
|
|
7
7
|
const apiKey = config.apiKey ?? process.env.KIIPU_API_KEY ?? '';
|
|
8
8
|
if (!apiKey) {
|
|
9
9
|
return {
|
|
@@ -20,16 +20,16 @@ function getPostApiClient(config) {
|
|
|
20
20
|
}),
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
export async function
|
|
24
|
-
const { client, error } =
|
|
23
|
+
export async function executeNoteAction(config, input) {
|
|
24
|
+
const { client, error } = getNoteApiClient(config);
|
|
25
25
|
if (!client) {
|
|
26
26
|
return error;
|
|
27
27
|
}
|
|
28
28
|
if (input.action === 'create') {
|
|
29
|
-
const response = await client.
|
|
29
|
+
const response = await client.createNote({
|
|
30
30
|
requestId: randomUUID(),
|
|
31
31
|
requestedAt: new Date().toISOString(),
|
|
32
|
-
traceId: `${input.traceIdPrefix ?? '
|
|
32
|
+
traceId: `${input.traceIdPrefix ?? 'note'}-${Date.now()}`,
|
|
33
33
|
rawText: input.content,
|
|
34
34
|
sourceType: 'skill_command',
|
|
35
35
|
sourceMessageId: input.sourceMessageId ?? `local-${Date.now()}`,
|
|
@@ -44,18 +44,18 @@ export async function executePostAction(config, input) {
|
|
|
44
44
|
}
|
|
45
45
|
return {
|
|
46
46
|
ok: true,
|
|
47
|
-
message: `
|
|
47
|
+
message: `Note created. Note id ${String(response.data.id)} is now visible in the feed.`,
|
|
48
48
|
data: response.data,
|
|
49
49
|
requestId: response.requestId,
|
|
50
|
-
|
|
50
|
+
noteId: String(response.data.id),
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
if (input.action === 'delete') {
|
|
54
|
-
const response = await client.
|
|
54
|
+
const response = await client.deleteNote({
|
|
55
55
|
requestId: randomUUID(),
|
|
56
56
|
requestedAt: new Date().toISOString(),
|
|
57
57
|
traceId: `${input.traceIdPrefix ?? 'delete'}-${Date.now()}`,
|
|
58
|
-
|
|
58
|
+
noteId: input.noteId,
|
|
59
59
|
});
|
|
60
60
|
if (!response.ok) {
|
|
61
61
|
return {
|
|
@@ -65,18 +65,18 @@ export async function executePostAction(config, input) {
|
|
|
65
65
|
}
|
|
66
66
|
return {
|
|
67
67
|
ok: true,
|
|
68
|
-
message: '
|
|
68
|
+
message: 'Note deleted. The current note is no longer visible in the feed.',
|
|
69
69
|
data: response.data,
|
|
70
70
|
requestId: response.requestId,
|
|
71
|
-
|
|
71
|
+
noteId: null,
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
74
|
if (input.action === 'restore') {
|
|
75
|
-
const response = await client.
|
|
75
|
+
const response = await client.restoreNote({
|
|
76
76
|
requestId: randomUUID(),
|
|
77
77
|
requestedAt: new Date().toISOString(),
|
|
78
78
|
traceId: `${input.traceIdPrefix ?? 'restore'}-${Date.now()}`,
|
|
79
|
-
|
|
79
|
+
noteId: input.noteId,
|
|
80
80
|
});
|
|
81
81
|
if (!response.ok) {
|
|
82
82
|
return {
|
|
@@ -86,17 +86,17 @@ export async function executePostAction(config, input) {
|
|
|
86
86
|
}
|
|
87
87
|
return {
|
|
88
88
|
ok: true,
|
|
89
|
-
message: `
|
|
89
|
+
message: `Note restored. Note id ${input.noteId} is now back in the feed.`,
|
|
90
90
|
data: response.data,
|
|
91
91
|
requestId: response.requestId,
|
|
92
|
-
|
|
92
|
+
noteId: input.noteId,
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
const response = await client.
|
|
95
|
+
const response = await client.permanentDeleteNote({
|
|
96
96
|
requestId: randomUUID(),
|
|
97
97
|
requestedAt: new Date().toISOString(),
|
|
98
98
|
traceId: `${input.traceIdPrefix ?? 'purge'}-${Date.now()}`,
|
|
99
|
-
|
|
99
|
+
noteId: input.noteId,
|
|
100
100
|
});
|
|
101
101
|
if (!response.ok) {
|
|
102
102
|
return {
|
|
@@ -106,9 +106,9 @@ export async function executePostAction(config, input) {
|
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
108
|
ok: true,
|
|
109
|
-
message: `
|
|
109
|
+
message: `Note permanently deleted. Note id ${input.noteId} has been removed from the database.`,
|
|
110
110
|
data: response.data,
|
|
111
111
|
requestId: response.requestId,
|
|
112
|
-
|
|
112
|
+
noteId: null,
|
|
113
113
|
};
|
|
114
114
|
}
|
|
@@ -23,52 +23,55 @@ function formatTags(tags, limit) {
|
|
|
23
23
|
: [];
|
|
24
24
|
return normalized.length > 0 ? normalized.map((tag) => `#${tag}`).join(', ') : 'none';
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
const content = (
|
|
26
|
+
function getNotePreview(note) {
|
|
27
|
+
const content = (note.title?.trim() ||
|
|
28
|
+
note.finalText?.trim() ||
|
|
29
|
+
note.rawText?.trim() ||
|
|
30
|
+
'').replace(/\s+/g, ' ');
|
|
28
31
|
if (!content) {
|
|
29
32
|
return '(empty)';
|
|
30
33
|
}
|
|
31
34
|
return content.length > 100 ? `${content.slice(0, 97)}...` : content;
|
|
32
35
|
}
|
|
33
|
-
function getStatusFlags(
|
|
36
|
+
function getStatusFlags(note) {
|
|
34
37
|
const flags = [];
|
|
35
|
-
if (
|
|
38
|
+
if (note.isPinned) {
|
|
36
39
|
flags.push('pinned');
|
|
37
40
|
}
|
|
38
|
-
if (
|
|
41
|
+
if (note.isStarred) {
|
|
39
42
|
flags.push('starred');
|
|
40
43
|
}
|
|
41
44
|
return flags.length > 0 ? flags.join(', ') : 'none';
|
|
42
45
|
}
|
|
43
|
-
export function
|
|
46
|
+
export function formatNoteCollection(title, notes) {
|
|
44
47
|
const lines = [title, ''];
|
|
45
|
-
if (
|
|
46
|
-
lines.push('No
|
|
48
|
+
if (notes.length === 0) {
|
|
49
|
+
lines.push('No notes found.');
|
|
47
50
|
return lines.join('\n');
|
|
48
51
|
}
|
|
49
|
-
for (const
|
|
50
|
-
lines.push(`${
|
|
51
|
-
lines.push(` flags: ${getStatusFlags(
|
|
52
|
-
lines.push(` ${
|
|
52
|
+
for (const note of notes) {
|
|
53
|
+
lines.push(`${note.id} ${formatTimestamp(note.updatedAt ?? note.createdAt)}`);
|
|
54
|
+
lines.push(` flags: ${getStatusFlags(note)} visibility: ${note.visibility} tags: ${formatTags(note.tags, 3)}`);
|
|
55
|
+
lines.push(` ${getNotePreview(note)}`);
|
|
53
56
|
lines.push('');
|
|
54
57
|
}
|
|
55
58
|
return lines.slice(0, -1).join('\n');
|
|
56
59
|
}
|
|
57
|
-
export function
|
|
58
|
-
const title =
|
|
59
|
-
const body =
|
|
60
|
+
export function formatNoteDetail(note) {
|
|
61
|
+
const title = note.title?.trim() || '(untitled)';
|
|
62
|
+
const body = note.finalText?.trim() || note.rawText?.trim() || '(empty)';
|
|
60
63
|
return [
|
|
61
64
|
title,
|
|
62
65
|
'',
|
|
63
66
|
body,
|
|
64
67
|
'',
|
|
65
|
-
`id: ${
|
|
66
|
-
`visibility: ${
|
|
67
|
-
`created: ${formatTimestamp(
|
|
68
|
-
`updated: ${formatTimestamp(
|
|
69
|
-
`tags: ${formatTags(
|
|
70
|
-
`folder: ${
|
|
71
|
-
`pinned: ${
|
|
72
|
-
`starred: ${
|
|
68
|
+
`id: ${note.id}`,
|
|
69
|
+
`visibility: ${note.visibility}`,
|
|
70
|
+
`created: ${formatTimestamp(note.createdAt)}`,
|
|
71
|
+
`updated: ${formatTimestamp(note.updatedAt)}`,
|
|
72
|
+
`tags: ${formatTags(note.tags)}`,
|
|
73
|
+
`folder: ${note.folder ? `${note.folder.name} (${note.folder.id})` : 'none'}`,
|
|
74
|
+
`pinned: ${note.isPinned ? 'yes' : 'no'}`,
|
|
75
|
+
`starred: ${note.isStarred ? 'yes' : 'no'}`,
|
|
73
76
|
].join('\n');
|
|
74
77
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiipu/cli",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Kiipu CLI for local authentication, doctor checks, and direct
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "Kiipu CLI for local authentication, doctor checks, and direct note actions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|