tiddlywiki-mcp-server 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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/embeddings/database.d.ts +53 -0
  4. package/dist/embeddings/database.d.ts.map +1 -0
  5. package/dist/embeddings/database.js +212 -0
  6. package/dist/embeddings/database.js.map +1 -0
  7. package/dist/embeddings/ollama-client.d.ts +39 -0
  8. package/dist/embeddings/ollama-client.d.ts.map +1 -0
  9. package/dist/embeddings/ollama-client.js +190 -0
  10. package/dist/embeddings/ollama-client.js.map +1 -0
  11. package/dist/embeddings/sync-worker.d.ts +49 -0
  12. package/dist/embeddings/sync-worker.d.ts.map +1 -0
  13. package/dist/embeddings/sync-worker.js +244 -0
  14. package/dist/embeddings/sync-worker.js.map +1 -0
  15. package/dist/filter-reference.d.ts +8 -0
  16. package/dist/filter-reference.d.ts.map +1 -0
  17. package/dist/filter-reference.js +159 -0
  18. package/dist/filter-reference.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +450 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/logger.d.ts +17 -0
  24. package/dist/logger.d.ts.map +1 -0
  25. package/dist/logger.js +33 -0
  26. package/dist/logger.js.map +1 -0
  27. package/dist/service-discovery.d.ts +24 -0
  28. package/dist/service-discovery.d.ts.map +1 -0
  29. package/dist/service-discovery.js +82 -0
  30. package/dist/service-discovery.js.map +1 -0
  31. package/dist/tiddlywiki-http.d.ts +55 -0
  32. package/dist/tiddlywiki-http.d.ts.map +1 -0
  33. package/dist/tiddlywiki-http.js +253 -0
  34. package/dist/tiddlywiki-http.js.map +1 -0
  35. package/dist/tools/create-tiddler.d.ts +15 -0
  36. package/dist/tools/create-tiddler.d.ts.map +1 -0
  37. package/dist/tools/create-tiddler.js +61 -0
  38. package/dist/tools/create-tiddler.js.map +1 -0
  39. package/dist/tools/delete-tiddler.d.ts +9 -0
  40. package/dist/tools/delete-tiddler.d.ts.map +1 -0
  41. package/dist/tools/delete-tiddler.js +40 -0
  42. package/dist/tools/delete-tiddler.js.map +1 -0
  43. package/dist/tools/index.d.ts +6 -0
  44. package/dist/tools/index.d.ts.map +1 -0
  45. package/dist/tools/index.js +7 -0
  46. package/dist/tools/index.js.map +1 -0
  47. package/dist/tools/search-tiddlers.d.ts +12 -0
  48. package/dist/tools/search-tiddlers.d.ts.map +1 -0
  49. package/dist/tools/search-tiddlers.js +189 -0
  50. package/dist/tools/search-tiddlers.js.map +1 -0
  51. package/dist/tools/types.d.ts +101 -0
  52. package/dist/tools/types.d.ts.map +1 -0
  53. package/dist/tools/types.js +55 -0
  54. package/dist/tools/types.js.map +1 -0
  55. package/dist/tools/update-tiddler.d.ts +9 -0
  56. package/dist/tools/update-tiddler.d.ts.map +1 -0
  57. package/dist/tools/update-tiddler.js +90 -0
  58. package/dist/tools/update-tiddler.js.map +1 -0
  59. package/package.json +67 -0
package/dist/logger.js ADDED
@@ -0,0 +1,33 @@
1
+ // ABOUTME: Logging utility with timestamps and debug mode support
2
+ // ABOUTME: Set LOG_DEBUG=true to enable verbose debug logging
3
+ const DEBUG_ENABLED = process.env.LOG_DEBUG === 'true';
4
+ function getTimestamp() {
5
+ return new Date().toISOString();
6
+ }
7
+ /**
8
+ * Log informational messages (always shown)
9
+ */
10
+ export function log(message, ...args) {
11
+ console.log(`[${getTimestamp()}]`, message, ...args);
12
+ }
13
+ /**
14
+ * Log error messages (always shown)
15
+ */
16
+ export function error(message, ...args) {
17
+ console.error(`[${getTimestamp()}]`, message, ...args);
18
+ }
19
+ /**
20
+ * Log warning messages (always shown)
21
+ */
22
+ export function warn(message, ...args) {
23
+ console.warn(`[${getTimestamp()}]`, message, ...args);
24
+ }
25
+ /**
26
+ * Log debug messages (only shown when LOG_DEBUG=true)
27
+ */
28
+ export function debug(message, ...args) {
29
+ if (DEBUG_ENABLED) {
30
+ console.log(`[${getTimestamp()}] [DEBUG]`, message, ...args);
31
+ }
32
+ }
33
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,8DAA8D;AAE9D,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC;AAEvD,SAAS,YAAY;IACnB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,GAAG,IAAe;IACrD,OAAO,CAAC,GAAG,CAAC,IAAI,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,GAAG,IAAe;IACvD,OAAO,CAAC,KAAK,CAAC,IAAI,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe,EAAE,GAAG,IAAe;IACtD,OAAO,CAAC,IAAI,CAAC,IAAI,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,GAAG,IAAe;IACvD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,IAAI,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface ServiceEndpoint {
2
+ host: string;
3
+ port: number;
4
+ }
5
+ /**
6
+ * Resolve a Consul service name to host and port via SRV record
7
+ * @param serviceName - Consul service name (e.g., "wiki.service.consul")
8
+ * @returns Service endpoint with host and port
9
+ */
10
+ export declare function resolveConsulService(serviceName: string): Promise<ServiceEndpoint>;
11
+ /**
12
+ * Build HTTP URL from a service URL, Consul service name, or hostname:port
13
+ *
14
+ * Supports three formats:
15
+ * - Full URL: "http://localhost:8080" or "https://wiki.example.com" -> used directly
16
+ * - Consul service: "wiki.service.consul" -> resolved via SRV DNS
17
+ * - Hostname:port: "localhost:8080" -> prepended with http://
18
+ *
19
+ * @param serviceOrUrl - URL, Consul service name, or hostname:port
20
+ * @param path - Optional path to append
21
+ * @returns Full HTTP URL
22
+ */
23
+ export declare function getServiceUrl(serviceOrUrl: string, path?: string): Promise<string>;
24
+ //# sourceMappingURL=service-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-discovery.d.ts","sourceRoot":"","sources":["../src/service-discovery.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAYD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgDxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB5F"}
@@ -0,0 +1,82 @@
1
+ // ABOUTME: Service discovery module for resolving TiddlyWiki server URLs
2
+ // ABOUTME: Supports direct URLs, Consul SRV DNS, and hostname:port formats
3
+ import { promises as dns } from 'dns';
4
+ import * as logger from './logger.js';
5
+ // DNS resolution timeout (10 seconds)
6
+ const DNS_TIMEOUT = 10000;
7
+ /**
8
+ * Wrap a promise with a timeout
9
+ */
10
+ async function withTimeout(promise, ms, errorMsg) {
11
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(errorMsg)), ms));
12
+ return Promise.race([promise, timeout]);
13
+ }
14
+ /**
15
+ * Resolve a Consul service name to host and port via SRV record
16
+ * @param serviceName - Consul service name (e.g., "wiki.service.consul")
17
+ * @returns Service endpoint with host and port
18
+ */
19
+ export async function resolveConsulService(serviceName) {
20
+ try {
21
+ logger.debug(`[ServiceDiscovery] Resolving SRV record for ${serviceName}...`);
22
+ // Resolve SRV record using Node.js DNS with timeout
23
+ const srvRecords = await withTimeout(dns.resolveSrv(serviceName), DNS_TIMEOUT, `DNS SRV resolution timed out for ${serviceName} after ${DNS_TIMEOUT}ms`);
24
+ if (!srvRecords || srvRecords.length === 0) {
25
+ throw new Error(`No SRV records found for ${serviceName}`);
26
+ }
27
+ // Use the first SRV record (could be enhanced with priority/weight sorting)
28
+ const srv = srvRecords[0];
29
+ const port = srv.port;
30
+ const hostname = srv.name;
31
+ // Resolve the hostname to IP address with timeout
32
+ try {
33
+ const addresses = await withTimeout(dns.resolve4(hostname), DNS_TIMEOUT, `DNS A record resolution timed out for ${hostname} after ${DNS_TIMEOUT}ms`);
34
+ if (!addresses || addresses.length === 0) {
35
+ // If A record resolution fails, try using the hostname as-is
36
+ logger.warn(`[ServiceDiscovery] Could not resolve ${hostname}, using as-is`);
37
+ return { host: hostname, port };
38
+ }
39
+ const host = addresses[0];
40
+ logger.debug(`[ServiceDiscovery] Resolved ${serviceName} -> ${host}:${port}`);
41
+ return { host, port };
42
+ }
43
+ catch (addrError) {
44
+ // If A record resolution fails (including timeout), try using the hostname as-is
45
+ const errMsg = addrError instanceof Error ? addrError.message : String(addrError);
46
+ logger.warn(`[ServiceDiscovery] Could not resolve ${hostname}: ${errMsg}, using as-is`);
47
+ return { host: hostname, port };
48
+ }
49
+ }
50
+ catch (error) {
51
+ const err = error;
52
+ throw new Error(`Failed to resolve Consul service ${serviceName}: ${err.message}`);
53
+ }
54
+ }
55
+ /**
56
+ * Build HTTP URL from a service URL, Consul service name, or hostname:port
57
+ *
58
+ * Supports three formats:
59
+ * - Full URL: "http://localhost:8080" or "https://wiki.example.com" -> used directly
60
+ * - Consul service: "wiki.service.consul" -> resolved via SRV DNS
61
+ * - Hostname:port: "localhost:8080" -> prepended with http://
62
+ *
63
+ * @param serviceOrUrl - URL, Consul service name, or hostname:port
64
+ * @param path - Optional path to append
65
+ * @returns Full HTTP URL
66
+ */
67
+ export async function getServiceUrl(serviceOrUrl, path = '') {
68
+ const basePath = path ? (path.startsWith('/') ? path : `/${path}`) : '';
69
+ // If already a full URL, use it directly
70
+ if (serviceOrUrl.startsWith('http://') || serviceOrUrl.startsWith('https://')) {
71
+ const base = serviceOrUrl.replace(/\/$/, ''); // trim trailing slash
72
+ return `${base}${basePath}`;
73
+ }
74
+ // If it looks like a Consul service name, resolve via SRV
75
+ if (serviceOrUrl.includes('.service.consul')) {
76
+ const endpoint = await resolveConsulService(serviceOrUrl);
77
+ return `http://${endpoint.host}:${endpoint.port}${basePath}`;
78
+ }
79
+ // Otherwise treat as hostname:port
80
+ return `http://${serviceOrUrl}${basePath}`;
81
+ }
82
+ //# sourceMappingURL=service-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-discovery.js","sourceRoot":"","sources":["../src/service-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ export interface Tiddler {
2
+ title: string;
3
+ text?: string;
4
+ type?: string;
5
+ tags?: string;
6
+ created?: string;
7
+ creator?: string;
8
+ modified?: string;
9
+ modifier?: string;
10
+ revision?: number;
11
+ bag?: string;
12
+ [key: string]: any;
13
+ }
14
+ export interface TiddlyWikiConfig {
15
+ tiddlywikiUrl: string;
16
+ authHeader: string;
17
+ authUser: string;
18
+ }
19
+ /**
20
+ * Initialize the TiddlyWiki HTTP client
21
+ */
22
+ export declare function initTiddlyWiki(cfg: TiddlyWikiConfig): void;
23
+ /**
24
+ * Get the configured auth user
25
+ */
26
+ export declare function getAuthUser(): string;
27
+ /**
28
+ * Query tiddlers using filter syntax
29
+ */
30
+ export declare function queryTiddlers(filter: string, includeText?: boolean, offset?: number, limit?: number): Promise<Tiddler[]>;
31
+ /**
32
+ * Get a single tiddler by title
33
+ */
34
+ export declare function getTiddler(title: string): Promise<Tiddler | null>;
35
+ /**
36
+ * Create or update a tiddler
37
+ */
38
+ export declare function putTiddler(tiddler: Tiddler): Promise<void>;
39
+ /**
40
+ * Delete a tiddler
41
+ */
42
+ export declare function deleteTiddler(title: string): Promise<void>;
43
+ /**
44
+ * Generate a TiddlyWiki timestamp (YYYYMMDDhhmmssSSS format)
45
+ */
46
+ export declare function generateTimestamp(date?: Date): string;
47
+ /**
48
+ * Create a new tiddler with proper defaults
49
+ */
50
+ export declare function createTiddlerObject(title: string, text: string, tags: string | undefined, type: string | undefined, creator: string): Tiddler;
51
+ /**
52
+ * Update an existing tiddler while preserving metadata
53
+ */
54
+ export declare function updateTiddlerObject(current: Tiddler, updates: Partial<Tiddler>, modifier: string): Tiddler;
55
+ //# sourceMappingURL=tiddlywiki-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiddlywiki-http.d.ts","sourceRoot":"","sources":["../src/tiddlywiki-http.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAUD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAG1D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AA6DD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,OAAe,EAC5B,MAAM,GAAE,MAAU,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,EAAE,CAAC,CAyDpB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA8BvE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoChE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAYjE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,YAAK,EACjB,IAAI,EAAE,MAAM,YAAkB,EAC9B,OAAO,EAAE,MAAM,GACd,OAAO,CAST;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EACzB,QAAQ,EAAE,MAAM,GACf,OAAO,CAeT"}
@@ -0,0 +1,253 @@
1
+ // ABOUTME: HTTP client for TiddlyWiki server communication
2
+ // ABOUTME: Handles tiddler CRUD operations with proper metadata preservation
3
+ import { getServiceUrl } from './service-discovery.js';
4
+ import * as logger from './logger.js';
5
+ // Timeout configuration (in milliseconds)
6
+ const TIMEOUT_READ = 30000; // 30 seconds for read operations
7
+ const TIMEOUT_WRITE = 60000; // 60 seconds for write operations
8
+ /**
9
+ * Fetch with timeout using AbortController
10
+ */
11
+ async function fetchWithTimeout(url, options, timeoutMs, operationName) {
12
+ const controller = new AbortController();
13
+ const timeoutId = setTimeout(() => {
14
+ logger.warn(`[TiddlyWiki HTTP] ${operationName} timed out after ${timeoutMs}ms`);
15
+ controller.abort();
16
+ }, timeoutMs);
17
+ try {
18
+ const response = await fetch(url, { ...options, signal: controller.signal });
19
+ return response;
20
+ }
21
+ catch (error) {
22
+ if (error instanceof Error && error.name === 'AbortError') {
23
+ throw new Error(`${operationName} timed out after ${timeoutMs}ms`);
24
+ }
25
+ throw error;
26
+ }
27
+ finally {
28
+ clearTimeout(timeoutId);
29
+ }
30
+ }
31
+ let config = null;
32
+ let baseUrlCache = null;
33
+ let cacheTime = 0;
34
+ const CACHE_TTL = 60000; // 1 minute
35
+ // Mutex for base URL resolution to prevent duplicate DNS lookups
36
+ let pendingResolution = null;
37
+ /**
38
+ * Initialize the TiddlyWiki HTTP client
39
+ */
40
+ export function initTiddlyWiki(cfg) {
41
+ config = cfg;
42
+ logger.log('[TiddlyWiki HTTP] Initialized with URL:', cfg.tiddlywikiUrl);
43
+ }
44
+ /**
45
+ * Get the configured auth user
46
+ */
47
+ export function getAuthUser() {
48
+ if (!config) {
49
+ throw new Error('TiddlyWiki client not initialized');
50
+ }
51
+ return config.authUser;
52
+ }
53
+ /**
54
+ * Get the base URL for TiddlyWiki API, with caching and mutex.
55
+ *
56
+ * Uses a mutex to prevent duplicate DNS lookups when multiple concurrent
57
+ * requests arrive while the cache is stale. The first request initiates
58
+ * resolution, subsequent requests await the same promise.
59
+ */
60
+ async function getBaseUrl() {
61
+ if (!config) {
62
+ throw new Error('TiddlyWiki client not initialized');
63
+ }
64
+ const now = Date.now();
65
+ // Return cached value if still valid
66
+ if (baseUrlCache && now - cacheTime < CACHE_TTL) {
67
+ return baseUrlCache;
68
+ }
69
+ // If resolution is already in progress, wait for it
70
+ if (pendingResolution) {
71
+ return pendingResolution;
72
+ }
73
+ // Start new resolution with mutex
74
+ pendingResolution = (async () => {
75
+ try {
76
+ const url = await getServiceUrl(config.tiddlywikiUrl, '');
77
+ baseUrlCache = url;
78
+ cacheTime = Date.now();
79
+ return url;
80
+ }
81
+ finally {
82
+ pendingResolution = null;
83
+ }
84
+ })();
85
+ return pendingResolution;
86
+ }
87
+ /**
88
+ * Get common headers for TiddlyWiki API requests
89
+ */
90
+ function getHeaders(includeJson = false) {
91
+ if (!config) {
92
+ throw new Error('TiddlyWiki client not initialized');
93
+ }
94
+ const headers = {
95
+ [config.authHeader]: config.authUser,
96
+ };
97
+ if (includeJson) {
98
+ headers['Content-Type'] = 'application/json';
99
+ headers['x-requested-with'] = 'TiddlyWiki';
100
+ }
101
+ return headers;
102
+ }
103
+ /**
104
+ * Query tiddlers using filter syntax
105
+ */
106
+ export async function queryTiddlers(filter, includeText = false, offset = 0, limit) {
107
+ const baseUrl = await getBaseUrl();
108
+ const encodedFilter = encodeURIComponent(filter);
109
+ const url = `${baseUrl}/recipes/default/tiddlers.json?filter=${encodedFilter}`;
110
+ const filterPreview = filter.length > 80 ? filter.substring(0, 80) + '...' : filter;
111
+ logger.debug(`[TiddlyWiki HTTP] queryTiddlers: filter="${filterPreview}" includeText=${includeText}`);
112
+ const response = await fetchWithTimeout(url, { method: 'GET', headers: getHeaders() }, TIMEOUT_READ, `queryTiddlers(filter="${filterPreview}")`);
113
+ if (!response.ok) {
114
+ const errorBody = await response.text().catch(() => '(no body)');
115
+ logger.error(`[TiddlyWiki HTTP] queryTiddlers failed: ${response.status} ${response.statusText} - ${errorBody}`);
116
+ throw new Error(`Failed to query tiddlers: ${response.status} ${response.statusText}`);
117
+ }
118
+ let tiddlers = (await response.json());
119
+ logger.debug(`[TiddlyWiki HTTP] queryTiddlers: ${tiddlers.length} tiddlers matched`);
120
+ // Apply offset and limit BEFORE fetching full content (optimization)
121
+ const endIndex = limit !== undefined ? offset + limit : undefined;
122
+ tiddlers = tiddlers.slice(offset, endIndex);
123
+ // If includeText is false, the API already excludes text by default
124
+ // If includeText is true, we need to fetch each tiddler individually
125
+ if (includeText && tiddlers.length > 0) {
126
+ logger.debug(`[TiddlyWiki HTTP] Fetching full content for ${tiddlers.length} tiddlers...`);
127
+ // Use Promise.allSettled to avoid cascade failures
128
+ const results = await Promise.allSettled(tiddlers.map((t) => getTiddler(t.title)));
129
+ const successful = results
130
+ .filter((r) => r.status === 'fulfilled')
131
+ .map((r) => r.value)
132
+ .filter((t) => t !== null);
133
+ const failed = results.filter((r) => r.status === 'rejected').length;
134
+ if (failed > 0) {
135
+ logger.warn(`[TiddlyWiki HTTP] ${failed}/${tiddlers.length} tiddlers failed to fetch`);
136
+ }
137
+ logger.debug(`[TiddlyWiki HTTP] Successfully fetched ${successful.length} tiddlers with content`);
138
+ return successful;
139
+ }
140
+ return tiddlers;
141
+ }
142
+ /**
143
+ * Get a single tiddler by title
144
+ */
145
+ export async function getTiddler(title) {
146
+ const baseUrl = await getBaseUrl();
147
+ const encodedTitle = encodeURIComponent(title);
148
+ const url = `${baseUrl}/recipes/default/tiddlers/${encodedTitle}`;
149
+ const titlePreview = title.length > 50 ? title.substring(0, 50) + '...' : title;
150
+ logger.debug(`[TiddlyWiki HTTP] getTiddler: "${titlePreview}"`);
151
+ const response = await fetchWithTimeout(url, { method: 'GET', headers: getHeaders() }, TIMEOUT_READ, `getTiddler("${titlePreview}")`);
152
+ if (response.status === 404) {
153
+ logger.debug(`[TiddlyWiki HTTP] getTiddler: "${titlePreview}" not found (404)`);
154
+ return null;
155
+ }
156
+ if (!response.ok) {
157
+ const errorBody = await response.text().catch(() => '(no body)');
158
+ logger.error(`[TiddlyWiki HTTP] getTiddler failed: ${response.status} ${response.statusText} - ${errorBody}`);
159
+ throw new Error(`Failed to get tiddler "${title}": ${response.status} ${response.statusText}`);
160
+ }
161
+ logger.debug(`[TiddlyWiki HTTP] getTiddler: "${titlePreview}" OK`);
162
+ return (await response.json());
163
+ }
164
+ /**
165
+ * Create or update a tiddler
166
+ */
167
+ export async function putTiddler(tiddler) {
168
+ const baseUrl = await getBaseUrl();
169
+ const encodedTitle = encodeURIComponent(tiddler.title);
170
+ const url = `${baseUrl}/recipes/default/tiddlers/${encodedTitle}`;
171
+ // Remove server-managed fields (but keep modified/modifier which we set explicitly)
172
+ const { revision, bag, ...tiddlerFields } = tiddler;
173
+ const titlePreview = tiddler.title.length > 50 ? tiddler.title.substring(0, 50) + '...' : tiddler.title;
174
+ logger.debug(`[TiddlyWiki HTTP] putTiddler: "${titlePreview}" (${JSON.stringify(tiddlerFields).length} bytes)`);
175
+ const response = await fetchWithTimeout(url, {
176
+ method: 'PUT',
177
+ headers: getHeaders(true),
178
+ body: JSON.stringify(tiddlerFields),
179
+ }, TIMEOUT_WRITE, `putTiddler("${titlePreview}")`);
180
+ if (!response.ok) {
181
+ const errorBody = await response.text().catch(() => '(no body)');
182
+ logger.error(`[TiddlyWiki HTTP] putTiddler failed: ${response.status} ${response.statusText} - ${errorBody}`);
183
+ throw new Error(`Failed to put tiddler "${tiddler.title}": ${response.status} ${response.statusText} - ${errorBody}`);
184
+ }
185
+ logger.debug(`[TiddlyWiki HTTP] putTiddler: "${titlePreview}" OK (${response.status})`);
186
+ }
187
+ /**
188
+ * Delete a tiddler
189
+ */
190
+ export async function deleteTiddler(title) {
191
+ const baseUrl = await getBaseUrl();
192
+ const encodedTitle = encodeURIComponent(title);
193
+ const url = `${baseUrl}/bags/default/tiddlers/${encodedTitle}`;
194
+ const titlePreview = title.length > 50 ? title.substring(0, 50) + '...' : title;
195
+ logger.debug(`[TiddlyWiki HTTP] deleteTiddler: "${titlePreview}"`);
196
+ const response = await fetchWithTimeout(url, {
197
+ method: 'DELETE',
198
+ headers: getHeaders(true),
199
+ }, TIMEOUT_WRITE, `deleteTiddler("${titlePreview}")`);
200
+ if (!response.ok) {
201
+ const errorBody = await response.text().catch(() => '(no body)');
202
+ logger.error(`[TiddlyWiki HTTP] deleteTiddler failed: ${response.status} ${response.statusText} - ${errorBody}`);
203
+ throw new Error(`Failed to delete tiddler "${title}": ${response.status} ${response.statusText} - ${errorBody}`);
204
+ }
205
+ logger.debug(`[TiddlyWiki HTTP] deleteTiddler: "${titlePreview}" OK (${response.status})`);
206
+ }
207
+ /**
208
+ * Generate a TiddlyWiki timestamp (YYYYMMDDhhmmssSSS format)
209
+ */
210
+ export function generateTimestamp(date = new Date()) {
211
+ const pad = (n, width = 2) => n.toString().padStart(width, '0');
212
+ const year = date.getUTCFullYear();
213
+ const month = pad(date.getUTCMonth() + 1);
214
+ const day = pad(date.getUTCDate());
215
+ const hours = pad(date.getUTCHours());
216
+ const minutes = pad(date.getUTCMinutes());
217
+ const seconds = pad(date.getUTCSeconds());
218
+ const millis = pad(date.getUTCMilliseconds(), 3);
219
+ return `${year}${month}${day}${hours}${minutes}${seconds}${millis}`;
220
+ }
221
+ /**
222
+ * Create a new tiddler with proper defaults
223
+ */
224
+ export function createTiddlerObject(title, text, tags = '', type = 'text/markdown', creator) {
225
+ return {
226
+ title,
227
+ text,
228
+ type,
229
+ tags,
230
+ created: generateTimestamp(),
231
+ creator,
232
+ };
233
+ }
234
+ /**
235
+ * Update an existing tiddler while preserving metadata
236
+ */
237
+ export function updateTiddlerObject(current, updates, modifier) {
238
+ return {
239
+ ...current,
240
+ ...updates,
241
+ // Always preserve these fields from the current tiddler
242
+ title: current.title,
243
+ created: current.created,
244
+ creator: current.creator,
245
+ // Set modification metadata
246
+ modified: generateTimestamp(),
247
+ modifier,
248
+ // Remove server-managed fields
249
+ revision: undefined,
250
+ bag: undefined,
251
+ };
252
+ }
253
+ //# sourceMappingURL=tiddlywiki-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiddlywiki-http.js","sourceRoot":"","sources":["../src/tiddlywiki-http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type Tiddler } from '../tiddlywiki-http.js';
2
+ import type { ToolResult } from './types.js';
3
+ import { CreateTiddlerInput } from './types.js';
4
+ /**
5
+ * Format a tiddler for preview display.
6
+ * Exported for use by delete-tiddler handler.
7
+ */
8
+ export declare function formatTiddlerPreview(tiddler: Tiddler): string;
9
+ /**
10
+ * Handle create_tiddler tool requests.
11
+ * Checks for duplicates, creates the tiddler, and returns a preview.
12
+ */
13
+ export declare function handleCreateTiddler(args: unknown): Promise<ToolResult>;
14
+ export { CreateTiddlerInput };
15
+ //# sourceMappingURL=create-tiddler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-tiddler.d.ts","sourceRoot":"","sources":["../../src/tools/create-tiddler.ts"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAa7D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA0C5E;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,61 @@
1
+ // ABOUTME: Handler for the create_tiddler MCP tool
2
+ // ABOUTME: Creates new tiddlers with preview and custom field support
3
+ import { getTiddler, putTiddler, createTiddlerObject, getAuthUser, } from '../tiddlywiki-http.js';
4
+ import { CreateTiddlerInput } from './types.js';
5
+ /**
6
+ * Format a tiddler for preview display.
7
+ * Exported for use by delete-tiddler handler.
8
+ */
9
+ export function formatTiddlerPreview(tiddler) {
10
+ const lines = [];
11
+ lines.push(`**Title:** ${tiddler.title}`);
12
+ lines.push(`**Type:** ${tiddler.type || 'text/vnd.tiddlywiki'}`);
13
+ lines.push(`**Tags:** ${tiddler.tags || '(none)'}`);
14
+ lines.push('');
15
+ lines.push('**Content:**');
16
+ lines.push('```');
17
+ lines.push(tiddler.text || '(empty)');
18
+ lines.push('```');
19
+ return lines.join('\n');
20
+ }
21
+ /**
22
+ * Handle create_tiddler tool requests.
23
+ * Checks for duplicates, creates the tiddler, and returns a preview.
24
+ */
25
+ export async function handleCreateTiddler(args) {
26
+ const input = CreateTiddlerInput.parse(args);
27
+ // Check if tiddler already exists
28
+ const existing = await getTiddler(input.title);
29
+ if (existing) {
30
+ return {
31
+ content: [
32
+ {
33
+ type: 'text',
34
+ text: JSON.stringify({ error: `Tiddler already exists: ${input.title}. Use update_tiddler to modify it.` }, null, 2),
35
+ },
36
+ ],
37
+ isError: true,
38
+ };
39
+ }
40
+ // Create new tiddler object with custom fields
41
+ const { title, text, tags, type, ...customFields } = input;
42
+ const newTiddler = {
43
+ ...createTiddlerObject(title, text, tags || '', type || 'text/markdown', getAuthUser()),
44
+ ...customFields, // Add any custom fields
45
+ };
46
+ // Generate preview
47
+ const preview = formatTiddlerPreview(newTiddler);
48
+ // Create the tiddler
49
+ await putTiddler(newTiddler);
50
+ return {
51
+ content: [
52
+ {
53
+ type: 'text',
54
+ text: `## Created: "${input.title}"\n\n${preview}`,
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ // Re-export the input schema for use in tool registration
60
+ export { CreateTiddlerInput };
61
+ //# sourceMappingURL=create-tiddler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-tiddler.js","sourceRoot":"","sources":["../../src/tools/create-tiddler.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,sEAAsE;AAEtE,OAAO,EACL,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,WAAW,GAEZ,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,IAAI,IAAI,qBAAqB,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAa;IACrD,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE7C,kCAAkC;IAClC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,KAAK,EAAE,2BAA2B,KAAK,CAAC,KAAK,oCAAoC,EAAE,EACrF,IAAI,EACJ,CAAC,CACF;iBACF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,YAAY,EAAE,GAAG,KAAK,CAAC;IAC3D,MAAM,UAAU,GAAG;QACjB,GAAG,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,WAAW,EAAE,CAAC;QACvF,GAAG,YAAY,EAAE,wBAAwB;KAC1C,CAAC;IAEF,mBAAmB;IACnB,MAAM,OAAO,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAEjD,qBAAqB;IACrB,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAE7B,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,gBAAgB,KAAK,CAAC,KAAK,QAAQ,OAAO,EAAE;aACnD;SACF;KACF,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ToolResult } from './types.js';
2
+ import { DeleteTiddlerInput } from './types.js';
3
+ /**
4
+ * Handle delete_tiddler tool requests.
5
+ * Shows a preview of the tiddler content before deletion.
6
+ */
7
+ export declare function handleDeleteTiddler(args: unknown): Promise<ToolResult>;
8
+ export { DeleteTiddlerInput };
9
+ //# sourceMappingURL=delete-tiddler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-tiddler.d.ts","sourceRoot":"","sources":["../../src/tools/delete-tiddler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA+B5E;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,40 @@
1
+ // ABOUTME: Handler for the delete_tiddler MCP tool
2
+ // ABOUTME: Deletes tiddlers with preview of what will be deleted
3
+ import { getTiddler, deleteTiddler } from '../tiddlywiki-http.js';
4
+ import { DeleteTiddlerInput } from './types.js';
5
+ import { formatTiddlerPreview } from './create-tiddler.js';
6
+ /**
7
+ * Handle delete_tiddler tool requests.
8
+ * Shows a preview of the tiddler content before deletion.
9
+ */
10
+ export async function handleDeleteTiddler(args) {
11
+ const input = DeleteTiddlerInput.parse(args);
12
+ // Get current tiddler to show what will be deleted
13
+ const current = await getTiddler(input.title);
14
+ if (!current) {
15
+ return {
16
+ content: [
17
+ {
18
+ type: 'text',
19
+ text: JSON.stringify({ error: `Tiddler not found: ${input.title}` }, null, 2),
20
+ },
21
+ ],
22
+ isError: true,
23
+ };
24
+ }
25
+ // Generate preview of what will be deleted
26
+ const preview = formatTiddlerPreview(current);
27
+ // Delete the tiddler
28
+ await deleteTiddler(input.title);
29
+ return {
30
+ content: [
31
+ {
32
+ type: 'text',
33
+ text: `## Deleted: "${input.title}"\n\n${preview}`,
34
+ },
35
+ ],
36
+ };
37
+ }
38
+ // Re-export the input schema for use in tool registration
39
+ export { DeleteTiddlerInput };
40
+ //# sourceMappingURL=delete-tiddler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-tiddler.js","sourceRoot":"","sources":["../../src/tools/delete-tiddler.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,iEAAiE;AAEjE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAa;IACrD,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE7C,mDAAmD;IACnD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;iBAC9E;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAE9C,qBAAqB;IACrB,MAAM,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,gBAAgB,KAAK,CAAC,KAAK,QAAQ,OAAO,EAAE;aACnD;SACF;KACF,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { handleSearchTiddlers, SearchTiddlersInput } from './search-tiddlers.js';
2
+ export { handleUpdateTiddler, UpdateTiddlerInput } from './update-tiddler.js';
3
+ export { handleCreateTiddler, CreateTiddlerInput, formatTiddlerPreview } from './create-tiddler.js';
4
+ export { handleDeleteTiddler, DeleteTiddlerInput } from './delete-tiddler.js';
5
+ export type { ToolResult, ToolDependencies, SearchTiddlersInputType, UpdateTiddlerInputType, CreateTiddlerInputType, DeleteTiddlerInputType, } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}