mcp-rubber-duck 1.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 (184) hide show
  1. package/.dockerignore +19 -0
  2. package/.env.desktop.example +145 -0
  3. package/.env.example +45 -0
  4. package/.env.pi.example +106 -0
  5. package/.env.template +165 -0
  6. package/.eslintrc.json +40 -0
  7. package/.github/ISSUE_TEMPLATE/bug_report.md +65 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +58 -0
  9. package/.github/ISSUE_TEMPLATE/question.md +67 -0
  10. package/.github/pull_request_template.md +111 -0
  11. package/.github/workflows/docker-build.yml +138 -0
  12. package/.github/workflows/release.yml +182 -0
  13. package/.github/workflows/security.yml +141 -0
  14. package/.github/workflows/semantic-release.yml +89 -0
  15. package/.prettierrc +10 -0
  16. package/.releaserc.json +66 -0
  17. package/CHANGELOG.md +95 -0
  18. package/CONTRIBUTING.md +242 -0
  19. package/Dockerfile +62 -0
  20. package/LICENSE +21 -0
  21. package/README.md +803 -0
  22. package/audit-ci.json +8 -0
  23. package/config/claude_desktop.json +14 -0
  24. package/config/config.example.json +91 -0
  25. package/dist/config/config.d.ts +51 -0
  26. package/dist/config/config.d.ts.map +1 -0
  27. package/dist/config/config.js +301 -0
  28. package/dist/config/config.js.map +1 -0
  29. package/dist/config/types.d.ts +356 -0
  30. package/dist/config/types.d.ts.map +1 -0
  31. package/dist/config/types.js +41 -0
  32. package/dist/config/types.js.map +1 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +109 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/providers/duck-provider-enhanced.d.ts +29 -0
  38. package/dist/providers/duck-provider-enhanced.d.ts.map +1 -0
  39. package/dist/providers/duck-provider-enhanced.js +230 -0
  40. package/dist/providers/duck-provider-enhanced.js.map +1 -0
  41. package/dist/providers/enhanced-manager.d.ts +54 -0
  42. package/dist/providers/enhanced-manager.d.ts.map +1 -0
  43. package/dist/providers/enhanced-manager.js +217 -0
  44. package/dist/providers/enhanced-manager.js.map +1 -0
  45. package/dist/providers/manager.d.ts +28 -0
  46. package/dist/providers/manager.d.ts.map +1 -0
  47. package/dist/providers/manager.js +204 -0
  48. package/dist/providers/manager.js.map +1 -0
  49. package/dist/providers/provider.d.ts +29 -0
  50. package/dist/providers/provider.d.ts.map +1 -0
  51. package/dist/providers/provider.js +179 -0
  52. package/dist/providers/provider.js.map +1 -0
  53. package/dist/providers/types.d.ts +69 -0
  54. package/dist/providers/types.d.ts.map +1 -0
  55. package/dist/providers/types.js +2 -0
  56. package/dist/providers/types.js.map +1 -0
  57. package/dist/server.d.ts +24 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +501 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/services/approval.d.ts +44 -0
  62. package/dist/services/approval.d.ts.map +1 -0
  63. package/dist/services/approval.js +159 -0
  64. package/dist/services/approval.js.map +1 -0
  65. package/dist/services/cache.d.ts +21 -0
  66. package/dist/services/cache.d.ts.map +1 -0
  67. package/dist/services/cache.js +63 -0
  68. package/dist/services/cache.js.map +1 -0
  69. package/dist/services/conversation.d.ts +24 -0
  70. package/dist/services/conversation.d.ts.map +1 -0
  71. package/dist/services/conversation.js +108 -0
  72. package/dist/services/conversation.js.map +1 -0
  73. package/dist/services/function-bridge.d.ts +41 -0
  74. package/dist/services/function-bridge.d.ts.map +1 -0
  75. package/dist/services/function-bridge.js +259 -0
  76. package/dist/services/function-bridge.js.map +1 -0
  77. package/dist/services/health.d.ts +17 -0
  78. package/dist/services/health.d.ts.map +1 -0
  79. package/dist/services/health.js +77 -0
  80. package/dist/services/health.js.map +1 -0
  81. package/dist/services/mcp-client-manager.d.ts +49 -0
  82. package/dist/services/mcp-client-manager.d.ts.map +1 -0
  83. package/dist/services/mcp-client-manager.js +279 -0
  84. package/dist/services/mcp-client-manager.js.map +1 -0
  85. package/dist/tools/approve-mcp-request.d.ts +9 -0
  86. package/dist/tools/approve-mcp-request.d.ts.map +1 -0
  87. package/dist/tools/approve-mcp-request.js +111 -0
  88. package/dist/tools/approve-mcp-request.js.map +1 -0
  89. package/dist/tools/ask-duck.d.ts +9 -0
  90. package/dist/tools/ask-duck.d.ts.map +1 -0
  91. package/dist/tools/ask-duck.js +43 -0
  92. package/dist/tools/ask-duck.js.map +1 -0
  93. package/dist/tools/chat-duck.d.ts +9 -0
  94. package/dist/tools/chat-duck.d.ts.map +1 -0
  95. package/dist/tools/chat-duck.js +57 -0
  96. package/dist/tools/chat-duck.js.map +1 -0
  97. package/dist/tools/clear-conversations.d.ts +8 -0
  98. package/dist/tools/clear-conversations.d.ts.map +1 -0
  99. package/dist/tools/clear-conversations.js +17 -0
  100. package/dist/tools/clear-conversations.js.map +1 -0
  101. package/dist/tools/compare-ducks.d.ts +8 -0
  102. package/dist/tools/compare-ducks.d.ts.map +1 -0
  103. package/dist/tools/compare-ducks.js +49 -0
  104. package/dist/tools/compare-ducks.js.map +1 -0
  105. package/dist/tools/duck-council.d.ts +8 -0
  106. package/dist/tools/duck-council.d.ts.map +1 -0
  107. package/dist/tools/duck-council.js +69 -0
  108. package/dist/tools/duck-council.js.map +1 -0
  109. package/dist/tools/get-pending-approvals.d.ts +15 -0
  110. package/dist/tools/get-pending-approvals.d.ts.map +1 -0
  111. package/dist/tools/get-pending-approvals.js +74 -0
  112. package/dist/tools/get-pending-approvals.js.map +1 -0
  113. package/dist/tools/list-ducks.d.ts +9 -0
  114. package/dist/tools/list-ducks.d.ts.map +1 -0
  115. package/dist/tools/list-ducks.js +47 -0
  116. package/dist/tools/list-ducks.js.map +1 -0
  117. package/dist/tools/list-models.d.ts +8 -0
  118. package/dist/tools/list-models.d.ts.map +1 -0
  119. package/dist/tools/list-models.js +72 -0
  120. package/dist/tools/list-models.js.map +1 -0
  121. package/dist/tools/mcp-status.d.ts +17 -0
  122. package/dist/tools/mcp-status.d.ts.map +1 -0
  123. package/dist/tools/mcp-status.js +100 -0
  124. package/dist/tools/mcp-status.js.map +1 -0
  125. package/dist/utils/ascii-art.d.ts +19 -0
  126. package/dist/utils/ascii-art.d.ts.map +1 -0
  127. package/dist/utils/ascii-art.js +73 -0
  128. package/dist/utils/ascii-art.js.map +1 -0
  129. package/dist/utils/logger.d.ts +3 -0
  130. package/dist/utils/logger.d.ts.map +1 -0
  131. package/dist/utils/logger.js +86 -0
  132. package/dist/utils/logger.js.map +1 -0
  133. package/dist/utils/safe-logger.d.ts +23 -0
  134. package/dist/utils/safe-logger.d.ts.map +1 -0
  135. package/dist/utils/safe-logger.js +145 -0
  136. package/dist/utils/safe-logger.js.map +1 -0
  137. package/docker-compose.yml +161 -0
  138. package/jest.config.js +26 -0
  139. package/package.json +65 -0
  140. package/scripts/build-multiarch.sh +290 -0
  141. package/scripts/deploy-raspbian.sh +410 -0
  142. package/scripts/deploy.sh +322 -0
  143. package/scripts/gh-deploy.sh +343 -0
  144. package/scripts/setup-docker-raspbian.sh +530 -0
  145. package/server.json +8 -0
  146. package/src/config/config.ts +357 -0
  147. package/src/config/types.ts +89 -0
  148. package/src/index.ts +114 -0
  149. package/src/providers/duck-provider-enhanced.ts +294 -0
  150. package/src/providers/enhanced-manager.ts +290 -0
  151. package/src/providers/manager.ts +257 -0
  152. package/src/providers/provider.ts +207 -0
  153. package/src/providers/types.ts +78 -0
  154. package/src/server.ts +603 -0
  155. package/src/services/approval.ts +225 -0
  156. package/src/services/cache.ts +79 -0
  157. package/src/services/conversation.ts +146 -0
  158. package/src/services/function-bridge.ts +329 -0
  159. package/src/services/health.ts +107 -0
  160. package/src/services/mcp-client-manager.ts +362 -0
  161. package/src/tools/approve-mcp-request.ts +126 -0
  162. package/src/tools/ask-duck.ts +74 -0
  163. package/src/tools/chat-duck.ts +82 -0
  164. package/src/tools/clear-conversations.ts +24 -0
  165. package/src/tools/compare-ducks.ts +67 -0
  166. package/src/tools/duck-council.ts +88 -0
  167. package/src/tools/get-pending-approvals.ts +90 -0
  168. package/src/tools/list-ducks.ts +65 -0
  169. package/src/tools/list-models.ts +101 -0
  170. package/src/tools/mcp-status.ts +117 -0
  171. package/src/utils/ascii-art.ts +85 -0
  172. package/src/utils/logger.ts +116 -0
  173. package/src/utils/safe-logger.ts +165 -0
  174. package/systemd/mcp-rubber-duck-with-ollama.service +55 -0
  175. package/systemd/mcp-rubber-duck.service +58 -0
  176. package/test-functionality.js +147 -0
  177. package/test-mcp-interface.js +221 -0
  178. package/tests/ascii-art.test.ts +36 -0
  179. package/tests/config.test.ts +239 -0
  180. package/tests/conversation.test.ts +308 -0
  181. package/tests/mcp-bridge.test.ts +291 -0
  182. package/tests/providers.test.ts +269 -0
  183. package/tests/tools/clear-conversations.test.ts +163 -0
  184. package/tsconfig.json +26 -0
@@ -0,0 +1,159 @@
1
+ import { logger } from '../utils/logger.js';
2
+ import { SafeLogger } from '../utils/safe-logger.js';
3
+ import { randomUUID } from 'crypto';
4
+ export class ApprovalService {
5
+ pendingApprovals = new Map();
6
+ approvalTimeout;
7
+ cleanupInterval = null;
8
+ approvedToolsForSession = new Set();
9
+ constructor(approvalTimeoutSeconds = 300) {
10
+ this.approvalTimeout = approvalTimeoutSeconds * 1000; // Convert to milliseconds
11
+ this.startCleanupTimer();
12
+ }
13
+ createApprovalRequest(duckName, mcpServer, toolName, args) {
14
+ const id = randomUUID();
15
+ const now = Date.now();
16
+ const request = {
17
+ id,
18
+ timestamp: now,
19
+ duckName,
20
+ mcpServer,
21
+ toolName,
22
+ arguments: args,
23
+ status: 'pending',
24
+ expiresAt: now + this.approvalTimeout,
25
+ };
26
+ this.pendingApprovals.set(id, request);
27
+ const safeMessage = SafeLogger.createApprovalMessage(duckName, mcpServer, toolName, args);
28
+ logger.info(`Created approval request ${id} for ${duckName} to call ${mcpServer}:${toolName}`);
29
+ SafeLogger.debug(`Approval request details:`, { id, duckName, mcpServer, toolName, safeMessage });
30
+ return request;
31
+ }
32
+ getApprovalRequest(id) {
33
+ const request = this.pendingApprovals.get(id);
34
+ // Check if expired
35
+ if (request && Date.now() > request.expiresAt && request.status === 'pending') {
36
+ request.status = 'expired';
37
+ logger.info(`Approval request ${id} has expired`);
38
+ }
39
+ return request;
40
+ }
41
+ getApprovalStatus(id) {
42
+ const request = this.getApprovalRequest(id);
43
+ return request?.status;
44
+ }
45
+ approveRequest(id, approvedBy = 'user') {
46
+ const request = this.getApprovalRequest(id);
47
+ if (!request) {
48
+ logger.warn(`Approval request ${id} not found`);
49
+ return false;
50
+ }
51
+ if (request.status !== 'pending') {
52
+ logger.warn(`Approval request ${id} is not pending (status: ${request.status})`);
53
+ return false;
54
+ }
55
+ if (Date.now() > request.expiresAt) {
56
+ request.status = 'expired';
57
+ logger.warn(`Approval request ${id} has expired`);
58
+ return false;
59
+ }
60
+ request.status = 'approved';
61
+ request.approvedBy = approvedBy;
62
+ // Mark tool as approved for this session
63
+ const sessionKey = this.createSessionKey(request.duckName, request.mcpServer, request.toolName);
64
+ this.approvedToolsForSession.add(sessionKey);
65
+ logger.info(`Approval request ${id} approved by ${approvedBy} - tool ${sessionKey} now approved for session`);
66
+ return true;
67
+ }
68
+ denyRequest(id, reason) {
69
+ const request = this.getApprovalRequest(id);
70
+ if (!request) {
71
+ logger.warn(`Approval request ${id} not found`);
72
+ return false;
73
+ }
74
+ if (request.status !== 'pending') {
75
+ logger.warn(`Approval request ${id} is not pending (status: ${request.status})`);
76
+ return false;
77
+ }
78
+ request.status = 'denied';
79
+ request.deniedReason = reason;
80
+ logger.info(`Approval request ${id} denied${reason ? `: ${reason}` : ''}`);
81
+ return true;
82
+ }
83
+ getPendingApprovals() {
84
+ // Clean up expired requests first
85
+ this.cleanupExpired();
86
+ return Array.from(this.pendingApprovals.values())
87
+ .filter(request => request.status === 'pending');
88
+ }
89
+ getAllApprovals() {
90
+ // Clean up expired requests first
91
+ this.cleanupExpired();
92
+ return Array.from(this.pendingApprovals.values());
93
+ }
94
+ getApprovalsByDuck(duckName) {
95
+ return Array.from(this.pendingApprovals.values())
96
+ .filter(request => request.duckName === duckName);
97
+ }
98
+ cleanupExpired() {
99
+ const now = Date.now();
100
+ let cleanedUp = 0;
101
+ for (const [id, request] of this.pendingApprovals.entries()) {
102
+ if (now > request.expiresAt && request.status === 'pending') {
103
+ request.status = 'expired';
104
+ logger.debug(`Marked approval request ${id} as expired`);
105
+ cleanedUp++;
106
+ }
107
+ }
108
+ return cleanedUp;
109
+ }
110
+ startCleanupTimer() {
111
+ // Clean up expired requests every minute
112
+ this.cleanupInterval = setInterval(() => {
113
+ const cleaned = this.cleanupExpired();
114
+ if (cleaned > 0) {
115
+ logger.debug(`Cleaned up ${cleaned} expired approval requests`);
116
+ }
117
+ }, 60000);
118
+ }
119
+ shutdown() {
120
+ if (this.cleanupInterval) {
121
+ clearInterval(this.cleanupInterval);
122
+ this.cleanupInterval = null;
123
+ }
124
+ }
125
+ // Session-based approval methods
126
+ createSessionKey(duckName, mcpServer, toolName) {
127
+ return `${duckName}:${mcpServer}:${toolName}`;
128
+ }
129
+ isToolApprovedForSession(duckName, mcpServer, toolName) {
130
+ const sessionKey = this.createSessionKey(duckName, mcpServer, toolName);
131
+ return this.approvedToolsForSession.has(sessionKey);
132
+ }
133
+ markToolAsApprovedForSession(duckName, mcpServer, toolName) {
134
+ const sessionKey = this.createSessionKey(duckName, mcpServer, toolName);
135
+ this.approvedToolsForSession.add(sessionKey);
136
+ logger.info(`Tool ${sessionKey} marked as approved for session`);
137
+ }
138
+ clearSessionApprovals() {
139
+ const count = this.approvedToolsForSession.size;
140
+ this.approvedToolsForSession.clear();
141
+ logger.info(`Cleared ${count} session approvals`);
142
+ }
143
+ getSessionApprovals() {
144
+ return Array.from(this.approvedToolsForSession);
145
+ }
146
+ // For debugging/admin purposes
147
+ getStats() {
148
+ this.cleanupExpired();
149
+ const all = Array.from(this.pendingApprovals.values());
150
+ return {
151
+ total: all.length,
152
+ pending: all.filter(r => r.status === 'pending').length,
153
+ approved: all.filter(r => r.status === 'approved').length,
154
+ denied: all.filter(r => r.status === 'denied').length,
155
+ expired: all.filter(r => r.status === 'expired').length,
156
+ };
157
+ }
158
+ }
159
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../src/services/approval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare class ResponseCache {
2
+ private cache;
3
+ constructor(ttlSeconds?: number);
4
+ generateKey(provider: string, prompt: string, options?: Record<string, unknown>): string;
5
+ get<T>(key: string): T | undefined;
6
+ set<T>(key: string, value: T, ttl?: number): boolean;
7
+ has(key: string): boolean;
8
+ delete(key: string): number;
9
+ flush(): void;
10
+ getStats(): {
11
+ keys: number;
12
+ hits: number;
13
+ misses: number;
14
+ hitRate: number;
15
+ };
16
+ getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl?: number): Promise<{
17
+ value: T;
18
+ cached: boolean;
19
+ }>;
20
+ }
21
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"AAIA,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAY;gBAEb,UAAU,GAAE,MAAY;IAYpC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAKxF,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAIlC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAQpD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI3B,KAAK,IAAI,IAAI;IAKb,QAAQ;;;;;;IAWF,QAAQ,CAAC,CAAC,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CAc1C"}
@@ -0,0 +1,63 @@
1
+ import NodeCache from 'node-cache';
2
+ import { createHash } from 'crypto';
3
+ import { logger } from '../utils/logger.js';
4
+ export class ResponseCache {
5
+ cache;
6
+ constructor(ttlSeconds = 300) {
7
+ this.cache = new NodeCache({
8
+ stdTTL: ttlSeconds,
9
+ checkperiod: ttlSeconds * 0.2,
10
+ useClones: false,
11
+ });
12
+ this.cache.on('expired', (key) => {
13
+ logger.debug(`Cache expired for key: ${key}`);
14
+ });
15
+ }
16
+ generateKey(provider, prompt, options) {
17
+ const data = JSON.stringify({ provider, prompt, options });
18
+ return createHash('sha256').update(data).digest('hex');
19
+ }
20
+ get(key) {
21
+ return this.cache.get(key);
22
+ }
23
+ set(key, value, ttl) {
24
+ if (ttl !== undefined) {
25
+ return this.cache.set(key, value, ttl);
26
+ }
27
+ else {
28
+ return this.cache.set(key, value);
29
+ }
30
+ }
31
+ has(key) {
32
+ return this.cache.has(key);
33
+ }
34
+ delete(key) {
35
+ return this.cache.del(key);
36
+ }
37
+ flush() {
38
+ this.cache.flushAll();
39
+ logger.debug('Cache flushed');
40
+ }
41
+ getStats() {
42
+ const stats = this.cache.getStats();
43
+ return {
44
+ keys: this.cache.keys().length,
45
+ hits: stats.hits,
46
+ misses: stats.misses,
47
+ hitRate: stats.hits / (stats.hits + stats.misses) || 0,
48
+ };
49
+ }
50
+ // Helper method for caching provider responses
51
+ async getOrSet(key, fetcher, ttl) {
52
+ const cached = this.get(key);
53
+ if (cached !== undefined) {
54
+ logger.debug(`Cache hit for key: ${key}`);
55
+ return { value: cached, cached: true };
56
+ }
57
+ logger.debug(`Cache miss for key: ${key}`);
58
+ const value = await fetcher();
59
+ this.set(key, value, ttl);
60
+ return { value, cached: false };
61
+ }
62
+ }
63
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/services/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Conversation, ConversationMessage } from '../config/types.js';
2
+ export declare class ConversationManager {
3
+ private conversations;
4
+ private maxConversationSize;
5
+ createConversation(id: string, provider: string): Conversation;
6
+ getConversation(id: string): Conversation | undefined;
7
+ addMessage(conversationId: string, message: ConversationMessage): Conversation;
8
+ switchProvider(conversationId: string, newProvider: string): Conversation;
9
+ listConversations(): Array<{
10
+ id: string;
11
+ provider: string;
12
+ messageCount: number;
13
+ createdAt: Date;
14
+ updatedAt: Date;
15
+ }>;
16
+ deleteConversation(id: string): boolean;
17
+ clearOldConversations(maxAge?: number): void;
18
+ getConversationContext(id: string, maxMessages?: number): ConversationMessage[];
19
+ clearAll(): {
20
+ conversationsCleared: number;
21
+ messagesCleared: number;
22
+ };
23
+ }
24
+ //# sourceMappingURL=conversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/services/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,mBAAmB,CAAM;IAEjC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;IAc9D,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIrD,UAAU,CACR,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,mBAAmB,GAC3B,YAAY;IAqBf,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY;IAsBzE,iBAAiB,IAAI,KAAK,CAAC;QACzB,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,IAAI,CAAC;QAChB,SAAS,EAAE,IAAI,CAAC;KACjB,CAAC;IAUF,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQvC,qBAAqB,CAAC,MAAM,GAAE,MAA4B;IAgB1D,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAgB/E,QAAQ,IAAI;QAAE,oBAAoB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE;CAkBtE"}
@@ -0,0 +1,108 @@
1
+ import { logger } from '../utils/logger.js';
2
+ export class ConversationManager {
3
+ conversations = new Map();
4
+ maxConversationSize = 50; // Maximum messages per conversation
5
+ createConversation(id, provider) {
6
+ const conversation = {
7
+ id,
8
+ messages: [],
9
+ provider,
10
+ createdAt: new Date(),
11
+ updatedAt: new Date(),
12
+ };
13
+ this.conversations.set(id, conversation);
14
+ logger.debug(`Created new conversation: ${id}`);
15
+ return conversation;
16
+ }
17
+ getConversation(id) {
18
+ return this.conversations.get(id);
19
+ }
20
+ addMessage(conversationId, message) {
21
+ const conversation = this.conversations.get(conversationId);
22
+ if (!conversation) {
23
+ throw new Error(`Conversation ${conversationId} not found`);
24
+ }
25
+ conversation.messages.push(message);
26
+ conversation.updatedAt = new Date();
27
+ // Trim conversation if too long
28
+ if (conversation.messages.length > this.maxConversationSize) {
29
+ const toRemove = conversation.messages.length - this.maxConversationSize;
30
+ conversation.messages = conversation.messages.slice(toRemove);
31
+ logger.debug(`Trimmed ${toRemove} messages from conversation ${conversationId}`);
32
+ }
33
+ this.conversations.set(conversationId, conversation);
34
+ return conversation;
35
+ }
36
+ switchProvider(conversationId, newProvider) {
37
+ const conversation = this.conversations.get(conversationId);
38
+ if (!conversation) {
39
+ throw new Error(`Conversation ${conversationId} not found`);
40
+ }
41
+ conversation.provider = newProvider;
42
+ conversation.updatedAt = new Date();
43
+ // Add a system message noting the provider switch
44
+ conversation.messages.push({
45
+ role: 'system',
46
+ content: `Switched to ${newProvider} duck`,
47
+ timestamp: new Date(),
48
+ provider: newProvider,
49
+ });
50
+ this.conversations.set(conversationId, conversation);
51
+ return conversation;
52
+ }
53
+ listConversations() {
54
+ return Array.from(this.conversations.values()).map(conv => ({
55
+ id: conv.id,
56
+ provider: conv.provider,
57
+ messageCount: conv.messages.length,
58
+ createdAt: conv.createdAt,
59
+ updatedAt: conv.updatedAt,
60
+ }));
61
+ }
62
+ deleteConversation(id) {
63
+ const deleted = this.conversations.delete(id);
64
+ if (deleted) {
65
+ logger.debug(`Deleted conversation: ${id}`);
66
+ }
67
+ return deleted;
68
+ }
69
+ clearOldConversations(maxAge = 24 * 60 * 60 * 1000) {
70
+ const now = Date.now();
71
+ let deleted = 0;
72
+ for (const [id, conversation] of this.conversations) {
73
+ if (now - conversation.updatedAt.getTime() > maxAge) {
74
+ this.conversations.delete(id);
75
+ deleted++;
76
+ }
77
+ }
78
+ if (deleted > 0) {
79
+ logger.info(`Cleared ${deleted} old conversations`);
80
+ }
81
+ }
82
+ getConversationContext(id, maxMessages) {
83
+ const conversation = this.conversations.get(id);
84
+ if (!conversation) {
85
+ return [];
86
+ }
87
+ const messages = conversation.messages;
88
+ if (maxMessages && messages.length > maxMessages) {
89
+ return messages.slice(-maxMessages);
90
+ }
91
+ return messages;
92
+ }
93
+ clearAll() {
94
+ let totalMessages = 0;
95
+ // Count total messages across all conversations
96
+ for (const conversation of this.conversations.values()) {
97
+ totalMessages += conversation.messages.length;
98
+ }
99
+ const conversationsCleared = this.conversations.size;
100
+ this.conversations.clear();
101
+ logger.info(`Cleared ${conversationsCleared} conversations with ${totalMessages} total messages`);
102
+ return {
103
+ conversationsCleared,
104
+ messagesCleared: totalMessages,
105
+ };
106
+ }
107
+ }
108
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/services/conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { MCPClientManager, MCPTool } from './mcp-client-manager.js';
2
+ import { ApprovalService } from './approval.js';
3
+ export interface FunctionDefinition {
4
+ name: string;
5
+ description: string;
6
+ parameters: Record<string, unknown>;
7
+ }
8
+ export interface FunctionCallResult {
9
+ success: boolean;
10
+ needsApproval?: boolean;
11
+ approvalId?: string;
12
+ data?: unknown;
13
+ error?: string;
14
+ message?: string;
15
+ }
16
+ export declare class FunctionBridge {
17
+ private mcpManager;
18
+ private approvalService;
19
+ private trustedTools;
20
+ private trustedToolsByServer;
21
+ private ajv;
22
+ private toolSchemas;
23
+ private approvalMode;
24
+ constructor(mcpManager: MCPClientManager, approvalService: ApprovalService, trustedTools?: string[], approvalMode?: 'always' | 'trusted' | 'never', trustedToolsByServer?: Record<string, string[]>);
25
+ getFunctionDefinitions(): Promise<FunctionDefinition[]>;
26
+ private convertMCPToolToFunction;
27
+ private validateToolArguments;
28
+ handleFunctionCall(duckName: string, functionName: string, args: Record<string, unknown>): Promise<FunctionCallResult>;
29
+ private extractServerFromFunctionName;
30
+ private extractToolFromFunctionName;
31
+ isToolAvailable(serverName: string, toolName: string): Promise<boolean>;
32
+ getAvailableToolsByServer(): Promise<Record<string, MCPTool[]>>;
33
+ updateTrustedTools(trustedTools: string[], trustedToolsByServer?: Record<string, string[]>): void;
34
+ getStats(): {
35
+ totalFunctions: number;
36
+ serverCount: number;
37
+ trustedToolCount: number;
38
+ connectedServers: string[];
39
+ };
40
+ }
41
+ //# sourceMappingURL=function-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-bridge.d.ts","sourceRoot":"","sources":["../../src/services/function-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,oBAAoB,CAAuC;IACnE,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,WAAW,CAAmD;IACtE,OAAO,CAAC,YAAY,CAAiC;gBAGnD,UAAU,EAAE,gBAAgB,EAC5B,eAAe,EAAE,eAAe,EAChC,YAAY,GAAE,MAAM,EAAO,EAC3B,YAAY,GAAE,QAAQ,GAAG,SAAS,GAAG,OAAkB,EACvD,oBAAoB,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAM;IAe/C,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAsB7D,OAAO,CAAC,wBAAwB;IA+BhC,OAAO,CAAC,qBAAqB;IA0BvB,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,kBAAkB,CAAC;IA6H9B,OAAO,CAAC,6BAA6B;IAMrC,OAAO,CAAC,2BAA2B;IAO7B,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvE,yBAAyB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAqBrE,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IAcjG,QAAQ,IAAI;QACV,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B;CAQF"}