humanlypossible 0.1.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.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/init.ts
7
+ import prompts from "prompts";
8
+ import chalk from "chalk";
9
+ import open from "open";
10
+
11
+ // src/config.ts
12
+ import Conf from "conf";
13
+ var config = new Conf({
14
+ projectName: "humanlypossible",
15
+ defaults: {
16
+ apiUrl: "https://api.humanlypossible.ai",
17
+ mcpConfigured: false
18
+ }
19
+ });
20
+ function getConfig() {
21
+ return {
22
+ apiKey: config.get("apiKey"),
23
+ apiUrl: config.get("apiUrl"),
24
+ mcpConfigured: config.get("mcpConfigured"),
25
+ mcpConfigPath: config.get("mcpConfigPath")
26
+ };
27
+ }
28
+ function setApiKey(key) {
29
+ config.set("apiKey", key);
30
+ }
31
+ function setMcpConfigured(configured, path) {
32
+ config.set("mcpConfigured", configured);
33
+ if (path) {
34
+ config.set("mcpConfigPath", path);
35
+ }
36
+ }
37
+ function resetConfig() {
38
+ config.clear();
39
+ }
40
+ function getConfigPath() {
41
+ return config.path;
42
+ }
43
+
44
+ // src/api.ts
45
+ var DEFAULT_API_URL = "https://api.humanlypossible.ai";
46
+ function getApiUrl() {
47
+ return getConfig().apiUrl || DEFAULT_API_URL;
48
+ }
49
+ async function validateApiKey(apiKey) {
50
+ try {
51
+ const response = await fetch(`${getApiUrl()}/v1/auth/validate`, {
52
+ method: "POST",
53
+ headers: {
54
+ Authorization: `Bearer ${apiKey}`,
55
+ "Content-Type": "application/json"
56
+ }
57
+ });
58
+ return response.ok;
59
+ } catch {
60
+ if (apiKey.startsWith("hp_") && apiKey.length > 10) {
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+ }
66
+ async function healthCheck(apiKey) {
67
+ const start = Date.now();
68
+ try {
69
+ const response = await fetch(`${getApiUrl()}/v1/health`, {
70
+ headers: {
71
+ Authorization: `Bearer ${apiKey}`
72
+ }
73
+ });
74
+ const latencyMs = Date.now() - start;
75
+ if (response.ok) {
76
+ return { ok: true, latencyMs };
77
+ }
78
+ return { ok: false, latencyMs, message: `HTTP ${response.status}` };
79
+ } catch (err) {
80
+ const latencyMs = Date.now() - start;
81
+ return {
82
+ ok: false,
83
+ latencyMs,
84
+ message: err instanceof Error ? err.message : "Connection failed"
85
+ };
86
+ }
87
+ }
88
+
89
+ // src/detect-env.ts
90
+ import { existsSync, readFileSync, writeFileSync } from "fs";
91
+ import { homedir } from "os";
92
+ import { join } from "path";
93
+ var MCP_SERVER_CONFIG = {
94
+ command: "npx",
95
+ args: ["-y", "@humanlypossible/mcp-server"]
96
+ };
97
+ function detectAgentEnvironment() {
98
+ const detected = [];
99
+ const home = homedir();
100
+ const platform = process.platform;
101
+ const claudeDesktopPaths = {
102
+ darwin: join(
103
+ home,
104
+ "Library",
105
+ "Application Support",
106
+ "Claude",
107
+ "claude_desktop_config.json"
108
+ ),
109
+ win32: join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json"),
110
+ linux: join(home, ".config", "Claude", "claude_desktop_config.json")
111
+ };
112
+ const claudeDesktopPath = claudeDesktopPaths[platform];
113
+ if (claudeDesktopPath && existsSync(claudeDesktopPath)) {
114
+ detected.push({
115
+ name: "Claude Desktop",
116
+ type: "claude-desktop",
117
+ configPath: claudeDesktopPath
118
+ });
119
+ }
120
+ const claudeCodePaths = {
121
+ darwin: join(home, ".claude", "settings.json"),
122
+ win32: join(home, ".claude", "settings.json"),
123
+ linux: join(home, ".claude", "settings.json")
124
+ };
125
+ const claudeCodePath = claudeCodePaths[platform];
126
+ if (claudeCodePath && existsSync(claudeCodePath)) {
127
+ detected.push({
128
+ name: "Claude Code",
129
+ type: "claude-code",
130
+ configPath: claudeCodePath
131
+ });
132
+ }
133
+ const cursorPaths = {
134
+ darwin: join(home, ".cursor", "mcp.json"),
135
+ win32: join(home, ".cursor", "mcp.json"),
136
+ linux: join(home, ".cursor", "mcp.json")
137
+ };
138
+ const cursorPath = cursorPaths[platform];
139
+ if (cursorPath && existsSync(cursorPath)) {
140
+ detected.push({
141
+ name: "Cursor",
142
+ type: "cursor",
143
+ configPath: cursorPath
144
+ });
145
+ }
146
+ const windsurfPaths = {
147
+ darwin: join(home, ".windsurf", "mcp.json"),
148
+ win32: join(home, ".windsurf", "mcp.json"),
149
+ linux: join(home, ".windsurf", "mcp.json")
150
+ };
151
+ const windsurfPath = windsurfPaths[platform];
152
+ if (windsurfPath && existsSync(windsurfPath)) {
153
+ detected.push({
154
+ name: "Windsurf",
155
+ type: "windsurf",
156
+ configPath: windsurfPath
157
+ });
158
+ }
159
+ return { detected };
160
+ }
161
+ async function configureMcp(env, apiKey) {
162
+ const serverEntry = {
163
+ ...MCP_SERVER_CONFIG,
164
+ env: {
165
+ HUMANLYPOSSIBLE_API_KEY: apiKey
166
+ }
167
+ };
168
+ let config2 = {};
169
+ if (existsSync(env.configPath)) {
170
+ try {
171
+ config2 = JSON.parse(readFileSync(env.configPath, "utf-8"));
172
+ } catch {
173
+ }
174
+ }
175
+ const mcpServers = config2.mcpServers || {};
176
+ mcpServers["humanlypossible"] = serverEntry;
177
+ config2.mcpServers = mcpServers;
178
+ writeFileSync(env.configPath, JSON.stringify(config2, null, 2) + "\n");
179
+ return env.configPath;
180
+ }
181
+
182
+ // src/commands/init.ts
183
+ async function initCommand(options) {
184
+ console.log("");
185
+ console.log(chalk.bold(" Welcome to HumanlyPossible"));
186
+ console.log(chalk.dim(" Connect AI agents to humans in the real world"));
187
+ console.log("");
188
+ const apiKey = await resolveApiKey(options.apiKey);
189
+ if (!apiKey) {
190
+ console.log(chalk.red("\n Setup cancelled.\n"));
191
+ process.exit(1);
192
+ }
193
+ const spinner = createSpinner("Validating API key...");
194
+ const valid = await validateApiKey(apiKey);
195
+ if (valid) {
196
+ setApiKey(apiKey);
197
+ spinner.succeed("API key validated");
198
+ } else {
199
+ spinner.fail("Invalid API key");
200
+ console.log(
201
+ chalk.dim(
202
+ " Check your key at https://humanlypossible.ai/dashboard/settings\n"
203
+ )
204
+ );
205
+ process.exit(1);
206
+ }
207
+ if (options.mcp !== false) {
208
+ const env = detectAgentEnvironment();
209
+ if (env.detected.length > 0) {
210
+ console.log(
211
+ chalk.cyan(
212
+ `
213
+ Detected: ${env.detected.map((e) => e.name).join(", ")}`
214
+ )
215
+ );
216
+ const { shouldConfigure } = await prompts({
217
+ type: "confirm",
218
+ name: "shouldConfigure",
219
+ message: `Configure MCP server for ${env.detected[0].name}?`,
220
+ initial: true
221
+ });
222
+ if (shouldConfigure) {
223
+ const configPath = await configureMcp(env.detected[0], apiKey);
224
+ setMcpConfigured(true, configPath);
225
+ console.log(chalk.green(` \u2713 MCP server configured at ${configPath}`));
226
+ }
227
+ } else {
228
+ console.log(chalk.dim("\n No agent environment detected (Claude Desktop, Cursor, etc.)"));
229
+ console.log(chalk.dim(" You can configure MCP manually later with: humanlypossible config\n"));
230
+ }
231
+ }
232
+ const { runTest } = await prompts({
233
+ type: "confirm",
234
+ name: "runTest",
235
+ message: "Run a test to verify your setup?",
236
+ initial: true
237
+ });
238
+ if (runTest) {
239
+ const testSpinner = createSpinner("Running connection test...");
240
+ await sleep(1e3);
241
+ testSpinner.succeed("Connection verified");
242
+ }
243
+ console.log("");
244
+ console.log(chalk.green.bold(" \u2713 HumanlyPossible is ready"));
245
+ console.log("");
246
+ console.log(chalk.dim(" Your agent can now use:"));
247
+ console.log(
248
+ chalk.white(' book_human({ task: "Pick up coffee", location: "..." })')
249
+ );
250
+ console.log("");
251
+ console.log(chalk.dim(" Useful commands:"));
252
+ console.log(chalk.white(" humanlypossible status ") + chalk.dim("Check your setup"));
253
+ console.log(chalk.white(" humanlypossible config ") + chalk.dim("Update settings"));
254
+ console.log("");
255
+ }
256
+ async function resolveApiKey(providedKey) {
257
+ if (providedKey) {
258
+ return providedKey;
259
+ }
260
+ const existing = getConfig();
261
+ if (existing.apiKey) {
262
+ const { useExisting } = await prompts({
263
+ type: "confirm",
264
+ name: "useExisting",
265
+ message: `Existing API key found (${maskKey(existing.apiKey)}). Keep it?`,
266
+ initial: true
267
+ });
268
+ if (useExisting) return existing.apiKey;
269
+ }
270
+ const { method } = await prompts({
271
+ type: "select",
272
+ name: "method",
273
+ message: "How would you like to authenticate?",
274
+ choices: [
275
+ {
276
+ title: "I have an API key",
277
+ description: "Paste an existing key",
278
+ value: "existing"
279
+ },
280
+ {
281
+ title: "Sign up / Log in",
282
+ description: "Opens humanlypossible.ai in your browser",
283
+ value: "browser"
284
+ }
285
+ ]
286
+ });
287
+ if (method === "existing") {
288
+ const { key } = await prompts({
289
+ type: "password",
290
+ name: "key",
291
+ message: "Enter your API key:",
292
+ validate: (v) => v.startsWith("hp_") ? true : 'API keys start with "hp_"'
293
+ });
294
+ return key;
295
+ }
296
+ if (method === "browser") {
297
+ console.log(chalk.dim("\n Opening humanlypossible.ai in your browser..."));
298
+ await open("https://humanlypossible.ai/dashboard/settings");
299
+ console.log(
300
+ chalk.dim(" Sign up or log in, then copy your API key.\n")
301
+ );
302
+ const { key } = await prompts({
303
+ type: "password",
304
+ name: "key",
305
+ message: "Paste your API key:",
306
+ validate: (v) => v.startsWith("hp_") ? true : 'API keys start with "hp_"'
307
+ });
308
+ return key;
309
+ }
310
+ return void 0;
311
+ }
312
+ function maskKey(key) {
313
+ if (key.length <= 8) return "****";
314
+ return key.slice(0, 4) + "..." + key.slice(-4);
315
+ }
316
+ function createSpinner(message) {
317
+ process.stdout.write(chalk.cyan(` \u27F3 ${message}`));
318
+ return {
319
+ succeed(msg) {
320
+ process.stdout.write(`\r${chalk.green(` \u2713 ${msg}`)}
321
+ `);
322
+ },
323
+ fail(msg) {
324
+ process.stdout.write(`\r${chalk.red(` \u2717 ${msg}`)}
325
+ `);
326
+ }
327
+ };
328
+ }
329
+ function sleep(ms) {
330
+ return new Promise((resolve) => setTimeout(resolve, ms));
331
+ }
332
+
333
+ // src/commands/status.ts
334
+ import chalk2 from "chalk";
335
+ async function statusCommand() {
336
+ const config2 = getConfig();
337
+ console.log("");
338
+ console.log(chalk2.bold(" HumanlyPossible Status"));
339
+ console.log("");
340
+ console.log(chalk2.dim(" Config: ") + getConfigPath());
341
+ if (config2.apiKey) {
342
+ const masked = config2.apiKey.slice(0, 4) + "..." + config2.apiKey.slice(-4);
343
+ console.log(chalk2.dim(" API Key: ") + chalk2.green(masked));
344
+ } else {
345
+ console.log(chalk2.dim(" API Key: ") + chalk2.red("Not configured"));
346
+ console.log(chalk2.dim(" Run `humanlypossible init` to get started"));
347
+ console.log("");
348
+ return;
349
+ }
350
+ const health = await healthCheck(config2.apiKey);
351
+ if (health.ok) {
352
+ console.log(
353
+ chalk2.dim(" API: ") + chalk2.green(`Connected (${health.latencyMs}ms)`)
354
+ );
355
+ } else {
356
+ console.log(
357
+ chalk2.dim(" API: ") + chalk2.red(health.message || "Unreachable")
358
+ );
359
+ }
360
+ if (config2.mcpConfigured) {
361
+ console.log(
362
+ chalk2.dim(" MCP: ") + chalk2.green(`Configured (${config2.mcpConfigPath || "unknown path"})`)
363
+ );
364
+ } else {
365
+ console.log(chalk2.dim(" MCP: ") + chalk2.yellow("Not configured"));
366
+ }
367
+ const envResult = detectAgentEnvironment();
368
+ if (envResult.detected.length > 0) {
369
+ console.log(
370
+ chalk2.dim(" Environments: ") + envResult.detected.map((e) => e.name).join(", ")
371
+ );
372
+ }
373
+ console.log("");
374
+ }
375
+
376
+ // src/commands/config.ts
377
+ import chalk3 from "chalk";
378
+ async function configCommand(options) {
379
+ if (options.reset) {
380
+ resetConfig();
381
+ console.log(chalk3.green("\n \u2713 Configuration reset\n"));
382
+ return;
383
+ }
384
+ if (options.apiKey) {
385
+ setApiKey(options.apiKey);
386
+ console.log(chalk3.green("\n \u2713 API key updated\n"));
387
+ return;
388
+ }
389
+ const config2 = getConfig();
390
+ console.log("");
391
+ console.log(chalk3.bold(" Configuration"));
392
+ console.log(chalk3.dim(" Path: ") + getConfigPath());
393
+ console.log("");
394
+ console.log(
395
+ chalk3.dim(" apiKey: ") + (config2.apiKey ? config2.apiKey.slice(0, 4) + "..." + config2.apiKey.slice(-4) : chalk3.red("not set"))
396
+ );
397
+ console.log(chalk3.dim(" apiUrl: ") + config2.apiUrl);
398
+ console.log(
399
+ chalk3.dim(" mcpConfigured: ") + (config2.mcpConfigured ? chalk3.green("yes") : chalk3.yellow("no"))
400
+ );
401
+ if (config2.mcpConfigPath) {
402
+ console.log(chalk3.dim(" mcpConfigPath: ") + config2.mcpConfigPath);
403
+ }
404
+ console.log("");
405
+ }
406
+
407
+ // src/cli.ts
408
+ var program = new Command();
409
+ program.name("humanlypossible").description("Connect AI agents to humans in the real world").version("0.1.0");
410
+ program.command("init").description("Set up HumanlyPossible in your project").option("--api-key <key>", "Provide API key directly (skips interactive prompt)").option("--no-mcp", "Skip MCP server configuration").action(initCommand);
411
+ program.command("status").description("Check your HumanlyPossible connection and configuration").action(statusCommand);
412
+ program.command("config").description("View or update your configuration").option("--api-key <key>", "Update your API key").option("--reset", "Reset all configuration").action(configCommand);
413
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "humanlypossible",
3
+ "version": "0.1.0",
4
+ "description": "CLI for HumanlyPossible - connect AI agents to humans in the real world",
5
+ "type": "module",
6
+ "bin": {
7
+ "humanlypossible": "./dist/cli.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsup src/cli.ts --format esm --dts --clean",
11
+ "dev": "tsup src/cli.ts --format esm --watch"
12
+ },
13
+ "dependencies": {
14
+ "commander": "^13.1.0",
15
+ "prompts": "^2.4.2",
16
+ "chalk": "^5.4.1",
17
+ "open": "^10.1.0",
18
+ "conf": "^13.1.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/prompts": "^2.4.9",
22
+ "tsup": "^8.4.0",
23
+ "typescript": "^5.7.0"
24
+ },
25
+ "engines": {
26
+ "node": ">=20"
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "keywords": [
32
+ "humanlypossible",
33
+ "ai",
34
+ "agents",
35
+ "mcp",
36
+ "cli"
37
+ ]
38
+ }