@unifiedmemory/cli 1.2.0 → 1.3.1

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/.env.example CHANGED
@@ -1,29 +1,44 @@
1
1
  # UnifiedMemory CLI Configuration
2
- # Copy this file to .env and fill in your values
2
+ #
3
+ # ============================================
4
+ # IMPORTANT: This file is OPTIONAL
5
+ # ============================================
6
+ # The CLI includes production defaults for all values below.
7
+ # This file is only needed if you want to override defaults
8
+ # (e.g., for development, testing, or custom deployments).
9
+ #
10
+ # For normal usage, you can delete this file - the CLI will work without it.
11
+ #
12
+ # To use custom values:
13
+ # 1. Copy this file to .env
14
+ # 2. Uncomment and modify the values you want to override
15
+ # 3. Leave other values commented to use the built-in defaults
3
16
 
4
17
  # ============================================
5
- # REQUIRED: Clerk OAuth Configuration
18
+ # Clerk OAuth Configuration
6
19
  # ============================================
7
- # Get these from your Clerk dashboard: https://dashboard.clerk.com
8
- CLERK_CLIENT_ID=your_clerk_client_id_here
9
- CLERK_DOMAIN=your-app.clerk.accounts.dev
20
+ # Production defaults are included in the CLI
21
+ # Only override these if using a custom Clerk instance
22
+ # CLERK_CLIENT_ID=custom_clerk_client_id
23
+ # CLERK_DOMAIN=custom-app.clerk.accounts.dev
10
24
 
11
25
  # ============================================
12
- # REQUIRED: API Configuration
26
+ # API Configuration
13
27
  # ============================================
14
- # Your UnifiedMemory API gateway URL
15
- API_ENDPOINT=https://your-api-gateway.zuplo.dev
28
+ # Production default is included in the CLI
29
+ # Only override this for local testing or custom deployments
30
+ # API_ENDPOINT=https://custom-api-gateway.zuplo.dev
16
31
 
17
32
  # ============================================
18
- # OPTIONAL: OAuth Flow Configuration
33
+ # OAuth Flow Configuration
19
34
  # ============================================
20
- # Customize the OAuth redirect URI and local server port
21
- # Default values work for most users
35
+ # Defaults to localhost:3333 for the OAuth callback server
36
+ # Customize only if you need a different port or URL
22
37
  # REDIRECT_URI=http://localhost:3333/callback
23
38
  # PORT=3333
24
39
 
25
40
  # ============================================
26
- # OPTIONAL: Clerk Client Secret
41
+ # Clerk Client Secret (Optional)
27
42
  # ============================================
28
43
  # Not required for PKCE flow (recommended)
29
44
  # Only set this if specifically instructed
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - **lib/config.js** - Embedded production defaults for zero-configuration installation
13
+ - Added default values for `CLERK_CLIENT_ID`, `CLERK_DOMAIN`, and `API_ENDPOINT`
14
+ - Users no longer need to create `.env` files after `npm install`
15
+ - Environment variables can still override defaults for development/testing
16
+ - Simplified `validateConfig()` to remove "missing environment variables" errors
17
+ - CLI now works immediately after installation with no setup required
18
+
19
+ - **.env.example** - Updated documentation to clarify optional nature
20
+ - Added prominent note that the file is OPTIONAL
21
+ - Explained that production defaults are included in the CLI
22
+ - Commented out all example values to emphasize optional overrides
23
+ - Clarified when overrides might be needed (development, testing, custom deployments)
24
+
25
+ - **README.md** - Improved installation and configuration documentation
26
+ - Added "No configuration required!" note to installation section
27
+ - Renamed "Configuration" to "Advanced Configuration (Optional)"
28
+ - Removed "Missing environment variables" from troubleshooting
29
+ - Emphasized zero-friction installation experience
30
+
10
31
  ## [1.2.0] - 2026-01-08
11
32
 
12
33
  ### Added
package/README.md CHANGED
@@ -171,6 +171,8 @@ npm install -g @unifiedmemory/cli
171
171
  um --version
172
172
  ```
173
173
 
174
+ **No configuration required!** The CLI includes production defaults and works immediately after installation.
175
+
174
176
  **Option 2: Use with npx (no installation)**
175
177
  ```bash
176
178
  npx @unifiedmemory/cli init
@@ -213,43 +215,35 @@ Tokens automatically refresh. If you see auth errors:
213
215
  um login
214
216
  ```
215
217
 
216
- ### Missing environment variables
217
- If you see "Missing required environment variables" error:
218
- 1. Copy `.env.example` to `.env` in the CLI installation directory
219
- 2. Fill in your Clerk and API credentials
220
- 3. See Configuration section below for details
218
+ ## Advanced Configuration (Optional)
221
219
 
222
- ## Configuration
220
+ **For most users, no configuration is needed!** The CLI includes production defaults and works out of the box.
223
221
 
224
- The CLI requires environment variables for Clerk OAuth and API access. These should never be hardcoded in your project.
222
+ For development, testing, or custom deployments, you can override defaults by creating a `.env` file:
225
223
 
226
- **Step 1: Create `.env` file**
224
+ **Step 1: Create `.env` file** (optional)
227
225
  ```bash
228
226
  # In the um-cli installation directory (find with: npm root -g)
229
227
  cp .env.example .env
230
228
  ```
231
229
 
232
- **Step 2: Add your credentials**
230
+ **Step 2: Override the values you need** (optional)
233
231
  ```bash
234
- # Required: Clerk OAuth Configuration
235
- CLERK_CLIENT_ID=your_clerk_client_id_here
236
- CLERK_DOMAIN=your-app.clerk.accounts.dev
237
-
238
- # Required: API Configuration
239
- API_ENDPOINT=https://your-api-gateway.zuplo.dev
240
- ```
232
+ # Optional: Override production defaults
233
+ CLERK_CLIENT_ID=custom_clerk_client_id
234
+ CLERK_DOMAIN=custom-app.clerk.accounts.dev
235
+ API_ENDPOINT=https://custom-api-gateway.zuplo.dev
241
236
 
242
- Get these values from:
243
- - **Clerk credentials**: [Clerk Dashboard](https://dashboard.clerk.com)
244
- - **API endpoint**: Your UnifiedMemory deployment
245
-
246
- **Optional configuration**:
247
- ```bash
248
- # Customize OAuth redirect (defaults shown)
237
+ # Optional: Customize OAuth redirect (defaults to localhost:3333)
249
238
  REDIRECT_URI=http://localhost:3333/callback
250
239
  PORT=3333
251
240
  ```
252
241
 
242
+ **When you might need this**:
243
+ - 🔧 **Development**: Testing with a local API backend
244
+ - 🧪 **Testing**: Using a staging or test Clerk instance
245
+ - 🏢 **Custom Deployment**: Running your own UnifiedMemory instance
246
+
253
247
  See `.env.example` for the complete template with documentation.
254
248
 
255
249
  ## Privacy & Security
@@ -52,6 +52,7 @@ export async function record(summary, options = {}) {
52
52
  };
53
53
 
54
54
  // 5. Prepare tool arguments
55
+ // Note: headers (X-Org-Id, X-User-Id) are handled at HTTP level by authHeaders
55
56
  const toolArgs = {
56
57
  body: {
57
58
  summary_text: summary,
@@ -59,10 +60,6 @@ export async function record(summary, options = {}) {
59
60
  source: options.source || 'um-cli',
60
61
  confidence: options.confidence ? parseFloat(options.confidence) : 0.7,
61
62
  tags: options.tags ? options.tags.split(',') : []
62
- },
63
- headers: {
64
- 'X-Org-Id': tokenData.selectedOrg?.id || tokenData.decoded?.sub,
65
- 'X-User-Id': tokenData.decoded?.sub
66
63
  }
67
64
  };
68
65
 
@@ -89,22 +86,47 @@ export async function record(summary, options = {}) {
89
86
  projectContext
90
87
  );
91
88
 
92
- // 7. Handle response
89
+ // 7. Handle response - validate success properly
93
90
  if (result.content && Array.isArray(result.content)) {
94
91
  const textContent = result.content.find(c => c.type === 'text');
95
92
  if (textContent) {
96
- const response = JSON.parse(textContent.text);
97
- console.log(chalk.green('✓ Note created successfully'));
98
- console.log(chalk.gray(` Note ID: ${response.note_id || 'N/A'}`));
99
- if (response.confidence) {
100
- console.log(chalk.gray(` Confidence: ${response.confidence}`));
93
+ try {
94
+ const response = JSON.parse(textContent.text);
95
+
96
+ // Check for error in response
97
+ if (result.isError || response.error || response.detail) {
98
+ throw new Error(response.error || response.detail || 'Note creation failed');
99
+ }
100
+
101
+ console.log(chalk.green('✓ Note created successfully'));
102
+ console.log(chalk.gray(` Note ID: ${response.note_id || 'N/A'}`));
103
+ if (response.confidence) {
104
+ console.log(chalk.gray(` Confidence: ${response.confidence}`));
105
+ }
106
+ return response;
107
+ } catch (parseError) {
108
+ if (parseError.message.includes('Note creation failed')) {
109
+ throw parseError;
110
+ }
111
+ throw new Error(`Failed to parse API response: ${parseError.message}`);
101
112
  }
102
- return response;
103
113
  }
104
114
  }
105
115
 
106
- console.log(chalk.green('✓ Note created'));
107
- return result;
116
+ // Check for direct note response (some backends return this directly)
117
+ if (result.note_id) {
118
+ console.log(chalk.green('✓ Note created successfully'));
119
+ console.log(chalk.gray(` Note ID: ${result.note_id}`));
120
+ return result;
121
+ }
122
+
123
+ // Check for error indicators
124
+ if (result.error || result.detail || result.isError) {
125
+ throw new Error(result.error || result.detail || 'Note creation failed');
126
+ }
127
+
128
+ // Unknown response format - fail explicitly instead of silent success
129
+ throw new Error('Unexpected response format from API');
108
130
 
109
131
  } catch (error) {
110
132
  console.error(chalk.red('✗ Failed to create note:'));
package/lib/config.js CHANGED
@@ -9,49 +9,37 @@ const __dirname = dirname(__filename);
9
9
  dotenvConfig({ path: join(__dirname, '..', '.env') });
10
10
 
11
11
  export const config = {
12
- // Required: Clerk OAuth configuration
13
- clerkClientId: process.env.CLERK_CLIENT_ID,
12
+ // Clerk OAuth configuration (production defaults, can be overridden via env vars)
13
+ clerkClientId: process.env.CLERK_CLIENT_ID || 'nULlnomaKB9rRGP2',
14
14
  clerkClientSecret: process.env.CLERK_CLIENT_SECRET, // Optional for PKCE flow
15
- clerkDomain: process.env.CLERK_DOMAIN,
15
+ clerkDomain: process.env.CLERK_DOMAIN || 'clear-caiman-45.clerk.accounts.dev',
16
16
 
17
- // Required: API configuration
18
- apiEndpoint: process.env.API_ENDPOINT,
17
+ // API configuration (production default, can be overridden via env var)
18
+ apiEndpoint: process.env.API_ENDPOINT || 'https://rose-asp-main-1c0b114.d2.zuplo.dev',
19
19
 
20
- // Optional: OAuth flow configuration (non-sensitive defaults OK)
20
+ // OAuth flow configuration (localhost defaults for callback server)
21
21
  redirectUri: process.env.REDIRECT_URI || 'http://localhost:3333/callback',
22
22
  port: parseInt(process.env.PORT || '3333', 10)
23
23
  };
24
24
 
25
- // Validation function - ensures required configuration is present
25
+ // Validation function - validates configuration values
26
26
  export function validateConfig() {
27
- const missing = [];
28
-
29
- if (!config.clerkClientId) {
30
- missing.push('CLERK_CLIENT_ID');
31
- }
32
-
33
- if (!config.clerkDomain) {
34
- missing.push('CLERK_DOMAIN');
35
- }
36
-
37
- if (!config.apiEndpoint) {
38
- missing.push('API_ENDPOINT');
39
- }
40
-
41
- if (missing.length > 0) {
42
- throw new Error(
43
- `Missing required environment variables: ${missing.join(', ')}\n\n` +
44
- `Please create a .env file in the project root with these values.\n` +
45
- `See .env.example for a template.`
46
- );
47
- }
48
-
49
- // Validate URL format for apiEndpoint
27
+ // Validate URL format for apiEndpoint (now guaranteed to exist via defaults)
50
28
  try {
51
29
  new URL(config.apiEndpoint);
52
30
  } catch (e) {
53
31
  throw new Error(`API_ENDPOINT must be a valid URL (got: ${config.apiEndpoint})`);
54
32
  }
55
33
 
34
+ // Validate clerkDomain is not empty (basic sanity check)
35
+ if (!config.clerkDomain || config.clerkDomain.trim() === '') {
36
+ throw new Error('CLERK_DOMAIN cannot be empty');
37
+ }
38
+
39
+ // Validate clerkClientId is not empty (basic sanity check)
40
+ if (!config.clerkClientId || config.clerkClientId.trim() === '') {
41
+ throw new Error('CLERK_CLIENT_ID cannot be empty');
42
+ }
43
+
56
44
  return true;
57
45
  }
package/lib/mcp-proxy.js CHANGED
@@ -14,6 +14,23 @@ function transformToolSchema(tool) {
14
14
  // Deep clone to avoid mutations
15
15
  const transformed = JSON.parse(JSON.stringify(tool));
16
16
 
17
+ // Remove headers entirely - proxy handles all headers at HTTP level
18
+ // AI never needs to provide X-Org-Id, X-User-Id, etc.
19
+ if (transformed.inputSchema?.properties?.headers) {
20
+ delete transformed.inputSchema.properties.headers;
21
+
22
+ // Also remove from required array if present
23
+ if (transformed.inputSchema.required && Array.isArray(transformed.inputSchema.required)) {
24
+ transformed.inputSchema.required = transformed.inputSchema.required.filter(
25
+ field => field !== 'headers'
26
+ );
27
+
28
+ if (transformed.inputSchema.required.length === 0) {
29
+ delete transformed.inputSchema.required;
30
+ }
31
+ }
32
+ }
33
+
17
34
  // Check if tool has pathParams in schema
18
35
  if (!transformed.inputSchema?.properties?.pathParams) {
19
36
  return transformed;
@@ -79,22 +96,31 @@ function injectContextParams(args, authContext, projectContext) {
79
96
  injected.pathParams = {};
80
97
  }
81
98
 
99
+ // Ensure headers object exists (gateway expects these in tool args)
100
+ if (!injected.headers) {
101
+ injected.headers = {};
102
+ }
103
+
82
104
  // Inject user ID from decoded JWT
83
105
  if (authContext?.decoded?.sub) {
84
106
  injected.pathParams.user = authContext.decoded.sub;
107
+ injected.headers['X-User-Id'] = authContext.decoded.sub;
85
108
  }
86
109
 
87
110
  // Inject org ID (from selectedOrg or fallback to user ID for personal account)
88
111
  if (authContext?.selectedOrg?.id) {
89
112
  injected.pathParams.org = authContext.selectedOrg.id;
113
+ injected.headers['X-Org-Id'] = authContext.selectedOrg.id;
90
114
  } else if (authContext?.decoded?.sub) {
91
115
  // Fallback to user ID for personal account context
92
116
  injected.pathParams.org = authContext.decoded.sub;
117
+ injected.headers['X-Org-Id'] = authContext.decoded.sub;
93
118
  }
94
119
 
95
120
  // Inject project ID from project config
96
121
  if (projectContext?.project_id) {
97
122
  injected.pathParams.proj = projectContext.project_id;
123
+ injected.headers['X-Project-Id'] = projectContext.project_id;
98
124
  }
99
125
 
100
126
  return injected;
@@ -1,72 +1,82 @@
1
1
  // Unique marker to detect if instructions already present
2
- export const MEMORY_INSTRUCTIONS_MARKER = '<!-- UNIFIEDMEMORY_INSTRUCTIONS_V1 -->';
2
+ export const MEMORY_INSTRUCTIONS_MARKER = '<!-- UNIFIEDMEMORY_INSTRUCTIONS_V2 -->';
3
3
 
4
4
  export function getMemoryInstructions() {
5
5
  return `${MEMORY_INSTRUCTIONS_MARKER}
6
6
 
7
- # UnifiedMemory Automatic Integration
7
+ # UnifiedMemory Integration (REQUIRED)
8
8
 
9
- When working in this project, automatically integrate with UnifiedMemory to maintain project knowledge:
9
+ This project uses UnifiedMemory for persistent knowledge management. The \`unifiedmemory\` MCP server is configured and MUST be used for all relevant queries.
10
10
 
11
- ## 1. Search Before Responding
11
+ ## Available Tools
12
12
 
13
- **When**: User submits any query or request
14
- **Action**: Use the \`unifiedmemory\` MCP tool to search for relevant context
15
- **Usage**:
16
- - Send the user's query to the search tool
17
- - Review the search results for relevant prior work, decisions, or context
18
- - Incorporate findings into your response
13
+ The \`unifiedmemory\` MCP server provides these tools (call them like any MCP tool):
19
14
 
20
- Example:
21
- \`\`\`
22
- User: "Add dark mode to the dashboard"
23
- Search: unifiedmemory search --query "dark mode dashboard styling"
24
- Review results for existing patterns or decisions
25
- Respond with context-aware answer
26
- \`\`\`
15
+ | Tool | Purpose | Required Parameters |
16
+ |------|---------|---------------------|
17
+ | \`search_notes\` | **Primary tool** - Search project knowledge base | \`query\` (search text) |
18
+ | \`create_note\` | Record decisions, plans, or completions | \`summary_text\`, \`topic\` |
19
+ | \`list_notes\` | List all notes in current project | None |
20
+ | \`get_note\` | Retrieve a specific note by ID | \`note_id\` |
21
+ | \`list_topics\` | List available topics/categories | None |
22
+ | \`create_topic\` | Create a new topic for organization | \`name\` |
23
+ | \`list_projects\` | List available projects | None |
27
24
 
28
- ## 2. Record Plans
25
+ All tools automatically use the correct project context - no additional configuration needed.
29
26
 
30
- **When**: Creating an implementation plan or design approach
31
- **Action**: Record the plan as a note using the \`unifiedmemory\` tool
32
- **Format**:
33
- - Include: objective, approach, key steps, important decisions
34
- - Keep concise but informative
35
- - Limit to under 1000 characters for optimal indexing
27
+ ## MANDATORY: Search Before Implementing
36
28
 
37
- Example:
38
- \`\`\`
39
- Plan created for dark mode feature
40
- → unifiedmemory create_note --content "Plan: Dark mode implementation. Approach: CSS variables + localStorage persistence. Steps: 1) Define color tokens, 2) Add toggle component, 3) Persist preference. Decision: Use system preference as default."
41
- \`\`\`
29
+ **REQUIREMENT**: Before responding to ANY coding task, feature request, or implementation question, you MUST:
30
+
31
+ 1. Call the \`search_notes\` tool with the user's query or relevant keywords
32
+ 2. Review returned results for prior decisions, patterns, or context
33
+ 3. Incorporate relevant findings into your response
34
+ 4. Mention what context you found (or didn't find) in your response
35
+
36
+ ### When to Search
42
37
 
43
- ## 3. Record Task Completions
38
+ You MUST search before:
39
+ - Implementing any feature (search for existing patterns)
40
+ - Fixing any bug (search for related issues)
41
+ - Answering architecture questions (search for design decisions)
42
+ - Modifying any component (search for existing conventions)
43
+ - ANY coding task, no exceptions
44
44
 
45
- **When**: After completing any task, feature, or significant milestone
46
- **Action**: Create a summary note using the \`unifiedmemory\` tool
47
- **Format**:
48
- - Summarize what was accomplished and why
49
- - Include key technical decisions or gotchas
50
- - **IMPORTANT**: Limit to under 1000 characters
51
- - Focus on outcomes, not detailed code
45
+ ### Example Workflow
52
46
 
53
- Example:
54
47
  \`\`\`
55
- Completed dark mode feature
56
- → unifiedmemory create_note --content "Completed: Dark mode toggle in dashboard. Implemented CSS custom properties with theme switcher component. User preference stored in localStorage. Respects system prefers-color-scheme by default. All components updated to use theme tokens."
48
+ User: "Add authentication to the API"
49
+
50
+ Step 1: Call search_notes with query "authentication API security"
51
+ Step 2: Review results - found: "Decision: Use JWT with refresh tokens"
52
+ Step 3: Implement following the established pattern
53
+ Step 4: Respond: "Based on prior decisions in UnifiedMemory, I'll use JWT..."
57
54
  \`\`\`
58
55
 
59
- ## Summary Guidelines
56
+ ## Do NOT Skip These Tools
57
+
58
+ - ❌ NEVER start implementing without calling \`search_notes\` first
59
+ - ❌ NEVER assume patterns without checking the knowledge base
60
+ - ❌ NEVER skip search for "simple" tasks - context always helps
61
+ - ✅ ALWAYS search even if you think you know the answer
62
+ - ✅ ALWAYS mention search results (or lack thereof) in your response
63
+ - ✅ ALWAYS use these tools when they can provide relevant context
64
+
65
+ ## Recording Knowledge with create_note
66
+
67
+ After completing significant work, use \`create_note\` to record:
68
+ - Implementation decisions and rationale
69
+ - Completed features or fixes
70
+ - Architectural patterns established
71
+ - Gotchas or lessons learned
72
+
73
+ Keep notes concise (under 1000 characters) and focus on the "why" not the "what".
74
+
75
+ ## Additional Tools
60
76
 
61
- - **DO**: Search context before responding
62
- - ✅ **DO**: Record plans and completions automatically
63
- - ✅ **DO**: Keep notes under 1000 characters
64
- - ✅ **DO**: Focus on decisions, outcomes, and context
65
- - ❌ **DON'T**: Record trivial tasks (typo fixes, minor edits)
66
- - ❌ **DON'T**: Include full code in notes
67
- - ❌ **DON'T**: Duplicate information already in git commits
77
+ Use \`list_topics\` to understand project organization, \`list_notes\` to browse available knowledge, and \`get_note\` to retrieve full details of relevant notes found via search.
68
78
 
69
79
  ---
70
- *Auto-generated by UnifiedMemory CLI v1.0*
80
+ *UnifiedMemory CLI - Knowledge that persists*
71
81
  `;
72
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifiedmemory/cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "UnifiedMemory CLI - AI code assistant integration",
5
5
  "main": "index.js",
6
6
  "type": "module",