hippocampus-mcp 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 (70) hide show
  1. package/README.md +284 -0
  2. package/dist/aws/credentials-provider.d.ts +20 -0
  3. package/dist/aws/credentials-provider.d.ts.map +1 -0
  4. package/dist/aws/credentials-provider.js +107 -0
  5. package/dist/aws/credentials-provider.js.map +1 -0
  6. package/dist/config/environment.d.ts +12 -0
  7. package/dist/config/environment.d.ts.map +1 -0
  8. package/dist/config/environment.js +42 -0
  9. package/dist/config/environment.js.map +1 -0
  10. package/dist/config/index.d.ts +2 -0
  11. package/dist/config/index.d.ts.map +1 -0
  12. package/dist/config/index.js +2 -0
  13. package/dist/config/index.js.map +1 -0
  14. package/dist/data/dynamodb-client.d.ts +25 -0
  15. package/dist/data/dynamodb-client.d.ts.map +1 -0
  16. package/dist/data/dynamodb-client.js +107 -0
  17. package/dist/data/dynamodb-client.js.map +1 -0
  18. package/dist/data/entity-manager.d.ts +31 -0
  19. package/dist/data/entity-manager.d.ts.map +1 -0
  20. package/dist/data/entity-manager.js +330 -0
  21. package/dist/data/entity-manager.js.map +1 -0
  22. package/dist/data/models.d.ts +67 -0
  23. package/dist/data/models.d.ts.map +1 -0
  24. package/dist/data/models.js +19 -0
  25. package/dist/data/models.js.map +1 -0
  26. package/dist/data/preference-manager.d.ts +11 -0
  27. package/dist/data/preference-manager.d.ts.map +1 -0
  28. package/dist/data/preference-manager.js +47 -0
  29. package/dist/data/preference-manager.js.map +1 -0
  30. package/dist/data/search-engine.d.ts +19 -0
  31. package/dist/data/search-engine.d.ts.map +1 -0
  32. package/dist/data/search-engine.js +164 -0
  33. package/dist/data/search-engine.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +105 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/mcp/resource-registry.d.ts +18 -0
  39. package/dist/mcp/resource-registry.d.ts.map +1 -0
  40. package/dist/mcp/resource-registry.js +140 -0
  41. package/dist/mcp/resource-registry.js.map +1 -0
  42. package/dist/mcp/tool-handler.d.ts +37 -0
  43. package/dist/mcp/tool-handler.d.ts.map +1 -0
  44. package/dist/mcp/tool-handler.js +221 -0
  45. package/dist/mcp/tool-handler.js.map +1 -0
  46. package/dist/mcp/tool-registry.d.ts +6 -0
  47. package/dist/mcp/tool-registry.d.ts.map +1 -0
  48. package/dist/mcp/tool-registry.js +619 -0
  49. package/dist/mcp/tool-registry.js.map +1 -0
  50. package/dist/protocol/jsonrpc-handler.d.ts +36 -0
  51. package/dist/protocol/jsonrpc-handler.d.ts.map +1 -0
  52. package/dist/protocol/jsonrpc-handler.js +143 -0
  53. package/dist/protocol/jsonrpc-handler.js.map +1 -0
  54. package/dist/protocol/stdio-handler.d.ts +20 -0
  55. package/dist/protocol/stdio-handler.d.ts.map +1 -0
  56. package/dist/protocol/stdio-handler.js +100 -0
  57. package/dist/protocol/stdio-handler.js.map +1 -0
  58. package/dist/protocol/types.d.ts +38 -0
  59. package/dist/protocol/types.d.ts.map +1 -0
  60. package/dist/protocol/types.js +11 -0
  61. package/dist/protocol/types.js.map +1 -0
  62. package/dist/utils/errors.d.ts +2 -0
  63. package/dist/utils/errors.d.ts.map +1 -0
  64. package/dist/utils/errors.js +2 -0
  65. package/dist/utils/errors.js.map +1 -0
  66. package/dist/utils/logger.d.ts +2 -0
  67. package/dist/utils/logger.d.ts.map +1 -0
  68. package/dist/utils/logger.js +2 -0
  69. package/dist/utils/logger.js.map +1 -0
  70. package/package.json +81 -0
package/README.md ADDED
@@ -0,0 +1,284 @@
1
+ # Hippocampus MCP
2
+
3
+ **Personal Knowledge MCP Server** - Provides AI assistants with access to personal knowledge, preferences, and contextual information stored in AWS DynamoDB.
4
+
5
+ ## Features
6
+
7
+ - **Personal Knowledge Management**: Store and retrieve notes, preferences, and contextual information
8
+ - **Semantic Search**: Find relevant information using natural language queries
9
+ - **Category Organization**: Organize knowledge by categories (work, personal, technical, etc.)
10
+ - **AWS Integration**: Leverages DynamoDB for scalable, serverless storage
11
+ - **MCP Protocol**: Standard Model Context Protocol implementation for AI assistant integration
12
+
13
+ ## Prerequisites
14
+
15
+ - Node.js 18.0.0 or higher
16
+ - AWS Account with DynamoDB access
17
+ - AWS CLI configured with credentials (or AWS SSO profile)
18
+
19
+ ## Installation
20
+
21
+ ### Quick Start (Recommended)
22
+
23
+ Add to your MCP client configuration (e.g., `~/.kiro/settings/mcp.json` or `.cursor/mcp.json`):
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "hippocampus-mcp": {
29
+ "command": "npx",
30
+ "args": ["-y", "hippocampus-mcp@latest"],
31
+ "env": {
32
+ "AWS_PROFILE": "your-profile-name",
33
+ "AWS_REGION": "us-east-1",
34
+ "DYNAMODB_TABLE_NAME": "your-table-name"
35
+ },
36
+ "disabled": false,
37
+ "autoApprove": []
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ That's it! The MCP client will automatically download and run the server when needed.
44
+
45
+ ### Manual Installation
46
+
47
+ ```bash
48
+ npm install -g hippocampus-mcp
49
+ ```
50
+
51
+ ## Configuration
52
+
53
+ The server requires the following environment variables:
54
+
55
+ | Variable | Description | Default | Required |
56
+ |----------|-------------|---------|----------|
57
+ | `AWS_PROFILE` | AWS CLI profile name | - | No* |
58
+ | `AWS_REGION` | AWS region for DynamoDB | `us-east-1` | No |
59
+ | `DYNAMODB_TABLE_NAME` | DynamoDB table name | `personal-knowledge` | No |
60
+
61
+ *Either `AWS_PROFILE` or standard AWS credentials (access key/secret) must be configured.
62
+
63
+ ## AWS Setup
64
+
65
+ ### 1. Create DynamoDB Table
66
+
67
+ You can deploy the required infrastructure using AWS CDK (included in this package):
68
+
69
+ ```bash
70
+ # Clone the repository
71
+ git clone https://github.com/yourusername/hippocampus-mcp.git
72
+ cd hippocampus-mcp
73
+
74
+ # Install dependencies
75
+ npm install
76
+
77
+ # Deploy infrastructure
78
+ npm run cdk:deploy
79
+ ```
80
+
81
+ Or create manually:
82
+ - Table name: `personal-knowledge` (or your custom name)
83
+ - Partition key: `PK` (String)
84
+ - Sort key: `SK` (String)
85
+ - GSI: `GSI1` with `GSI1PK` (String) and `GSI1SK` (String)
86
+
87
+ ### 2. Configure AWS Credentials
88
+
89
+ ```bash
90
+ # Option 1: AWS SSO
91
+ aws sso login --profile your-profile-name
92
+
93
+ # Option 2: AWS CLI credentials
94
+ aws configure
95
+ ```
96
+
97
+ ## Usage with MCP Clients
98
+
99
+ ### Kiro IDE
100
+
101
+ Edit `~/.kiro/settings/mcp.json`:
102
+
103
+ ```json
104
+ {
105
+ "mcpServers": {
106
+ "hippocampus-mcp": {
107
+ "command": "npx",
108
+ "args": ["-y", "hippocampus-mcp@latest"],
109
+ "env": {
110
+ "AWS_PROFILE": "hc1",
111
+ "AWS_REGION": "us-east-1",
112
+ "DYNAMODB_TABLE_NAME": "hc1-model-knowledge-241763622848"
113
+ }
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### Cursor
120
+
121
+ Edit `~/.cursor/mcp.json` or `.cursor/mcp.json` in your project:
122
+
123
+ ```json
124
+ {
125
+ "mcpServers": {
126
+ "hippocampus-mcp": {
127
+ "command": "npx",
128
+ "args": ["-y", "hippocampus-mcp@latest"],
129
+ "env": {
130
+ "AWS_PROFILE": "hc1",
131
+ "AWS_REGION": "us-east-1"
132
+ }
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Claude Desktop
139
+
140
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
141
+
142
+ ```json
143
+ {
144
+ "mcpServers": {
145
+ "hippocampus-mcp": {
146
+ "command": "npx",
147
+ "args": ["-y", "hippocampus-mcp@latest"],
148
+ "env": {
149
+ "AWS_PROFILE": "hc1",
150
+ "AWS_REGION": "us-east-1"
151
+ }
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ ## Available Tools
158
+
159
+ The server provides the following MCP tools:
160
+
161
+ ### Knowledge Management
162
+ - `create_note` - Create a new note with content and metadata
163
+ - `get_note` - Retrieve a specific note by ID
164
+ - `update_note` - Update an existing note
165
+ - `delete_note` - Delete a note
166
+ - `list_notes` - List all notes with optional filtering
167
+
168
+ ### Search
169
+ - `search_notes` - Semantic search across all notes
170
+ - `search_by_category` - Find notes by category
171
+
172
+ ### Preferences
173
+ - `set_preference` - Store a user preference
174
+ - `get_preference` - Retrieve a preference value
175
+ - `list_preferences` - List all preferences
176
+
177
+ ## Available Resources
178
+
179
+ The server exposes the following MCP resources:
180
+
181
+ - `knowledge://notes` - Access to all notes
182
+ - `knowledge://preferences` - Access to user preferences
183
+ - `knowledge://categories` - List of available categories
184
+
185
+ ## Example Interactions
186
+
187
+ ```
188
+ User: "Remember that I prefer dark mode for all applications"
189
+ AI: [Uses set_preference tool]
190
+
191
+ User: "What are my preferences for UI themes?"
192
+ AI: [Uses get_preference tool]
193
+
194
+ User: "Create a note about the AWS CDK deployment process"
195
+ AI: [Uses create_note tool]
196
+
197
+ User: "Find all my notes about AWS"
198
+ AI: [Uses search_notes tool]
199
+ ```
200
+
201
+ ## Development
202
+
203
+ ### Local Development
204
+
205
+ ```bash
206
+ # Clone repository
207
+ git clone https://github.com/yourusername/hippocampus-mcp.git
208
+ cd hippocampus-mcp
209
+
210
+ # Install dependencies
211
+ npm install
212
+
213
+ # Build
214
+ npm run build
215
+
216
+ # Run locally
217
+ npm start
218
+
219
+ # Run tests
220
+ npm test
221
+ ```
222
+
223
+ ### Testing with MCP Inspector
224
+
225
+ ```bash
226
+ # Install MCP Inspector
227
+ npm install -g @modelcontextprotocol/inspector
228
+
229
+ # Run inspector
230
+ mcp-inspector npx hippocampus-mcp
231
+ ```
232
+
233
+ ## Security Considerations
234
+
235
+ - AWS credentials are never transmitted - they remain local to your machine
236
+ - All data is stored in your own AWS account
237
+ - The server runs locally and communicates via stdio (no network exposure)
238
+ - Follow AWS IAM best practices for credential management
239
+
240
+ ## Cost Considerations
241
+
242
+ - DynamoDB: Pay-per-request pricing (very low cost for personal use)
243
+ - Typical usage: < $1/month for individual users
244
+ - No additional AWS services required
245
+
246
+ ## Troubleshooting
247
+
248
+ ### Server won't start
249
+ - Verify AWS credentials: `aws sts get-caller-identity --profile your-profile`
250
+ - Check DynamoDB table exists: `aws dynamodb describe-table --table-name your-table --profile your-profile`
251
+ - Review logs in MCP client (usually stderr output)
252
+
253
+ ### Permission errors
254
+ - Ensure IAM user/role has DynamoDB permissions:
255
+ - `dynamodb:PutItem`
256
+ - `dynamodb:GetItem`
257
+ - `dynamodb:Query`
258
+ - `dynamodb:Scan`
259
+ - `dynamodb:UpdateItem`
260
+ - `dynamodb:DeleteItem`
261
+
262
+ ### Connection issues
263
+ - Verify network connectivity to AWS
264
+ - Check AWS region configuration
265
+ - Ensure MCP client is properly configured
266
+
267
+ ## Contributing
268
+
269
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
270
+
271
+ ## License
272
+
273
+ MIT License - see [LICENSE](LICENSE) file for details.
274
+
275
+ ## Support
276
+
277
+ - Issues: https://github.com/yourusername/hippocampus-mcp/issues
278
+ - Documentation: https://github.com/yourusername/hippocampus-mcp/wiki
279
+
280
+ ## Related Projects
281
+
282
+ - [Model Context Protocol](https://modelcontextprotocol.io/)
283
+ - [AWS MCP Servers](https://github.com/awslabs/mcp)
284
+ - [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
@@ -0,0 +1,20 @@
1
+ import type { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@aws-sdk/types';
2
+ export declare class CredentialsError extends Error {
3
+ readonly cause?: Error;
4
+ constructor(message: string, cause?: Error);
5
+ }
6
+ export interface CredentialsProviderConfig {
7
+ profile?: string;
8
+ region?: string;
9
+ }
10
+ export interface CredentialsResult {
11
+ credentials: AwsCredentialIdentity;
12
+ profile?: string;
13
+ source: string;
14
+ }
15
+ export declare function createCredentialsProvider(config?: CredentialsProviderConfig): AwsCredentialIdentityProvider;
16
+ export declare function loadCredentials(config?: CredentialsProviderConfig): Promise<CredentialsResult>;
17
+ export declare function validateCredentials(config?: CredentialsProviderConfig): Promise<boolean>;
18
+ export declare function getProfileName(config?: CredentialsProviderConfig): string;
19
+ export declare function getRegion(config?: CredentialsProviderConfig): string;
20
+ //# sourceMappingURL=credentials-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials-provider.d.ts","sourceRoot":"","sources":["../../src/aws/credentials-provider.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAK3F,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAyB,KAAK,CAAC,EAAE,KAAK,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAK3C;AAKD,MAAM,WAAW,yBAAyB;IAIxC,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,MAAM,WAAW,iBAAiB;IAIhC,WAAW,EAAE,qBAAqB,CAAC;IAKnC,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAcD,wBAAgB,yBAAyB,CACvC,MAAM,GAAE,yBAA8B,GACrC,6BAA6B,CAU/B;AAYD,wBAAsB,eAAe,CACnC,MAAM,GAAE,yBAA8B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAiDD,wBAAsB,mBAAmB,CACvC,MAAM,GAAE,yBAA8B,GACrC,OAAO,CAAC,OAAO,CAAC,CAalB;AAQD,wBAAgB,cAAc,CAAC,MAAM,GAAE,yBAA8B,GAAG,MAAM,CAE7E;AAQD,wBAAgB,SAAS,CAAC,MAAM,GAAE,yBAA8B,GAAG,MAAM,CAExE"}
@@ -0,0 +1,107 @@
1
+ import { fromIni } from '@aws-sdk/credential-provider-ini';
2
+ import { fromEnv } from '@aws-sdk/credential-provider-env';
3
+ import { defaultProvider } from '@aws-sdk/credential-provider-node';
4
+ export class CredentialsError extends Error {
5
+ cause;
6
+ constructor(message, cause) {
7
+ super(message);
8
+ this.name = 'CredentialsError';
9
+ this.cause = cause;
10
+ }
11
+ }
12
+ export function createCredentialsProvider(config = {}) {
13
+ const profile = config.profile || process.env['AWS_PROFILE'] || 'hc1';
14
+ const region = config.region || process.env['AWS_REGION'] || 'us-east-1';
15
+ return defaultProvider({
16
+ profile,
17
+ clientConfig: { region },
18
+ });
19
+ }
20
+ export async function loadCredentials(config = {}) {
21
+ const profile = config.profile || process.env['AWS_PROFILE'] || 'hc1';
22
+ const region = config.region || process.env['AWS_REGION'] || 'us-east-1';
23
+ try {
24
+ try {
25
+ const envProvider = fromEnv();
26
+ const credentials = await envProvider();
27
+ return {
28
+ credentials,
29
+ source: 'environment',
30
+ };
31
+ }
32
+ catch {
33
+ }
34
+ try {
35
+ const profileProvider = fromIni({ profile });
36
+ const credentials = await profileProvider();
37
+ return {
38
+ credentials,
39
+ profile,
40
+ source: 'profile',
41
+ };
42
+ }
43
+ catch {
44
+ }
45
+ const chainProvider = defaultProvider({
46
+ profile,
47
+ clientConfig: { region },
48
+ });
49
+ const credentials = await chainProvider();
50
+ return {
51
+ credentials,
52
+ profile,
53
+ source: 'credential-chain',
54
+ };
55
+ }
56
+ catch (error) {
57
+ const errorMessage = buildCredentialsErrorMessage(profile, error);
58
+ throw new CredentialsError(errorMessage, error);
59
+ }
60
+ }
61
+ function buildCredentialsErrorMessage(profile, error) {
62
+ const errorDetails = error instanceof Error ? error.message : String(error);
63
+ return `Failed to load AWS credentials for profile "${profile}".
64
+
65
+ Possible causes:
66
+ 1. AWS credentials are not configured on this machine
67
+ 2. The profile "${profile}" does not exist in ~/.aws/credentials
68
+ 3. The credentials file is malformed or inaccessible
69
+ 4. Environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set
70
+
71
+ To fix this issue:
72
+
73
+ Option 1: Configure AWS credentials using the AWS CLI
74
+ $ aws configure --profile ${profile}
75
+
76
+ Option 2: Set environment variables
77
+ $ export AWS_ACCESS_KEY_ID=your_access_key
78
+ $ export AWS_SECRET_ACCESS_KEY=your_secret_key
79
+ $ export AWS_REGION=us-east-1
80
+
81
+ Option 3: Use a different profile
82
+ $ export AWS_PROFILE=your_profile_name
83
+
84
+ For more information, see:
85
+ https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html
86
+
87
+ Original error: ${errorDetails}`;
88
+ }
89
+ export async function validateCredentials(config = {}) {
90
+ try {
91
+ await loadCredentials(config);
92
+ return true;
93
+ }
94
+ catch (error) {
95
+ if (error instanceof CredentialsError) {
96
+ throw error;
97
+ }
98
+ throw new CredentialsError('Failed to validate AWS credentials', error);
99
+ }
100
+ }
101
+ export function getProfileName(config = {}) {
102
+ return config.profile || process.env['AWS_PROFILE'] || 'hc1';
103
+ }
104
+ export function getRegion(config = {}) {
105
+ return config.region || process.env['AWS_REGION'] || 'us-east-1';
106
+ }
107
+ //# sourceMappingURL=credentials-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials-provider.js","sourceRoot":"","sources":["../../src/aws/credentials-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface Config {
2
+ awsRegion: string;
3
+ awsProfile: string;
4
+ tableName: string;
5
+ }
6
+ export declare class ConfigurationError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ export declare function loadConfig(): Config;
10
+ export declare function getConfig(): Config;
11
+ export declare function resetConfig(): void;
12
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/config/environment.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,MAAM;IAErB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAQD,wBAAgB,UAAU,IAAI,MAAM,CAcnC;AAyCD,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAKD,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
@@ -0,0 +1,42 @@
1
+ export class ConfigurationError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'ConfigurationError';
5
+ }
6
+ }
7
+ export function loadConfig() {
8
+ const awsRegion = process.env['AWS_REGION']?.trim() || 'us-east-1';
9
+ const awsProfile = process.env['AWS_PROFILE']?.trim() || 'hc1';
10
+ const tableName = process.env['TABLE_NAME']?.trim() || 'hc1-model-knowledge-241763622848';
11
+ validateConfig({ awsRegion, awsProfile, tableName });
12
+ return {
13
+ awsRegion,
14
+ awsProfile,
15
+ tableName,
16
+ };
17
+ }
18
+ function validateConfig(config) {
19
+ if (!config.awsRegion) {
20
+ throw new ConfigurationError('AWS_REGION cannot be empty');
21
+ }
22
+ if (!config.awsProfile) {
23
+ throw new ConfigurationError('AWS_PROFILE cannot be empty');
24
+ }
25
+ if (!config.tableName) {
26
+ throw new ConfigurationError('TABLE_NAME cannot be empty');
27
+ }
28
+ if (!config.tableName.startsWith('hc1-')) {
29
+ console.warn(`Warning: TABLE_NAME "${config.tableName}" does not follow project naming convention (hc1-*)`);
30
+ }
31
+ }
32
+ let cachedConfig = null;
33
+ export function getConfig() {
34
+ if (!cachedConfig) {
35
+ cachedConfig = loadConfig();
36
+ }
37
+ return cachedConfig;
38
+ }
39
+ export function resetConfig() {
40
+ cachedConfig = null;
41
+ }
42
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../src/config/environment.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAQD,MAAM,UAAU,UAAU;IAExB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,WAAW,CAAC;IACnE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,KAAK,CAAC;IAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,kCAAkC,CAAC;IAG1F,cAAc,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,SAAS;QACT,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC;AAQD,SAAS,cAAc,CAAC,MAAc;IAGpC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,kBAAkB,CAAC,4BAA4B,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,kBAAkB,CAAC,6BAA6B,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,kBAAkB,CAAC,4BAA4B,CAAC,CAAC;IAC7D,CAAC;IAGD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,IAAI,CACV,wBAAwB,MAAM,CAAC,SAAS,qDAAqD,CAC9F,CAAC;IACJ,CAAC;AACH,CAAC;AAKD,IAAI,YAAY,GAAkB,IAAI,CAAC;AAOvC,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,UAAU,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAKD,MAAM,UAAU,WAAW;IACzB,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { loadConfig, getConfig, resetConfig, ConfigurationError, type Config } from './environment';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { loadConfig, getConfig, resetConfig, ConfigurationError } from './environment';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAe,MAAM,eAAe,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type PutCommandInput, type GetCommandInput, type QueryCommandInput, type ScanCommandInput, type PutCommandOutput, type GetCommandOutput, type QueryCommandOutput, type ScanCommandOutput } from '@aws-sdk/lib-dynamodb';
2
+ export declare class DynamoDBError extends Error {
3
+ readonly cause?: Error;
4
+ readonly operation: string;
5
+ constructor(operation: string, message: string, cause?: Error);
6
+ }
7
+ export interface DynamoDBClientConfig {
8
+ region?: string;
9
+ profile?: string;
10
+ tableName?: string;
11
+ }
12
+ export declare class DynamoDBClientWrapper {
13
+ private readonly client;
14
+ private readonly tableName;
15
+ constructor(config?: DynamoDBClientConfig);
16
+ getTableName(): string;
17
+ putItem(item: Record<string, any>, options?: Omit<PutCommandInput, 'TableName' | 'Item'>): Promise<PutCommandOutput>;
18
+ getItem(key: Record<string, any>, options?: Omit<GetCommandInput, 'TableName' | 'Key'>): Promise<GetCommandOutput>;
19
+ query(options: Omit<QueryCommandInput, 'TableName'>): Promise<QueryCommandOutput>;
20
+ scan(options?: Omit<ScanCommandInput, 'TableName'>): Promise<ScanCommandOutput>;
21
+ private getErrorMessage;
22
+ close(): Promise<void>;
23
+ }
24
+ export declare function createDynamoDBClient(config?: DynamoDBClientConfig): DynamoDBClientWrapper;
25
+ //# sourceMappingURL=dynamodb-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamodb-client.d.ts","sourceRoot":"","sources":["../../src/data/dynamodb-client.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAyB,KAAK,CAAC,EAAE,KAAK,CAAC;IACvC,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAEtB,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAM9D;AAKD,MAAM,WAAW,oBAAoB;IAInC,MAAM,CAAC,EAAE,MAAM,CAAC;IAKhB,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAOvB,MAAM,GAAE,oBAAyB;IAwC7C,YAAY,IAAI,MAAM;IAYhB,OAAO,CACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,MAAM,CAAC,GACpD,OAAO,CAAC,gBAAgB,CAAC;IA0BtB,OAAO,CACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACxB,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,KAAK,CAAC,GACnD,OAAO,CAAC,gBAAgB,CAAC;IAyBtB,KAAK,CACT,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,GAC5C,OAAO,CAAC,kBAAkB,CAAC;IAwBxB,IAAI,CACR,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,GAC5C,OAAO,CAAC,iBAAiB,CAAC;IAuB7B,OAAO,CAAC,eAAe;IAUjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAQD,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,qBAAqB,CAEzF"}
@@ -0,0 +1,107 @@
1
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
2
+ import { DynamoDBDocumentClient, PutCommand, GetCommand, QueryCommand, ScanCommand, } from '@aws-sdk/lib-dynamodb';
3
+ import { createCredentialsProvider, getRegion } from '../aws/credentials-provider.js';
4
+ export class DynamoDBError extends Error {
5
+ cause;
6
+ operation;
7
+ constructor(operation, message, cause) {
8
+ super(message);
9
+ this.name = 'DynamoDBError';
10
+ this.operation = operation;
11
+ this.cause = cause;
12
+ }
13
+ }
14
+ export class DynamoDBClientWrapper {
15
+ client;
16
+ tableName;
17
+ constructor(config = {}) {
18
+ const region = config.region || getRegion({ region: config.region });
19
+ const credentialsProvider = createCredentialsProvider({
20
+ profile: config.profile,
21
+ region,
22
+ });
23
+ const baseClient = new DynamoDBClient({
24
+ region,
25
+ credentials: credentialsProvider,
26
+ });
27
+ this.client = DynamoDBDocumentClient.from(baseClient, {
28
+ marshallOptions: {
29
+ convertEmptyValues: false,
30
+ removeUndefinedValues: true,
31
+ convertClassInstanceToMap: true,
32
+ },
33
+ unmarshallOptions: {
34
+ wrapNumbers: false,
35
+ },
36
+ });
37
+ this.tableName = config.tableName ||
38
+ process.env['TABLE_NAME'] ||
39
+ 'hc1-model-knowledge-241763622848';
40
+ }
41
+ getTableName() {
42
+ return this.tableName;
43
+ }
44
+ async putItem(item, options) {
45
+ try {
46
+ const command = new PutCommand({
47
+ TableName: this.tableName,
48
+ Item: item,
49
+ ...options,
50
+ });
51
+ return await this.client.send(command);
52
+ }
53
+ catch (error) {
54
+ throw new DynamoDBError('PutItem', `Failed to put item in table ${this.tableName}: ${this.getErrorMessage(error)}`, error);
55
+ }
56
+ }
57
+ async getItem(key, options) {
58
+ try {
59
+ const command = new GetCommand({
60
+ TableName: this.tableName,
61
+ Key: key,
62
+ ...options,
63
+ });
64
+ return await this.client.send(command);
65
+ }
66
+ catch (error) {
67
+ throw new DynamoDBError('GetItem', `Failed to get item from table ${this.tableName}: ${this.getErrorMessage(error)}`, error);
68
+ }
69
+ }
70
+ async query(options) {
71
+ try {
72
+ const command = new QueryCommand({
73
+ TableName: this.tableName,
74
+ ...options,
75
+ });
76
+ return await this.client.send(command);
77
+ }
78
+ catch (error) {
79
+ throw new DynamoDBError('Query', `Failed to query table ${this.tableName}: ${this.getErrorMessage(error)}`, error);
80
+ }
81
+ }
82
+ async scan(options) {
83
+ try {
84
+ const command = new ScanCommand({
85
+ TableName: this.tableName,
86
+ ...options,
87
+ });
88
+ return await this.client.send(command);
89
+ }
90
+ catch (error) {
91
+ throw new DynamoDBError('Scan', `Failed to scan table ${this.tableName}: ${this.getErrorMessage(error)}`, error);
92
+ }
93
+ }
94
+ getErrorMessage(error) {
95
+ if (error instanceof Error) {
96
+ return error.message;
97
+ }
98
+ return String(error);
99
+ }
100
+ async close() {
101
+ this.client.destroy();
102
+ }
103
+ }
104
+ export function createDynamoDBClient(config) {
105
+ return new DynamoDBClientWrapper(config);
106
+ }
107
+ //# sourceMappingURL=dynamodb-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamodb-client.js","sourceRoot":"","sources":["../../src/data/dynamodb-client.ts"],"names":[],"mappings":"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"}