delimit-cli 4.1.35 → 4.1.37

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 CHANGED
@@ -161,6 +161,12 @@ npx delimit-cli hooks install # Install git pre-commit hook
161
161
  npx delimit-cli hooks install --pre-push # Also add pre-push hook
162
162
  npx delimit-cli ci # Generate GitHub Action workflow
163
163
  npx delimit-cli ci --strict --dry-run # Preview strict workflow
164
+ npx delimit-cli remember "Redis uses JWT 15min" # Save a persistent memory
165
+ npx delimit-cli recall redis # Search memories
166
+ npx delimit-cli recall # Show recent memories
167
+ npx delimit-cli recall --tag deploy --all # Filter by tag, show all
168
+ npx delimit-cli recall --export # Export as markdown
169
+ npx delimit-cli forget abc123 # Delete a memory by ID
164
170
  npx delimit-cli doctor # Check setup health
165
171
  npx delimit-cli uninstall --dry-run # Preview removal
166
172
  ```
@@ -67,7 +67,8 @@ function normalizeNaturalLanguageArgs(argv) {
67
67
 
68
68
  const explicitCommands = new Set([
69
69
  'install', 'mode', 'status', 'session', 'build', 'ask', 'policy', 'auth', 'audit',
70
- 'explain-decision', 'uninstall', 'proxy', 'hook', 'version', 'vault', 'deliberate'
70
+ 'explain-decision', 'uninstall', 'proxy', 'hook', 'version', 'vault', 'deliberate',
71
+ 'remember', 'recall', 'forget'
71
72
  ]);
72
73
  if (explicitCommands.has((raw[0] || '').toLowerCase())) {
73
74
  return raw;
@@ -3849,6 +3850,20 @@ program
3849
3850
  console.log(chalk.dim(` Tier: pro`));
3850
3851
  if (customerEmail) console.log(chalk.dim(` Email: ${customerEmail}`));
3851
3852
  console.log('');
3853
+
3854
+ // Activation telemetry — notify the team
3855
+ try {
3856
+ await axios.post('https://delimit.ai/api/activation', {
3857
+ event: 'license_activated',
3858
+ license_id: licenseId,
3859
+ email: customerEmail,
3860
+ machine_hash: machineHash,
3861
+ version: require('../package.json').version,
3862
+ platform: process.platform,
3863
+ node_version: process.version,
3864
+ activated_at: new Date().toISOString(),
3865
+ }, { timeout: 5000 }).catch(() => {});
3866
+ } catch {}
3852
3867
  });
3853
3868
 
3854
3869
  // ---------------------------------------------------------------------------
@@ -4228,5 +4243,227 @@ program
4228
4243
  console.log(chalk.gray(' The badge links to Delimit so visitors can learn more.\n'));
4229
4244
  });
4230
4245
 
4246
+ // ---------------------------------------------------------------------------
4247
+ // Memory commands: remember, recall, forget
4248
+ // ---------------------------------------------------------------------------
4249
+
4250
+ const MEMORY_DIR = path.join(os.homedir(), '.delimit', 'memory');
4251
+ const MEMORY_FILE = path.join(MEMORY_DIR, 'memories.jsonl');
4252
+
4253
+ const KNOWN_TECH_TERMS = new Set([
4254
+ 'redis', 'jwt', 'docker', 'k8s', 'kubernetes', 'aws', 'gcp', 'azure', 'api',
4255
+ 'graphql', 'rest', 'grpc', 'postgres', 'mysql', 'mongo', 'mongodb', 'nginx',
4256
+ 'kafka', 'rabbitmq', 'terraform', 'ansible', 'helm', 'react', 'vue', 'angular',
4257
+ 'node', 'python', 'rust', 'go', 'java', 'typescript', 'webpack', 'vite',
4258
+ 'supabase', 'firebase', 'vercel', 'netlify', 'cloudflare', 'lambda', 'sqs',
4259
+ 'sns', 's3', 'ec2', 'ecs', 'eks', 'fargate', 'dynamodb', 'elasticsearch',
4260
+ 'kibana', 'prometheus', 'grafana', 'datadog', 'sentry', 'pagerduty',
4261
+ 'github', 'gitlab', 'bitbucket', 'jira', 'linear', 'notion', 'slack',
4262
+ 'openapi', 'swagger', 'oauth', 'saml', 'sso', 'cicd', 'ci', 'cd',
4263
+ 'cdn', 'dns', 'ssl', 'tls', 'http', 'https', 'websocket', 'ssh',
4264
+ 'cron', 'celery', 'sidekiq', 'redis', 'memcached', 'clickhouse',
4265
+ ]);
4266
+
4267
+ function generateShortId() {
4268
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
4269
+ let id = '';
4270
+ for (let i = 0; i < 6; i++) {
4271
+ id += chars[Math.floor(Math.random() * chars.length)];
4272
+ }
4273
+ return id;
4274
+ }
4275
+
4276
+ function extractTags(text) {
4277
+ const tags = new Set();
4278
+ const words = text.split(/[\s,;:.!?()\[\]{}"']+/).filter(Boolean);
4279
+ for (const word of words) {
4280
+ // @mentions
4281
+ if (word.startsWith('@') && word.length > 1) {
4282
+ tags.add(word.toLowerCase());
4283
+ continue;
4284
+ }
4285
+ // ALL_CAPS words (at least 2 chars, allow underscores)
4286
+ if (/^[A-Z][A-Z0-9_]{1,}$/.test(word)) {
4287
+ tags.add(word.toLowerCase());
4288
+ continue;
4289
+ }
4290
+ // Known tech terms
4291
+ const lower = word.toLowerCase().replace(/[^a-z0-9]/g, '');
4292
+ if (lower.length >= 2 && KNOWN_TECH_TERMS.has(lower)) {
4293
+ tags.add(lower);
4294
+ }
4295
+ }
4296
+ return [...tags];
4297
+ }
4298
+
4299
+ function readMemories() {
4300
+ if (!fs.existsSync(MEMORY_FILE)) return [];
4301
+ const lines = fs.readFileSync(MEMORY_FILE, 'utf-8').split('\n').filter(l => l.trim());
4302
+ const memories = [];
4303
+ for (const line of lines) {
4304
+ try { memories.push(JSON.parse(line)); } catch {}
4305
+ }
4306
+ return memories;
4307
+ }
4308
+
4309
+ function writeMemories(memories) {
4310
+ fs.mkdirSync(MEMORY_DIR, { recursive: true });
4311
+ fs.writeFileSync(MEMORY_FILE, memories.map(m => JSON.stringify(m)).join('\n') + (memories.length ? '\n' : ''));
4312
+ }
4313
+
4314
+ function relativeTime(isoDate) {
4315
+ const now = Date.now();
4316
+ const then = new Date(isoDate).getTime();
4317
+ const diffSec = Math.floor((now - then) / 1000);
4318
+ if (diffSec < 60) return 'just now';
4319
+ const diffMin = Math.floor(diffSec / 60);
4320
+ if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`;
4321
+ const diffHr = Math.floor(diffMin / 60);
4322
+ if (diffHr < 24) return `${diffHr} hour${diffHr === 1 ? '' : 's'} ago`;
4323
+ const diffDay = Math.floor(diffHr / 24);
4324
+ if (diffDay < 7) return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
4325
+ const diffWeek = Math.floor(diffDay / 7);
4326
+ if (diffWeek < 5) return `${diffWeek} week${diffWeek === 1 ? '' : 's'} ago`;
4327
+ const diffMonth = Math.floor(diffDay / 30);
4328
+ if (diffMonth < 12) return `${diffMonth} month${diffMonth === 1 ? '' : 's'} ago`;
4329
+ const diffYear = Math.floor(diffDay / 365);
4330
+ return `${diffYear} year${diffYear === 1 ? '' : 's'} ago`;
4331
+ }
4332
+
4333
+ function displayMemory(mem) {
4334
+ console.log(` ${chalk.gray('[' + mem.id + ']')} ${chalk.gray(relativeTime(mem.created))}`);
4335
+ console.log(` ${mem.text}`);
4336
+ if (mem.tags && mem.tags.length > 0) {
4337
+ console.log(` ${chalk.blue(mem.tags.map(t => '#' + t).join(' '))}`);
4338
+ }
4339
+ console.log('');
4340
+ }
4341
+
4342
+ program
4343
+ .command('remember <text...>')
4344
+ .description('Save a memory that persists across all AI assistants')
4345
+ .option('--tag <tag>', 'Add a manual tag (repeatable)', (val, prev) => prev ? [...prev, val] : [val])
4346
+ .action((textParts, options) => {
4347
+ const text = textParts.join(' ');
4348
+ const autoTags = extractTags(text);
4349
+ const manualTags = (options.tag || []).map(t => t.toLowerCase());
4350
+ const allTags = [...new Set([...autoTags, ...manualTags])];
4351
+
4352
+ const memories = readMemories();
4353
+ const entry = {
4354
+ id: generateShortId(),
4355
+ text,
4356
+ tags: allTags,
4357
+ created: new Date().toISOString(),
4358
+ source: 'cli',
4359
+ };
4360
+ memories.push(entry);
4361
+ writeMemories(memories);
4362
+
4363
+ console.log(chalk.green(`\n Remembered.`) + chalk.gray(` (${memories.length} memor${memories.length === 1 ? 'y' : 'ies'} total)\n`));
4364
+ });
4365
+
4366
+ program
4367
+ .command('recall [query...]')
4368
+ .description('Search your memories — with no query, shows the most recent')
4369
+ .option('--tag <tag>', 'Filter by tag')
4370
+ .option('--all', 'Show all memories')
4371
+ .option('--forget <id>', 'Delete a memory by ID')
4372
+ .option('--export', 'Export memories as markdown')
4373
+ .action((queryParts, options) => {
4374
+ const memories = readMemories();
4375
+
4376
+ // --forget mode
4377
+ if (options.forget) {
4378
+ const idx = memories.findIndex(m => m.id === options.forget);
4379
+ if (idx === -1) {
4380
+ console.log(chalk.red(`\n No memory found with ID: ${options.forget}\n`));
4381
+ process.exit(1);
4382
+ }
4383
+ memories.splice(idx, 1);
4384
+ writeMemories(memories);
4385
+ console.log(chalk.green(`\n Forgotten.`) + chalk.gray(` (${memories.length} memor${memories.length === 1 ? 'y' : 'ies'} remaining)\n`));
4386
+ return;
4387
+ }
4388
+
4389
+ if (memories.length === 0) {
4390
+ console.log(chalk.gray('\n No memories yet. Save one with:\n'));
4391
+ console.log(` ${chalk.green('delimit remember')} "Your first memory"\n`);
4392
+ return;
4393
+ }
4394
+
4395
+ // --export mode
4396
+ if (options.export) {
4397
+ console.log('# Delimit Memories\n');
4398
+ for (const mem of memories) {
4399
+ const date = new Date(mem.created).toISOString().split('T')[0];
4400
+ console.log(`- **${date}** — ${mem.text}`);
4401
+ if (mem.tags && mem.tags.length > 0) {
4402
+ console.log(` Tags: ${mem.tags.map(t => '`' + t + '`').join(', ')}`);
4403
+ }
4404
+ }
4405
+ console.log(`\n_${memories.length} memories exported._`);
4406
+ return;
4407
+ }
4408
+
4409
+ let results = [...memories];
4410
+ const query = (queryParts || []).join(' ').trim().toLowerCase();
4411
+
4412
+ // Filter by tag
4413
+ if (options.tag) {
4414
+ const tagFilter = options.tag.toLowerCase();
4415
+ results = results.filter(m => m.tags && m.tags.some(t => t.includes(tagFilter)));
4416
+ }
4417
+
4418
+ // Filter by query (case-insensitive substring on text + tags)
4419
+ if (query) {
4420
+ results = results.filter(m => {
4421
+ const haystack = (m.text + ' ' + (m.tags || []).join(' ')).toLowerCase();
4422
+ return haystack.includes(query);
4423
+ });
4424
+ }
4425
+
4426
+ // Unless --all, limit to last 10
4427
+ const total = results.length;
4428
+ if (!options.all && !query && !options.tag) {
4429
+ results = results.slice(-10);
4430
+ }
4431
+
4432
+ // Display newest first
4433
+ results.reverse();
4434
+
4435
+ console.log(chalk.bold('\n Delimit Memories\n'));
4436
+
4437
+ if (results.length === 0) {
4438
+ console.log(chalk.gray(' No matching memories found.\n'));
4439
+ return;
4440
+ }
4441
+
4442
+ for (const mem of results) {
4443
+ displayMemory(mem);
4444
+ }
4445
+
4446
+ const shownCount = results.length;
4447
+ const label = query || options.tag
4448
+ ? `${shownCount} memor${shownCount === 1 ? 'y' : 'ies'} found`
4449
+ : `${shownCount} shown`;
4450
+ console.log(chalk.gray(` ${label} (${memories.length} total)\n`));
4451
+ });
4452
+
4453
+ program
4454
+ .command('forget <id>')
4455
+ .description('Delete a memory by ID (alias for recall --forget)')
4456
+ .action((id) => {
4457
+ const memories = readMemories();
4458
+ const idx = memories.findIndex(m => m.id === id);
4459
+ if (idx === -1) {
4460
+ console.log(chalk.red(`\n No memory found with ID: ${id}\n`));
4461
+ process.exit(1);
4462
+ }
4463
+ memories.splice(idx, 1);
4464
+ writeMemories(memories);
4465
+ console.log(chalk.green(`\n Forgotten.`) + chalk.gray(` (${memories.length} memor${memories.length === 1 ? 'y' : 'ies'} remaining)\n`));
4466
+ });
4467
+
4231
4468
  const normalizedArgs = normalizeNaturalLanguageArgs(process.argv);
4232
4469
  program.parse([process.argv[0], process.argv[1], ...normalizedArgs]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "delimit-cli",
3
3
  "mcpName": "io.github.delimit-ai/delimit-mcp-server",
4
- "version": "4.1.35",
4
+ "version": "4.1.37",
5
5
  "description": "Unify Claude Code, Codex, Cursor, and Gemini CLI with persistent context, governance, and multi-model debate.",
6
6
  "main": "index.js",
7
7
  "files": [