@contextai-core/cli 0.1.4 → 0.1.6

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/MCP_GUIDE.md CHANGED
@@ -26,9 +26,29 @@ The `contextai` CLI now exposes three "Agent-Aware" commands.
26
26
  ## 2. Native MCP Server (Official Support)
27
27
  For environments that support the full Model Context Protocol (like **Claude Desktop** or **Smithery**), you can configure ContextAI as a native server.
28
28
 
29
- ### Claude Desktop Configuration
29
+ ### 1. Install Globally (Recommended for Speed & Offline)
30
+ Run this once in your terminal:
31
+ ```bash
32
+ npm install -g @contextai-core/cli
33
+ ```
34
+
35
+ ### 2. Configure Claude Desktop
30
36
  Add this to your `claude_desktop_config.json`:
31
37
 
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "contextai": {
42
+ "command": "contextai",
43
+ "args": ["mcp"]
44
+ }
45
+ }
46
+ }
47
+ ```
48
+ *Note: This runs the locally installed binary. It is instant and works offline.*
49
+
50
+ ### Alternative: npx (Zero-Install)
51
+ If you prefer not to install globally, use `npx`. Note that this checks for updates on every run, which may be slower.
32
52
  ```json
33
53
  {
34
54
  "mcpServers": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contextai-core/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Give your AI agents persistent memory. Install pre-built context packs for Cursor, Windsurf, Copilot & more.",
5
5
  "author": "ContextAI",
6
6
  "license": "ISC",
@@ -29,7 +29,6 @@
29
29
  "MCP_GUIDE.md",
30
30
  "README.md"
31
31
  ],
32
- "type": "module",
33
32
  "dependencies": {
34
33
  "@modelcontextprotocol/sdk": "^1.25.1",
35
34
  "@supabase/supabase-js": "^2.89.0",
@@ -42,4 +41,4 @@
42
41
  "ora": "^8.0.0",
43
42
  "zod": "^4.2.1"
44
43
  }
45
- }
44
+ }
@@ -3,13 +3,34 @@ import chalk from "chalk";
3
3
  import path from "path";
4
4
  import fs from "fs";
5
5
 
6
+ /**
7
+ * Standard AGENTS.md content
8
+ * The vendor-neutral standard for AI agent context
9
+ */
10
+ const AGENTS_MD_CONTENT = `# AI Agent Context
11
+ <!-- Auto-generated by ContextAI — Do not edit, managed by .ai/ -->
12
+
13
+ ## 🚨 Boot Protocol
14
+
15
+ **System:** ContextAI (Unified Context Protocol)
16
+ **Root Context:** \`.ai/boot.md\`
17
+
18
+ **Instructions for Agents:**
19
+ 1. Read \`.ai/boot.md\` immediately.
20
+ 2. Follow the boot protocol described there.
21
+ 3. Load the project state from \`.ai/*/context/MASTER.md\`.
22
+
23
+ > This file adheres to the [AGENTS.md](https://agents.md) standard for AI discovery.
24
+ `;
25
+
6
26
  /**
7
27
  * Initializes the ContextAI Shared Brain (.ai).
8
- * Creates the directory structure but installs NO packs by default.
28
+ * Creates directory structure and the generic AGENTS.md discovery file.
9
29
  */
10
30
  export async function init() {
11
31
  console.log(chalk.green('🧠 Initializing ContextAI Shared Brain...'));
12
- const aiDir = path.join(process.cwd(), '.ai');
32
+ const cwd = process.cwd();
33
+ const aiDir = path.join(cwd, '.ai');
13
34
 
14
35
  // 1. Create .ai directory if missing
15
36
  if (!fs.existsSync(aiDir)) {
@@ -19,8 +40,94 @@ export async function init() {
19
40
  console.log(chalk.yellow(' .ai/ directory already exists.'));
20
41
  }
21
42
 
43
+ // 2. Create context.json manifest if missing
44
+ const manifestPath = path.join(aiDir, 'context.json');
45
+ if (!fs.existsSync(manifestPath)) {
46
+ fs.writeFileSync(manifestPath, JSON.stringify({
47
+ version: "1.0.0",
48
+ packages: {}
49
+ }, null, 2));
50
+ console.log(chalk.blue(' Created context.json manifest.'));
51
+ }
52
+
53
+ // 3. Create boot.md router
54
+ const bootPath = path.join(aiDir, 'boot.md');
55
+ if (!fs.existsSync(bootPath)) {
56
+ fs.writeFileSync(bootPath, `# AI Context System
57
+
58
+ > **Agents: Start here.**
59
+
60
+ ## Installed Packs
61
+ Check \`context.json\` for installed packs, then read the boot.md inside each pack.
62
+
63
+ ## Quick Boot
64
+ \`\`\`bash
65
+ # 1. Find installed packs
66
+ cat .ai/context.json
67
+
68
+ # 2. Read the pack's boot protocol
69
+ cat .ai/<pack-name>/boot.md
70
+
71
+ # 3. Load project state
72
+ cat .ai/<pack-name>/context/MASTER.md
73
+ \`\`\`
74
+
75
+ ## No Pack Installed?
76
+ Run: \`npx contextai install @newraozxcode/ucp\`
77
+ `);
78
+ console.log(chalk.blue(' Created boot.md router.'));
79
+ }
80
+
81
+ // 4. Create AGENTS.md (The Standard)
82
+ console.log(chalk.blue('\nšŸ“” Configuring agent discovery...'));
83
+ const agentsPath = path.join(cwd, 'AGENTS.md');
84
+
85
+ if (!fs.existsSync(agentsPath)) {
86
+ fs.writeFileSync(agentsPath, AGENTS_MD_CONTENT);
87
+ console.log(chalk.green(' āœ“ Created AGENTS.md (Standard)'));
88
+ } else {
89
+ console.log(chalk.gray(' AGENTS.md already exists, skipping.'));
90
+ }
91
+
92
+ // 5. Inject link into README.md
93
+ const readmePath = path.join(cwd, 'README.md');
94
+ const linkText = `\n\n> šŸ¤– **AI Agents:** Please read [AGENTS.md](AGENTS.md) for context.`;
95
+
96
+ if (fs.existsSync(readmePath)) {
97
+ const content = fs.readFileSync(readmePath, 'utf8');
98
+ if (!content.includes('AGENTS.md')) {
99
+ fs.appendFileSync(readmePath, linkText);
100
+ console.log(chalk.green(' āœ“ Updated README.md with agent link'));
101
+ } else {
102
+ console.log(chalk.gray(' README.md already has agent link.'));
103
+ }
104
+ } else {
105
+ fs.writeFileSync(readmePath, `# Project\n${linkText}`);
106
+ console.log(chalk.green(' āœ“ Created README.md with agent link'));
107
+ }
108
+
109
+ // 6. Update .gitignore if exists
110
+ const gitignorePath = path.join(cwd, '.gitignore');
111
+ if (fs.existsSync(gitignorePath)) {
112
+ let gitignore = fs.readFileSync(gitignorePath, 'utf8');
113
+ const additions = ['.ai/*/context/active/', '.ai/*/archive/'];
114
+ let added = false;
115
+
116
+ for (const pattern of additions) {
117
+ if (!gitignore.includes(pattern)) {
118
+ gitignore += `\n${pattern}`;
119
+ added = true;
120
+ }
121
+ }
122
+
123
+ if (added) {
124
+ fs.writeFileSync(gitignorePath, gitignore);
125
+ console.log(chalk.blue(' Updated .gitignore with context exclusions.'));
126
+ }
127
+ }
128
+
22
129
  console.log(chalk.green('\nāœ… Initialization Complete!'));
23
- console.log(chalk.white(' Your project is ready context.'));
130
+ console.log(chalk.white(' Your project is ready for AI context.'));
24
131
  console.log(chalk.cyan('\n Next Step: Install a Context Pack'));
25
132
  console.log(chalk.gray(' $ npx contextai install @<username>/ucp'));
26
133
  }
@@ -18,6 +18,11 @@ function loadCredentials() {
18
18
  }
19
19
 
20
20
  export async function installPackage(packageSlug, options = {}) {
21
+ // Special Alias for UCP
22
+ if (packageSlug === 'ucp') {
23
+ packageSlug = '@contextai/ucp';
24
+ }
25
+
21
26
  const spinner = ora(`Installing ${packageSlug}...`).start();
22
27
 
23
28
  const aiDir = path.join(process.cwd(), '.ai');
@@ -33,7 +38,9 @@ export async function installPackage(packageSlug, options = {}) {
33
38
  // 1. Fetch pack from Supabase
34
39
  spinner.text = `Fetching pack info for ${packageSlug}...`;
35
40
 
36
- const { data: purchaseData, error: purchaseError } = await getSupabase()
41
+ const supabase = getSupabase();
42
+
43
+ const { data: pack, error } = await supabase
37
44
  .from('packs')
38
45
  .select('*')
39
46
  .eq('slug', packageSlug)
@@ -124,7 +131,7 @@ export async function installPackage(packageSlug, options = {}) {
124
131
  let targetDir = '';
125
132
  if (packageSlug.startsWith('@')) {
126
133
  const [scope, name] = packageSlug.substring(1).split('/');
127
- targetDir = path.join(aiDir, '@' + scope, name);
134
+ targetDir = path.join(aiDir, `${scope}-${name}`);
128
135
  } else {
129
136
  targetDir = path.join(aiDir, packageSlug);
130
137
  }
@@ -153,10 +160,13 @@ export async function installPackage(packageSlug, options = {}) {
153
160
  const tempDir = path.join(os.tmpdir(), `contextai-${Date.now()}`);
154
161
  zip.extractAllTo(tempDir, true);
155
162
 
156
- // Find actual root
157
- const items = fs.readdirSync(tempDir);
158
- const rootItem = items.find(i => fs.statSync(path.join(tempDir, i)).isDirectory());
159
- const sourceDir = rootItem ? path.join(tempDir, rootItem) : tempDir;
163
+ // Find actual root (only unwrap if it's a single folder)
164
+ const items = fs.readdirSync(tempDir).filter(i => !i.startsWith('.') && i !== '__MACOSX');
165
+ let sourceDir = tempDir;
166
+
167
+ if (items.length === 1 && fs.statSync(path.join(tempDir, items[0])).isDirectory()) {
168
+ sourceDir = path.join(tempDir, items[0]);
169
+ }
160
170
 
161
171
  spinner.text = 'Injecting Verified Context...';
162
172
  copyRecursiveSync(sourceDir, targetDir);
@@ -240,7 +250,7 @@ async function installFromLocal(localPkg, packageName, aiDir, manifestPath, spin
240
250
  targetDir = path.join(aiDir, 'ucp');
241
251
  } else if (packageName.startsWith('@')) {
242
252
  const [scope, name] = packageName.substring(1).split('/');
243
- targetDir = path.join(aiDir, '@' + scope, name);
253
+ targetDir = path.join(aiDir, `${scope}-${name}`);
244
254
  } else {
245
255
  targetDir = path.join(aiDir, packageName);
246
256
  }