@sarkar-ai/deskmate 0.2.1 → 0.3.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/dist/cli.js CHANGED
@@ -35,9 +35,19 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.buildAllowedUsers = buildAllowedUsers;
38
- require("dotenv/config");
38
+ const dotenv = __importStar(require("dotenv"));
39
39
  const fs = __importStar(require("fs"));
40
40
  const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ // Load .env: try cwd first (source install / service), then ~/.config/deskmate/ (npm global)
43
+ const cwdEnv = path.join(process.cwd(), ".env");
44
+ const configEnv = path.join(os.homedir(), ".config", "deskmate", ".env");
45
+ if (fs.existsSync(cwdEnv)) {
46
+ dotenv.config({ path: cwdEnv });
47
+ }
48
+ else if (fs.existsSync(configEnv)) {
49
+ dotenv.config({ path: configEnv });
50
+ }
41
51
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"));
42
52
  const VERSION = pkg.version;
43
53
  const BOT_NAME = process.env.BOT_NAME || "Deskmate";
@@ -49,10 +59,9 @@ Usage:
49
59
  deskmate <command> [options]
50
60
 
51
61
  Commands:
52
- telegram Start the Telegram bot (default)
62
+ (default) Start the gateway (multi-client)
53
63
  mcp Start the MCP server
54
- both Start both Telegram bot and MCP server
55
- gateway Start the multi-client gateway
64
+ both Start gateway + MCP server
56
65
  init Interactive setup wizard
57
66
 
58
67
  Options:
@@ -60,18 +69,17 @@ Options:
60
69
  -v, --version Show version number
61
70
 
62
71
  Examples:
63
- deskmate Start in Telegram mode
64
- deskmate telegram Start the Telegram bot
72
+ deskmate Start the gateway
65
73
  deskmate mcp Start the MCP server
66
- deskmate gateway Start multi-client gateway
74
+ deskmate both Start gateway + MCP
67
75
  deskmate init Run the setup wizard
68
76
  deskmate --version Print version
69
77
 
70
78
  Environment:
71
- AGENT_PROVIDER Agent provider (default: claude-code)
79
+ ALLOWED_USERS Multi-client allowlist (e.g. telegram:123,discord:456)
72
80
  TELEGRAM_BOT_TOKEN Telegram bot token
73
81
  ANTHROPIC_API_KEY Anthropic API key
74
- ALLOWED_USERS Multi-client allowlist (e.g. telegram:123,discord:456)
82
+ AGENT_PROVIDER Agent provider (default: claude-code)
75
83
  `);
76
84
  }
77
85
  function buildAllowedUsers() {
@@ -99,7 +107,7 @@ function buildAllowedUsers() {
99
107
  }
100
108
  async function main() {
101
109
  const args = process.argv.slice(2);
102
- const command = args.find((a) => !a.startsWith("-")) || "telegram";
110
+ const command = args.find((a) => !a.startsWith("-")) || "gateway";
103
111
  const flags = new Set(args.filter((a) => a.startsWith("-")));
104
112
  if (flags.has("--help") || flags.has("-h")) {
105
113
  printHelp();
@@ -109,16 +117,35 @@ async function main() {
109
117
  console.log(VERSION);
110
118
  process.exit(0);
111
119
  }
112
- // If no explicit command and no .env found, suggest running init
120
+ // If no explicit command and no .env found anywhere, suggest running init
113
121
  if (!args.find((a) => !a.startsWith("-")) &&
114
- !fs.existsSync(path.join(process.cwd(), ".env"))) {
122
+ !fs.existsSync(cwdEnv) &&
123
+ !fs.existsSync(configEnv)) {
115
124
  console.log(`No .env file found. Run "deskmate init" to get started.\n`);
116
125
  }
117
126
  switch (command) {
118
- case "telegram": {
119
- console.log(`Starting ${BOT_NAME} in telegram mode...`);
120
- const { startTelegramBot } = await Promise.resolve().then(() => __importStar(require("./telegram/bot")));
121
- await startTelegramBot();
127
+ case "telegram":
128
+ console.warn('[deprecated] "deskmate telegram" is deprecated. The gateway is now the default. Starting gateway...');
129
+ // fall through
130
+ case "gateway": {
131
+ console.log(`Starting ${BOT_NAME} in gateway mode...`);
132
+ const { Gateway } = await Promise.resolve().then(() => __importStar(require("./gateway")));
133
+ const { TelegramClient } = await Promise.resolve().then(() => __importStar(require("./clients/telegram")));
134
+ const allowedUsers = buildAllowedUsers();
135
+ if (allowedUsers.length === 0) {
136
+ console.error("No allowed users configured. Set ALLOWED_USERS or ALLOWED_USER_ID in your .env");
137
+ process.exit(1);
138
+ }
139
+ const gateway = new Gateway({
140
+ botName: BOT_NAME,
141
+ workingDir: process.env.WORKING_DIR || process.env.HOME || "/",
142
+ allowedUsers,
143
+ maxTurns: 10,
144
+ });
145
+ if (process.env.TELEGRAM_BOT_TOKEN) {
146
+ gateway.registerClient(new TelegramClient(process.env.TELEGRAM_BOT_TOKEN));
147
+ }
148
+ await gateway.start();
122
149
  break;
123
150
  }
124
151
  case "mcp": {
@@ -128,19 +155,10 @@ async function main() {
128
155
  break;
129
156
  }
130
157
  case "both": {
131
- console.log(`Starting ${BOT_NAME} in both mode...`);
132
- const [{ startTelegramBot: startBot }, { startMcpServer: startMcp }] = await Promise.all([
133
- Promise.resolve().then(() => __importStar(require("./telegram/bot"))),
134
- Promise.resolve().then(() => __importStar(require("./mcp/server"))),
135
- ]);
136
- startBot().catch(console.error);
137
- await startMcp();
138
- break;
139
- }
140
- case "gateway": {
141
- console.log(`Starting ${BOT_NAME} in gateway mode...`);
158
+ console.log(`Starting ${BOT_NAME} in gateway + mcp mode...`);
142
159
  const { Gateway } = await Promise.resolve().then(() => __importStar(require("./gateway")));
143
160
  const { TelegramClient } = await Promise.resolve().then(() => __importStar(require("./clients/telegram")));
161
+ const { startMcpServer } = await Promise.resolve().then(() => __importStar(require("./mcp/server")));
144
162
  const allowedUsers = buildAllowedUsers();
145
163
  if (allowedUsers.length === 0) {
146
164
  console.error("No allowed users configured. Set ALLOWED_USERS or ALLOWED_USER_ID in your .env");
@@ -155,7 +173,8 @@ async function main() {
155
173
  if (process.env.TELEGRAM_BOT_TOKEN) {
156
174
  gateway.registerClient(new TelegramClient(process.env.TELEGRAM_BOT_TOKEN));
157
175
  }
158
- await gateway.start();
176
+ gateway.start().catch(console.error);
177
+ await startMcpServer();
159
178
  break;
160
179
  }
161
180
  case "setup":
package/dist/index.js CHANGED
@@ -33,8 +33,20 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- require("dotenv/config");
37
- const mode = process.argv[2] || "telegram";
36
+ const dotenv = __importStar(require("dotenv"));
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ // Load .env: try cwd first (source install / service), then ~/.config/deskmate/ (npm global)
41
+ const cwdEnv = path.join(process.cwd(), ".env");
42
+ const configEnv = path.join(os.homedir(), ".config", "deskmate", ".env");
43
+ if (fs.existsSync(cwdEnv)) {
44
+ dotenv.config({ path: cwdEnv });
45
+ }
46
+ else if (fs.existsSync(configEnv)) {
47
+ dotenv.config({ path: configEnv });
48
+ }
49
+ const mode = process.argv[2] || "gateway";
38
50
  const BOT_NAME = process.env.BOT_NAME || "Deskmate";
39
51
  /** Parse ALLOWED_USERS (multi-client) and ALLOWED_USER_ID (legacy) into UserIdentity[] */
40
52
  function buildAllowedUsers() {
@@ -64,31 +76,12 @@ function buildAllowedUsers() {
64
76
  return users;
65
77
  }
66
78
  async function main() {
67
- console.log(`🚀 Starting ${BOT_NAME} in ${mode} mode...`);
68
79
  switch (mode) {
69
80
  case "telegram":
70
- // Telegram bot mode - natural language interface
71
- const { startTelegramBot } = await Promise.resolve().then(() => __importStar(require("./telegram/bot")));
72
- await startTelegramBot();
73
- break;
74
- case "mcp":
75
- // MCP server mode - for Claude.ai / MCP clients
76
- const { startMcpServer } = await Promise.resolve().then(() => __importStar(require("./mcp/server")));
77
- await startMcpServer();
78
- break;
79
- case "both":
80
- // Run both (MCP on stdio, Telegram in background)
81
- console.log("Starting both Telegram bot and MCP server...");
82
- const [{ startTelegramBot: startBot }, { startMcpServer: startMcp }] = await Promise.all([
83
- Promise.resolve().then(() => __importStar(require("./telegram/bot"))),
84
- Promise.resolve().then(() => __importStar(require("./mcp/server"))),
85
- ]);
86
- // Start Telegram in background (for approval notifications)
87
- startBot().catch(console.error);
88
- // Start MCP (this blocks on stdio)
89
- await startMcp();
90
- break;
81
+ console.warn('[deprecated] "telegram" mode is deprecated. The gateway is now the default. Starting gateway...');
82
+ // fall through
91
83
  case "gateway": {
84
+ console.log(`Starting ${BOT_NAME} in gateway mode...`);
92
85
  const { Gateway } = await Promise.resolve().then(() => __importStar(require("./gateway")));
93
86
  const { TelegramClient } = await Promise.resolve().then(() => __importStar(require("./clients/telegram")));
94
87
  const allowedUsers = buildAllowedUsers();
@@ -109,9 +102,38 @@ async function main() {
109
102
  await gateway.start();
110
103
  break;
111
104
  }
105
+ case "mcp": {
106
+ console.log(`Starting ${BOT_NAME} in mcp mode...`);
107
+ const { startMcpServer } = await Promise.resolve().then(() => __importStar(require("./mcp/server")));
108
+ await startMcpServer();
109
+ break;
110
+ }
111
+ case "both": {
112
+ console.log(`Starting ${BOT_NAME} in gateway + mcp mode...`);
113
+ const { Gateway } = await Promise.resolve().then(() => __importStar(require("./gateway")));
114
+ const { TelegramClient } = await Promise.resolve().then(() => __importStar(require("./clients/telegram")));
115
+ const { startMcpServer } = await Promise.resolve().then(() => __importStar(require("./mcp/server")));
116
+ const allowedUsers = buildAllowedUsers();
117
+ if (allowedUsers.length === 0) {
118
+ throw new Error("No allowed users configured. Set ALLOWED_USERS or ALLOWED_USER_ID in your .env");
119
+ }
120
+ const gateway = new Gateway({
121
+ botName: BOT_NAME,
122
+ workingDir: process.env.WORKING_DIR || process.env.HOME || "/",
123
+ allowedUsers,
124
+ maxTurns: 10,
125
+ });
126
+ if (process.env.TELEGRAM_BOT_TOKEN) {
127
+ gateway.registerClient(new TelegramClient(process.env.TELEGRAM_BOT_TOKEN));
128
+ }
129
+ // Start gateway in background, MCP on stdio
130
+ gateway.start().catch(console.error);
131
+ await startMcpServer();
132
+ break;
133
+ }
112
134
  default:
113
135
  console.error(`Unknown mode: ${mode}`);
114
- console.error("Usage: npm start [telegram|mcp|both|gateway]");
136
+ console.error("Usage: npm start [gateway|mcp|both]");
115
137
  process.exit(1);
116
138
  }
117
139
  }
@@ -121,10 +143,10 @@ main().catch((error) => {
121
143
  });
122
144
  // Graceful shutdown
123
145
  process.on("SIGINT", () => {
124
- console.log("\n👋 Shutting down...");
146
+ console.log("\nShutting down...");
125
147
  process.exit(0);
126
148
  });
127
149
  process.on("SIGTERM", () => {
128
- console.log("\n👋 Shutting down...");
150
+ console.log("\nShutting down...");
129
151
  process.exit(0);
130
152
  });
package/install.sh CHANGED
@@ -1,4 +1,13 @@
1
1
  #!/bin/bash
2
+ #
3
+ # Deskmate Installer (source clone path)
4
+ #
5
+ # This script is for users who cloned the repo from source:
6
+ # git clone https://github.com/sarkar-ai-taken/deskmate.git
7
+ # cd deskmate && ./install.sh
8
+ #
9
+ # For npm global installs, use: deskmate init
10
+ #
2
11
 
3
12
  set -e
4
13
 
@@ -116,61 +125,127 @@ echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━
116
125
  echo -e "${YELLOW}Configuring environment...${NC}"
117
126
  echo ""
118
127
 
119
- CONFIGURE_ENV=true
128
+ # Helper: read a value from existing .env
129
+ env_get() {
130
+ local key="$1"
131
+ if [ -f "$PROJECT_DIR/.env" ]; then
132
+ grep -E "^${key}=" "$PROJECT_DIR/.env" 2>/dev/null | head -1 | cut -d'=' -f2-
133
+ fi
134
+ }
120
135
 
121
- if [ -f "$PROJECT_DIR/.env" ]; then
122
- echo -e "${GREEN}Found existing .env file.${NC}"
123
- read -p "Reconfigure? [y/N]: " RECONFIGURE
124
- if [ "$RECONFIGURE" != "y" ] && [ "$RECONFIGURE" != "Y" ]; then
125
- CONFIGURE_ENV=false
126
- echo -e "${GREEN}✓ Keeping existing .env${NC}"
136
+ # Helper: mask a secret value for display
137
+ mask_value() {
138
+ local val="$1"
139
+ local len=${#val}
140
+ if [ "$len" -le 8 ]; then
141
+ echo "****"
142
+ else
143
+ echo "${val:0:4}...${val: -4}"
127
144
  fi
145
+ }
146
+
147
+ # Load existing values (if any)
148
+ EXISTING_API_KEY=$(env_get ANTHROPIC_API_KEY)
149
+ EXISTING_TOKEN=$(env_get TELEGRAM_BOT_TOKEN)
150
+ EXISTING_USER_ID=$(env_get ALLOWED_USER_ID)
151
+ EXISTING_USERS=$(env_get ALLOWED_USERS)
152
+ EXISTING_WORKING_DIR=$(env_get WORKING_DIR)
153
+ EXISTING_BOT_NAME=$(env_get BOT_NAME)
154
+ EXISTING_LOG_LEVEL=$(env_get LOG_LEVEL)
155
+ EXISTING_REQUIRE_APPROVAL=$(env_get REQUIRE_APPROVAL_FOR_ALL)
156
+ EXISTING_ALLOWED_FOLDERS=$(env_get ALLOWED_FOLDERS)
157
+
158
+ HAS_EXISTING=false
159
+ if [ -f "$PROJECT_DIR/.env" ] && [ -n "$EXISTING_TOKEN$EXISTING_API_KEY$EXISTING_USERS$EXISTING_USER_ID" ]; then
160
+ HAS_EXISTING=true
161
+ echo -e "${GREEN}Found existing .env — press Enter to keep current values.${NC}"
128
162
  fi
129
163
 
130
- if [ "$CONFIGURE_ENV" = true ]; then
131
- echo ""
132
- echo -e "${YELLOW}Enter your credentials (press Enter to skip optional fields):${NC}"
133
- echo ""
164
+ echo ""
165
+ echo -e "${YELLOW}Enter your credentials (press Enter to keep existing / skip):${NC}"
166
+ echo ""
134
167
 
168
+ # Anthropic API Key
169
+ if [ -n "$EXISTING_API_KEY" ]; then
170
+ read -p " Anthropic API Key [$(mask_value "$EXISTING_API_KEY")]: " ANTHROPIC_API_KEY
171
+ ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-$EXISTING_API_KEY}
172
+ else
135
173
  read -p " Anthropic API Key: " ANTHROPIC_API_KEY
136
174
  if [ -z "$ANTHROPIC_API_KEY" ]; then
137
175
  echo -e " ${RED}Warning: No API key entered. You'll need to set ANTHROPIC_API_KEY in .env later.${NC}"
138
176
  fi
177
+ fi
139
178
 
140
- echo ""
179
+ # Telegram
180
+ echo ""
181
+ if [ -z "$EXISTING_TOKEN" ]; then
141
182
  echo -e " ${BLUE}Telegram setup — get these from Telegram:${NC}"
142
183
  echo -e " Bot token → message @BotFather, send /newbot"
143
184
  echo -e " User ID → message @userinfobot, copy the number"
144
185
  echo ""
186
+ fi
145
187
 
188
+ if [ -n "$EXISTING_TOKEN" ]; then
189
+ read -p " Telegram Bot Token [$(mask_value "$EXISTING_TOKEN")]: " TELEGRAM_BOT_TOKEN
190
+ TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-$EXISTING_TOKEN}
191
+ else
146
192
  read -p " Telegram Bot Token (from @BotFather): " TELEGRAM_BOT_TOKEN
193
+ fi
194
+
195
+ # User ID / Allowed Users
196
+ if [ -n "$EXISTING_USERS" ]; then
197
+ read -p " Allowed users [$EXISTING_USERS]: " ALLOWED_USERS_INPUT
198
+ ALLOWED_USERS_VAL=${ALLOWED_USERS_INPUT:-$EXISTING_USERS}
199
+ TELEGRAM_USER_ID="$EXISTING_USER_ID"
200
+ elif [ -n "$EXISTING_USER_ID" ]; then
201
+ read -p " Telegram User ID [$EXISTING_USER_ID]: " TELEGRAM_USER_ID
202
+ TELEGRAM_USER_ID=${TELEGRAM_USER_ID:-$EXISTING_USER_ID}
203
+ ALLOWED_USERS_VAL="telegram:${TELEGRAM_USER_ID}"
204
+ else
147
205
  read -p " Telegram User ID (from @userinfobot): " TELEGRAM_USER_ID
206
+ ALLOWED_USERS_VAL="telegram:${TELEGRAM_USER_ID}"
207
+ fi
148
208
 
149
- echo ""
150
- read -p " Working directory (default: $HOME): " WORKING_DIR
151
- WORKING_DIR=${WORKING_DIR:-$HOME}
209
+ echo ""
210
+ WORKING_DIR_DEFAULT=${EXISTING_WORKING_DIR:-$HOME}
211
+ read -p " Working directory [$WORKING_DIR_DEFAULT]: " WORKING_DIR
212
+ WORKING_DIR=${WORKING_DIR:-$WORKING_DIR_DEFAULT}
152
213
 
153
- read -p " Bot name (default: Deskmate): " BOT_NAME
154
- BOT_NAME=${BOT_NAME:-Deskmate}
214
+ BOT_NAME_DEFAULT=${EXISTING_BOT_NAME:-Deskmate}
215
+ read -p " Bot name [$BOT_NAME_DEFAULT]: " BOT_NAME
216
+ BOT_NAME=${BOT_NAME:-$BOT_NAME_DEFAULT}
155
217
 
156
- # Write .env
157
- cat > "$PROJECT_DIR/.env" << EOF
218
+ # Carry over existing values we don't prompt for
219
+ LOG_LEVEL=${EXISTING_LOG_LEVEL:-info}
220
+ REQUIRE_APPROVAL=${EXISTING_REQUIRE_APPROVAL:-false}
221
+ ALLOWED_FOLDERS_VAL=${EXISTING_ALLOWED_FOLDERS}
222
+
223
+ # Write .env
224
+ cat > "$PROJECT_DIR/.env" << EOF
158
225
  # Deskmate Configuration (generated by install.sh)
159
226
 
227
+ ALLOWED_USERS=${ALLOWED_USERS_VAL}
160
228
  TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
161
- ALLOWED_USER_ID=${TELEGRAM_USER_ID}
162
- ALLOWED_USERS=telegram:${TELEGRAM_USER_ID}
163
229
  ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
164
230
  AGENT_PROVIDER=claude-code
165
231
  WORKING_DIR=${WORKING_DIR}
166
232
  BOT_NAME=${BOT_NAME}
167
- LOG_LEVEL=info
168
- REQUIRE_APPROVAL_FOR_ALL=false
233
+ LOG_LEVEL=${LOG_LEVEL}
234
+ REQUIRE_APPROVAL_FOR_ALL=${REQUIRE_APPROVAL}
169
235
  EOF
170
236
 
171
- echo -e "\n${GREEN}✓ .env file written${NC}"
237
+ # Add legacy user ID if we have one
238
+ if [ -n "$TELEGRAM_USER_ID" ]; then
239
+ echo "ALLOWED_USER_ID=${TELEGRAM_USER_ID}" >> "$PROJECT_DIR/.env"
240
+ fi
241
+
242
+ # Carry over allowed folders
243
+ if [ -n "$ALLOWED_FOLDERS_VAL" ]; then
244
+ echo "ALLOWED_FOLDERS=${ALLOWED_FOLDERS_VAL}" >> "$PROJECT_DIR/.env"
172
245
  fi
173
246
 
247
+ echo -e "\n${GREEN}✓ .env file written${NC}"
248
+
174
249
  # =============================================================================
175
250
  # 3. Build
176
251
  # =============================================================================
@@ -283,6 +358,10 @@ if [ "$PLATFORM" = "macos" ]; then
283
358
  echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
284
359
  echo -e "${YELLOW}Configuring folder access...${NC}"
285
360
  echo ""
361
+ if [ -n "$ALLOWED_FOLDERS_VAL" ]; then
362
+ echo -e " Current allowed folders: ${GREEN}${ALLOWED_FOLDERS_VAL}${NC}"
363
+ echo ""
364
+ fi
286
365
  echo -e "macOS will ask for permission when the agent accesses protected folders."
287
366
  echo -e "Let's configure which folders the agent should have access to."
288
367
  echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarkar-ai/deskmate",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Control your local machine from anywhere using natural language via Telegram or MCP.",
5
5
  "author": "Deskmate Contributors",
6
6
  "license": "MIT",
@@ -47,12 +47,11 @@
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsc",
50
- "start": "node dist/index.js telegram",
51
- "start:telegram": "node dist/index.js telegram",
50
+ "start": "node dist/index.js",
52
51
  "start:mcp": "node dist/index.js mcp",
53
52
  "start:gateway": "node dist/index.js gateway",
54
53
  "start:both": "node dist/index.js both",
55
- "dev": "tsx src/index.ts telegram",
54
+ "dev": "tsx src/index.ts",
56
55
  "dev:mcp": "tsx src/index.ts mcp",
57
56
  "test": "vitest run",
58
57
  "prepublishOnly": "npm run build"
@@ -60,6 +59,7 @@
60
59
  "dependencies": {
61
60
  "@anthropic-ai/claude-agent-sdk": "^0.2.6",
62
61
  "@modelcontextprotocol/sdk": "^1.0.0",
62
+ "@sarkar-ai/deskmate": "^0.2.1",
63
63
  "dotenv": "^16.3.1",
64
64
  "grammy": "^1.21.1",
65
65
  "zod": "^4.0.0"