lingot 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.
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # lingot
2
+
3
+ The standard library for AI agents. Intelligence blocks that make Cursor, Windsurf, and Claude Code measurably better at writing code.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install a block
9
+ npx lingot add supabase-auth
10
+
11
+ # Detect your stack and see recommendations
12
+ npx lingot init
13
+
14
+ # Install multiple blocks
15
+ npx lingot add drizzle-orm stripe-billing tailwind-v4
16
+ ```
17
+
18
+ ## What Are Intelligence Blocks?
19
+
20
+ Each block contains 4 files of curated, token-optimized context:
21
+
22
+ - **knowledge.md** — Dense domain knowledge, mental models, architecture patterns
23
+ - **rules.xml** — ALWAYS/NEVER heuristic rules that prevent hallucinations
24
+ - **examples.yaml** — Few-shot input/output examples for common tasks
25
+ - **manifest.json** — Metadata, version, scope coverage
26
+
27
+ Load blocks into your AI agent's context to get measurably better output. Our Supabase Auth block improved LLM accuracy from 35.3% to 100% on domain-specific tasks.
28
+
29
+ ## Commands
30
+
31
+ | Command | Description |
32
+ |---------|-------------|
33
+ | `lingot add <name>` | Install a block from the registry |
34
+ | `lingot init` | Scan package.json and suggest relevant blocks |
35
+ | `lingot list` | List installed blocks |
36
+ | `lingot inspect <name>` | Show block details and token counts |
37
+ | `lingot serve` | Start local MCP server for installed blocks |
38
+
39
+ ## 40+ Blocks Available
40
+
41
+ Auth, frontend, backend, database, AI SDKs, payments, testing, DevOps, and more.
42
+
43
+ Browse all blocks at [lingot.sh](https://lingot.sh).
44
+
45
+ ## MCP Integration
46
+
47
+ Start the local MCP server to expose installed blocks to any MCP-compatible agent:
48
+
49
+ ```bash
50
+ lingot serve
51
+ ```
52
+
53
+ This provides two tools:
54
+ - `search_packages` — Find relevant blocks by topic or domain
55
+ - `get_package_context` — Load block content into agent context
56
+
57
+ ## License
58
+
59
+ MIT
package/bin/lingot.js ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { install } from '../lib/install.js';
4
+ import { init } from '../lib/init.js';
5
+ import { list } from '../lib/list.js';
6
+ import { serve } from '../lib/serve.js';
7
+ import { inspect } from '../lib/inspect.js';
8
+ import { PACKAGES_DIR } from '../lib/config.js';
9
+
10
+ const [,, command, ...args] = process.argv;
11
+
12
+ const HELP = `
13
+ lingot — The standard library for AI agents.
14
+
15
+ Usage:
16
+ lingot add <name> Install an intelligence block from the registry
17
+ lingot init Detect your stack and suggest relevant blocks
18
+ lingot list List installed blocks
19
+ lingot inspect <name> Show block details and token counts
20
+ lingot serve Start local MCP server for installed blocks
21
+ lingot help Show this help
22
+
23
+ Blocks are installed to: ${PACKAGES_DIR}
24
+
25
+ Examples:
26
+ npx lingot add supabase-auth
27
+ npx lingot init
28
+ npx lingot add drizzle-orm stripe-billing tailwind-v4
29
+
30
+ Registry: https://lingot.sh
31
+ `;
32
+
33
+ async function main() {
34
+ switch (command) {
35
+ case 'add':
36
+ case 'install':
37
+ case 'i':
38
+ if (!args[0]) {
39
+ console.error('Usage: lingot add <block-name> [block-name...]');
40
+ process.exit(1);
41
+ }
42
+ for (const name of args) {
43
+ await install(name);
44
+ }
45
+ break;
46
+
47
+ case 'init':
48
+ await init();
49
+ break;
50
+
51
+ case 'list':
52
+ case 'ls':
53
+ await list();
54
+ break;
55
+
56
+ case 'inspect':
57
+ if (!args[0]) {
58
+ console.error('Usage: lingot inspect <block-name>');
59
+ process.exit(1);
60
+ }
61
+ await inspect(args[0]);
62
+ break;
63
+
64
+ case 'serve':
65
+ await serve();
66
+ break;
67
+
68
+ case 'help':
69
+ case '--help':
70
+ case '-h':
71
+ case undefined:
72
+ console.log(HELP);
73
+ break;
74
+
75
+ default:
76
+ console.error(`Unknown command: ${command}`);
77
+ console.log(HELP);
78
+ process.exit(1);
79
+ }
80
+ }
81
+
82
+ main().catch(err => {
83
+ console.error(err.message);
84
+ process.exit(1);
85
+ });
package/lib/config.js ADDED
@@ -0,0 +1,5 @@
1
+ import { join } from 'path';
2
+ import { homedir } from 'os';
3
+
4
+ export const PACKAGES_DIR = join(homedir(), '.lingot', 'packages');
5
+ export const REGISTRY_URL = 'https://lingot.sh/api/v1';
package/lib/init.js ADDED
@@ -0,0 +1,104 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { REGISTRY_URL } from './config.js';
4
+
5
+ // Maps package.json dependency names to lingot block slugs
6
+ const DEPENDENCY_MAP = {
7
+ '@supabase/supabase-js': 'supabase-auth',
8
+ '@supabase/ssr': 'supabase-auth',
9
+ 'next': 'nextjs-app-router',
10
+ 'typescript': 'typescript-strict',
11
+ 'tailwindcss': 'tailwind-patterns',
12
+ '@tailwindcss/vite': 'tailwind-v4',
13
+ 'drizzle-orm': 'drizzle-orm',
14
+ 'drizzle-kit': 'drizzle-orm',
15
+ 'zod': 'zod',
16
+ 'stripe': 'stripe-billing',
17
+ '@aws-sdk/client-s3': 'aws-s3-v3',
18
+ 'resend': 'resend',
19
+ '@tanstack/react-query': 'tanstack-query',
20
+ '@prisma/client': 'prisma',
21
+ 'prisma': 'prisma',
22
+ 'openai': 'openai',
23
+ '@anthropic-ai/sdk': 'anthropic',
24
+ 'react-email': 'react-email',
25
+ '@react-email/components': 'react-email',
26
+ 'ioredis': 'redis',
27
+ '@upstash/redis': 'redis',
28
+ 'vitest': 'vitest',
29
+ 'framer-motion': 'framer-motion',
30
+ 'motion': 'framer-motion',
31
+ 'next-auth': 'next-auth',
32
+ '@trpc/server': 'trpc',
33
+ '@trpc/client': 'trpc',
34
+ 'react-hook-form': 'react-hook-form',
35
+ '@clerk/nextjs': 'clerk',
36
+ 'mongoose': 'mongoose',
37
+ 'zustand': 'zustand',
38
+ 'uploadthing': 'uploadthing',
39
+ '@uploadthing/react': 'uploadthing',
40
+ 'lucia': 'lucia-auth',
41
+ 'arctic': 'lucia-auth',
42
+ 'swr': 'swr',
43
+ 'eslint': 'eslint',
44
+ '@playwright/test': 'playwright',
45
+ 'next-intl': 'next-intl',
46
+ 'convex': 'convex',
47
+ 'turbo': 'turborepo',
48
+ 'nuxt': 'nuxt',
49
+ 'cypress': 'cypress',
50
+ 'prettier': 'prettier',
51
+ };
52
+
53
+ export async function init() {
54
+ const pkgPath = join(process.cwd(), 'package.json');
55
+
56
+ if (!existsSync(pkgPath)) {
57
+ console.error('No package.json found in current directory.');
58
+ console.error('Run this command from your project root.');
59
+ process.exit(1);
60
+ }
61
+
62
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
63
+ const allDeps = {
64
+ ...pkg.dependencies,
65
+ ...pkg.devDependencies,
66
+ };
67
+
68
+ const detected = new Set();
69
+ for (const dep of Object.keys(allDeps)) {
70
+ if (DEPENDENCY_MAP[dep]) {
71
+ detected.add(DEPENDENCY_MAP[dep]);
72
+ }
73
+ }
74
+
75
+ if (detected.size === 0) {
76
+ console.log('\nNo matching blocks found for your dependencies.');
77
+ console.log('Browse all 40+ blocks at https://lingot.sh');
78
+ return;
79
+ }
80
+
81
+ const blocks = [...detected].sort();
82
+
83
+ console.log(`\nDetected ${blocks.length} relevant intelligence blocks:\n`);
84
+
85
+ for (const slug of blocks) {
86
+ console.log(` lingot add ${slug}`);
87
+ }
88
+
89
+ console.log(`\nInstall all at once:`);
90
+ console.log(` lingot add ${blocks.join(' ')}`);
91
+
92
+ // SaaS stack upsell — if user has auth + payments + db detected
93
+ const hasSaasStack = detected.has('supabase-auth') || detected.has('next-auth') || detected.has('clerk');
94
+ const hasPayments = detected.has('stripe-billing');
95
+ const hasDb = detected.has('drizzle-orm') || detected.has('prisma') || detected.has('mongoose');
96
+
97
+ if (hasSaasStack && (hasPayments || hasDb)) {
98
+ console.log(`\n \u{1F4A1} SaaS stack detected. Give your AI the integration patterns`);
99
+ console.log(` to wire auth, payments, and database together securely:`);
100
+ console.log(` npx lingot add saas-blueprint (https://lingot.sh/blueprint)`);
101
+ }
102
+
103
+ console.log();
104
+ }
package/lib/inspect.js ADDED
@@ -0,0 +1,55 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { PACKAGES_DIR } from './config.js';
4
+
5
+ function fmt(num) {
6
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
7
+ }
8
+
9
+ export async function inspect(name) {
10
+ const pkgDir = join(PACKAGES_DIR, name);
11
+ const manifestPath = join(pkgDir, 'manifest.json');
12
+
13
+ if (!existsSync(manifestPath)) {
14
+ throw new Error(`Package not found: ${name}\nRun 'lingot list' to see installed packages.`);
15
+ }
16
+
17
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
18
+
19
+ console.log(`\n${manifest.name}@${manifest.version}`);
20
+ console.log(`${'─'.repeat(50)}`);
21
+ console.log(`Description: ${manifest.description}`);
22
+ console.log(`Domain: ${manifest.domain}`);
23
+ console.log(`Category: ${manifest.category}`);
24
+ console.log(`Requires: ${manifest.requires?.join(', ') || 'none'}`);
25
+ console.log(`Keywords: ${manifest.keywords?.join(', ')}`);
26
+ console.log(`Author: ${manifest.author}`);
27
+ console.log(`License: ${manifest.license}`);
28
+ console.log();
29
+
30
+ if (manifest.quality) {
31
+ const q = manifest.quality;
32
+ const compression = (q.source_tokens / manifest.tokens.total).toFixed(1);
33
+ const coveragePct = Math.round((q.scope.covered_items / q.scope.total_items) * 100);
34
+
35
+ console.log(`Quality:`);
36
+ console.log(` Compression: ${compression}x (${fmt(q.source_tokens)} source tokens -> ${fmt(manifest.tokens.total)} block tokens)`);
37
+ console.log(` Coverage: ${coveragePct}% of ${q.scope.type} (${q.scope.covered_items}/${q.scope.total_items} items)`);
38
+ console.log(` Scope: ${q.scope.description}`);
39
+ console.log(` Verified: ${q.verified} (${q.timestamp})`);
40
+ console.log(` Status: ${q.maintenance}`);
41
+ console.log();
42
+ }
43
+
44
+ console.log(`Tokens:`);
45
+ console.log(` knowledge: ${fmt(manifest.tokens.knowledge)}`);
46
+ console.log(` rules: ${fmt(manifest.tokens.rules)}`);
47
+ console.log(` examples: ${fmt(manifest.tokens.examples)}`);
48
+ console.log(` total: ${fmt(manifest.tokens.total)}`);
49
+ console.log();
50
+ console.log(`Sources:`);
51
+ for (const src of manifest.sources || []) {
52
+ console.log(` ${src.title}: ${src.url}`);
53
+ }
54
+ console.log();
55
+ }
package/lib/install.js ADDED
@@ -0,0 +1,114 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { createHash } from 'crypto';
4
+ import { PACKAGES_DIR, REGISTRY_URL } from './config.js';
5
+
6
+ function computeIntegrity(filePath) {
7
+ const content = readFileSync(filePath);
8
+ const hash = createHash('sha256').update(content).digest('hex');
9
+ return `sha256-${hash}`;
10
+ }
11
+
12
+ function updateLockfile(manifest) {
13
+ const lockPath = join(process.cwd(), 'aipkg.lock');
14
+ let lock = { lockfileVersion: 1, packages: {} };
15
+
16
+ if (existsSync(lockPath)) {
17
+ lock = JSON.parse(readFileSync(lockPath, 'utf-8'));
18
+ }
19
+
20
+ lock.packages[manifest.name] = {
21
+ version: manifest.version,
22
+ integrity: computeIntegrity(join(PACKAGES_DIR, manifest.name, 'knowledge.md')),
23
+ tokens: manifest.tokens?.total || 0,
24
+ requires: manifest.requires || [],
25
+ };
26
+
27
+ writeFileSync(lockPath, JSON.stringify(lock, null, 2) + '\n');
28
+ return lockPath;
29
+ }
30
+
31
+ function isLocalPath(arg) {
32
+ return arg.startsWith('.') || arg.startsWith('/') || arg.startsWith('~');
33
+ }
34
+
35
+ async function fetchFile(url) {
36
+ const res = await fetch(url);
37
+ if (!res.ok) throw new Error(`Failed to download ${url}: ${res.status}`);
38
+ return res.text();
39
+ }
40
+
41
+ async function installRemote(packageName) {
42
+ // Fetch metadata from registry
43
+ console.log(`Resolving ${packageName}...`);
44
+ const metaRes = await fetch(`${REGISTRY_URL}/packages/${packageName}`);
45
+ if (!metaRes.ok) {
46
+ throw new Error(`Package not found: ${packageName}`);
47
+ }
48
+ const meta = await metaRes.json();
49
+
50
+ const destDir = join(PACKAGES_DIR, packageName);
51
+ mkdirSync(destDir, { recursive: true });
52
+
53
+ // Download all 4 files in parallel
54
+ console.log(`Downloading ${meta.name}@${meta.version}...`);
55
+ const files = ['manifest', 'knowledge', 'rules', 'examples'];
56
+ const filenames = {
57
+ manifest: 'manifest.json',
58
+ knowledge: 'knowledge.md',
59
+ rules: 'rules.xml',
60
+ examples: 'examples.yaml',
61
+ };
62
+
63
+ const downloads = await Promise.all(
64
+ files.map(async (key) => {
65
+ const content = await fetchFile(meta.files[key]);
66
+ return { key, content };
67
+ })
68
+ );
69
+
70
+ for (const { key, content } of downloads) {
71
+ writeFileSync(join(destDir, filenames[key]), content);
72
+ }
73
+
74
+ const manifest = JSON.parse(readFileSync(join(destDir, 'manifest.json'), 'utf-8'));
75
+ const lockPath = updateLockfile(manifest);
76
+
77
+ console.log(`✓ Installed ${manifest.name}@${manifest.version} (${manifest.tokens.total} tokens)`);
78
+ console.log(` → ${destDir}`);
79
+ console.log(` → ${lockPath}`);
80
+ }
81
+
82
+ async function installLocal(sourcePath) {
83
+ const manifestPath = join(sourcePath, 'manifest.json');
84
+ if (!existsSync(manifestPath)) {
85
+ throw new Error(`No manifest.json found in ${sourcePath}`);
86
+ }
87
+
88
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
89
+
90
+ const required = ['knowledge.md', 'rules.xml', 'examples.yaml'];
91
+ for (const file of required) {
92
+ if (!existsSync(join(sourcePath, file))) {
93
+ throw new Error(`Missing required file: ${file}`);
94
+ }
95
+ }
96
+
97
+ const destDir = join(PACKAGES_DIR, manifest.name);
98
+ mkdirSync(destDir, { recursive: true });
99
+ cpSync(sourcePath, destDir, { recursive: true });
100
+
101
+ const lockPath = updateLockfile(manifest);
102
+
103
+ console.log(`✓ Installed ${manifest.name}@${manifest.version} (${manifest.tokens.total} tokens)`);
104
+ console.log(` → ${destDir}`);
105
+ console.log(` → ${lockPath}`);
106
+ }
107
+
108
+ export async function install(arg) {
109
+ if (isLocalPath(arg)) {
110
+ await installLocal(arg);
111
+ } else {
112
+ await installRemote(arg);
113
+ }
114
+ }
package/lib/list.js ADDED
@@ -0,0 +1,32 @@
1
+ import { readdirSync, readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { PACKAGES_DIR } from './config.js';
4
+
5
+ export async function list() {
6
+ if (!existsSync(PACKAGES_DIR)) {
7
+ console.log('No packages installed.');
8
+ console.log(`Install path: ${PACKAGES_DIR}`);
9
+ return;
10
+ }
11
+
12
+ const dirs = readdirSync(PACKAGES_DIR, { withFileTypes: true })
13
+ .filter(d => d.isDirectory());
14
+
15
+ if (dirs.length === 0) {
16
+ console.log('No packages installed.');
17
+ return;
18
+ }
19
+
20
+ console.log(`\nInstalled packages (${PACKAGES_DIR}):\n`);
21
+
22
+ for (const dir of dirs) {
23
+ const manifestPath = join(PACKAGES_DIR, dir.name, 'manifest.json');
24
+ if (!existsSync(manifestPath)) continue;
25
+
26
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
27
+ const tokens = manifest.tokens?.total || '?';
28
+ console.log(` ${manifest.name}@${manifest.version} (${tokens} tokens)`);
29
+ console.log(` ${manifest.description}`);
30
+ console.log();
31
+ }
32
+ }
package/lib/serve.js ADDED
@@ -0,0 +1,256 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import {
4
+ ListResourcesRequestSchema,
5
+ ReadResourceRequestSchema,
6
+ ListToolsRequestSchema,
7
+ CallToolRequestSchema,
8
+ } from '@modelcontextprotocol/sdk/types.js';
9
+ import { readdirSync, readFileSync, existsSync } from 'fs';
10
+ import { join } from 'path';
11
+ import { PACKAGES_DIR } from './config.js';
12
+
13
+ function loadPackages() {
14
+ if (!existsSync(PACKAGES_DIR)) return [];
15
+
16
+ return readdirSync(PACKAGES_DIR, { withFileTypes: true })
17
+ .filter(d => d.isDirectory())
18
+ .map(d => {
19
+ const dir = join(PACKAGES_DIR, d.name);
20
+ const manifestPath = join(dir, 'manifest.json');
21
+ if (!existsSync(manifestPath)) return null;
22
+
23
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
24
+ return { dir, manifest };
25
+ })
26
+ .filter(Boolean);
27
+ }
28
+
29
+ function readFile(pkgDir, filename) {
30
+ const filepath = join(pkgDir, filename);
31
+ return existsSync(filepath) ? readFileSync(filepath, 'utf-8') : '';
32
+ }
33
+
34
+ function buildCombined(pkgDir) {
35
+ const knowledge = readFile(pkgDir, 'knowledge.md');
36
+ const rules = readFile(pkgDir, 'rules.xml');
37
+ const examples = readFile(pkgDir, 'examples.yaml');
38
+
39
+ return [
40
+ knowledge,
41
+ '',
42
+ rules,
43
+ '',
44
+ '# Examples',
45
+ '```yaml',
46
+ examples,
47
+ '```',
48
+ ].join('\n');
49
+ }
50
+
51
+ export async function serve() {
52
+ const server = new Server(
53
+ { name: 'lingot-registry', version: '1.0.0' },
54
+ { capabilities: { resources: {}, tools: {} } }
55
+ );
56
+
57
+ // List all resources from installed packages
58
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
59
+ const packages = loadPackages();
60
+ const resources = [];
61
+
62
+ for (const pkg of packages) {
63
+ const name = pkg.manifest.name;
64
+
65
+ // Combined resource
66
+ resources.push({
67
+ uri: `aipkg://local/${name}/combined`,
68
+ name: `${name} (full context)`,
69
+ description: pkg.manifest.description,
70
+ mimeType: 'text/markdown',
71
+ });
72
+
73
+ // Granular resources
74
+ resources.push({
75
+ uri: `aipkg://local/${name}/knowledge`,
76
+ name: `${name}/knowledge`,
77
+ description: `Domain knowledge for ${name}`,
78
+ mimeType: 'text/markdown',
79
+ });
80
+ resources.push({
81
+ uri: `aipkg://local/${name}/rules`,
82
+ name: `${name}/rules`,
83
+ description: `Constraints and heuristics for ${name}`,
84
+ mimeType: 'application/xml',
85
+ });
86
+ resources.push({
87
+ uri: `aipkg://local/${name}/examples`,
88
+ name: `${name}/examples`,
89
+ description: `Few-shot examples for ${name}`,
90
+ mimeType: 'text/yaml',
91
+ });
92
+ }
93
+
94
+ return { resources };
95
+ });
96
+
97
+ // Read a specific resource
98
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
99
+ const uri = request.params.uri;
100
+ const match = uri.match(/^aipkg:\/\/local\/([^/]+)\/(.+)$/);
101
+ if (!match) {
102
+ throw new Error(`Invalid resource URI: ${uri}`);
103
+ }
104
+
105
+ const [, pkgName, part] = match;
106
+ const pkgDir = join(PACKAGES_DIR, pkgName);
107
+
108
+ if (!existsSync(pkgDir)) {
109
+ throw new Error(`Package not found: ${pkgName}`);
110
+ }
111
+
112
+ let content;
113
+ let mimeType = 'text/plain';
114
+
115
+ switch (part) {
116
+ case 'combined':
117
+ content = buildCombined(pkgDir);
118
+ mimeType = 'text/markdown';
119
+ break;
120
+ case 'knowledge':
121
+ content = readFile(pkgDir, 'knowledge.md');
122
+ mimeType = 'text/markdown';
123
+ break;
124
+ case 'rules':
125
+ content = readFile(pkgDir, 'rules.xml');
126
+ mimeType = 'application/xml';
127
+ break;
128
+ case 'examples':
129
+ content = readFile(pkgDir, 'examples.yaml');
130
+ mimeType = 'text/yaml';
131
+ break;
132
+ default:
133
+ throw new Error(`Unknown resource part: ${part}`);
134
+ }
135
+
136
+ return {
137
+ contents: [{ uri, mimeType, text: content }],
138
+ };
139
+ });
140
+
141
+ // List available tools
142
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
143
+ return {
144
+ tools: [
145
+ {
146
+ name: 'search_packages',
147
+ description: 'Search locally installed Lingot intelligence blocks by topic, domain, or category. Returns verified, version-locked context packages with token counts. Use when you need authoritative reference material for a specific technology or domain.',
148
+ inputSchema: {
149
+ type: 'object',
150
+ properties: {
151
+ query: {
152
+ type: 'string',
153
+ description: 'Search term to match against package names, descriptions, and keywords',
154
+ },
155
+ domain: {
156
+ type: 'string',
157
+ description: 'Filter by domain (e.g., payments, infrastructure)',
158
+ },
159
+ category: {
160
+ type: 'string',
161
+ description: 'Filter by category (e.g., developer, architect)',
162
+ },
163
+ },
164
+ },
165
+ },
166
+ {
167
+ name: 'get_package_context',
168
+ description: 'Retrieve the full verified context of an Ingot intelligence block. Returns curated domain knowledge, strict heuristic constraints, and schema-validated code examples. Use to ensure syntax compliance with the latest API patterns.',
169
+ inputSchema: {
170
+ type: 'object',
171
+ properties: {
172
+ name: {
173
+ type: 'string',
174
+ description: 'The package name (e.g., stripe-webhooks)',
175
+ },
176
+ part: {
177
+ type: 'string',
178
+ enum: ['combined', 'knowledge', 'rules', 'examples'],
179
+ description: 'Which part to retrieve. Defaults to combined.',
180
+ },
181
+ },
182
+ required: ['name'],
183
+ },
184
+ },
185
+ ],
186
+ };
187
+ });
188
+
189
+ // Handle tool calls
190
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
191
+ const { name, arguments: args } = request.params;
192
+
193
+ if (name === 'search_packages') {
194
+ const packages = loadPackages();
195
+ const query = (args.query || '').toLowerCase();
196
+ const domain = args.domain?.toLowerCase();
197
+ const category = args.category?.toLowerCase();
198
+
199
+ const results = packages.filter(pkg => {
200
+ const m = pkg.manifest;
201
+ const matchesQuery = !query ||
202
+ m.name.includes(query) ||
203
+ m.description.toLowerCase().includes(query) ||
204
+ m.keywords?.some(k => k.toLowerCase().includes(query));
205
+ const matchesDomain = !domain || m.domain?.toLowerCase() === domain;
206
+ const matchesCategory = !category || m.category?.toLowerCase() === category;
207
+ return matchesQuery && matchesDomain && matchesCategory;
208
+ });
209
+
210
+ const text = results.length === 0
211
+ ? 'No packages found.'
212
+ : results.map(pkg => {
213
+ const m = pkg.manifest;
214
+ return `${m.name}@${m.version} (${m.tokens.total} tokens)\n ${m.description}\n domain: ${m.domain} | category: ${m.category}\n keywords: ${m.keywords?.join(', ')}`;
215
+ }).join('\n\n');
216
+
217
+ return { content: [{ type: 'text', text }] };
218
+ }
219
+
220
+ if (name === 'get_package_context') {
221
+ const pkgName = args.name;
222
+ const part = args.part || 'combined';
223
+ const pkgDir = join(PACKAGES_DIR, pkgName);
224
+
225
+ if (!existsSync(pkgDir)) {
226
+ return { content: [{ type: 'text', text: `Package not found: ${pkgName}` }] };
227
+ }
228
+
229
+ let content;
230
+ switch (part) {
231
+ case 'combined':
232
+ content = buildCombined(pkgDir);
233
+ break;
234
+ case 'knowledge':
235
+ content = readFile(pkgDir, 'knowledge.md');
236
+ break;
237
+ case 'rules':
238
+ content = readFile(pkgDir, 'rules.xml');
239
+ break;
240
+ case 'examples':
241
+ content = readFile(pkgDir, 'examples.yaml');
242
+ break;
243
+ default:
244
+ content = buildCombined(pkgDir);
245
+ }
246
+
247
+ return { content: [{ type: 'text', text: content }] };
248
+ }
249
+
250
+ throw new Error(`Unknown tool: ${name}`);
251
+ });
252
+
253
+ const transport = new StdioServerTransport();
254
+ await server.connect(transport);
255
+ // Server is now running on stdio
256
+ }
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "lingot",
3
+ "version": "1.0.0",
4
+ "description": "The standard library for AI agents. Intelligence blocks that make Cursor, Windsurf, and Claude Code measurably better.",
5
+ "type": "module",
6
+ "bin": {
7
+ "lingot": "./bin/lingot.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node bin/lingot.js list"
11
+ },
12
+ "keywords": ["ai", "agents", "context", "mcp", "cursor", "windsurf", "claude", "intelligence-blocks", "llm"],
13
+ "author": "Lingot <hello@lingot.sh>",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/lingot-sh/lingot"
18
+ },
19
+ "homepage": "https://lingot.sh",
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.0.0"
22
+ }
23
+ }