obsidian-mcp-server 1.5.8 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -104
- package/dist/config/index.d.ts +41 -0
- package/dist/config/index.js +191 -0
- package/dist/index.d.ts +1 -5
- package/dist/index.js +296 -18
- package/dist/mcp-server/server.d.ts +33 -0
- package/dist/mcp-server/server.js +211 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/logic.d.ts +51 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/logic.js +168 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/registration.d.ts +19 -0
- package/dist/mcp-server/tools/obsidianDeleteFileTool/registration.js +91 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.d.ts +77 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/logic.js +341 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.d.ts +18 -0
- package/dist/mcp-server/tools/obsidianGlobalSearchTool/registration.js +69 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/logic.d.ts +64 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/logic.js +179 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/registration.d.ts +19 -0
- package/dist/mcp-server/tools/obsidianListFilesTool/registration.js +96 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.d.ts +3 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/index.js +2 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.d.ts +42 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/logic.js +152 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.d.ts +3 -0
- package/dist/mcp-server/tools/obsidianManageFrontmatterTool/registration.js +52 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/index.d.ts +3 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/index.js +2 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/logic.d.ts +28 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/logic.js +161 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/registration.d.ts +3 -0
- package/dist/mcp-server/tools/obsidianManageTagsTool/registration.js +52 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/logic.d.ts +87 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/logic.js +216 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/registration.d.ts +20 -0
- package/dist/mcp-server/tools/obsidianReadFileTool/registration.js +101 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.d.ts +255 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/logic.js +583 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.d.ts +22 -0
- package/dist/mcp-server/tools/obsidianSearchReplaceTool/registration.js +111 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/index.d.ts +12 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/index.js +12 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/logic.d.ts +183 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/logic.js +490 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/registration.d.ts +21 -0
- package/dist/mcp-server/tools/obsidianUpdateFileTool/registration.js +108 -0
- package/dist/mcp-server/transports/authentication/authContext.d.ts +33 -0
- package/dist/mcp-server/transports/authentication/authContext.js +24 -0
- package/dist/mcp-server/transports/authentication/authMiddleware.d.ts +30 -0
- package/dist/mcp-server/transports/authentication/authMiddleware.js +145 -0
- package/dist/mcp-server/transports/authentication/authUtils.d.ts +18 -0
- package/dist/mcp-server/transports/authentication/authUtils.js +45 -0
- package/dist/mcp-server/transports/authentication/oauthMiddleware.d.ts +24 -0
- package/dist/mcp-server/transports/authentication/oauthMiddleware.js +109 -0
- package/dist/mcp-server/transports/authentication/types.d.ts +17 -0
- package/dist/mcp-server/transports/authentication/types.js +5 -0
- package/dist/mcp-server/transports/httpTransport.d.ts +24 -0
- package/dist/mcp-server/transports/httpTransport.js +496 -0
- package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
- package/dist/mcp-server/transports/stdioTransport.js +63 -0
- package/dist/services/obsidianRestAPI/index.d.ts +15 -0
- package/dist/services/obsidianRestAPI/index.js +17 -0
- package/dist/services/obsidianRestAPI/methods/activeFileMethods.d.ts +38 -0
- package/dist/services/obsidianRestAPI/methods/activeFileMethods.js +62 -0
- package/dist/services/obsidianRestAPI/methods/commandMethods.d.ts +22 -0
- package/dist/services/obsidianRestAPI/methods/commandMethods.js +31 -0
- package/dist/services/obsidianRestAPI/methods/openMethods.d.ts +16 -0
- package/dist/services/obsidianRestAPI/methods/openMethods.js +21 -0
- package/dist/services/obsidianRestAPI/methods/patchMethods.d.ts +37 -0
- package/dist/services/obsidianRestAPI/methods/patchMethods.js +94 -0
- package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.d.ts +42 -0
- package/dist/services/obsidianRestAPI/methods/periodicNoteMethods.js +66 -0
- package/dist/services/obsidianRestAPI/methods/searchMethods.d.ts +25 -0
- package/dist/services/obsidianRestAPI/methods/searchMethods.js +36 -0
- package/dist/services/obsidianRestAPI/methods/vaultMethods.d.ts +58 -0
- package/dist/services/obsidianRestAPI/methods/vaultMethods.js +144 -0
- package/dist/services/obsidianRestAPI/service.d.ts +195 -0
- package/dist/services/obsidianRestAPI/service.js +379 -0
- package/dist/services/obsidianRestAPI/types.d.ts +127 -0
- package/dist/services/obsidianRestAPI/types.js +7 -0
- package/dist/services/obsidianRestAPI/vaultCache/index.d.ts +4 -0
- package/dist/services/obsidianRestAPI/vaultCache/index.js +4 -0
- package/dist/services/obsidianRestAPI/vaultCache/service.d.ts +88 -0
- package/dist/services/obsidianRestAPI/vaultCache/service.js +299 -0
- package/dist/types-global/errors.d.ts +73 -0
- package/dist/types-global/errors.js +71 -0
- package/dist/utils/index.d.ts +5 -8
- package/dist/utils/index.js +13 -9
- package/dist/utils/internal/asyncUtils.d.ts +54 -0
- package/dist/utils/internal/asyncUtils.js +101 -0
- package/dist/utils/internal/errorHandler.d.ts +176 -0
- package/dist/utils/internal/errorHandler.js +351 -0
- package/dist/utils/internal/index.d.ts +4 -0
- package/dist/utils/internal/index.js +4 -0
- package/dist/utils/internal/logger.d.ts +141 -0
- package/dist/utils/internal/logger.js +406 -0
- package/dist/utils/internal/requestContext.d.ts +83 -0
- package/dist/utils/internal/requestContext.js +72 -0
- package/dist/utils/metrics/index.d.ts +1 -0
- package/dist/utils/metrics/index.js +1 -0
- package/dist/utils/metrics/tokenCounter.d.ts +27 -0
- package/dist/utils/metrics/tokenCounter.js +128 -0
- package/dist/utils/obsidian/index.d.ts +5 -0
- package/dist/utils/obsidian/index.js +5 -0
- package/dist/utils/obsidian/obsidianApiUtils.d.ts +14 -0
- package/dist/utils/obsidian/obsidianApiUtils.js +29 -0
- package/dist/utils/obsidian/obsidianStatUtils.d.ts +68 -0
- package/dist/utils/obsidian/obsidianStatUtils.js +143 -0
- package/dist/utils/parsing/dateParser.d.ts +56 -0
- package/dist/utils/parsing/dateParser.js +104 -0
- package/dist/utils/parsing/index.d.ts +2 -0
- package/dist/utils/parsing/index.js +3 -0
- package/dist/utils/parsing/jsonParser.d.ts +80 -0
- package/dist/utils/parsing/jsonParser.js +133 -0
- package/dist/utils/security/idGenerator.d.ts +140 -0
- package/dist/utils/security/idGenerator.js +194 -0
- package/dist/utils/security/index.d.ts +3 -0
- package/dist/utils/security/index.js +3 -0
- package/dist/utils/security/rateLimiter.d.ts +156 -0
- package/dist/utils/security/rateLimiter.js +235 -0
- package/dist/utils/security/sanitization.d.ts +244 -0
- package/dist/utils/security/sanitization.js +599 -0
- package/package.json +58 -37
- package/dist/index.js.map +0 -1
- package/dist/mcp/handlers.d.ts +0 -29
- package/dist/mcp/handlers.js +0 -305
- package/dist/mcp/handlers.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.js +0 -7
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -18
- package/dist/mcp/server.js +0 -240
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -70
- package/dist/mcp/types.js +0 -49
- package/dist/mcp/types.js.map +0 -1
- package/dist/obsidian/client.d.ts +0 -109
- package/dist/obsidian/client.js +0 -403
- package/dist/obsidian/client.js.map +0 -1
- package/dist/obsidian/errors.d.ts +0 -28
- package/dist/obsidian/errors.js +0 -75
- package/dist/obsidian/errors.js.map +0 -1
- package/dist/obsidian/index.d.ts +0 -6
- package/dist/obsidian/index.js +0 -7
- package/dist/obsidian/index.js.map +0 -1
- package/dist/obsidian/types.d.ts +0 -107
- package/dist/obsidian/types.js +0 -12
- package/dist/obsidian/types.js.map +0 -1
- package/dist/resources/index.d.ts +0 -13
- package/dist/resources/index.js +0 -15
- package/dist/resources/index.js.map +0 -1
- package/dist/resources/tags.d.ts +0 -39
- package/dist/resources/tags.js +0 -257
- package/dist/resources/tags.js.map +0 -1
- package/dist/resources/types.d.ts +0 -27
- package/dist/resources/types.js +0 -5
- package/dist/resources/types.js.map +0 -1
- package/dist/tools/base.d.ts +0 -46
- package/dist/tools/base.js +0 -88
- package/dist/tools/base.js.map +0 -1
- package/dist/tools/files/content.d.ts +0 -58
- package/dist/tools/files/content.js +0 -171
- package/dist/tools/files/content.js.map +0 -1
- package/dist/tools/files/index.d.ts +0 -14
- package/dist/tools/files/index.js +0 -22
- package/dist/tools/files/index.js.map +0 -1
- package/dist/tools/files/list.d.ts +0 -35
- package/dist/tools/files/list.js +0 -133
- package/dist/tools/files/list.js.map +0 -1
- package/dist/tools/index.d.ts +0 -21
- package/dist/tools/index.js +0 -31
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/properties/index.d.ts +0 -14
- package/dist/tools/properties/index.js +0 -19
- package/dist/tools/properties/index.js.map +0 -1
- package/dist/tools/properties/manager.d.ts +0 -62
- package/dist/tools/properties/manager.js +0 -302
- package/dist/tools/properties/manager.js.map +0 -1
- package/dist/tools/properties/tools.d.ts +0 -47
- package/dist/tools/properties/tools.js +0 -239
- package/dist/tools/properties/tools.js.map +0 -1
- package/dist/tools/properties/types.d.ts +0 -141
- package/dist/tools/properties/types.js +0 -70
- package/dist/tools/properties/types.js.map +0 -1
- package/dist/tools/search/complex.d.ts +0 -38
- package/dist/tools/search/complex.js +0 -270
- package/dist/tools/search/complex.js.map +0 -1
- package/dist/tools/search/index.d.ts +0 -14
- package/dist/tools/search/index.js +0 -20
- package/dist/tools/search/index.js.map +0 -1
- package/dist/tools/search/simple.d.ts +0 -25
- package/dist/tools/search/simple.js +0 -127
- package/dist/tools/search/simple.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -24
- package/dist/utils/errors.js +0 -59
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/idGenerator.d.ts +0 -15
- package/dist/utils/idGenerator.js +0 -21
- package/dist/utils/idGenerator.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logging.d.ts +0 -245
- package/dist/utils/logging.js +0 -417
- package/dist/utils/logging.js.map +0 -1
- package/dist/utils/rate-limiting.d.ts +0 -50
- package/dist/utils/rate-limiting.js +0 -94
- package/dist/utils/rate-limiting.js.map +0 -1
- package/dist/utils/tokenization.d.ts +0 -28
- package/dist/utils/tokenization.js +0 -75
- package/dist/utils/tokenization.js.map +0 -1
- package/dist/utils/validation.d.ts +0 -22
- package/dist/utils/validation.js +0 -92
- package/dist/utils/validation.js.map +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { encoding_for_model } from "tiktoken";
|
|
2
|
+
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
3
|
+
// Import utils from the main barrel file (ErrorHandler, logger, RequestContext from ../internal/*)
|
|
4
|
+
import { ErrorHandler, logger } from "../index.js";
|
|
5
|
+
// Define the model used specifically for token counting
|
|
6
|
+
const TOKENIZATION_MODEL = "gpt-4o"; // Note this is strictly for token counting, not the model used for inference
|
|
7
|
+
/**
|
|
8
|
+
* Calculates the number of tokens for a given text using the 'gpt-4o' tokenizer.
|
|
9
|
+
* Uses ErrorHandler for consistent error management.
|
|
10
|
+
*
|
|
11
|
+
* @param text - The input text to tokenize.
|
|
12
|
+
* @param context - Optional request context for logging and error handling.
|
|
13
|
+
* @returns The number of tokens.
|
|
14
|
+
* @throws {McpError} Throws an McpError if tokenization fails.
|
|
15
|
+
*/
|
|
16
|
+
export async function countTokens(text, context) {
|
|
17
|
+
// Wrap the synchronous operation in tryCatch which handles both sync/async
|
|
18
|
+
return ErrorHandler.tryCatch(() => {
|
|
19
|
+
let encoding = null;
|
|
20
|
+
try {
|
|
21
|
+
// Always use the defined TOKENIZATION_MODEL
|
|
22
|
+
encoding = encoding_for_model(TOKENIZATION_MODEL);
|
|
23
|
+
const tokens = encoding.encode(text);
|
|
24
|
+
return tokens.length;
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
encoding?.free(); // Ensure the encoder is freed if it was successfully created
|
|
28
|
+
}
|
|
29
|
+
}, {
|
|
30
|
+
operation: "countTokens",
|
|
31
|
+
context: context,
|
|
32
|
+
input: { textSample: text.substring(0, 50) + "..." }, // Log sanitized input
|
|
33
|
+
errorCode: BaseErrorCode.INTERNAL_ERROR, // Use INTERNAL_ERROR for external lib issues
|
|
34
|
+
// rethrow is implicitly true for tryCatch
|
|
35
|
+
// Removed onErrorReturn as we now rethrow
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the number of tokens for chat messages using the ChatCompletionMessageParam structure
|
|
40
|
+
* and the 'gpt-4o' tokenizer, considering special tokens and message overhead.
|
|
41
|
+
* This implementation is based on OpenAI's guidelines for gpt-4/gpt-3.5-turbo models.
|
|
42
|
+
* Uses ErrorHandler for consistent error management.
|
|
43
|
+
*
|
|
44
|
+
* See: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
|
45
|
+
*
|
|
46
|
+
* @param messages - An array of chat messages in the `ChatCompletionMessageParam` format.
|
|
47
|
+
* @param context - Optional request context for logging and error handling.
|
|
48
|
+
* @returns The estimated number of tokens.
|
|
49
|
+
* @throws {McpError} Throws an McpError if tokenization fails.
|
|
50
|
+
*/
|
|
51
|
+
export async function countChatTokens(messages, // Use the complex type
|
|
52
|
+
context) {
|
|
53
|
+
// Wrap the synchronous operation in tryCatch
|
|
54
|
+
return ErrorHandler.tryCatch(() => {
|
|
55
|
+
let encoding = null;
|
|
56
|
+
let num_tokens = 0;
|
|
57
|
+
try {
|
|
58
|
+
// Always use the defined TOKENIZATION_MODEL
|
|
59
|
+
encoding = encoding_for_model(TOKENIZATION_MODEL);
|
|
60
|
+
// Define tokens per message/name based on gpt-4o (same as gpt-4/gpt-3.5-turbo)
|
|
61
|
+
const tokens_per_message = 3;
|
|
62
|
+
const tokens_per_name = 1;
|
|
63
|
+
for (const message of messages) {
|
|
64
|
+
num_tokens += tokens_per_message;
|
|
65
|
+
// Encode role
|
|
66
|
+
num_tokens += encoding.encode(message.role).length;
|
|
67
|
+
// Encode content - handle potential null or array content (vision)
|
|
68
|
+
if (typeof message.content === "string") {
|
|
69
|
+
num_tokens += encoding.encode(message.content).length;
|
|
70
|
+
}
|
|
71
|
+
else if (Array.isArray(message.content)) {
|
|
72
|
+
// Handle multi-part content (e.g., text + image) - simplified: encode text parts only
|
|
73
|
+
for (const part of message.content) {
|
|
74
|
+
if (part.type === "text") {
|
|
75
|
+
num_tokens += encoding.encode(part.text).length;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Add placeholder token count for non-text parts (e.g., images) if needed
|
|
79
|
+
// This requires specific model knowledge (e.g., OpenAI vision model token costs)
|
|
80
|
+
logger.warning(`Non-text content part found (type: ${part.type}), token count contribution ignored.`, context);
|
|
81
|
+
// num_tokens += IMAGE_TOKEN_COST; // Placeholder
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} // else: content is null, add 0 tokens
|
|
85
|
+
// Encode name if present (often associated with 'tool' or 'function' roles in newer models)
|
|
86
|
+
if ("name" in message && message.name) {
|
|
87
|
+
num_tokens += tokens_per_name;
|
|
88
|
+
num_tokens += encoding.encode(message.name).length;
|
|
89
|
+
}
|
|
90
|
+
// --- Handle tool calls (specific to newer models) ---
|
|
91
|
+
// Assistant message requesting tool calls
|
|
92
|
+
if (message.role === "assistant" &&
|
|
93
|
+
"tool_calls" in message &&
|
|
94
|
+
message.tool_calls) {
|
|
95
|
+
for (const tool_call of message.tool_calls) {
|
|
96
|
+
// Add tokens for the function name and arguments
|
|
97
|
+
if (tool_call.function.name) {
|
|
98
|
+
num_tokens += encoding.encode(tool_call.function.name).length;
|
|
99
|
+
}
|
|
100
|
+
if (tool_call.function.arguments) {
|
|
101
|
+
// Arguments are often JSON strings
|
|
102
|
+
num_tokens += encoding.encode(tool_call.function.arguments).length;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Tool message providing results
|
|
107
|
+
if (message.role === "tool" &&
|
|
108
|
+
"tool_call_id" in message &&
|
|
109
|
+
message.tool_call_id) {
|
|
110
|
+
num_tokens += encoding.encode(message.tool_call_id).length;
|
|
111
|
+
// Content of the tool message (the result) is already handled by the string content check above
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
num_tokens += 3; // every reply is primed with <|start|>assistant<|message|>
|
|
115
|
+
return num_tokens;
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
encoding?.free();
|
|
119
|
+
}
|
|
120
|
+
}, {
|
|
121
|
+
operation: "countChatTokens",
|
|
122
|
+
context: context,
|
|
123
|
+
input: { messageCount: messages.length }, // Log sanitized input
|
|
124
|
+
errorCode: BaseErrorCode.INTERNAL_ERROR, // Use INTERNAL_ERROR
|
|
125
|
+
// rethrow is implicitly true for tryCatch
|
|
126
|
+
// Removed onErrorReturn
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ObsidianApiUtils
|
|
3
|
+
* @description
|
|
4
|
+
* Internal utilities for the Obsidian REST API service.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Encodes a vault-relative file path correctly for API URLs.
|
|
8
|
+
* Ensures path separators '/' are not encoded, but individual components are.
|
|
9
|
+
* Handles leading slashes correctly.
|
|
10
|
+
*
|
|
11
|
+
* @param filePath - The raw vault-relative file path (e.g., "/Notes/My File.md" or "Notes/My File.md").
|
|
12
|
+
* @returns The URL-encoded path suitable for appending to `/vault`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodeVaultPath(filePath: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ObsidianApiUtils
|
|
3
|
+
* @description
|
|
4
|
+
* Internal utilities for the Obsidian REST API service.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Encodes a vault-relative file path correctly for API URLs.
|
|
8
|
+
* Ensures path separators '/' are not encoded, but individual components are.
|
|
9
|
+
* Handles leading slashes correctly.
|
|
10
|
+
*
|
|
11
|
+
* @param filePath - The raw vault-relative file path (e.g., "/Notes/My File.md" or "Notes/My File.md").
|
|
12
|
+
* @returns The URL-encoded path suitable for appending to `/vault`.
|
|
13
|
+
*/
|
|
14
|
+
export function encodeVaultPath(filePath) {
|
|
15
|
+
// 1. Trim whitespace and remove any leading/trailing slashes for consistent processing.
|
|
16
|
+
const trimmedPath = filePath.trim().replace(/^\/+|\/+$/g, "");
|
|
17
|
+
// 2. If the original path was just '/' or empty, return an empty string (represents root for files).
|
|
18
|
+
if (trimmedPath === "") {
|
|
19
|
+
// For file operations, the API expects /vault/filename.md at the root,
|
|
20
|
+
// so an empty encoded path segment is correct here.
|
|
21
|
+
// For listFiles, we handle the root case separately.
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
// 3. Split into components, encode each component, then rejoin with literal '/'.
|
|
25
|
+
const encodedComponents = trimmedPath.split("/").map(encodeURIComponent);
|
|
26
|
+
const encodedPath = encodedComponents.join("/");
|
|
27
|
+
// 4. Prepend the leading slash.
|
|
28
|
+
return `/${encodedPath}`;
|
|
29
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utilities for formatting Obsidian stat objects,
|
|
3
|
+
* including timestamps and calculating estimated token counts.
|
|
4
|
+
* @module src/utils/obsidian/obsidianStatUtils
|
|
5
|
+
*/
|
|
6
|
+
import { RequestContext } from "../internal/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* Formats a Unix timestamp (in milliseconds since the epoch) into a human-readable string.
|
|
9
|
+
*
|
|
10
|
+
* @param {number | undefined | null} timestampMs - The Unix timestamp in milliseconds.
|
|
11
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
12
|
+
* @param {string} [formatString=DEFAULT_TIMESTAMP_FORMAT] - Optional format string adhering to `date-fns` tokens.
|
|
13
|
+
* Defaults to 'hh:mm:ss a | MM-dd-yyyy'.
|
|
14
|
+
* @returns {string} The formatted timestamp string.
|
|
15
|
+
* @throws {McpError} If the provided `timestampMs` is invalid (e.g., undefined, null, not a finite number, or results in an invalid Date object).
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatTimestamp(timestampMs: number | undefined | null, context: RequestContext, formatString?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Represents the structure of an Obsidian API Stat object.
|
|
20
|
+
*/
|
|
21
|
+
export interface ObsidianStat {
|
|
22
|
+
/** Creation time as a Unix timestamp (milliseconds). */
|
|
23
|
+
ctime: number;
|
|
24
|
+
/** Modification time as a Unix timestamp (milliseconds). */
|
|
25
|
+
mtime: number;
|
|
26
|
+
/** File size in bytes. */
|
|
27
|
+
size: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Represents formatted timestamp information derived from an Obsidian Stat object.
|
|
31
|
+
*/
|
|
32
|
+
export interface FormattedTimestamps {
|
|
33
|
+
/** Human-readable creation time string. */
|
|
34
|
+
createdTime: string;
|
|
35
|
+
/** Human-readable modification time string. */
|
|
36
|
+
modifiedTime: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Formats the `ctime` (creation time) and `mtime` (modification time) from an
|
|
40
|
+
* Obsidian API Stat object into human-readable strings.
|
|
41
|
+
*
|
|
42
|
+
* @param {ObsidianStat | undefined | null} stat - The Stat object from the Obsidian API.
|
|
43
|
+
* If undefined or null, placeholder strings ('N/A') are returned.
|
|
44
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
45
|
+
* @returns {FormattedTimestamps} An object containing `createdTime` and `modifiedTime` strings.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatStatTimestamps(stat: ObsidianStat | undefined | null, context: RequestContext): FormattedTimestamps;
|
|
48
|
+
/**
|
|
49
|
+
* Represents a fully formatted stat object, including human-readable timestamps
|
|
50
|
+
* and an estimated token count for the file content.
|
|
51
|
+
*/
|
|
52
|
+
export interface FormattedStatWithTokenCount extends FormattedTimestamps {
|
|
53
|
+
/** Estimated number of tokens in the file content. -1 if counting failed or content was empty. */
|
|
54
|
+
tokenCountEstimate: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates a formatted stat object that includes human-readable timestamps
|
|
58
|
+
* (creation and modification times) and an estimated token count for the provided file content.
|
|
59
|
+
*
|
|
60
|
+
* @param {ObsidianStat | null | undefined} stat - The original Stat object from the Obsidian API.
|
|
61
|
+
* If null or undefined, the function will return the input value (null or undefined).
|
|
62
|
+
* @param {string} content - The file content string from which to calculate the token count.
|
|
63
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
64
|
+
* @returns {Promise<FormattedStatWithTokenCount | null | undefined>} A promise resolving to an object
|
|
65
|
+
* containing `createdTime`, `modifiedTime`, and `tokenCountEstimate`. Returns `null` or `undefined`
|
|
66
|
+
* if the input `stat` object was `null` or `undefined`, respectively.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createFormattedStatWithTokenCount(stat: ObsidianStat | null | undefined, content: string, context: RequestContext): Promise<FormattedStatWithTokenCount | null | undefined>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utilities for formatting Obsidian stat objects,
|
|
3
|
+
* including timestamps and calculating estimated token counts.
|
|
4
|
+
* @module src/utils/obsidian/obsidianStatUtils
|
|
5
|
+
*/
|
|
6
|
+
import { format } from "date-fns";
|
|
7
|
+
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
8
|
+
import { logger } from "../internal/index.js";
|
|
9
|
+
import { countTokens } from "../metrics/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Default format string for timestamps, providing a human-readable date and time.
|
|
12
|
+
* Example output: "08:40:00 PM | 05-02-2025"
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_TIMESTAMP_FORMAT = "hh:mm:ss a | MM-dd-yyyy";
|
|
15
|
+
/**
|
|
16
|
+
* Formats a Unix timestamp (in milliseconds since the epoch) into a human-readable string.
|
|
17
|
+
*
|
|
18
|
+
* @param {number | undefined | null} timestampMs - The Unix timestamp in milliseconds.
|
|
19
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
20
|
+
* @param {string} [formatString=DEFAULT_TIMESTAMP_FORMAT] - Optional format string adhering to `date-fns` tokens.
|
|
21
|
+
* Defaults to 'hh:mm:ss a | MM-dd-yyyy'.
|
|
22
|
+
* @returns {string} The formatted timestamp string.
|
|
23
|
+
* @throws {McpError} If the provided `timestampMs` is invalid (e.g., undefined, null, not a finite number, or results in an invalid Date object).
|
|
24
|
+
*/
|
|
25
|
+
export function formatTimestamp(timestampMs, context, formatString = DEFAULT_TIMESTAMP_FORMAT) {
|
|
26
|
+
const operation = "formatTimestamp";
|
|
27
|
+
if (timestampMs === undefined ||
|
|
28
|
+
timestampMs === null ||
|
|
29
|
+
!Number.isFinite(timestampMs)) {
|
|
30
|
+
const errorMessage = `Invalid timestamp provided for formatting: ${timestampMs}`;
|
|
31
|
+
logger.warning(errorMessage, { ...context, operation });
|
|
32
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, errorMessage, {
|
|
33
|
+
...context,
|
|
34
|
+
operation,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const date = new Date(timestampMs);
|
|
39
|
+
if (isNaN(date.getTime())) {
|
|
40
|
+
const errorMessage = `Timestamp resulted in an invalid date: ${timestampMs}`;
|
|
41
|
+
logger.warning(errorMessage, { ...context, operation });
|
|
42
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, errorMessage, {
|
|
43
|
+
...context,
|
|
44
|
+
operation,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return format(date, formatString);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const errorMessage = `Failed to format timestamp ${timestampMs}: ${error instanceof Error ? error.message : String(error)}`;
|
|
51
|
+
logger.error(errorMessage, error instanceof Error ? error : undefined, {
|
|
52
|
+
...context,
|
|
53
|
+
operation,
|
|
54
|
+
});
|
|
55
|
+
throw new McpError(BaseErrorCode.INTERNAL_ERROR, errorMessage, {
|
|
56
|
+
...context,
|
|
57
|
+
operation,
|
|
58
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Formats the `ctime` (creation time) and `mtime` (modification time) from an
|
|
64
|
+
* Obsidian API Stat object into human-readable strings.
|
|
65
|
+
*
|
|
66
|
+
* @param {ObsidianStat | undefined | null} stat - The Stat object from the Obsidian API.
|
|
67
|
+
* If undefined or null, placeholder strings ('N/A') are returned.
|
|
68
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
69
|
+
* @returns {FormattedTimestamps} An object containing `createdTime` and `modifiedTime` strings.
|
|
70
|
+
*/
|
|
71
|
+
export function formatStatTimestamps(stat, context) {
|
|
72
|
+
const operation = "formatStatTimestamps";
|
|
73
|
+
if (!stat) {
|
|
74
|
+
logger.debug("Stat object is undefined or null, returning N/A for timestamps.", { ...context, operation });
|
|
75
|
+
return {
|
|
76
|
+
createdTime: "N/A",
|
|
77
|
+
modifiedTime: "N/A",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
return {
|
|
82
|
+
createdTime: formatTimestamp(stat.ctime, context),
|
|
83
|
+
modifiedTime: formatTimestamp(stat.mtime, context),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Log the error from formatTimestamp if it occurs during this higher-level operation
|
|
88
|
+
logger.error(`Error formatting timestamps within formatStatTimestamps for ctime: ${stat.ctime}, mtime: ${stat.mtime}`, error instanceof Error ? error : undefined, { ...context, operation });
|
|
89
|
+
// Return N/A as a fallback if formatting fails at this stage
|
|
90
|
+
return {
|
|
91
|
+
createdTime: "N/A",
|
|
92
|
+
modifiedTime: "N/A",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Creates a formatted stat object that includes human-readable timestamps
|
|
98
|
+
* (creation and modification times) and an estimated token count for the provided file content.
|
|
99
|
+
*
|
|
100
|
+
* @param {ObsidianStat | null | undefined} stat - The original Stat object from the Obsidian API.
|
|
101
|
+
* If null or undefined, the function will return the input value (null or undefined).
|
|
102
|
+
* @param {string} content - The file content string from which to calculate the token count.
|
|
103
|
+
* @param {RequestContext} context - The request context for logging and error reporting.
|
|
104
|
+
* @returns {Promise<FormattedStatWithTokenCount | null | undefined>} A promise resolving to an object
|
|
105
|
+
* containing `createdTime`, `modifiedTime`, and `tokenCountEstimate`. Returns `null` or `undefined`
|
|
106
|
+
* if the input `stat` object was `null` or `undefined`, respectively.
|
|
107
|
+
*/
|
|
108
|
+
export async function createFormattedStatWithTokenCount(stat, content, context) {
|
|
109
|
+
const operation = "createFormattedStatWithTokenCount";
|
|
110
|
+
if (stat === null || stat === undefined) {
|
|
111
|
+
logger.debug("Input stat is null or undefined, returning as is.", {
|
|
112
|
+
...context,
|
|
113
|
+
operation,
|
|
114
|
+
});
|
|
115
|
+
return stat; // Return original null/undefined
|
|
116
|
+
}
|
|
117
|
+
const formattedTimestamps = formatStatTimestamps(stat, context);
|
|
118
|
+
let tokenCountEstimate = -1; // Default: indicates error or empty content
|
|
119
|
+
if (content && content.trim().length > 0) {
|
|
120
|
+
try {
|
|
121
|
+
tokenCountEstimate = await countTokens(content, context);
|
|
122
|
+
}
|
|
123
|
+
catch (tokenError) {
|
|
124
|
+
logger.warning(`Failed to count tokens for stat object. Error: ${tokenError instanceof Error ? tokenError.message : String(tokenError)}`, {
|
|
125
|
+
...context,
|
|
126
|
+
operation,
|
|
127
|
+
originalError: tokenError instanceof Error
|
|
128
|
+
? tokenError.message
|
|
129
|
+
: String(tokenError),
|
|
130
|
+
});
|
|
131
|
+
// tokenCountEstimate remains -1
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
logger.debug("Content is empty or whitespace-only, setting tokenCountEstimate to 0.", { ...context, operation });
|
|
136
|
+
tokenCountEstimate = 0;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
createdTime: formattedTimestamps.createdTime,
|
|
140
|
+
modifiedTime: formattedTimestamps.modifiedTime,
|
|
141
|
+
tokenCountEstimate: tokenCountEstimate,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides utilities for parsing natural language date strings
|
|
3
|
+
* into Date objects or detailed parsing results using the 'chrono-node' library.
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
|
+
*/
|
|
6
|
+
import * as chrono from "chrono-node";
|
|
7
|
+
import { RequestContext } from "../internal/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Parses a natural language date string (e.g., "tomorrow", "in 5 days", "2024-01-15")
|
|
10
|
+
* into a JavaScript `Date` object.
|
|
11
|
+
*
|
|
12
|
+
* @async
|
|
13
|
+
* @param {string} text - The natural language date string to parse.
|
|
14
|
+
* @param {RequestContext} context - The request context for logging and error tracking.
|
|
15
|
+
* @param {Date} [refDate] - Optional reference date for parsing relative date expressions.
|
|
16
|
+
* Defaults to the current date and time if not provided.
|
|
17
|
+
* @returns {Promise<Date | null>} A promise that resolves to a `Date` object representing
|
|
18
|
+
* the parsed date, or `null` if `chrono-node` could not parse the input string into a date.
|
|
19
|
+
* @throws {McpError} If an unexpected error occurs during the parsing process,
|
|
20
|
+
* an `McpError` with `BaseErrorCode.PARSING_ERROR` is thrown.
|
|
21
|
+
*/
|
|
22
|
+
declare function parseDateString(text: string, context: RequestContext, refDate?: Date): Promise<Date | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Parses a natural language date string and returns detailed parsing results,
|
|
25
|
+
* including all components and their confidence levels, as provided by `chrono-node`.
|
|
26
|
+
*
|
|
27
|
+
* @async
|
|
28
|
+
* @param {string} text - The natural language date string to parse.
|
|
29
|
+
* @param {RequestContext} context - The request context for logging and error tracking.
|
|
30
|
+
* @param {Date} [refDate] - Optional reference date for parsing relative date expressions.
|
|
31
|
+
* Defaults to the current date and time if not provided.
|
|
32
|
+
* @returns {Promise<chrono.ParsedResult[]>} A promise that resolves to an array of
|
|
33
|
+
* `chrono.ParsedResult` objects. The array will be empty if no date components
|
|
34
|
+
* could be parsed from the input string.
|
|
35
|
+
* @throws {McpError} If an unexpected error occurs during the parsing process,
|
|
36
|
+
* an `McpError` with `BaseErrorCode.PARSING_ERROR` is thrown.
|
|
37
|
+
*/
|
|
38
|
+
declare function parseDateStringDetailed(text: string, context: RequestContext, refDate?: Date): Promise<chrono.ParsedResult[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Provides methods for parsing natural language date strings.
|
|
41
|
+
* - `parseToDate`: Parses a string to a single `Date` object or `null`.
|
|
42
|
+
* - `getDetailedResults`: Provides comprehensive parsing results from `chrono-node`.
|
|
43
|
+
*/
|
|
44
|
+
export declare const dateParser: {
|
|
45
|
+
/**
|
|
46
|
+
* Parses a natural language date string into a `Date` object.
|
|
47
|
+
* @see {@link parseDateString}
|
|
48
|
+
*/
|
|
49
|
+
parseToDate: typeof parseDateString;
|
|
50
|
+
/**
|
|
51
|
+
* Parses a natural language date string and returns detailed `chrono.ParsedResult` objects.
|
|
52
|
+
* @see {@link parseDateStringDetailed}
|
|
53
|
+
*/
|
|
54
|
+
getDetailedResults: typeof parseDateStringDetailed;
|
|
55
|
+
};
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides utilities for parsing natural language date strings
|
|
3
|
+
* into Date objects or detailed parsing results using the 'chrono-node' library.
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
|
+
*/
|
|
6
|
+
import * as chrono from "chrono-node";
|
|
7
|
+
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
8
|
+
import { ErrorHandler, logger } from "../internal/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Parses a natural language date string (e.g., "tomorrow", "in 5 days", "2024-01-15")
|
|
11
|
+
* into a JavaScript `Date` object.
|
|
12
|
+
*
|
|
13
|
+
* @async
|
|
14
|
+
* @param {string} text - The natural language date string to parse.
|
|
15
|
+
* @param {RequestContext} context - The request context for logging and error tracking.
|
|
16
|
+
* @param {Date} [refDate] - Optional reference date for parsing relative date expressions.
|
|
17
|
+
* Defaults to the current date and time if not provided.
|
|
18
|
+
* @returns {Promise<Date | null>} A promise that resolves to a `Date` object representing
|
|
19
|
+
* the parsed date, or `null` if `chrono-node` could not parse the input string into a date.
|
|
20
|
+
* @throws {McpError} If an unexpected error occurs during the parsing process,
|
|
21
|
+
* an `McpError` with `BaseErrorCode.PARSING_ERROR` is thrown.
|
|
22
|
+
*/
|
|
23
|
+
async function parseDateString(text, context, refDate) {
|
|
24
|
+
const operation = "parseDateString";
|
|
25
|
+
// Ensure context for logging includes all relevant details
|
|
26
|
+
const logContext = {
|
|
27
|
+
...context,
|
|
28
|
+
operation,
|
|
29
|
+
inputText: text,
|
|
30
|
+
refDate: refDate?.toISOString(),
|
|
31
|
+
};
|
|
32
|
+
logger.debug(`Attempting to parse date string: "${text}"`, logContext);
|
|
33
|
+
return await ErrorHandler.tryCatch(async () => {
|
|
34
|
+
// chrono.parseDate returns a Date object or null if no date is found.
|
|
35
|
+
const parsedDate = chrono.parseDate(text, refDate, { forwardDate: true });
|
|
36
|
+
if (parsedDate) {
|
|
37
|
+
logger.debug(`Successfully parsed "${text}" to ${parsedDate.toISOString()}`, logContext);
|
|
38
|
+
return parsedDate;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// This is not an error, but chrono-node couldn't find a date.
|
|
42
|
+
logger.info(`Could not parse a date from string: "${text}"`, logContext);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}, {
|
|
46
|
+
operation,
|
|
47
|
+
context: logContext, // Pass the enriched logContext
|
|
48
|
+
input: { text, refDate: refDate?.toISOString() }, // Log refDate as ISO string for consistency
|
|
49
|
+
errorCode: BaseErrorCode.PARSING_ERROR, // Default error code for unexpected parsing failures
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses a natural language date string and returns detailed parsing results,
|
|
54
|
+
* including all components and their confidence levels, as provided by `chrono-node`.
|
|
55
|
+
*
|
|
56
|
+
* @async
|
|
57
|
+
* @param {string} text - The natural language date string to parse.
|
|
58
|
+
* @param {RequestContext} context - The request context for logging and error tracking.
|
|
59
|
+
* @param {Date} [refDate] - Optional reference date for parsing relative date expressions.
|
|
60
|
+
* Defaults to the current date and time if not provided.
|
|
61
|
+
* @returns {Promise<chrono.ParsedResult[]>} A promise that resolves to an array of
|
|
62
|
+
* `chrono.ParsedResult` objects. The array will be empty if no date components
|
|
63
|
+
* could be parsed from the input string.
|
|
64
|
+
* @throws {McpError} If an unexpected error occurs during the parsing process,
|
|
65
|
+
* an `McpError` with `BaseErrorCode.PARSING_ERROR` is thrown.
|
|
66
|
+
*/
|
|
67
|
+
async function parseDateStringDetailed(text, context, refDate) {
|
|
68
|
+
const operation = "parseDateStringDetailed";
|
|
69
|
+
const logContext = {
|
|
70
|
+
...context,
|
|
71
|
+
operation,
|
|
72
|
+
inputText: text,
|
|
73
|
+
refDate: refDate?.toISOString(),
|
|
74
|
+
};
|
|
75
|
+
logger.debug(`Attempting detailed parse of date string: "${text}"`, logContext);
|
|
76
|
+
return await ErrorHandler.tryCatch(async () => {
|
|
77
|
+
// chrono.parse returns an array of results.
|
|
78
|
+
const results = chrono.parse(text, refDate, { forwardDate: true });
|
|
79
|
+
logger.debug(`Detailed parse of "${text}" resulted in ${results.length} result(s).`, logContext);
|
|
80
|
+
return results;
|
|
81
|
+
}, {
|
|
82
|
+
operation,
|
|
83
|
+
context: logContext,
|
|
84
|
+
input: { text, refDate: refDate?.toISOString() },
|
|
85
|
+
errorCode: BaseErrorCode.PARSING_ERROR,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Provides methods for parsing natural language date strings.
|
|
90
|
+
* - `parseToDate`: Parses a string to a single `Date` object or `null`.
|
|
91
|
+
* - `getDetailedResults`: Provides comprehensive parsing results from `chrono-node`.
|
|
92
|
+
*/
|
|
93
|
+
export const dateParser = {
|
|
94
|
+
/**
|
|
95
|
+
* Parses a natural language date string into a `Date` object.
|
|
96
|
+
* @see {@link parseDateString}
|
|
97
|
+
*/
|
|
98
|
+
parseToDate: parseDateString,
|
|
99
|
+
/**
|
|
100
|
+
* Parses a natural language date string and returns detailed `chrono.ParsedResult` objects.
|
|
101
|
+
* @see {@link parseDateStringDetailed}
|
|
102
|
+
*/
|
|
103
|
+
getDetailedResults: parseDateStringDetailed,
|
|
104
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a utility class for parsing potentially partial JSON strings,
|
|
3
|
+
* with support for handling and logging optional LLM <think> blocks.
|
|
4
|
+
* It wraps the 'partial-json' library.
|
|
5
|
+
* @module src/utils/parsing/jsonParser
|
|
6
|
+
*/
|
|
7
|
+
import { RequestContext } from "../internal/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Enum mirroring `partial-json`'s `Allow` constants. These constants specify
|
|
10
|
+
* what types of partial JSON structures are permissible during parsing.
|
|
11
|
+
* They can be combined using bitwise OR (e.g., `Allow.STR | Allow.OBJ`).
|
|
12
|
+
*
|
|
13
|
+
* - `Allow.OBJ`: Allows partial objects (e.g., `{"key": "value",`)
|
|
14
|
+
* - `Allow.ARR`: Allows partial arrays (e.g., `[1, 2,`)
|
|
15
|
+
* - `Allow.STR`: Allows partial strings (e.g., `"abc`)
|
|
16
|
+
* - `Allow.NUM`: Allows partial numbers (e.g., `1.2e+`)
|
|
17
|
+
* - `Allow.BOOL`: Allows partial booleans (e.g., `tru`)
|
|
18
|
+
* - `Allow.NULL`: Allows partial nulls (e.g., `nul`)
|
|
19
|
+
* - `Allow.ALL`: Allows all types of partial JSON structures (default).
|
|
20
|
+
*/
|
|
21
|
+
export declare const Allow: {
|
|
22
|
+
STR: number;
|
|
23
|
+
NUM: number;
|
|
24
|
+
ARR: number;
|
|
25
|
+
OBJ: number;
|
|
26
|
+
NULL: number;
|
|
27
|
+
BOOL: number;
|
|
28
|
+
NAN: number;
|
|
29
|
+
INFINITY: number;
|
|
30
|
+
_INFINITY: number;
|
|
31
|
+
INF: number;
|
|
32
|
+
SPECIAL: number;
|
|
33
|
+
ATOM: number;
|
|
34
|
+
COLLECTION: number;
|
|
35
|
+
ALL: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Utility class for parsing JSON strings that may be partial or incomplete.
|
|
39
|
+
* It wraps the 'partial-json' library to provide a consistent parsing interface
|
|
40
|
+
* and includes logic to handle and log optional `<think>...</think>` blocks
|
|
41
|
+
* that might precede the JSON content (often found in LLM outputs).
|
|
42
|
+
*/
|
|
43
|
+
declare class JsonParser {
|
|
44
|
+
/**
|
|
45
|
+
* Parses a JSON string, which may be partial or prefixed with an LLM `<think>` block.
|
|
46
|
+
*
|
|
47
|
+
* @template T The expected type of the parsed JavaScript value. Defaults to `any`.
|
|
48
|
+
* @param {string} jsonString - The JSON string to parse.
|
|
49
|
+
* @param {number} [allowPartial=Allow.ALL] - A bitwise OR combination of `Allow` constants
|
|
50
|
+
* specifying which types of partial JSON structures are permissible (e.g., `Allow.OBJ | Allow.ARR`).
|
|
51
|
+
* Defaults to `Allow.ALL`, permitting any form of partial JSON.
|
|
52
|
+
* @param {RequestContext} [providedContext] - Optional `RequestContext` for logging,
|
|
53
|
+
* especially for capturing `<think>` block content or parsing errors.
|
|
54
|
+
* @returns {T} The parsed JavaScript value.
|
|
55
|
+
* @throws {McpError} Throws an `McpError` with `BaseErrorCode.VALIDATION_ERROR` if:
|
|
56
|
+
* - The string is empty after removing a `<think>` block.
|
|
57
|
+
* - The remaining content does not appear to be a valid JSON structure (object, array, or permitted primitive).
|
|
58
|
+
* - The `partial-json` library encounters a parsing error.
|
|
59
|
+
*/
|
|
60
|
+
parse<T = any>(jsonString: string, allowPartial?: number, providedContext?: RequestContext): T;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Singleton instance of the `JsonParser`.
|
|
64
|
+
* Use this instance for all partial JSON parsing needs.
|
|
65
|
+
*
|
|
66
|
+
* Example:
|
|
67
|
+
* ```typescript
|
|
68
|
+
* import { jsonParser, Allow, RequestContext } from './jsonParser';
|
|
69
|
+
* import { requestContextService } from '../internal'; // Assuming requestContextService is exported from internal utils
|
|
70
|
+
* const context: RequestContext = requestContextService.createRequestContext({ operation: 'MyOperation' });
|
|
71
|
+
* try {
|
|
72
|
+
* const data = jsonParser.parse('<think>Thinking...</think>{"key": "value", "arr": [1,', Allow.ALL, context);
|
|
73
|
+
* console.log(data); // Output: { key: "value", arr: [ 1 ] }
|
|
74
|
+
* } catch (e) {
|
|
75
|
+
* console.error("Parsing failed:", e);
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare const jsonParser: JsonParser;
|
|
80
|
+
export {};
|