vertex-notes 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/bin/run.js +4 -0
- package/dist/chunk-4QLCD6TZ.js +479 -0
- package/dist/chunk-4QLCD6TZ.js.map +1 -0
- package/dist/chunk-DDFOKGIX.js +50 -0
- package/dist/chunk-DDFOKGIX.js.map +1 -0
- package/dist/chunk-FWK2J3FR.js +163 -0
- package/dist/chunk-FWK2J3FR.js.map +1 -0
- package/dist/chunk-PBF5EE4Y.js +42 -0
- package/dist/chunk-PBF5EE4Y.js.map +1 -0
- package/dist/commands/capture.js +44 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/daily.js +53 -0
- package/dist/commands/daily.js.map +1 -0
- package/dist/commands/delete.js +38 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/edit.js +88 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/export.js +46 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/hello.js +16 -0
- package/dist/commands/hello.js.map +1 -0
- package/dist/commands/help.js +108 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/interactive.js +211 -0
- package/dist/commands/interactive.js.map +1 -0
- package/dist/commands/login.js +162 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +17 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/new.js +28 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/notes.js +45 -0
- package/dist/commands/notes.js.map +1 -0
- package/dist/commands/restore.js +35 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/search.js +38 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.js +39 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tags.js +32 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/today.js +33 -0
- package/dist/commands/today.js.map +1 -0
- package/dist/commands/trash/empty.js +24 -0
- package/dist/commands/trash/empty.js.map +1 -0
- package/dist/commands/trash/index.js +37 -0
- package/dist/commands/trash/index.js.map +1 -0
- package/dist/commands/view.js +35 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/commands/whoami.js +22 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/client.js +11 -0
- package/dist/lib/client.js.map +1 -0
- package/dist/lib/config.js +13 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/md-to-tiptap.js +7 -0
- package/dist/lib/md-to-tiptap.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERTEX_VERSION
|
|
3
|
+
} from "../chunk-4QLCD6TZ.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/help.ts
|
|
6
|
+
import { Command } from "@oclif/core";
|
|
7
|
+
var DIM = "\x1B[90m";
|
|
8
|
+
var BOLD = "\x1B[1m";
|
|
9
|
+
var CYAN = "\x1B[36m";
|
|
10
|
+
var YELLOW = "\x1B[33m";
|
|
11
|
+
var GREEN = "\x1B[32m";
|
|
12
|
+
var PURPLE = "\x1B[35m";
|
|
13
|
+
var R = "\x1B[0m";
|
|
14
|
+
function heading(text) {
|
|
15
|
+
return `
|
|
16
|
+
${BOLD}${CYAN}${text}${R}`;
|
|
17
|
+
}
|
|
18
|
+
function row(cmd, desc) {
|
|
19
|
+
return ` ${GREEN}${cmd.padEnd(32)}${R}${DIM}${desc}${R}`;
|
|
20
|
+
}
|
|
21
|
+
function sub(text) {
|
|
22
|
+
return ` ${DIM}${text}${R}`;
|
|
23
|
+
}
|
|
24
|
+
var Help = class extends Command {
|
|
25
|
+
static description = "Show all Vertex CLI commands";
|
|
26
|
+
async run() {
|
|
27
|
+
this.log(`
|
|
28
|
+
${BOLD}${PURPLE}\u25B2 Vertex CLI${R} ${DIM}v${VERTEX_VERSION}${R}
|
|
29
|
+
${DIM}Your knowledge, structured \u2014 from the terminal.${R}
|
|
30
|
+
${heading("AUTH")}
|
|
31
|
+
${row("vertex login", "Log in (GitHub, Google, or Email)")}
|
|
32
|
+
${row("vertex logout", "Log out and clear saved session")}
|
|
33
|
+
${row("vertex whoami", "Show logged-in user email")}
|
|
34
|
+
${heading("NOTES")}
|
|
35
|
+
${row("vertex notes", "List all notes")}
|
|
36
|
+
${row("vertex new [title]", "Create a new note")}
|
|
37
|
+
${row("vertex view <title>", "View note as markdown")}
|
|
38
|
+
${row("vertex edit <title>", "Edit note in $EDITOR")}
|
|
39
|
+
${row("vertex daily", "View or create today's daily note")}
|
|
40
|
+
${row("vertex daily --last", "View most recent daily note")}
|
|
41
|
+
${heading("INTERACTIVE MODE")}
|
|
42
|
+
${row("vertex today", "Latest daily note \u2192 interactive")}
|
|
43
|
+
${row("vertex interactive <title>", "Open any note \u2192 interactive")}
|
|
44
|
+
|
|
45
|
+
${DIM}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${R}
|
|
46
|
+
${DIM}\u2502${R} ${YELLOW}\u2191 \u2193${R} ${DIM}\u2502${R} Move cursor between items ${DIM}\u2502${R}
|
|
47
|
+
${DIM}\u2502${R} ${YELLOW}Enter${R} ${DIM}\u2502${R} Toggle todo ${DIM}[ ] \u2192 [\u2713] \u2192 [ ]${R} ${DIM}\u2502${R}
|
|
48
|
+
${DIM}\u2502${R} ${YELLOW}t${R} ${DIM}\u2502${R} Add new todo ${DIM}\u2502${R}
|
|
49
|
+
${DIM}\u2502${R} ${YELLOW}n${R} ${DIM}\u2502${R} Add new text line ${DIM}\u2502${R}
|
|
50
|
+
${DIM}\u2502${R} ${YELLOW}d${R} ${DIM}\u2502${R} Delete item at cursor ${DIM}\u2502${R}
|
|
51
|
+
${DIM}\u2502${R} ${YELLOW}s${R} ${DIM}\u2502${R} Save changes ${DIM}\u2502${R}
|
|
52
|
+
${DIM}\u2502${R} ${YELLOW}q${R} ${DIM}\u2502${R} Quit ${DIM}(auto-saves if changed)${R} ${DIM}\u2502${R}
|
|
53
|
+
${DIM}\u2502${R} ${YELLOW}Esc${R} ${DIM}\u2502${R} Cancel input ${DIM}\u2502${R}
|
|
54
|
+
${DIM}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${R}
|
|
55
|
+
${heading("CAPTURE")}
|
|
56
|
+
${row('vertex capture "text"', "Quick capture to Inbox note")}
|
|
57
|
+
${heading("SEARCH & ORGANIZE")}
|
|
58
|
+
${row("vertex search <query>", "Search notes")}
|
|
59
|
+
${row("vertex tags", "List all tags")}
|
|
60
|
+
|
|
61
|
+
${DIM}Query syntax: ${PURPLE}keyword${R}${DIM} \xB7 ${PURPLE}#tag${R}${DIM} \xB7 ${PURPLE}type:todo${R}${DIM} \xB7 ${PURPLE}status:open${R}${DIM} \xB7 ${PURPLE}status:done${R}
|
|
62
|
+
${heading("EXPORT")}
|
|
63
|
+
${row("vertex export <title>", "Export as markdown to stdout")}
|
|
64
|
+
${row("vertex export <title> --json", "Export as JSON")}
|
|
65
|
+
${row("vertex export <title> -o file", "Export to file")}
|
|
66
|
+
${heading("TRASH")}
|
|
67
|
+
${row("vertex delete <title>", "Soft delete \u2192 trash")}
|
|
68
|
+
${row("vertex restore <title>", "Restore from trash")}
|
|
69
|
+
${row("vertex trash", "List trashed notes")}
|
|
70
|
+
${row("vertex trash:empty", "Permanently delete all trash")}
|
|
71
|
+
${heading("INFO")}
|
|
72
|
+
${row("vertex status", "Storage usage, note count, version")}
|
|
73
|
+
${row("vertex hello", "Verify CLI is working")}
|
|
74
|
+
${row("vertex help", "Show this help")}
|
|
75
|
+
${heading("EDITOR SYNTAX")}
|
|
76
|
+
${sub("for use with: vertex edit <title>")}
|
|
77
|
+
|
|
78
|
+
${DIM}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${R}
|
|
79
|
+
${DIM}\u2502${R} ${YELLOW}# ## ###${R} ${DIM}\u2502${R} Headings ${DIM}\u2502${R}
|
|
80
|
+
${DIM}\u2502${R} ${YELLOW}**bold** *italic*${R} ${DIM}\u2502${R} Formatting ${DIM}\u2502${R}
|
|
81
|
+
${DIM}\u2502${R} ${YELLOW}\`code\` ~~strike~~${R} ${DIM}\u2502${R} Inline code & strikethrough ${DIM}\u2502${R}
|
|
82
|
+
${DIM}\u2502${R} ${YELLOW}[[Link]] #tag${R} ${DIM}\u2502${R} Wiki links & tags ${DIM}\u2502${R}
|
|
83
|
+
${DIM}\u2502${R} ${YELLOW}- item${R} ${YELLOW}1. item${R} ${DIM}\u2502${R} Bullet & numbered lists ${DIM}\u2502${R}
|
|
84
|
+
${DIM}\u2502${R} ${YELLOW}- [x]${R} ${YELLOW}- [ ]${R} ${DIM}\u2502${R} Done & open tasks ${DIM}\u2502${R}
|
|
85
|
+
${DIM}\u2502${R} ${YELLOW}> quote${R} ${YELLOW}---${R} ${DIM}\u2502${R} Blockquote & divider ${DIM}\u2502${R}
|
|
86
|
+
${DIM}\u2502${R} ${YELLOW}\`\`\`lang ... \`\`\`${R} ${DIM}\u2502${R} Code block ${DIM}\u2502${R}
|
|
87
|
+
${DIM}\u2502${R} ${YELLOW}$$ ... $$${R} ${DIM}\u2502${R} Math block (LaTeX) ${DIM}\u2502${R}
|
|
88
|
+
${DIM}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${R}
|
|
89
|
+
${DIM}Web app only: mermaid, callouts, query blocks, file uploads${R}
|
|
90
|
+
${heading("TIPS")}
|
|
91
|
+
${DIM}\u2022${R} Title args use partial matching ${DIM}("proj" \u2192 "Project Plan")${R}
|
|
92
|
+
${DIM}\u2022${R} Set ${YELLOW}EDITOR=nano${R} or ${YELLOW}EDITOR="code --wait"${R} for preferred editor
|
|
93
|
+
${DIM}\u2022${R} Session stored in ${DIM}~/.vertex/config.json${R}
|
|
94
|
+
${DIM}\u2022${R} New users get 50 MB storage, upgradeable per account
|
|
95
|
+
${DIM}\u2022${R} ${GREEN}vertex today${R} is the fastest way to manage daily todos
|
|
96
|
+
${heading("EXAMPLES")}
|
|
97
|
+
${DIM}$${R} vertex today
|
|
98
|
+
${DIM}$${R} vertex capture "buy groceries"
|
|
99
|
+
${DIM}$${R} vertex search "#work type:todo status:open"
|
|
100
|
+
${DIM}$${R} vertex export "Meeting Notes" -o meeting.md
|
|
101
|
+
${DIM}$${R} EDITOR=nano vertex edit "Ideas"
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
export {
|
|
106
|
+
Help as default
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/help.ts"],"sourcesContent":["import { Command } from \"@oclif/core\";\nimport { VERTEX_VERSION } from \"@vertex/core\";\n\nconst DIM = \"\\x1b[90m\";\nconst BOLD = \"\\x1b[1m\";\nconst CYAN = \"\\x1b[36m\";\nconst YELLOW = \"\\x1b[33m\";\nconst GREEN = \"\\x1b[32m\";\nconst PURPLE = \"\\x1b[35m\";\nconst R = \"\\x1b[0m\";\n\nfunction heading(text: string): string {\n return `\\n ${BOLD}${CYAN}${text}${R}`;\n}\n\nfunction row(cmd: string, desc: string): string {\n return ` ${GREEN}${cmd.padEnd(32)}${R}${DIM}${desc}${R}`;\n}\n\nfunction sub(text: string): string {\n return ` ${DIM}${text}${R}`;\n}\n\nexport default class Help extends Command {\n static override description = \"Show all Vertex CLI commands\";\n\n async run(): Promise<void> {\n this.log(`\n ${BOLD}${PURPLE}▲ Vertex CLI${R} ${DIM}v${VERTEX_VERSION}${R}\n ${DIM}Your knowledge, structured — from the terminal.${R}\n${heading(\"AUTH\")}\n${row(\"vertex login\", \"Log in (GitHub, Google, or Email)\")}\n${row(\"vertex logout\", \"Log out and clear saved session\")}\n${row(\"vertex whoami\", \"Show logged-in user email\")}\n${heading(\"NOTES\")}\n${row(\"vertex notes\", \"List all notes\")}\n${row(\"vertex new [title]\", \"Create a new note\")}\n${row(\"vertex view <title>\", \"View note as markdown\")}\n${row(\"vertex edit <title>\", \"Edit note in $EDITOR\")}\n${row(\"vertex daily\", \"View or create today's daily note\")}\n${row(\"vertex daily --last\", \"View most recent daily note\")}\n${heading(\"INTERACTIVE MODE\")}\n${row(\"vertex today\", \"Latest daily note → interactive\")}\n${row(\"vertex interactive <title>\", \"Open any note → interactive\")}\n\n ${DIM}┌──────────┬────────────────────────────────────────────┐${R}\n ${DIM}│${R} ${YELLOW}↑ ↓${R} ${DIM}│${R} Move cursor between items ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}Enter${R} ${DIM}│${R} Toggle todo ${DIM}[ ] → [✓] → [ ]${R} ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}t${R} ${DIM}│${R} Add new todo ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}n${R} ${DIM}│${R} Add new text line ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}d${R} ${DIM}│${R} Delete item at cursor ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}s${R} ${DIM}│${R} Save changes ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}q${R} ${DIM}│${R} Quit ${DIM}(auto-saves if changed)${R} ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}Esc${R} ${DIM}│${R} Cancel input ${DIM}│${R}\n ${DIM}└──────────┴────────────────────────────────────────────┘${R}\n${heading(\"CAPTURE\")}\n${row(\"vertex capture \\\"text\\\"\", \"Quick capture to Inbox note\")}\n${heading(\"SEARCH & ORGANIZE\")}\n${row(\"vertex search <query>\", \"Search notes\")}\n${row(\"vertex tags\", \"List all tags\")}\n\n ${DIM}Query syntax: ${PURPLE}keyword${R}${DIM} · ${PURPLE}#tag${R}${DIM} · ${PURPLE}type:todo${R}${DIM} · ${PURPLE}status:open${R}${DIM} · ${PURPLE}status:done${R}\n${heading(\"EXPORT\")}\n${row(\"vertex export <title>\", \"Export as markdown to stdout\")}\n${row(\"vertex export <title> --json\", \"Export as JSON\")}\n${row(\"vertex export <title> -o file\", \"Export to file\")}\n${heading(\"TRASH\")}\n${row(\"vertex delete <title>\", \"Soft delete → trash\")}\n${row(\"vertex restore <title>\", \"Restore from trash\")}\n${row(\"vertex trash\", \"List trashed notes\")}\n${row(\"vertex trash:empty\", \"Permanently delete all trash\")}\n${heading(\"INFO\")}\n${row(\"vertex status\", \"Storage usage, note count, version\")}\n${row(\"vertex hello\", \"Verify CLI is working\")}\n${row(\"vertex help\", \"Show this help\")}\n${heading(\"EDITOR SYNTAX\")}\n${sub(\"for use with: vertex edit <title>\")}\n\n ${DIM}┌──────────────────────┬──────────────────────────────────┐${R}\n ${DIM}│${R} ${YELLOW}# ## ###${R} ${DIM}│${R} Headings ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}**bold** *italic*${R} ${DIM}│${R} Formatting ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}\\`code\\` ~~strike~~${R} ${DIM}│${R} Inline code & strikethrough ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}[[Link]] #tag${R} ${DIM}│${R} Wiki links & tags ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}- item${R} ${YELLOW}1. item${R} ${DIM}│${R} Bullet & numbered lists ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}- [x]${R} ${YELLOW}- [ ]${R} ${DIM}│${R} Done & open tasks ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}> quote${R} ${YELLOW}---${R} ${DIM}│${R} Blockquote & divider ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}\\`\\`\\`lang ... \\`\\`\\`${R} ${DIM}│${R} Code block ${DIM}│${R}\n ${DIM}│${R} ${YELLOW}$$ ... $$${R} ${DIM}│${R} Math block (LaTeX) ${DIM}│${R}\n ${DIM}└──────────────────────┴──────────────────────────────────┘${R}\n ${DIM}Web app only: mermaid, callouts, query blocks, file uploads${R}\n${heading(\"TIPS\")}\n ${DIM}•${R} Title args use partial matching ${DIM}(\"proj\" → \"Project Plan\")${R}\n ${DIM}•${R} Set ${YELLOW}EDITOR=nano${R} or ${YELLOW}EDITOR=\"code --wait\"${R} for preferred editor\n ${DIM}•${R} Session stored in ${DIM}~/.vertex/config.json${R}\n ${DIM}•${R} New users get 50 MB storage, upgradeable per account\n ${DIM}•${R} ${GREEN}vertex today${R} is the fastest way to manage daily todos\n${heading(\"EXAMPLES\")}\n ${DIM}$${R} vertex today\n ${DIM}$${R} vertex capture \"buy groceries\"\n ${DIM}$${R} vertex search \"#work type:todo status:open\"\n ${DIM}$${R} vertex export \"Meeting Notes\" -o meeting.md\n ${DIM}$${R} EDITOR=nano vertex edit \"Ideas\"\n`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClient,
|
|
3
|
+
getUserId
|
|
4
|
+
} from "../chunk-DDFOKGIX.js";
|
|
5
|
+
import "../chunk-PBF5EE4Y.js";
|
|
6
|
+
import {
|
|
7
|
+
getBlocksForNote,
|
|
8
|
+
listNotes,
|
|
9
|
+
saveNoteContent
|
|
10
|
+
} from "../chunk-4QLCD6TZ.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/interactive.ts
|
|
13
|
+
import { Command, Args } from "@oclif/core";
|
|
14
|
+
function blocksToItems(blocks) {
|
|
15
|
+
const items = [];
|
|
16
|
+
for (const b of blocks) {
|
|
17
|
+
const meta = b.metadata;
|
|
18
|
+
const tiptap = meta.tiptap;
|
|
19
|
+
if (!tiptap) {
|
|
20
|
+
if (b.content.trim()) items.push({ kind: "text", text: b.content, checked: false });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const type = tiptap.type;
|
|
24
|
+
if (type === "taskList") {
|
|
25
|
+
const children = tiptap.content ?? [];
|
|
26
|
+
for (const child of children) {
|
|
27
|
+
const attrs = child.attrs ?? {};
|
|
28
|
+
const checked = attrs.checked === true;
|
|
29
|
+
const text = extractText(child);
|
|
30
|
+
items.push({ kind: "todo", text, checked });
|
|
31
|
+
}
|
|
32
|
+
} else if (type === "paragraph" || type === "heading") {
|
|
33
|
+
const text = extractText(tiptap);
|
|
34
|
+
if (text.trim()) items.push({ kind: "text", text, checked: false });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return items;
|
|
38
|
+
}
|
|
39
|
+
function extractText(node) {
|
|
40
|
+
if (typeof node.text === "string") return node.text;
|
|
41
|
+
const content = node.content;
|
|
42
|
+
if (!content) return "";
|
|
43
|
+
return content.map(extractText).join("");
|
|
44
|
+
}
|
|
45
|
+
function itemsToTiptap(items) {
|
|
46
|
+
const content = [];
|
|
47
|
+
let i = 0;
|
|
48
|
+
while (i < items.length) {
|
|
49
|
+
const item = items[i];
|
|
50
|
+
if (item.kind === "todo") {
|
|
51
|
+
const taskItems = [];
|
|
52
|
+
while (i < items.length && items[i].kind === "todo") {
|
|
53
|
+
taskItems.push({
|
|
54
|
+
type: "taskItem",
|
|
55
|
+
attrs: { checked: items[i].checked },
|
|
56
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: items[i].text }] }]
|
|
57
|
+
});
|
|
58
|
+
i++;
|
|
59
|
+
}
|
|
60
|
+
content.push({ type: "taskList", content: taskItems });
|
|
61
|
+
} else {
|
|
62
|
+
content.push({
|
|
63
|
+
type: "paragraph",
|
|
64
|
+
content: [{ type: "text", text: item.text }]
|
|
65
|
+
});
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (content.length === 0) {
|
|
70
|
+
content.push({ type: "paragraph" });
|
|
71
|
+
}
|
|
72
|
+
return { type: "doc", content };
|
|
73
|
+
}
|
|
74
|
+
function render(items, cursor, mode, inputBuffer, noteTitle) {
|
|
75
|
+
process.stdout.write("\x1Bc");
|
|
76
|
+
process.stdout.write(`\x1B[1m ${noteTitle}\x1B[0m
|
|
77
|
+
`);
|
|
78
|
+
process.stdout.write(`\x1B[90m \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m
|
|
79
|
+
|
|
80
|
+
`);
|
|
81
|
+
for (let i = 0; i < items.length; i++) {
|
|
82
|
+
const item = items[i];
|
|
83
|
+
const selected = i === cursor;
|
|
84
|
+
const prefix = selected ? "\x1B[36m \u25B8 \x1B[0m" : " ";
|
|
85
|
+
if (item.kind === "todo") {
|
|
86
|
+
const box = item.checked ? "\x1B[32m[\u2713]\x1B[0m" : "\x1B[90m[ ]\x1B[0m";
|
|
87
|
+
const text = item.checked ? `\x1B[90m\x1B[9m${item.text}\x1B[0m` : item.text;
|
|
88
|
+
process.stdout.write(`${prefix}${box} ${text}
|
|
89
|
+
`);
|
|
90
|
+
} else {
|
|
91
|
+
process.stdout.write(`${prefix}${item.text}
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (items.length === 0) {
|
|
96
|
+
process.stdout.write(" \x1B[90m(empty)\x1B[0m\n");
|
|
97
|
+
}
|
|
98
|
+
process.stdout.write(`
|
|
99
|
+
\x1B[90m \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m
|
|
100
|
+
`);
|
|
101
|
+
if (mode === "input-todo") {
|
|
102
|
+
process.stdout.write(` \x1B[33mNew todo:\x1B[0m ${inputBuffer}\x1B[7m \x1B[0m
|
|
103
|
+
`);
|
|
104
|
+
} else if (mode === "input-text") {
|
|
105
|
+
process.stdout.write(` \x1B[33mNew text:\x1B[0m ${inputBuffer}\x1B[7m \x1B[0m
|
|
106
|
+
`);
|
|
107
|
+
} else {
|
|
108
|
+
process.stdout.write(" \x1B[90m\u2191\u2193 move Enter toggle t new todo n new text d delete s save q quit\x1B[0m\n");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
var Interactive = class _Interactive extends Command {
|
|
112
|
+
static description = "Interactive note editor with todo toggling";
|
|
113
|
+
static args = {
|
|
114
|
+
title: Args.string({ description: "Note title (partial match)", required: true })
|
|
115
|
+
};
|
|
116
|
+
async run() {
|
|
117
|
+
const { args } = await this.parse(_Interactive);
|
|
118
|
+
const client = await getClient();
|
|
119
|
+
const userId = await getUserId();
|
|
120
|
+
const notes = await listNotes(client, { user_id: userId });
|
|
121
|
+
const query = args.title.toLowerCase();
|
|
122
|
+
const match = notes.find((n) => !n.deleted_at && n.title.toLowerCase().includes(query));
|
|
123
|
+
if (!match) {
|
|
124
|
+
this.error(`No note matching "${args.title}"`);
|
|
125
|
+
}
|
|
126
|
+
const blocks = await getBlocksForNote(client, match.id);
|
|
127
|
+
const items = blocksToItems(blocks);
|
|
128
|
+
let cursor = 0;
|
|
129
|
+
let dirty = false;
|
|
130
|
+
let mode = "normal";
|
|
131
|
+
let inputBuffer = "";
|
|
132
|
+
process.stdin.setRawMode(true);
|
|
133
|
+
process.stdin.resume();
|
|
134
|
+
process.stdin.setEncoding("utf8");
|
|
135
|
+
render(items, cursor, mode, inputBuffer, match.title);
|
|
136
|
+
const cleanup = () => {
|
|
137
|
+
process.stdin.setRawMode(false);
|
|
138
|
+
process.stdout.write("\x1Bc");
|
|
139
|
+
};
|
|
140
|
+
const save = async () => {
|
|
141
|
+
const tiptap = itemsToTiptap(items);
|
|
142
|
+
await saveNoteContent(client, match.id, userId, tiptap);
|
|
143
|
+
dirty = false;
|
|
144
|
+
};
|
|
145
|
+
process.stdin.on("data", async (key) => {
|
|
146
|
+
if (mode === "input-todo" || mode === "input-text") {
|
|
147
|
+
if (key === "\r" || key === "\n") {
|
|
148
|
+
if (inputBuffer.trim()) {
|
|
149
|
+
const newItem = mode === "input-todo" ? { kind: "todo", text: inputBuffer.trim(), checked: false } : { kind: "text", text: inputBuffer.trim(), checked: false };
|
|
150
|
+
items.splice(cursor + 1, 0, newItem);
|
|
151
|
+
cursor = Math.min(cursor + 1, items.length - 1);
|
|
152
|
+
dirty = true;
|
|
153
|
+
}
|
|
154
|
+
mode = "normal";
|
|
155
|
+
inputBuffer = "";
|
|
156
|
+
} else if (key === "\x1B") {
|
|
157
|
+
mode = "normal";
|
|
158
|
+
inputBuffer = "";
|
|
159
|
+
} else if (key === "\x7F") {
|
|
160
|
+
inputBuffer = inputBuffer.slice(0, -1);
|
|
161
|
+
} else if (key >= " ") {
|
|
162
|
+
inputBuffer += key;
|
|
163
|
+
}
|
|
164
|
+
render(items, cursor, mode, inputBuffer, match.title);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (key === "\x1B[A") {
|
|
168
|
+
cursor = Math.max(0, cursor - 1);
|
|
169
|
+
} else if (key === "\x1B[B") {
|
|
170
|
+
cursor = Math.min(items.length - 1, cursor + 1);
|
|
171
|
+
} else if (key === "\r" || key === "\n") {
|
|
172
|
+
if (items[cursor]?.kind === "todo") {
|
|
173
|
+
items[cursor].checked = !items[cursor].checked;
|
|
174
|
+
dirty = true;
|
|
175
|
+
}
|
|
176
|
+
} else if (key === "t") {
|
|
177
|
+
mode = "input-todo";
|
|
178
|
+
inputBuffer = "";
|
|
179
|
+
} else if (key === "n") {
|
|
180
|
+
mode = "input-text";
|
|
181
|
+
inputBuffer = "";
|
|
182
|
+
} else if (key === "d") {
|
|
183
|
+
if (items.length > 0) {
|
|
184
|
+
items.splice(cursor, 1);
|
|
185
|
+
cursor = Math.min(cursor, items.length - 1);
|
|
186
|
+
dirty = true;
|
|
187
|
+
}
|
|
188
|
+
} else if (key === "s") {
|
|
189
|
+
await save();
|
|
190
|
+
render(items, cursor, mode, inputBuffer, match.title);
|
|
191
|
+
process.stdout.write(" \x1B[32mSaved!\x1B[0m\n");
|
|
192
|
+
return;
|
|
193
|
+
} else if (key === "q" || key === "") {
|
|
194
|
+
if (dirty) {
|
|
195
|
+
await save();
|
|
196
|
+
cleanup();
|
|
197
|
+
this.log(`Saved: ${match.title}`);
|
|
198
|
+
} else {
|
|
199
|
+
cleanup();
|
|
200
|
+
this.log("No changes.");
|
|
201
|
+
}
|
|
202
|
+
process.exit(0);
|
|
203
|
+
}
|
|
204
|
+
render(items, cursor, mode, inputBuffer, match.title);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
export {
|
|
209
|
+
Interactive as default
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/interactive.ts"],"sourcesContent":["import { Command, Args } from \"@oclif/core\";\nimport { listNotes, getBlocksForNote, saveNoteContent, type Block } from \"@vertex/core\";\nimport { getClient, getUserId } from \"../lib/client.js\";\n\ninterface TuiItem {\n kind: \"text\" | \"todo\";\n text: string;\n checked: boolean;\n}\n\nfunction blocksToItems(blocks: Block[]): TuiItem[] {\n const items: TuiItem[] = [];\n for (const b of blocks) {\n const meta = b.metadata as Record<string, unknown>;\n const tiptap = meta.tiptap as Record<string, unknown> | undefined;\n if (!tiptap) {\n if (b.content.trim()) items.push({ kind: \"text\", text: b.content, checked: false });\n continue;\n }\n\n const type = tiptap.type as string;\n if (type === \"taskList\") {\n const children = (tiptap.content ?? []) as Array<Record<string, unknown>>;\n for (const child of children) {\n const attrs = (child.attrs ?? {}) as Record<string, unknown>;\n const checked = attrs.checked === true;\n const text = extractText(child);\n items.push({ kind: \"todo\", text, checked });\n }\n } else if (type === \"paragraph\" || type === \"heading\") {\n const text = extractText(tiptap);\n if (text.trim()) items.push({ kind: \"text\", text, checked: false });\n }\n }\n return items;\n}\n\nfunction extractText(node: Record<string, unknown>): string {\n if (typeof node.text === \"string\") return node.text;\n const content = node.content as Array<Record<string, unknown>> | undefined;\n if (!content) return \"\";\n return content.map(extractText).join(\"\");\n}\n\nfunction itemsToTiptap(items: TuiItem[]): Record<string, unknown> {\n const content: Array<Record<string, unknown>> = [];\n\n let i = 0;\n while (i < items.length) {\n const item = items[i];\n if (item.kind === \"todo\") {\n const taskItems: Array<Record<string, unknown>> = [];\n while (i < items.length && items[i].kind === \"todo\") {\n taskItems.push({\n type: \"taskItem\",\n attrs: { checked: items[i].checked },\n content: [{ type: \"paragraph\", content: [{ type: \"text\", text: items[i].text }] }],\n });\n i++;\n }\n content.push({ type: \"taskList\", content: taskItems });\n } else {\n content.push({\n type: \"paragraph\",\n content: [{ type: \"text\", text: item.text }],\n });\n i++;\n }\n }\n\n if (content.length === 0) {\n content.push({ type: \"paragraph\" });\n }\n\n return { type: \"doc\", content };\n}\n\nfunction render(items: TuiItem[], cursor: number, mode: string, inputBuffer: string, noteTitle: string): void {\n process.stdout.write(\"\\x1bc\");\n\n process.stdout.write(`\\x1b[1m ${noteTitle}\\x1b[0m\\n`);\n process.stdout.write(`\\x1b[90m ─────────────────────────────────────\\x1b[0m\\n\\n`);\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const selected = i === cursor;\n const prefix = selected ? \"\\x1b[36m ▸ \\x1b[0m\" : \" \";\n\n if (item.kind === \"todo\") {\n const box = item.checked ? \"\\x1b[32m[✓]\\x1b[0m\" : \"\\x1b[90m[ ]\\x1b[0m\";\n const text = item.checked ? `\\x1b[90m\\x1b[9m${item.text}\\x1b[0m` : item.text;\n process.stdout.write(`${prefix}${box} ${text}\\n`);\n } else {\n process.stdout.write(`${prefix}${item.text}\\n`);\n }\n }\n\n if (items.length === 0) {\n process.stdout.write(\" \\x1b[90m(empty)\\x1b[0m\\n\");\n }\n\n process.stdout.write(`\\n\\x1b[90m ─────────────────────────────────────\\x1b[0m\\n`);\n\n if (mode === \"input-todo\") {\n process.stdout.write(` \\x1b[33mNew todo:\\x1b[0m ${inputBuffer}\\x1b[7m \\x1b[0m\\n`);\n } else if (mode === \"input-text\") {\n process.stdout.write(` \\x1b[33mNew text:\\x1b[0m ${inputBuffer}\\x1b[7m \\x1b[0m\\n`);\n } else {\n process.stdout.write(\" \\x1b[90m↑↓ move Enter toggle t new todo n new text d delete s save q quit\\x1b[0m\\n\");\n }\n}\n\nexport default class Interactive extends Command {\n static override description = \"Interactive note editor with todo toggling\";\n\n static override args = {\n title: Args.string({ description: \"Note title (partial match)\", required: true }),\n };\n\n async run(): Promise<void> {\n const { args } = await this.parse(Interactive);\n const client = await getClient();\n const userId = await getUserId();\n const notes = await listNotes(client, { user_id: userId });\n const query = args.title.toLowerCase();\n const match = notes.find((n) => !n.deleted_at && n.title.toLowerCase().includes(query));\n\n if (!match) {\n this.error(`No note matching \"${args.title}\"`);\n }\n\n const blocks = await getBlocksForNote(client, match.id);\n const items = blocksToItems(blocks);\n let cursor = 0;\n let dirty = false;\n let mode = \"normal\";\n let inputBuffer = \"\";\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n\n render(items, cursor, mode, inputBuffer, match.title);\n\n const cleanup = () => {\n process.stdin.setRawMode(false);\n process.stdout.write(\"\\x1bc\");\n };\n\n const save = async () => {\n const tiptap = itemsToTiptap(items);\n await saveNoteContent(client, match.id, userId, tiptap);\n dirty = false;\n };\n\n process.stdin.on(\"data\", async (key: string) => {\n if (mode === \"input-todo\" || mode === \"input-text\") {\n if (key === \"\\r\" || key === \"\\n\") {\n if (inputBuffer.trim()) {\n const newItem: TuiItem = mode === \"input-todo\"\n ? { kind: \"todo\", text: inputBuffer.trim(), checked: false }\n : { kind: \"text\", text: inputBuffer.trim(), checked: false };\n items.splice(cursor + 1, 0, newItem);\n cursor = Math.min(cursor + 1, items.length - 1);\n dirty = true;\n }\n mode = \"normal\";\n inputBuffer = \"\";\n } else if (key === \"\\x1b\") {\n mode = \"normal\";\n inputBuffer = \"\";\n } else if (key === \"\\x7f\") {\n inputBuffer = inputBuffer.slice(0, -1);\n } else if (key >= \" \") {\n inputBuffer += key;\n }\n render(items, cursor, mode, inputBuffer, match.title);\n return;\n }\n\n if (key === \"\\x1b[A\") {\n cursor = Math.max(0, cursor - 1);\n } else if (key === \"\\x1b[B\") {\n cursor = Math.min(items.length - 1, cursor + 1);\n } else if (key === \"\\r\" || key === \"\\n\") {\n if (items[cursor]?.kind === \"todo\") {\n items[cursor].checked = !items[cursor].checked;\n dirty = true;\n }\n } else if (key === \"t\") {\n mode = \"input-todo\";\n inputBuffer = \"\";\n } else if (key === \"n\") {\n mode = \"input-text\";\n inputBuffer = \"\";\n } else if (key === \"d\") {\n if (items.length > 0) {\n items.splice(cursor, 1);\n cursor = Math.min(cursor, items.length - 1);\n dirty = true;\n }\n } else if (key === \"s\") {\n await save();\n render(items, cursor, mode, inputBuffer, match.title);\n process.stdout.write(\" \\x1b[32mSaved!\\x1b[0m\\n\");\n return;\n } else if (key === \"q\" || key === \"\\x03\") {\n if (dirty) {\n await save();\n cleanup();\n this.log(`Saved: ${match.title}`);\n } else {\n cleanup();\n this.log(\"No changes.\");\n }\n process.exit(0);\n }\n\n render(items, cursor, mode, inputBuffer, match.title);\n });\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadConfig,
|
|
3
|
+
saveConfig
|
|
4
|
+
} from "../chunk-PBF5EE4Y.js";
|
|
5
|
+
import {
|
|
6
|
+
createSupabaseClient
|
|
7
|
+
} from "../chunk-4QLCD6TZ.js";
|
|
8
|
+
|
|
9
|
+
// src/commands/login.ts
|
|
10
|
+
import { Command } from "@oclif/core";
|
|
11
|
+
import { createServer } from "http";
|
|
12
|
+
import { createInterface } from "readline";
|
|
13
|
+
var Login = class extends Command {
|
|
14
|
+
static description = "Log in to Vertex";
|
|
15
|
+
async run() {
|
|
16
|
+
const config = loadConfig();
|
|
17
|
+
this.log("\n How would you like to log in?\n");
|
|
18
|
+
this.log(" 1) GitHub");
|
|
19
|
+
this.log(" 2) Google");
|
|
20
|
+
this.log(" 3) Email & Password\n");
|
|
21
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
22
|
+
const choice = await new Promise((resolve) => {
|
|
23
|
+
rl.question(" Choice (1/2/3): ", (ans) => {
|
|
24
|
+
rl.close();
|
|
25
|
+
resolve(ans.trim());
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
if (choice === "3") {
|
|
29
|
+
await this.emailLogin(config);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const provider = choice === "2" ? "google" : "github";
|
|
33
|
+
await this.oauthLogin(config, provider);
|
|
34
|
+
}
|
|
35
|
+
async emailLogin(config) {
|
|
36
|
+
const rl1 = createInterface({ input: process.stdin, output: process.stdout });
|
|
37
|
+
const email = await new Promise((resolve) => {
|
|
38
|
+
rl1.question(" Email: ", (ans) => {
|
|
39
|
+
rl1.close();
|
|
40
|
+
resolve(ans.trim());
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
const rl2 = createInterface({ input: process.stdin, output: process.stdout });
|
|
44
|
+
const password = await new Promise((resolve) => {
|
|
45
|
+
rl2.question(" Password: ", (ans) => {
|
|
46
|
+
rl2.close();
|
|
47
|
+
resolve(ans.trim());
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
const rl3 = createInterface({ input: process.stdin, output: process.stdout });
|
|
51
|
+
const isSignup = await new Promise((resolve) => {
|
|
52
|
+
rl3.question(" Sign in or sign up? (in/up): ", (ans) => {
|
|
53
|
+
rl3.close();
|
|
54
|
+
resolve(ans.trim().toLowerCase());
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
58
|
+
if (isSignup === "up") {
|
|
59
|
+
const { error: error2 } = await client.auth.signUp({ email, password });
|
|
60
|
+
if (error2) {
|
|
61
|
+
this.error(`Sign up failed: ${error2.message}`);
|
|
62
|
+
}
|
|
63
|
+
this.log(" Check your email to confirm your account, then run: vertex login");
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
const { data, error } = await client.auth.signInWithPassword({ email, password });
|
|
67
|
+
if (error) {
|
|
68
|
+
this.error(`Login failed: ${error.message}`);
|
|
69
|
+
}
|
|
70
|
+
if (data.session) {
|
|
71
|
+
saveConfig({
|
|
72
|
+
accessToken: data.session.access_token,
|
|
73
|
+
refreshToken: data.session.refresh_token,
|
|
74
|
+
userId: data.session.user.id,
|
|
75
|
+
email: data.session.user.email
|
|
76
|
+
});
|
|
77
|
+
this.log(` Logged in as ${data.session.user.email}`);
|
|
78
|
+
}
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
async oauthLogin(config, provider) {
|
|
82
|
+
const port = 54321;
|
|
83
|
+
const redirectUrl = `http://localhost:${port}/callback`;
|
|
84
|
+
this.log(` Opening browser for ${provider} login...`);
|
|
85
|
+
const tokenPromise = new Promise((resolve, reject) => {
|
|
86
|
+
const server = createServer((req, res) => {
|
|
87
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
88
|
+
if (url.pathname === "/callback") {
|
|
89
|
+
const accessToken = url.searchParams.get("access_token");
|
|
90
|
+
const refreshToken = url.searchParams.get("refresh_token");
|
|
91
|
+
if (accessToken && refreshToken) {
|
|
92
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
93
|
+
res.end("<h2 style='font-family:sans-serif;text-align:center;margin-top:40vh'>Logged in! You can close this tab.</h2>");
|
|
94
|
+
server.close();
|
|
95
|
+
resolve({ access_token: accessToken, refresh_token: refreshToken });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
99
|
+
res.end(`
|
|
100
|
+
<html><body>
|
|
101
|
+
<script>
|
|
102
|
+
const hash = window.location.hash.substring(1);
|
|
103
|
+
const params = new URLSearchParams(hash);
|
|
104
|
+
const at = params.get("access_token");
|
|
105
|
+
const rt = params.get("refresh_token");
|
|
106
|
+
if (at && rt) {
|
|
107
|
+
window.location.href = "/callback?access_token=" + encodeURIComponent(at) + "&refresh_token=" + encodeURIComponent(rt);
|
|
108
|
+
} else {
|
|
109
|
+
document.body.innerHTML = "<h2 style='font-family:sans-serif;text-align:center;margin-top:40vh'>Login failed. Try again.</h2>";
|
|
110
|
+
}
|
|
111
|
+
</script>
|
|
112
|
+
<h2 style="font-family:sans-serif;text-align:center;margin-top:40vh">Completing login...</h2>
|
|
113
|
+
</body></html>
|
|
114
|
+
`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
res.writeHead(404);
|
|
118
|
+
res.end("Not found");
|
|
119
|
+
});
|
|
120
|
+
server.listen(port, () => {
|
|
121
|
+
const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
122
|
+
client.auth.signInWithOAuth({
|
|
123
|
+
provider,
|
|
124
|
+
options: { redirectTo: redirectUrl, skipBrowserRedirect: false }
|
|
125
|
+
}).then(({ data }) => {
|
|
126
|
+
if (data.url) {
|
|
127
|
+
import("child_process").then(({ exec }) => {
|
|
128
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
129
|
+
exec(`${cmd} "${data.url}"`);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
server.close();
|
|
136
|
+
reject(new Error("Login timed out after 120 seconds"));
|
|
137
|
+
}, 12e4);
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
const tokens = await tokenPromise;
|
|
141
|
+
const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
142
|
+
const { data } = await client.auth.setSession({
|
|
143
|
+
access_token: tokens.access_token,
|
|
144
|
+
refresh_token: tokens.refresh_token
|
|
145
|
+
});
|
|
146
|
+
saveConfig({
|
|
147
|
+
accessToken: tokens.access_token,
|
|
148
|
+
refreshToken: tokens.refresh_token,
|
|
149
|
+
userId: data.session?.user.id,
|
|
150
|
+
email: data.session?.user.email
|
|
151
|
+
});
|
|
152
|
+
this.log(` Logged in as ${data.session?.user.email ?? "unknown"}`);
|
|
153
|
+
process.exit(0);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
this.error(`Login failed: ${err instanceof Error ? err.message : err}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
export {
|
|
160
|
+
Login as default
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/login.ts"],"sourcesContent":["import { Command } from \"@oclif/core\";\nimport { createServer } from \"node:http\";\nimport { createInterface } from \"node:readline\";\nimport { createSupabaseClient } from \"@vertex/core\";\nimport { loadConfig, saveConfig } from \"../lib/config.js\";\n\nexport default class Login extends Command {\n static override description = \"Log in to Vertex\";\n\n async run(): Promise<void> {\n const config = loadConfig();\n\n this.log(\"\\n How would you like to log in?\\n\");\n this.log(\" 1) GitHub\");\n this.log(\" 2) Google\");\n this.log(\" 3) Email & Password\\n\");\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const choice = await new Promise<string>((resolve) => {\n rl.question(\" Choice (1/2/3): \", (ans) => { rl.close(); resolve(ans.trim()); });\n });\n\n if (choice === \"3\") {\n await this.emailLogin(config);\n return;\n }\n\n const provider = choice === \"2\" ? \"google\" : \"github\";\n await this.oauthLogin(config, provider);\n }\n\n private async emailLogin(config: ReturnType<typeof loadConfig>): Promise<void> {\n const rl1 = createInterface({ input: process.stdin, output: process.stdout });\n const email = await new Promise<string>((resolve) => {\n rl1.question(\" Email: \", (ans) => { rl1.close(); resolve(ans.trim()); });\n });\n\n const rl2 = createInterface({ input: process.stdin, output: process.stdout });\n const password = await new Promise<string>((resolve) => {\n rl2.question(\" Password: \", (ans) => { rl2.close(); resolve(ans.trim()); });\n });\n\n const rl3 = createInterface({ input: process.stdin, output: process.stdout });\n const isSignup = await new Promise<string>((resolve) => {\n rl3.question(\" Sign in or sign up? (in/up): \", (ans) => { rl3.close(); resolve(ans.trim().toLowerCase()); });\n });\n\n const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);\n\n if (isSignup === \"up\") {\n const { error } = await client.auth.signUp({ email, password });\n if (error) {\n this.error(`Sign up failed: ${error.message}`);\n }\n this.log(\" Check your email to confirm your account, then run: vertex login\");\n process.exit(0);\n }\n\n const { data, error } = await client.auth.signInWithPassword({ email, password });\n if (error) {\n this.error(`Login failed: ${error.message}`);\n }\n\n if (data.session) {\n saveConfig({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n userId: data.session.user.id,\n email: data.session.user.email,\n });\n this.log(` Logged in as ${data.session.user.email}`);\n }\n process.exit(0);\n }\n\n private async oauthLogin(config: ReturnType<typeof loadConfig>, provider: \"github\" | \"google\"): Promise<void> {\n const port = 54321;\n const redirectUrl = `http://localhost:${port}/callback`;\n\n this.log(` Opening browser for ${provider} login...`);\n\n const tokenPromise = new Promise<{ access_token: string; refresh_token: string }>((resolve, reject) => {\n const server = createServer((req, res) => {\n const url = new URL(req.url ?? \"/\", `http://localhost:${port}`);\n\n if (url.pathname === \"/callback\") {\n const accessToken = url.searchParams.get(\"access_token\");\n const refreshToken = url.searchParams.get(\"refresh_token\");\n\n if (accessToken && refreshToken) {\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\"<h2 style='font-family:sans-serif;text-align:center;margin-top:40vh'>Logged in! You can close this tab.</h2>\");\n server.close();\n resolve({ access_token: accessToken, refresh_token: refreshToken });\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(`\n <html><body>\n <script>\n const hash = window.location.hash.substring(1);\n const params = new URLSearchParams(hash);\n const at = params.get(\"access_token\");\n const rt = params.get(\"refresh_token\");\n if (at && rt) {\n window.location.href = \"/callback?access_token=\" + encodeURIComponent(at) + \"&refresh_token=\" + encodeURIComponent(rt);\n } else {\n document.body.innerHTML = \"<h2 style='font-family:sans-serif;text-align:center;margin-top:40vh'>Login failed. Try again.</h2>\";\n }\n </script>\n <h2 style=\"font-family:sans-serif;text-align:center;margin-top:40vh\">Completing login...</h2>\n </body></html>\n `);\n return;\n }\n\n res.writeHead(404);\n res.end(\"Not found\");\n });\n\n server.listen(port, () => {\n const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);\n client.auth.signInWithOAuth({\n provider,\n options: { redirectTo: redirectUrl, skipBrowserRedirect: false },\n }).then(({ data }) => {\n if (data.url) {\n import(\"node:child_process\").then(({ exec }) => {\n const cmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n exec(`${cmd} \"${data.url}\"`);\n });\n }\n });\n });\n\n setTimeout(() => {\n server.close();\n reject(new Error(\"Login timed out after 120 seconds\"));\n }, 120_000);\n });\n\n try {\n const tokens = await tokenPromise;\n\n const client = createSupabaseClient(config.supabaseUrl, config.supabaseAnonKey);\n const { data } = await client.auth.setSession({\n access_token: tokens.access_token,\n refresh_token: tokens.refresh_token,\n });\n\n saveConfig({\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n userId: data.session?.user.id,\n email: data.session?.user.email,\n });\n\n this.log(` Logged in as ${data.session?.user.email ?? \"unknown\"}`);\n process.exit(0);\n } catch (err) {\n this.error(`Login failed: ${err instanceof Error ? err.message : err}`);\n }\n }\n}\n"],"mappings":"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","names":["error"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearConfig
|
|
3
|
+
} from "../chunk-PBF5EE4Y.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/logout.ts
|
|
6
|
+
import { Command } from "@oclif/core";
|
|
7
|
+
var Logout = class extends Command {
|
|
8
|
+
static description = "Log out of Vertex";
|
|
9
|
+
async run() {
|
|
10
|
+
clearConfig();
|
|
11
|
+
this.log("Logged out.");
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
Logout as default
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/logout.ts"],"sourcesContent":["import { Command } from \"@oclif/core\";\nimport { clearConfig } from \"../lib/config.js\";\n\nexport default class Logout extends Command {\n static override description = \"Log out of Vertex\";\n\n async run(): Promise<void> {\n clearConfig();\n this.log(\"Logged out.\");\n }\n}\n"],"mappings":";;;;;AAAA,SAAS,eAAe;AAGxB,IAAqB,SAArB,cAAoC,QAAQ;AAAA,EAC1C,OAAgB,cAAc;AAAA,EAE9B,MAAM,MAAqB;AACzB,gBAAY;AACZ,SAAK,IAAI,aAAa;AAAA,EACxB;AACF;","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClient,
|
|
3
|
+
getUserId
|
|
4
|
+
} from "../chunk-DDFOKGIX.js";
|
|
5
|
+
import "../chunk-PBF5EE4Y.js";
|
|
6
|
+
import {
|
|
7
|
+
createNote
|
|
8
|
+
} from "../chunk-4QLCD6TZ.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/new.ts
|
|
11
|
+
import { Command, Args } from "@oclif/core";
|
|
12
|
+
var New = class _New extends Command {
|
|
13
|
+
static description = "Create a new note";
|
|
14
|
+
static args = {
|
|
15
|
+
title: Args.string({ description: "Note title", default: "Untitled" })
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { args } = await this.parse(_New);
|
|
19
|
+
const client = await getClient();
|
|
20
|
+
const userId = await getUserId();
|
|
21
|
+
const note = await createNote(client, { user_id: userId, title: args.title });
|
|
22
|
+
this.log(`Created: ${note.title} (${note.id})`);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export {
|
|
26
|
+
New as default
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=new.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/new.ts"],"sourcesContent":["import { Command, Args } from \"@oclif/core\";\nimport { createNote } from \"@vertex/core\";\nimport { getClient, getUserId } from \"../lib/client.js\";\n\nexport default class New extends Command {\n static override description = \"Create a new note\";\n\n static override args = {\n title: Args.string({ description: \"Note title\", default: \"Untitled\" }),\n };\n\n async run(): Promise<void> {\n const { args } = await this.parse(New);\n const client = await getClient();\n const userId = await getUserId();\n const note = await createNote(client, { user_id: userId, title: args.title });\n this.log(`Created: ${note.title} (${note.id})`);\n }\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,SAAS,YAAY;AAI9B,IAAqB,MAArB,MAAqB,aAAY,QAAQ;AAAA,EACvC,OAAgB,cAAc;AAAA,EAE9B,OAAgB,OAAO;AAAA,IACrB,OAAO,KAAK,OAAO,EAAE,aAAa,cAAc,SAAS,WAAW,CAAC;AAAA,EACvE;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,KAAK,IAAI,MAAM,KAAK,MAAM,IAAG;AACrC,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,OAAO,MAAM,WAAW,QAAQ,EAAE,SAAS,QAAQ,OAAO,KAAK,MAAM,CAAC;AAC5E,SAAK,IAAI,YAAY,KAAK,KAAK,KAAK,KAAK,EAAE,GAAG;AAAA,EAChD;AACF;","names":[]}
|