paper-manager 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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/ai/embed.d.ts +3 -0
  4. package/dist/ai/embed.js +13 -0
  5. package/dist/ai/embed.js.map +1 -0
  6. package/dist/ai/index.d.ts +2 -0
  7. package/dist/ai/index.js +3 -0
  8. package/dist/ai/index.js.map +1 -0
  9. package/dist/ai/provider.d.ts +3 -0
  10. package/dist/ai/provider.js +9 -0
  11. package/dist/ai/provider.js.map +1 -0
  12. package/dist/commands/config.d.ts +2 -0
  13. package/dist/commands/config.js +57 -0
  14. package/dist/commands/config.js.map +1 -0
  15. package/dist/commands/knowledge-base.d.ts +2 -0
  16. package/dist/commands/knowledge-base.js +152 -0
  17. package/dist/commands/knowledge-base.js.map +1 -0
  18. package/dist/commands/literature.d.ts +2 -0
  19. package/dist/commands/literature.js +302 -0
  20. package/dist/commands/literature.js.map +1 -0
  21. package/dist/config/index.d.ts +38 -0
  22. package/dist/config/index.js +107 -0
  23. package/dist/config/index.js.map +1 -0
  24. package/dist/db/index.d.ts +9 -0
  25. package/dist/db/index.js +76 -0
  26. package/dist/db/index.js.map +1 -0
  27. package/dist/db/operations/knowledge-bases.d.ts +10 -0
  28. package/dist/db/operations/knowledge-bases.js +25 -0
  29. package/dist/db/operations/knowledge-bases.js.map +1 -0
  30. package/dist/db/operations/literatures.d.ts +9 -0
  31. package/dist/db/operations/literatures.js +87 -0
  32. package/dist/db/operations/literatures.js.map +1 -0
  33. package/dist/db/project/knowledge-bases.d.ts +9 -0
  34. package/dist/db/project/knowledge-bases.js +15 -0
  35. package/dist/db/project/knowledge-bases.js.map +1 -0
  36. package/dist/db/project/literatures.d.ts +8 -0
  37. package/dist/db/project/literatures.js +24 -0
  38. package/dist/db/project/literatures.js.map +1 -0
  39. package/dist/db/schema.d.ts +2 -0
  40. package/dist/db/schema.js +26 -0
  41. package/dist/db/schema.js.map +1 -0
  42. package/dist/db/user/knowledge-bases.d.ts +9 -0
  43. package/dist/db/user/knowledge-bases.js +15 -0
  44. package/dist/db/user/knowledge-bases.js.map +1 -0
  45. package/dist/db/user/literatures.d.ts +8 -0
  46. package/dist/db/user/literatures.js +24 -0
  47. package/dist/db/user/literatures.js.map +1 -0
  48. package/dist/index.d.ts +2 -0
  49. package/dist/index.js +12 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/pdf/extractor.d.ts +2 -0
  52. package/dist/pdf/extractor.js +6 -0
  53. package/dist/pdf/extractor.js.map +1 -0
  54. package/dist/types/index.d.ts +74 -0
  55. package/dist/types/index.js +45 -0
  56. package/dist/types/index.js.map +1 -0
  57. package/dist/vector-store/embeddings.d.ts +8 -0
  58. package/dist/vector-store/embeddings.js +16 -0
  59. package/dist/vector-store/embeddings.js.map +1 -0
  60. package/dist/vector-store/index.d.ts +6 -0
  61. package/dist/vector-store/index.js +17 -0
  62. package/dist/vector-store/index.js.map +1 -0
  63. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Phantom
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # my-ts-starter
2
+
3
+ A minimal TypeScript project template with modern tooling powered by the [oxc](https://oxc.rs/) ecosystem.
4
+
5
+ ## Features
6
+
7
+ - **TypeScript** — Type-safe development with `tsc`
8
+ - **oxlint** — Fast linter with type-aware rules (via `oxlint-tsgolint`)
9
+ - **oxfmt** — Fast formatter
10
+
11
+ ## Getting Started
12
+
13
+ ```bash
14
+ # Install dependencies
15
+ pnpm install
16
+
17
+ # Type check
18
+ pnpm typecheck
19
+
20
+ # Lint
21
+ pnpm lint
22
+
23
+ # Format
24
+ pnpm fmt
25
+ ```
26
+
27
+ ## Available Scripts
28
+
29
+ | Script | Description |
30
+ | ---------------- | -------------------------------- |
31
+ | `pnpm typecheck` | Run TypeScript type checking |
32
+ | `pnpm lint` | Lint with oxlint (type-aware) |
33
+ | `pnpm lint:fix` | Lint and auto-fix |
34
+ | `pnpm fmt` | Format with oxfmt |
35
+ | `pnpm fmt:check` | Check formatting without writing |
36
+
37
+ ## License
38
+
39
+ [MIT](LICENSE)
@@ -0,0 +1,3 @@
1
+ import type { EmbeddingModelConfig } from "../types/index.js";
2
+ export declare function embed(config: EmbeddingModelConfig, text: string): Promise<number[]>;
3
+ export declare function embedMany(config: EmbeddingModelConfig, texts: string[]): Promise<number[][]>;
@@ -0,0 +1,13 @@
1
+ import { embed as aiEmbed, embedMany as aiEmbedMany } from "ai";
2
+ import { createEmbeddingModel } from "./provider.js";
3
+ export async function embed(config, text) {
4
+ const model = createEmbeddingModel(config);
5
+ const result = await aiEmbed({ model, value: text });
6
+ return result.embedding;
7
+ }
8
+ export async function embedMany(config, texts) {
9
+ const model = createEmbeddingModel(config);
10
+ const result = await aiEmbedMany({ model, values: texts });
11
+ return result.embeddings;
12
+ }
13
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/ai/embed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,IAAI,CAAC;AAGhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,MAA4B,EAAE,IAAY;IACpE,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,SAAS,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAA4B,EAC5B,KAAe;IAEf,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,UAAU,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { embed, embedMany } from "./embed.js";
2
+ export { createEmbeddingModel } from "./provider.js";
@@ -0,0 +1,3 @@
1
+ export { embed, embedMany } from "./embed.js";
2
+ export { createEmbeddingModel } from "./provider.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { EmbeddingModelV3 } from "@ai-sdk/provider";
2
+ import type { EmbeddingModelConfig } from "../types/index.js";
3
+ export declare function createEmbeddingModel(config: EmbeddingModelConfig): EmbeddingModelV3;
@@ -0,0 +1,9 @@
1
+ import { createOpenAI } from "@ai-sdk/openai";
2
+ export function createEmbeddingModel(config) {
3
+ const openai = createOpenAI({
4
+ apiKey: config.apiKey,
5
+ baseURL: config.baseUrl,
6
+ });
7
+ return openai.embedding(config.model);
8
+ }
9
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK9C,MAAM,UAAU,oBAAoB,CAAC,MAA4B;IAC/D,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createConfigCommand(): Command;
@@ -0,0 +1,57 @@
1
+ import { Command } from "commander";
2
+ import { listConfig, loadMergedConfig, removeConfig, setConfig } from "../config/index.js";
3
+ export function createConfigCommand() {
4
+ const config = new Command("config").description("Manage configuration");
5
+ config
6
+ .command("get <key>")
7
+ .description("Get a config value")
8
+ .option("--user", "Read from user config")
9
+ .action((key, options) => {
10
+ const source = options.user ? listConfig({ user: true }) : loadMergedConfig();
11
+ const value = source[key];
12
+ if (value === undefined) {
13
+ console.log(`Config "${key}" is not set.`);
14
+ }
15
+ else {
16
+ console.log(JSON.stringify(value, null, 2));
17
+ }
18
+ });
19
+ config
20
+ .command("set <key> <value>")
21
+ .description("Set a config value")
22
+ .option("--user", "Write to user config")
23
+ .action((key, rawValue, options) => {
24
+ let value;
25
+ try {
26
+ value = JSON.parse(rawValue);
27
+ }
28
+ catch {
29
+ value = rawValue;
30
+ }
31
+ setConfig(key, value, { user: options.user });
32
+ console.log(`Config "${key}" has been set.`);
33
+ });
34
+ config
35
+ .command("remove <key>")
36
+ .description("Remove a config key")
37
+ .option("--user", "Remove from user config")
38
+ .action((key, options) => {
39
+ removeConfig(key, { user: options.user });
40
+ console.log(`Config "${key}" has been removed.`);
41
+ });
42
+ config
43
+ .command("list")
44
+ .description("List all config")
45
+ .option("--user", "List user config only")
46
+ .action((options) => {
47
+ const result = options.user ? listConfig({ user: true }) : loadMergedConfig();
48
+ if (Object.keys(result).length === 0) {
49
+ console.log("No config set.");
50
+ }
51
+ else {
52
+ console.log(JSON.stringify(result, null, 2));
53
+ }
54
+ });
55
+ return config;
56
+ }
57
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createKnowledgeBaseCommand(): Command;
@@ -0,0 +1,152 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { Command } from "commander";
4
+ import { getConfig, getModelConfig, getPdfDir, getProjectDataDir, getUserDataDir, getVectorStoreDir, } from "../config/index.js";
5
+ import * as projectKb from "../db/project/knowledge-bases.js";
6
+ import * as projectLit from "../db/project/literatures.js";
7
+ import * as userKb from "../db/user/knowledge-bases.js";
8
+ import * as userLit from "../db/user/literatures.js";
9
+ import { queryVectorStore } from "../vector-store/index.js";
10
+ function resolveKnowledgeBase(id) {
11
+ const pkb = projectKb.getKnowledgeBase(id);
12
+ if (pkb)
13
+ return { kb: pkb, scope: "project" };
14
+ const ukb = userKb.getKnowledgeBase(id);
15
+ if (ukb)
16
+ return { kb: ukb, scope: "user" };
17
+ return null;
18
+ }
19
+ function getBaseDir(scope) {
20
+ return scope === "project" ? getProjectDataDir() : getUserDataDir();
21
+ }
22
+ export function createKnowledgeBaseCommand() {
23
+ const kb = new Command("kb").description("Manage knowledge bases");
24
+ kb.command("create <name>")
25
+ .description("Create a knowledge base")
26
+ .requiredOption("-d, --description <desc>", "Knowledge base description")
27
+ .option("-e, --embedding-model <id>", "Embedding model config ID")
28
+ .option("--user", "Create in user scope")
29
+ .action((name, options) => {
30
+ let embeddingModelId = options.embeddingModel;
31
+ if (!embeddingModelId) {
32
+ const defaultId = getConfig("defaultEmbeddingModelId");
33
+ if (!defaultId) {
34
+ console.error("Error: No embedding model specified and no default configured.");
35
+ process.exit(1);
36
+ }
37
+ embeddingModelId = defaultId;
38
+ }
39
+ // Validate model config exists
40
+ const models = getConfig("embeddingModels");
41
+ if (!models?.[embeddingModelId]) {
42
+ console.error(`Error: Embedding model "${embeddingModelId}" not found in config.`);
43
+ process.exit(1);
44
+ }
45
+ const create = options.user ? userKb.createKnowledgeBase : projectKb.createKnowledgeBase;
46
+ const result = create({
47
+ name,
48
+ description: options.description,
49
+ embeddingModelId,
50
+ });
51
+ console.log(`Knowledge base created: ${result.id}`);
52
+ console.log(` Name: ${result.name}`);
53
+ console.log(` Scope: ${options.user ? "user" : "project"}`);
54
+ });
55
+ kb.command("list")
56
+ .description("List knowledge bases")
57
+ .option("--user", "List user knowledge bases only")
58
+ .option("--all", "List all knowledge bases (default)")
59
+ .action((options) => {
60
+ let results = [];
61
+ if (options.user) {
62
+ results = userKb.listKnowledgeBases().map((k) => ({ ...k, scope: "user" }));
63
+ }
64
+ else {
65
+ const projectKbs = projectKb.listKnowledgeBases().map((k) => ({ ...k, scope: "project" }));
66
+ const userKbs = userKb.listKnowledgeBases().map((k) => ({ ...k, scope: "user" }));
67
+ results = [...projectKbs, ...userKbs];
68
+ }
69
+ if (results.length === 0) {
70
+ console.log("No knowledge bases found.");
71
+ return;
72
+ }
73
+ for (const kb of results) {
74
+ console.log(`[${kb.scope}] ${kb.id}`);
75
+ console.log(` Name: ${kb.name}`);
76
+ console.log(` Description: ${kb.description}`);
77
+ console.log(` Model: ${kb.embeddingModelId}`);
78
+ console.log(` Created: ${kb.createdAt.toISOString()}`);
79
+ console.log();
80
+ }
81
+ });
82
+ kb.command("remove <id>")
83
+ .description("Remove a knowledge base and all its data")
84
+ .action((id) => {
85
+ const resolved = resolveKnowledgeBase(id);
86
+ if (!resolved) {
87
+ console.error(`Knowledge base not found: ${id}`);
88
+ process.exit(1);
89
+ }
90
+ const { scope } = resolved;
91
+ const baseDir = getBaseDir(scope);
92
+ const litOps = scope === "project" ? projectLit : userLit;
93
+ const kbOps = scope === "project" ? projectKb : userKb;
94
+ // 1. Get all literatures in this KB
95
+ const literatures = litOps.getLiteraturesByKnowledgeBaseId(id);
96
+ // 2. Delete PDF files
97
+ const pdfDir = getPdfDir(baseDir);
98
+ for (const lit of literatures) {
99
+ const pdfPath = path.join(pdfDir, `${lit.id}.pdf`);
100
+ if (fs.existsSync(pdfPath)) {
101
+ fs.unlinkSync(pdfPath);
102
+ }
103
+ }
104
+ // 3. Delete literatures from DB
105
+ litOps.deleteLiteraturesByKnowledgeBaseId(id);
106
+ // 4. Delete vector store directory
107
+ const vectorDir = path.join(getVectorStoreDir(baseDir), id);
108
+ if (fs.existsSync(vectorDir)) {
109
+ fs.rmSync(vectorDir, { recursive: true });
110
+ }
111
+ // 5. Delete knowledge base
112
+ kbOps.deleteKnowledgeBase(id);
113
+ console.log(`Knowledge base "${id}" and all associated data removed.`);
114
+ });
115
+ kb.command("query <id> <query-text>")
116
+ .description("Query a knowledge base")
117
+ .option("-k, --top-k <number>", "Number of results", "5")
118
+ .action(async (id, queryText, options) => {
119
+ const resolved = resolveKnowledgeBase(id);
120
+ if (!resolved) {
121
+ console.error(`Knowledge base not found: ${id}`);
122
+ process.exit(1);
123
+ }
124
+ const { kb: kbMeta, scope } = resolved;
125
+ const baseDir = getBaseDir(scope);
126
+ const vectorDir = path.join(getVectorStoreDir(baseDir), id);
127
+ if (!fs.existsSync(vectorDir)) {
128
+ console.error("No vector store found for this knowledge base.");
129
+ process.exit(1);
130
+ }
131
+ const modelConfig = getModelConfig(kbMeta.embeddingModelId);
132
+ const k = parseInt(options.topK, 10);
133
+ const results = await queryVectorStore(modelConfig, vectorDir, queryText, k);
134
+ if (results.length === 0) {
135
+ console.log("No results found.");
136
+ return;
137
+ }
138
+ for (let i = 0; i < results.length; i++) {
139
+ const doc = results[i];
140
+ if (!doc)
141
+ continue;
142
+ console.log(`--- Result ${String(i + 1)} ---`);
143
+ console.log(doc.pageContent);
144
+ if (doc.metadata && Object.keys(doc.metadata).length > 0) {
145
+ console.log(` Metadata: ${JSON.stringify(doc.metadata)}`);
146
+ }
147
+ console.log();
148
+ }
149
+ });
150
+ return kb;
151
+ }
152
+ //# sourceMappingURL=knowledge-base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-base.js","sourceRoot":"","sources":["../../src/commands/knowledge-base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createLiteratureCommand(): Command;
@@ -0,0 +1,302 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
4
+ import cliProgress from "cli-progress";
5
+ import { Command } from "commander";
6
+ import { getModelConfig, getPdfDir, getProjectDataDir, getUserDataDir, getVectorStoreDir, } from "../config/index.js";
7
+ import * as projectKb from "../db/project/knowledge-bases.js";
8
+ import * as projectLit from "../db/project/literatures.js";
9
+ import * as userKb from "../db/user/knowledge-bases.js";
10
+ import * as userLit from "../db/user/literatures.js";
11
+ import { extractPdfContent } from "../pdf/extractor.js";
12
+ import { createVectorStore, loadVectorStore } from "../vector-store/index.js";
13
+ function resolveKnowledgeBase(id) {
14
+ const pkb = projectKb.getKnowledgeBase(id);
15
+ if (pkb)
16
+ return { kb: pkb, scope: "project" };
17
+ const ukb = userKb.getKnowledgeBase(id);
18
+ if (ukb)
19
+ return { kb: ukb, scope: "user" };
20
+ return null;
21
+ }
22
+ function getBaseDir(scope) {
23
+ return scope === "project" ? getProjectDataDir() : getUserDataDir();
24
+ }
25
+ function getLitOps(scope) {
26
+ return scope === "project" ? projectLit : userLit;
27
+ }
28
+ export function createLiteratureCommand() {
29
+ const lit = new Command("lit").description("Manage literatures");
30
+ // ─── lit add ───────────────────────────────────────────────
31
+ lit
32
+ .command("add <knowledge-base-id> <pdf-path>")
33
+ .description("Add a literature from a PDF file")
34
+ .option("-t, --title <title>", "Literature title")
35
+ .action(async (kbId, pdfPath, options) => {
36
+ const resolved = resolveKnowledgeBase(kbId);
37
+ if (!resolved) {
38
+ console.error(`Knowledge base not found: ${kbId}`);
39
+ process.exit(1);
40
+ }
41
+ const { kb, scope } = resolved;
42
+ const baseDir = getBaseDir(scope);
43
+ const litOps = getLitOps(scope);
44
+ // Resolve PDF path
45
+ const absolutePdfPath = path.resolve(pdfPath);
46
+ if (!fs.existsSync(absolutePdfPath)) {
47
+ console.error(`PDF file not found: ${absolutePdfPath}`);
48
+ process.exit(1);
49
+ }
50
+ const title = options.title ?? path.basename(pdfPath, path.extname(pdfPath));
51
+ console.log(`Extracting PDF content...`);
52
+ const docs = await extractPdfContent(absolutePdfPath);
53
+ console.log(` Extracted ${String(docs.length)} pages.`);
54
+ // Create literature record
55
+ const literature = litOps.createLiterature({
56
+ title,
57
+ titleTranslation: null,
58
+ author: null,
59
+ abstract: null,
60
+ summary: null,
61
+ keywords: [],
62
+ url: null,
63
+ notes: {},
64
+ knowledgeBaseId: kbId,
65
+ });
66
+ // Copy PDF to storage
67
+ const pdfDir = getPdfDir(baseDir);
68
+ fs.mkdirSync(pdfDir, { recursive: true });
69
+ fs.copyFileSync(absolutePdfPath, path.join(pdfDir, `${literature.id}.pdf`));
70
+ // Split text and add to vector store
71
+ console.log(`Splitting text...`);
72
+ const splitter = new RecursiveCharacterTextSplitter({
73
+ chunkSize: 1000,
74
+ chunkOverlap: 200,
75
+ });
76
+ const splitDocs = await splitter.splitDocuments(docs);
77
+ console.log(` Created ${String(splitDocs.length)} chunks.`);
78
+ // Add literature ID metadata to each chunk
79
+ for (const doc of splitDocs) {
80
+ doc.metadata = { ...doc.metadata, literatureId: literature.id };
81
+ }
82
+ const vectorDir = path.join(getVectorStoreDir(baseDir), kbId);
83
+ const modelConfig = getModelConfig(kb.embeddingModelId);
84
+ console.log(`Embedding and storing vectors...`);
85
+ const bar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
86
+ bar.start(splitDocs.length, 0);
87
+ // Check if vector store already exists
88
+ if (fs.existsSync(vectorDir)) {
89
+ const store = await loadVectorStore(modelConfig, vectorDir);
90
+ await store.addDocuments(splitDocs);
91
+ await store.save(vectorDir);
92
+ }
93
+ else {
94
+ fs.mkdirSync(vectorDir, { recursive: true });
95
+ await createVectorStore(splitDocs, modelConfig, vectorDir);
96
+ }
97
+ bar.update(splitDocs.length);
98
+ bar.stop();
99
+ console.log(`Literature added: ${literature.id}`);
100
+ console.log(` Title: ${literature.title}`);
101
+ });
102
+ // ─── lit remove ────────────────────────────────────────────
103
+ lit
104
+ .command("remove <knowledge-base-id> <id>")
105
+ .description("Remove a literature")
106
+ .action((kbId, id) => {
107
+ const resolved = resolveKnowledgeBase(kbId);
108
+ if (!resolved) {
109
+ console.error(`Knowledge base not found: ${kbId}`);
110
+ process.exit(1);
111
+ }
112
+ const { scope } = resolved;
113
+ const baseDir = getBaseDir(scope);
114
+ const litOps = getLitOps(scope);
115
+ const literature = litOps.getLiterature(id);
116
+ if (!literature) {
117
+ console.error(`Literature not found: ${id}`);
118
+ process.exit(1);
119
+ }
120
+ // Delete PDF
121
+ const pdfPath = path.join(getPdfDir(baseDir), `${id}.pdf`);
122
+ if (fs.existsSync(pdfPath)) {
123
+ fs.unlinkSync(pdfPath);
124
+ }
125
+ // Delete literature record
126
+ litOps.deleteLiterature(id);
127
+ console.log(`Literature "${id}" removed.`);
128
+ });
129
+ // ─── lit update ────────────────────────────────────────────
130
+ lit
131
+ .command("update <knowledge-base-id> <id>")
132
+ .description("Update a literature")
133
+ .option("-t, --title <title>", "Title")
134
+ .option("--title-translation <translation>", "Title translation")
135
+ .option("-a, --author <author>", "Author")
136
+ .option("--abstract <abstract>", "Abstract")
137
+ .option("--summary <summary>", "Summary")
138
+ .option("--url <url>", "URL")
139
+ .option("--keywords <keywords>", "Keywords (comma-separated)")
140
+ .action((kbId, id, options) => {
141
+ const resolved = resolveKnowledgeBase(kbId);
142
+ if (!resolved) {
143
+ console.error(`Knowledge base not found: ${kbId}`);
144
+ process.exit(1);
145
+ }
146
+ const litOps = getLitOps(resolved.scope);
147
+ const input = {};
148
+ if (options.title !== undefined)
149
+ input["title"] = options.title;
150
+ if (options.titleTranslation !== undefined)
151
+ input["titleTranslation"] = options.titleTranslation;
152
+ if (options.author !== undefined)
153
+ input["author"] = options.author;
154
+ if (options.abstract !== undefined)
155
+ input["abstract"] = options.abstract;
156
+ if (options.summary !== undefined)
157
+ input["summary"] = options.summary;
158
+ if (options.url !== undefined)
159
+ input["url"] = options.url;
160
+ if (options.keywords !== undefined)
161
+ input["keywords"] = options.keywords.split(",").map((k) => k.trim());
162
+ const updated = litOps.updateLiterature(id, input);
163
+ if (!updated) {
164
+ console.error(`Literature not found: ${id}`);
165
+ process.exit(1);
166
+ }
167
+ console.log(`Literature "${id}" updated.`);
168
+ });
169
+ // ─── lit list ──────────────────────────────────────────────
170
+ lit
171
+ .command("list <knowledge-base-id>")
172
+ .description("List literatures in a knowledge base")
173
+ .action((kbId) => {
174
+ const resolved = resolveKnowledgeBase(kbId);
175
+ if (!resolved) {
176
+ console.error(`Knowledge base not found: ${kbId}`);
177
+ process.exit(1);
178
+ }
179
+ const litOps = getLitOps(resolved.scope);
180
+ const literatures = litOps.listLiteratures(kbId);
181
+ if (literatures.length === 0) {
182
+ console.log("No literatures found.");
183
+ return;
184
+ }
185
+ for (const l of literatures) {
186
+ console.log(`${l.id}`);
187
+ console.log(` Title: ${l.title}`);
188
+ if (l.author)
189
+ console.log(` Author: ${l.author}`);
190
+ console.log(` Created: ${l.createdAt.toISOString()}`);
191
+ console.log();
192
+ }
193
+ });
194
+ // ─── lit show ──────────────────────────────────────────────
195
+ lit
196
+ .command("show <knowledge-base-id> <id>")
197
+ .description("Show literature details")
198
+ .action((kbId, id) => {
199
+ const resolved = resolveKnowledgeBase(kbId);
200
+ if (!resolved) {
201
+ console.error(`Knowledge base not found: ${kbId}`);
202
+ process.exit(1);
203
+ }
204
+ const litOps = getLitOps(resolved.scope);
205
+ const literature = litOps.getLiterature(id);
206
+ if (!literature) {
207
+ console.error(`Literature not found: ${id}`);
208
+ process.exit(1);
209
+ }
210
+ printLiterature(literature);
211
+ });
212
+ // ─── lit note ──────────────────────────────────────────────
213
+ const note = lit.command("note").description("Manage literature notes");
214
+ note
215
+ .command("list <literature-id>")
216
+ .description("List all notes for a literature")
217
+ .action((litId) => {
218
+ const literature = findLiterature(litId);
219
+ if (!literature) {
220
+ console.error(`Literature not found: ${litId}`);
221
+ process.exit(1);
222
+ }
223
+ const entries = Object.entries(literature.notes);
224
+ if (entries.length === 0) {
225
+ console.log("No notes found.");
226
+ return;
227
+ }
228
+ for (const [key, value] of entries) {
229
+ console.log(`${key}: ${value}`);
230
+ }
231
+ });
232
+ note
233
+ .command("set <literature-id> <key> <value>")
234
+ .description("Set a note on a literature")
235
+ .action((litId, key, value) => {
236
+ const found = findLiteratureWithScope(litId);
237
+ if (!found) {
238
+ console.error(`Literature not found: ${litId}`);
239
+ process.exit(1);
240
+ }
241
+ const litOps = getLitOps(found.scope);
242
+ const newNotes = { ...found.literature.notes, [key]: value };
243
+ litOps.updateLiterature(litId, { notes: newNotes });
244
+ console.log(`Note "${key}" set on literature "${litId}".`);
245
+ });
246
+ note
247
+ .command("remove <literature-id> <key>")
248
+ .description("Remove a note from a literature")
249
+ .action((litId, key) => {
250
+ const found = findLiteratureWithScope(litId);
251
+ if (!found) {
252
+ console.error(`Literature not found: ${litId}`);
253
+ process.exit(1);
254
+ }
255
+ const litOps = getLitOps(found.scope);
256
+ const newNotes = { ...found.literature.notes };
257
+ delete newNotes[key];
258
+ litOps.updateLiterature(litId, { notes: newNotes });
259
+ console.log(`Note "${key}" removed from literature "${litId}".`);
260
+ });
261
+ return lit;
262
+ }
263
+ // ─── Helpers ────────────────────────────────────────────────
264
+ function findLiterature(id) {
265
+ return projectLit.getLiterature(id) ?? userLit.getLiterature(id);
266
+ }
267
+ function findLiteratureWithScope(id) {
268
+ const pLit = projectLit.getLiterature(id);
269
+ if (pLit)
270
+ return { literature: pLit, scope: "project" };
271
+ const uLit = userLit.getLiterature(id);
272
+ if (uLit)
273
+ return { literature: uLit, scope: "user" };
274
+ return null;
275
+ }
276
+ function printLiterature(lit) {
277
+ console.log(`ID: ${lit.id}`);
278
+ console.log(`Title: ${lit.title}`);
279
+ if (lit.titleTranslation)
280
+ console.log(`Title (translated): ${lit.titleTranslation}`);
281
+ if (lit.author)
282
+ console.log(`Author: ${lit.author}`);
283
+ if (lit.abstract)
284
+ console.log(`Abstract: ${lit.abstract}`);
285
+ if (lit.summary)
286
+ console.log(`Summary: ${lit.summary}`);
287
+ if (lit.keywords.length > 0)
288
+ console.log(`Keywords: ${lit.keywords.join(", ")}`);
289
+ if (lit.url)
290
+ console.log(`URL: ${lit.url}`);
291
+ console.log(`Knowledge Base: ${lit.knowledgeBaseId}`);
292
+ console.log(`Created: ${lit.createdAt.toISOString()}`);
293
+ console.log(`Updated: ${lit.updatedAt.toISOString()}`);
294
+ const noteEntries = Object.entries(lit.notes);
295
+ if (noteEntries.length > 0) {
296
+ console.log(`Notes:`);
297
+ for (const [key, value] of noteEntries) {
298
+ console.log(` ${key}: ${value}`);
299
+ }
300
+ }
301
+ }
302
+ //# sourceMappingURL=literature.js.map