beecork 1.3.6 → 1.3.8

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
@@ -24,8 +24,8 @@ Message Claude Code from Telegram at 2am — it wakes up, does the work, message
24
24
  - **Virtual tabs** — Persistent Claude Code sessions with context that survives restarts.
25
25
  - **Task scheduling** — Tell Claude Code to set up recurring tasks via MCP tools — it wakes up, runs the task, reports back.
26
26
  - **Memory** — Cross-session memory so Claude Code never loses context.
27
- - **MCP server** — 38 tools Claude Code can call to manage tabs, memory, cron jobs, watchers, media, projects, and more.
28
- - **Smart routing** — Pipe brain routes messages to the right tab, tracks goals, learns from your usage.
27
+ - **MCP server** — 38 tools Claude Code can call to manage tabs, memory, cron jobs, watchers, media, folders, and more.
28
+ - **Smart routing** — Pipe brain routes messages to the right folder and tab, tracks goals, learns from your usage.
29
29
  - **Background service** — Runs as a launchd (macOS), systemd (Linux), or Task Scheduler (Windows) service. Starts on login, runs silently.
30
30
 
31
31
  ## Quick Start
@@ -89,7 +89,7 @@ beecork mcp list # List MCP server configs
89
89
  beecork media setup # Configure media generators
90
90
  beecork activity # View activity summary
91
91
  beecork history # Show activity timeline
92
- beecork projects # List discovered projects
92
+ beecork folders # List discovered folders
93
93
  beecork machines # List registered machines
94
94
  beecork templates # List tab templates
95
95
  beecork store search <q> # Search community extensions
@@ -147,44 +147,46 @@ export async function handleSharedCommand(ctx, tabManager) {
147
147
  }).join('\n\n');
148
148
  return { handled: true, response: `🖥 ${machines.length} machine(s):\n\n${list}` };
149
149
  }
150
- // /projects
151
- if (text === '/projects' || text.startsWith('/projects@')) {
150
+ // /folders (also accept legacy /projects)
151
+ if (text === '/folders' || text === '/projects' || text.startsWith('/folders@') || text.startsWith('/projects@')) {
152
152
  const { listProjects } = await import('../projects/index.js');
153
153
  const projects = listProjects();
154
154
  if (projects.length === 0)
155
- return { handled: true, response: 'No projects found. Create one with /newproject <name>' };
155
+ return { handled: true, response: 'No folders found. Create one with /newfolder <name>' };
156
156
  const userProjects = projects.filter((p) => p.type === 'user-project');
157
157
  const categories = projects.filter((p) => p.type === 'category');
158
- let msg = '📦 Projects:\n';
158
+ let msg = '📁 Folders:\n';
159
159
  if (userProjects.length > 0)
160
160
  msg += userProjects.map((p) => ` • ${p.name} — ${p.path}`).join('\n');
161
161
  if (categories.length > 0) {
162
- msg += '\n\n📁 Categories:\n';
162
+ msg += '\n\n📂 Categories:\n';
163
163
  msg += categories.map((p) => ` • ${p.name}`).join('\n');
164
164
  }
165
165
  return { handled: true, response: msg };
166
166
  }
167
- // /project <name>
168
- if (text.startsWith('/project ') && !text.startsWith('/projects')) {
169
- const name = text.slice(9).trim();
167
+ // /folder <name> (also accept legacy /project <name>)
168
+ if ((text.startsWith('/folder ') && !text.startsWith('/folders')) || (text.startsWith('/project ') && !text.startsWith('/projects'))) {
169
+ const prefix = text.startsWith('/folder ') ? '/folder ' : '/project ';
170
+ const name = text.slice(prefix.length).trim();
170
171
  const { getProject, setUserContext } = await import('../projects/index.js');
171
172
  const project = getProject(name);
172
173
  if (!project)
173
- return { handled: true, response: `Project "${name}" not found. Use /projects to list or /newproject to create.` };
174
+ return { handled: true, response: `Folder "${name}" not found. Use /folders to list or /newfolder to create.` };
174
175
  setUserContext(userId, project.name, project.name);
175
- return { handled: true, response: `Switched to project: ${project.name}\nPath: ${project.path}\n\nNext messages will work in this project.` };
176
+ return { handled: true, response: `Switched to folder: ${project.name}\nPath: ${project.path}\n\nNext messages will work in this folder.` };
176
177
  }
177
- // /newproject <name> [path]
178
- if (text.startsWith('/newproject ')) {
179
- const parts = text.slice(12).trim().split(/\s+/);
178
+ // /newfolder <name> [path] (also accept legacy /newproject)
179
+ if (text.startsWith('/newfolder ') || text.startsWith('/newproject ')) {
180
+ const prefix = text.startsWith('/newfolder ') ? '/newfolder ' : '/newproject ';
181
+ const parts = text.slice(prefix.length).trim().split(/\s+/);
180
182
  const name = parts[0];
181
183
  const customPath = parts[1] || undefined;
182
184
  if (!name)
183
- return { handled: true, response: 'Usage: /newproject <name> [path]' };
185
+ return { handled: true, response: 'Usage: /newfolder <name> [path]' };
184
186
  const { createProject, setUserContext } = await import('../projects/index.js');
185
187
  const project = createProject(name, customPath);
186
188
  setUserContext(userId, project.name, project.name);
187
- return { handled: true, response: `✓ Project "${name}" created at ${project.path}\nSwitched to this project.` };
189
+ return { handled: true, response: `✓ Folder "${name}" created at ${project.path}\nSwitched to this folder.` };
188
190
  }
189
191
  // /close <tab>
190
192
  if (text.startsWith('/close ')) {
@@ -197,16 +199,16 @@ export async function handleSharedCommand(ctx, tabManager) {
197
199
  const closed = closeTab(tabNameToClose);
198
200
  return { handled: true, response: closed ? `Tab "${tabNameToClose}" permanently closed. History deleted.` : `Tab "${tabNameToClose}" not found.` };
199
201
  }
200
- // /fresh <project>
202
+ // /fresh <folder>
201
203
  if (text.startsWith('/fresh ')) {
202
- const projectName = text.slice(7).trim();
204
+ const folderName = text.slice(7).trim();
203
205
  const { getProject, setUserContext } = await import('../projects/index.js');
204
- const project = getProject(projectName);
206
+ const project = getProject(folderName);
205
207
  if (!project)
206
- return { handled: true, response: `Project "${projectName}" not found.` };
207
- const freshTabName = `${projectName}-${Date.now().toString(36).slice(-4)}`;
208
+ return { handled: true, response: `Folder "${folderName}" not found.` };
209
+ const freshTabName = `${folderName}-${Date.now().toString(36).slice(-4)}`;
208
210
  setUserContext(userId, project.name, freshTabName);
209
- return { handled: true, response: `Fresh start in "${projectName}" (tab: ${freshTabName})\nSend your message now.` };
211
+ return { handled: true, response: `Fresh start in "${folderName}" (tab: ${freshTabName})\nSend your message now.` };
210
212
  }
211
213
  return { handled: false };
212
214
  }
package/dist/cli/setup.js CHANGED
@@ -202,6 +202,11 @@ export async function setupWizard() {
202
202
  console.log(' beecork dashboard — open web control panel');
203
203
  console.log(' beecork quickstart — full getting-started checklist');
204
204
  console.log('');
205
+ console.log(' ★ Recommended: Smart folder routing');
206
+ console.log(' If you work in multiple folders, Beecork can auto-detect which');
207
+ console.log(' folder you mean and route messages to the right tab.');
208
+ console.log(' Run: beecork pipe setup');
209
+ console.log('');
205
210
  console.log(' Add more channels:');
206
211
  console.log(' beecork whatsapp — connect WhatsApp');
207
212
  console.log(' beecork discord — connect Discord');
package/dist/index.js CHANGED
@@ -394,18 +394,19 @@ program
394
394
  console.log('');
395
395
  });
396
396
  program
397
- .command('projects')
398
- .description('List all discovered projects')
397
+ .command('folders')
398
+ .alias('projects')
399
+ .description('List all discovered folders')
399
400
  .action(async () => {
400
401
  const { listProjects } = await import('./projects/index.js');
401
402
  const projects = listProjects();
402
403
  if (projects.length === 0) {
403
- console.log('No projects found. Start the daemon to discover projects.');
404
+ console.log('No folders found. Start the daemon to discover folders.');
404
405
  return;
405
406
  }
406
- console.log(`\n${projects.length} project(s):\n`);
407
+ console.log(`\n${projects.length} folder(s):\n`);
407
408
  for (const p of projects) {
408
- const icon = p.type === 'category' ? '📁' : '📦';
409
+ const icon = p.type === 'category' ? '📂' : '📁';
409
410
  console.log(` ${icon} ${p.name} — ${p.path}`);
410
411
  }
411
412
  console.log('');
@@ -81,7 +81,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
81
81
  type: 'object',
82
82
  properties: {
83
83
  content: { type: 'string', description: 'The fact or information to remember' },
84
- scope: { type: 'string', enum: ['global', 'project', 'tab', 'auto'], description: 'Where to store: global (about the user), project (about this project), tab (about this conversation), or auto (Claude decides)' },
84
+ scope: { type: 'string', enum: ['global', 'project', 'tab', 'auto'], description: 'Where to store: global (about the user), project (about this folder), tab (about this conversation), or auto (Claude decides)' },
85
85
  category: { type: 'string', description: 'For global scope: people, preferences, routines, or general' },
86
86
  },
87
87
  required: ['content'],
@@ -324,7 +324,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
324
324
  },
325
325
  {
326
326
  name: 'beecork_machines',
327
- description: 'List registered machines and their project paths. Shows which machine handles which projects.',
327
+ description: 'List registered machines and their folder paths. Shows which machine handles which folders.',
328
328
  inputSchema: { type: 'object', properties: {} },
329
329
  },
330
330
  {
@@ -352,11 +352,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
352
352
  },
353
353
  {
354
354
  name: 'beecork_project_create',
355
- description: 'Create a new project folder in the workspace',
355
+ description: 'Register a new folder in the workspace',
356
356
  inputSchema: {
357
357
  type: 'object',
358
358
  properties: {
359
- name: { type: 'string', description: 'Project name' },
359
+ name: { type: 'string', description: 'Folder name' },
360
360
  path: { type: 'string', description: 'Optional: custom path. Defaults to workspace root.' },
361
361
  },
362
362
  required: ['name'],
@@ -364,7 +364,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
364
364
  },
365
365
  {
366
366
  name: 'beecork_project_list',
367
- description: 'List all known projects and categories',
367
+ description: 'List all known folders and categories',
368
368
  inputSchema: { type: 'object', properties: {} },
369
369
  },
370
370
  {
@@ -425,11 +425,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
425
425
  },
426
426
  {
427
427
  name: 'beecork_knowledge',
428
- description: 'List all knowledge Beecork has about the current context (global + project + tab)',
428
+ description: 'List all knowledge Beecork has about the current context (global + folder + tab)',
429
429
  inputSchema: {
430
430
  type: 'object',
431
431
  properties: {
432
- scope: { type: 'string', enum: ['global', 'project', 'tab', 'all'], description: 'Which layer to show (default: all)' },
432
+ scope: { type: 'string', enum: ['global', 'project', 'tab', 'all'], description: 'Which layer to show: global, project (folder), tab, or all (default: all)' },
433
433
  },
434
434
  },
435
435
  },
@@ -793,13 +793,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
793
793
  const { name, path: customPath } = args;
794
794
  const { createProject } = await import('../projects/index.js');
795
795
  const project = createProject(name, customPath);
796
- return ok(`Project "${name}" created at ${project.path}`);
796
+ return ok(`Folder "${name}" registered at ${project.path}`);
797
797
  }
798
798
  case 'beecork_project_list': {
799
799
  const { listProjects } = await import('../projects/index.js');
800
800
  const projects = listProjects();
801
801
  if (projects.length === 0)
802
- return ok('No projects discovered. Create one with beecork_project_create.');
802
+ return ok('No folders discovered. Create one with beecork_project_create.');
803
803
  const lines = projects.map(p => `${p.type === 'category' ? '📁' : '📦'} ${p.name} — ${p.path}`);
804
804
  return ok(lines.join('\n'));
805
805
  }
@@ -25,13 +25,13 @@ export class PipeBrain {
25
25
  const route = await this.route(message, decisions);
26
26
  // Step 2: Ensure the tab exists with the right working directory
27
27
  if (route.projectPath) {
28
- this.tabManager.ensureTab(route.tabName);
28
+ this.tabManager.ensureTab(route.tabName, route.projectPath);
29
29
  this.memory.updateProjectLastUsed(route.projectPath);
30
30
  }
31
31
  // Step 3: Send to Claude Code
32
32
  let result;
33
33
  try {
34
- result = await this.tabManager.sendMessage(route.tabName, message, { skipExtraction: true });
34
+ result = await this.tabManager.sendMessage(route.tabName, message, { skipExtraction: true, projectPath: route.projectPath ?? undefined });
35
35
  }
36
36
  catch (err) {
37
37
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beecork",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "Claude Code always-on infrastructure — a phone number, a memory, and an alarm clock",
5
5
  "type": "module",
6
6
  "bin": {