@alpacali/papyrus-cli 1.0.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/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/api.d.ts +67 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +247 -0
- package/dist/api.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +391 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cards.d.ts +52 -0
- package/dist/commands/cards.d.ts.map +1 -0
- package/dist/commands/cards.js +189 -0
- package/dist/commands/cards.js.map +1 -0
- package/dist/commands/data.d.ts +34 -0
- package/dist/commands/data.d.ts.map +1 -0
- package/dist/commands/data.js +230 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/review.d.ts +16 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +132 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/serve.d.ts +24 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +161 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +94 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +52 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +141 -0
- package/dist/utils.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Data Management Commands
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Backup command
|
|
6
|
+
*/
|
|
7
|
+
export declare function backupCommand(options: {
|
|
8
|
+
output?: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Restore command
|
|
12
|
+
*/
|
|
13
|
+
export declare function restoreCommand(backupPath: string, force?: boolean): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* List backups command
|
|
16
|
+
*/
|
|
17
|
+
export declare function listBackupsCommand(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Export command
|
|
20
|
+
*/
|
|
21
|
+
export declare function exportCommand(output: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Import command
|
|
24
|
+
*/
|
|
25
|
+
export declare function importCommand(filePath: string, force?: boolean): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Stats command
|
|
28
|
+
*/
|
|
29
|
+
export declare function statsCommand(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Clean old backups command
|
|
32
|
+
*/
|
|
33
|
+
export declare function cleanBackupsCommand(keep?: number): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/commands/data.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0BH;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BrF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkCxD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAejE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwClF;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBlD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAoClE"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Data Management Commands
|
|
3
|
+
*/
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "fs";
|
|
5
|
+
import { dirname, join, resolve } from "path";
|
|
6
|
+
import { createBackup, exportData, importData } from "../api.js";
|
|
7
|
+
import { getDataDir } from "../config.js";
|
|
8
|
+
import { formatFileSize, readFileSafe } from "../utils.js";
|
|
9
|
+
/**
|
|
10
|
+
* Get database file path
|
|
11
|
+
*/
|
|
12
|
+
function getDbPath() {
|
|
13
|
+
return join(getDataDir(), "Papyrusdata.db");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get backup directory path
|
|
17
|
+
*/
|
|
18
|
+
function getBackupDir() {
|
|
19
|
+
const dir = join(getDataDir(), "backups");
|
|
20
|
+
if (!existsSync(dir)) {
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
return dir;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Backup command
|
|
27
|
+
*/
|
|
28
|
+
export async function backupCommand(options) {
|
|
29
|
+
try {
|
|
30
|
+
// Try API backup first
|
|
31
|
+
const result = await createBackup();
|
|
32
|
+
console.log(`\nā
Backup created via API: ${result.path}`);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Fallback to local backup
|
|
36
|
+
const dbPath = getDbPath();
|
|
37
|
+
if (!existsSync(dbPath)) {
|
|
38
|
+
console.error("Database not found. Make sure Papyrus is set up correctly.");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
42
|
+
const backupName = options.output || `papyrus-backup-${timestamp}.db.bak`;
|
|
43
|
+
const backupPath = resolve(backupName);
|
|
44
|
+
// Ensure backup directory exists
|
|
45
|
+
const backupDir = dirname(backupPath);
|
|
46
|
+
if (!existsSync(backupDir)) {
|
|
47
|
+
mkdirSync(backupDir, { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
copyFileSync(dbPath, backupPath);
|
|
50
|
+
const size = statSync(backupPath).size;
|
|
51
|
+
console.log(`\nā
Backup created successfully!`);
|
|
52
|
+
console.log(` Path: ${backupPath}`);
|
|
53
|
+
console.log(` Size: ${formatFileSize(size)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Restore command
|
|
58
|
+
*/
|
|
59
|
+
export async function restoreCommand(backupPath, force = false) {
|
|
60
|
+
const resolvedPath = resolve(backupPath);
|
|
61
|
+
if (!existsSync(resolvedPath)) {
|
|
62
|
+
console.error(`Backup file not found: ${backupPath}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
const dbPath = getDbPath();
|
|
66
|
+
if (!force) {
|
|
67
|
+
const { confirm } = await import("../utils.js");
|
|
68
|
+
const confirmed = await confirm("This will overwrite your current database. Are you sure?");
|
|
69
|
+
if (!confirmed) {
|
|
70
|
+
console.log("Cancelled.");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Create safety backup first
|
|
75
|
+
const safetyBackup = `${dbPath}.safety-${Date.now()}.bak`;
|
|
76
|
+
if (existsSync(dbPath)) {
|
|
77
|
+
copyFileSync(dbPath, safetyBackup);
|
|
78
|
+
console.log(`Safety backup created: ${safetyBackup}`);
|
|
79
|
+
}
|
|
80
|
+
copyFileSync(resolvedPath, dbPath);
|
|
81
|
+
console.log(`\nā
Database restored from ${backupPath}`);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* List backups command
|
|
85
|
+
*/
|
|
86
|
+
export async function listBackupsCommand() {
|
|
87
|
+
const backupDir = getBackupDir();
|
|
88
|
+
if (!existsSync(backupDir)) {
|
|
89
|
+
console.log("No backups found.");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const files = readdirSync(backupDir)
|
|
93
|
+
.filter(f => f.endsWith(".bak") || f.endsWith(".db"))
|
|
94
|
+
.map(f => {
|
|
95
|
+
const path = join(backupDir, f);
|
|
96
|
+
const stats = statSync(path);
|
|
97
|
+
return {
|
|
98
|
+
name: f,
|
|
99
|
+
size: stats.size,
|
|
100
|
+
created: stats.birthtime,
|
|
101
|
+
path,
|
|
102
|
+
};
|
|
103
|
+
})
|
|
104
|
+
.sort((a, b) => b.created.getTime() - a.created.getTime());
|
|
105
|
+
if (files.length === 0) {
|
|
106
|
+
console.log("No backups found.");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
console.log(`\nš¦ Backups (${files.length}):\n`);
|
|
110
|
+
for (const file of files) {
|
|
111
|
+
console.log(` ${file.name}`);
|
|
112
|
+
console.log(` Size: ${formatFileSize(file.size)}`);
|
|
113
|
+
console.log(` Created: ${file.created.toLocaleString()}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Export command
|
|
118
|
+
*/
|
|
119
|
+
export async function exportCommand(output) {
|
|
120
|
+
try {
|
|
121
|
+
const data = await exportData();
|
|
122
|
+
const { writeFileSync } = await import("fs");
|
|
123
|
+
const json = JSON.stringify(data, null, 2);
|
|
124
|
+
writeFileSync(resolve(output), json, "utf-8");
|
|
125
|
+
const size = statSync(resolve(output)).size;
|
|
126
|
+
console.log(`\nā
Data exported to ${output}`);
|
|
127
|
+
console.log(` Size: ${formatFileSize(size)}`);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error(`Export failed: ${error}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Import command
|
|
136
|
+
*/
|
|
137
|
+
export async function importCommand(filePath, force = false) {
|
|
138
|
+
const resolvedPath = resolve(filePath);
|
|
139
|
+
if (!existsSync(resolvedPath)) {
|
|
140
|
+
console.error(`File not found: ${filePath}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const content = readFileSafe(resolvedPath);
|
|
144
|
+
if (!content) {
|
|
145
|
+
console.error(`Cannot read file: ${filePath}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
let data;
|
|
149
|
+
try {
|
|
150
|
+
data = JSON.parse(content);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
console.error("Invalid JSON file.");
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
if (!force) {
|
|
157
|
+
const { confirm } = await import("../utils.js");
|
|
158
|
+
const confirmed = await confirm("This will import data into your database. Continue?");
|
|
159
|
+
if (!confirmed) {
|
|
160
|
+
console.log("Cancelled.");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
await importData(data);
|
|
166
|
+
console.log(`\nā
Data imported successfully!`);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error(`Import failed: ${error}`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Stats command
|
|
175
|
+
*/
|
|
176
|
+
export async function statsCommand() {
|
|
177
|
+
const dataDir = getDataDir();
|
|
178
|
+
const dbPath = getDbPath();
|
|
179
|
+
console.log("\nš Data Statistics\n");
|
|
180
|
+
console.log(` Data Directory: ${dataDir}`);
|
|
181
|
+
if (existsSync(dbPath)) {
|
|
182
|
+
const stats = statSync(dbPath);
|
|
183
|
+
console.log(` Database Size: ${formatFileSize(stats.size)}`);
|
|
184
|
+
console.log(` Last Modified: ${stats.mtime.toLocaleString()}`);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.log(" Database: Not found");
|
|
188
|
+
}
|
|
189
|
+
// Count backups
|
|
190
|
+
const backupDir = getBackupDir();
|
|
191
|
+
if (existsSync(backupDir)) {
|
|
192
|
+
const backups = readdirSync(backupDir).filter(f => f.endsWith(".bak"));
|
|
193
|
+
console.log(` Backups: ${backups.length}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Clean old backups command
|
|
198
|
+
*/
|
|
199
|
+
export async function cleanBackupsCommand(keep = 10) {
|
|
200
|
+
const backupDir = getBackupDir();
|
|
201
|
+
if (!existsSync(backupDir)) {
|
|
202
|
+
console.log("No backups to clean.");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const files = readdirSync(backupDir)
|
|
206
|
+
.filter(f => f.endsWith(".bak"))
|
|
207
|
+
.map(f => ({
|
|
208
|
+
name: f,
|
|
209
|
+
path: join(backupDir, f),
|
|
210
|
+
created: statSync(join(backupDir, f)).birthtime,
|
|
211
|
+
}))
|
|
212
|
+
.sort((a, b) => b.created.getTime() - a.created.getTime());
|
|
213
|
+
if (files.length <= keep) {
|
|
214
|
+
console.log(`Only ${files.length} backup(s) found. Nothing to clean.`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const toDelete = files.slice(keep);
|
|
218
|
+
console.log(`\nš§¹ Cleaning ${toDelete.length} old backup(s)...\n`);
|
|
219
|
+
for (const file of toDelete) {
|
|
220
|
+
try {
|
|
221
|
+
unlinkSync(file.path);
|
|
222
|
+
console.log(` Deleted: ${file.name}`);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
console.log(` Failed to delete: ${file.name} (${error})`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
console.log(`\nā
Kept ${keep} most recent backup(s).`);
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/commands/data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Review Commands
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Interactive review session
|
|
6
|
+
*/
|
|
7
|
+
export declare function reviewCommand(): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Quick review (non-interactive)
|
|
10
|
+
*/
|
|
11
|
+
export declare function quickReviewCommand(): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Review stats command
|
|
14
|
+
*/
|
|
15
|
+
export declare function reviewStatsCommand(): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiCH;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAsEnD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAcxD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyBxD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Review Commands
|
|
3
|
+
*/
|
|
4
|
+
import { getReviewQueue, getReviewStats, submitReview } from "../api.js";
|
|
5
|
+
import { formatRelativeTime, prompt, truncate } from "../utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* Display card for review
|
|
8
|
+
*/
|
|
9
|
+
function displayReviewCard(card, index, total) {
|
|
10
|
+
console.clear();
|
|
11
|
+
console.log(`\nš Review (${index + 1}/${total})\n`);
|
|
12
|
+
console.log("ā".repeat(60));
|
|
13
|
+
console.log(`\nQ: ${card.q}\n`);
|
|
14
|
+
console.log("ā".repeat(60));
|
|
15
|
+
console.log("\nPress Enter to reveal answer...\n");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Display answer and rating options
|
|
19
|
+
*/
|
|
20
|
+
function displayAnswer(card) {
|
|
21
|
+
console.log("\n" + "ā".repeat(60));
|
|
22
|
+
console.log(`\nA: ${card.a}\n`);
|
|
23
|
+
console.log("ā".repeat(60));
|
|
24
|
+
console.log("\nRate your recall:");
|
|
25
|
+
console.log(" [1] Again - Complete blackout");
|
|
26
|
+
console.log(" [2] Hard - Incorrect response, remembered");
|
|
27
|
+
console.log(" [3] Good - Correct with difficulty");
|
|
28
|
+
console.log(" [4] Easy - Perfect response");
|
|
29
|
+
console.log(" [q] Quit review session\n");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Interactive review session
|
|
33
|
+
*/
|
|
34
|
+
export async function reviewCommand() {
|
|
35
|
+
const queue = await getReviewQueue();
|
|
36
|
+
if (queue.length === 0) {
|
|
37
|
+
console.log("\nš No cards are due for review!");
|
|
38
|
+
console.log(" Great job keeping up with your studies.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.log(`\nš Starting review session with ${queue.length} card(s)...\n`);
|
|
42
|
+
let completed = 0;
|
|
43
|
+
let skipped = 0;
|
|
44
|
+
for (let i = 0; i < queue.length; i++) {
|
|
45
|
+
const card = queue[i];
|
|
46
|
+
displayReviewCard(card, i, queue.length);
|
|
47
|
+
// Wait for Enter to reveal
|
|
48
|
+
await prompt("");
|
|
49
|
+
displayAnswer(card);
|
|
50
|
+
// Get rating
|
|
51
|
+
let validInput = false;
|
|
52
|
+
while (!validInput) {
|
|
53
|
+
const input = await prompt("Your rating: ");
|
|
54
|
+
if (input.toLowerCase() === "q") {
|
|
55
|
+
console.log("\nš Review session ended.");
|
|
56
|
+
console.log(` Completed: ${completed}, Skipped: ${skipped + queue.length - i}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const rating = parseInt(input, 10);
|
|
60
|
+
if (rating >= 1 && rating <= 4) {
|
|
61
|
+
// Map 1-4 to SM-2 quality ratings (0-5)
|
|
62
|
+
const quality = rating === 1 ? 0 : rating === 2 ? 3 : rating === 3 ? 4 : 5;
|
|
63
|
+
try {
|
|
64
|
+
await submitReview(card.id, quality);
|
|
65
|
+
completed++;
|
|
66
|
+
validInput = true;
|
|
67
|
+
// Show feedback
|
|
68
|
+
const feedback = rating === 1
|
|
69
|
+
? "š Don't worry, you'll get it next time!"
|
|
70
|
+
: rating === 2
|
|
71
|
+
? "š Keep practicing!"
|
|
72
|
+
: rating === 3
|
|
73
|
+
? "š Good job!"
|
|
74
|
+
: "š Excellent!";
|
|
75
|
+
console.log(`\n ${feedback}`);
|
|
76
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(`\n Error submitting review: ${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(" Please enter 1-4 or q to quit.");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
console.log("\nš Review session complete!");
|
|
88
|
+
console.log(` You reviewed ${completed} card(s).`);
|
|
89
|
+
console.log(" Keep up the great work!\n");
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Quick review (non-interactive)
|
|
93
|
+
*/
|
|
94
|
+
export async function quickReviewCommand() {
|
|
95
|
+
const stats = await getReviewStats();
|
|
96
|
+
console.log("\nš Review Statistics\n");
|
|
97
|
+
console.log(` Total Cards: ${stats.stats.total_cards}`);
|
|
98
|
+
console.log(` Due Today: ${stats.stats.due_today}`);
|
|
99
|
+
console.log(` New Cards: ${stats.stats.new_cards}`);
|
|
100
|
+
console.log(` Review Cards: ${stats.stats.review_cards}`);
|
|
101
|
+
if (stats.stats.due_today > 0) {
|
|
102
|
+
console.log(`\nš” Run 'papyrus review' to start your review session.`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log("\nš You're all caught up!");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Review stats command
|
|
110
|
+
*/
|
|
111
|
+
export async function reviewStatsCommand() {
|
|
112
|
+
const stats = await getReviewStats();
|
|
113
|
+
console.log("\nš Review Statistics\n");
|
|
114
|
+
console.log(` Total Cards: ${stats.stats.total_cards}`);
|
|
115
|
+
console.log(` Due Today: ${stats.stats.due_today}`);
|
|
116
|
+
console.log(` New Cards: ${stats.stats.new_cards}`);
|
|
117
|
+
console.log(` Review Cards: ${stats.stats.review_cards}`);
|
|
118
|
+
// Get queue for more details
|
|
119
|
+
const queue = await getReviewQueue();
|
|
120
|
+
if (queue.length > 0) {
|
|
121
|
+
console.log(`\nš Next ${Math.min(5, queue.length)} cards due:\n`);
|
|
122
|
+
for (let i = 0; i < Math.min(5, queue.length); i++) {
|
|
123
|
+
const card = queue[i];
|
|
124
|
+
console.log(` ${i + 1}. ${truncate(card.q, 45)}`);
|
|
125
|
+
console.log(` Due: ${formatRelativeTime(card.next_review)}`);
|
|
126
|
+
}
|
|
127
|
+
if (queue.length > 5) {
|
|
128
|
+
console.log(`\n ... and ${queue.length - 5} more`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Server Management Commands
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Start server command
|
|
6
|
+
*/
|
|
7
|
+
export declare function serveCommand(options: {
|
|
8
|
+
port?: number;
|
|
9
|
+
host?: string;
|
|
10
|
+
detach?: boolean;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Check server status
|
|
14
|
+
*/
|
|
15
|
+
export declare function statusCommand(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Stop server command (if running in background)
|
|
18
|
+
*/
|
|
19
|
+
export declare function stopCommand(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Open API documentation
|
|
22
|
+
*/
|
|
23
|
+
export declare function docsCommand(): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6BH;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEhB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BnD;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBjD;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBjD"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Papyrus CLI - Server Management Commands
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { join, resolve } from "path";
|
|
7
|
+
import { getApiUrl } from "../config.js";
|
|
8
|
+
import { healthCheck, isApiAvailable } from "../api.js";
|
|
9
|
+
/**
|
|
10
|
+
* Find Papyrus project root
|
|
11
|
+
*/
|
|
12
|
+
function findPapyrusRoot() {
|
|
13
|
+
// Check common locations
|
|
14
|
+
const candidates = [
|
|
15
|
+
resolve("../Papyrus"),
|
|
16
|
+
resolve("../../Papyrus"),
|
|
17
|
+
join(process.cwd(), "Papyrus"),
|
|
18
|
+
join(process.cwd(), "..", "Papyrus"),
|
|
19
|
+
];
|
|
20
|
+
for (const candidate of candidates) {
|
|
21
|
+
if (existsSync(join(candidate, "src", "papyrus_api", "main.py"))) {
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start server command
|
|
29
|
+
*/
|
|
30
|
+
export async function serveCommand(options) {
|
|
31
|
+
const papyrusRoot = findPapyrusRoot();
|
|
32
|
+
if (!papyrusRoot) {
|
|
33
|
+
console.error("Could not find Papyrus project root.");
|
|
34
|
+
console.error("Make sure Papyrus is installed in the parent directory.");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const port = options.port || 8000;
|
|
38
|
+
const host = options.host || "127.0.0.1";
|
|
39
|
+
console.log(`Starting Papyrus API server...`);
|
|
40
|
+
console.log(` Root: ${papyrusRoot}`);
|
|
41
|
+
console.log(` Host: ${host}`);
|
|
42
|
+
console.log(` Port: ${port}`);
|
|
43
|
+
const env = {
|
|
44
|
+
...process.env,
|
|
45
|
+
PYTHONPATH: join(papyrusRoot, "src"),
|
|
46
|
+
};
|
|
47
|
+
const args = [
|
|
48
|
+
"-m", "uvicorn",
|
|
49
|
+
"src.papyrus_api.main:app",
|
|
50
|
+
"--host", host,
|
|
51
|
+
"--port", port.toString(),
|
|
52
|
+
];
|
|
53
|
+
if (options.detach) {
|
|
54
|
+
// Detached mode - run in background
|
|
55
|
+
const { spawn: spawnWin } = await import("child_process");
|
|
56
|
+
const child = spawnWin("python", args, {
|
|
57
|
+
cwd: papyrusRoot,
|
|
58
|
+
env,
|
|
59
|
+
detached: true,
|
|
60
|
+
stdio: "ignore",
|
|
61
|
+
windowsHide: true,
|
|
62
|
+
});
|
|
63
|
+
child.unref();
|
|
64
|
+
console.log(`\nā
Server started in background (PID: ${child.pid})`);
|
|
65
|
+
console.log(` API: http://${host}:${port}`);
|
|
66
|
+
console.log(` Docs: http://${host}:${port}/docs`);
|
|
67
|
+
// Wait a moment and check if it's running
|
|
68
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
69
|
+
if (await isApiAvailable()) {
|
|
70
|
+
console.log(" Status: Running ā");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log(" Status: May have failed to start. Check logs.");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Foreground mode
|
|
78
|
+
console.log(`\nPress Ctrl+C to stop\n`);
|
|
79
|
+
const child = spawn("python", args, {
|
|
80
|
+
cwd: papyrusRoot,
|
|
81
|
+
env,
|
|
82
|
+
stdio: "inherit",
|
|
83
|
+
});
|
|
84
|
+
child.on("close", code => {
|
|
85
|
+
if (code !== 0) {
|
|
86
|
+
console.error(`Server exited with code ${code}`);
|
|
87
|
+
process.exit(code || 1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check server status
|
|
94
|
+
*/
|
|
95
|
+
export async function statusCommand() {
|
|
96
|
+
console.log("\nš Papyrus Server Status\n");
|
|
97
|
+
const apiUrl = getApiUrl();
|
|
98
|
+
console.log(` API URL: ${apiUrl}`);
|
|
99
|
+
const available = await isApiAvailable();
|
|
100
|
+
if (available) {
|
|
101
|
+
try {
|
|
102
|
+
const health = await healthCheck();
|
|
103
|
+
console.log(` Status: ${health.status === "ok" ? "ā
Running" : "ā ļø Unknown"}`);
|
|
104
|
+
// Get additional stats
|
|
105
|
+
const { getReviewStats } = await import("../api.js");
|
|
106
|
+
const stats = await getReviewStats();
|
|
107
|
+
console.log(`\n š Database Stats:`);
|
|
108
|
+
console.log(` Total Cards: ${stats.stats.total_cards}`);
|
|
109
|
+
console.log(` Due Today: ${stats.stats.due_today}`);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
console.log(" Status: ā ļø API available but returned error");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
console.log(" Status: ā Not running");
|
|
117
|
+
console.log(`\n Start with: papyrus serve`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Stop server command (if running in background)
|
|
122
|
+
*/
|
|
123
|
+
export async function stopCommand() {
|
|
124
|
+
const { exec } = await import("child_process");
|
|
125
|
+
const { promisify } = await import("util");
|
|
126
|
+
const execAsync = promisify(exec);
|
|
127
|
+
console.log("Stopping Papyrus server...");
|
|
128
|
+
try {
|
|
129
|
+
// Find and kill uvicorn processes
|
|
130
|
+
if (process.platform === "win32") {
|
|
131
|
+
await execAsync(`taskkill /F /IM python.exe /FI "WINDOWTITLE eq uvicorn*"`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
await execAsync(`pkill -f "uvicorn.*papyrus_api"`);
|
|
135
|
+
}
|
|
136
|
+
console.log("ā
Server stopped.");
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
console.log("Server may not be running or could not be stopped.");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Open API documentation
|
|
144
|
+
*/
|
|
145
|
+
export async function docsCommand() {
|
|
146
|
+
const apiUrl = getApiUrl();
|
|
147
|
+
const docsUrl = `${apiUrl}/docs`;
|
|
148
|
+
console.log(`Opening API documentation: ${docsUrl}`);
|
|
149
|
+
const { exec } = await import("child_process");
|
|
150
|
+
const command = process.platform === "win32"
|
|
151
|
+
? `start "" "${docsUrl}"`
|
|
152
|
+
: process.platform === "darwin"
|
|
153
|
+
? `open "${docsUrl}"`
|
|
154
|
+
: `xdg-open "${docsUrl}"`;
|
|
155
|
+
exec(command, error => {
|
|
156
|
+
if (error) {
|
|
157
|
+
console.log(`Please open manually: ${docsUrl}`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
|