Skip to content

Commit 350fef5

Browse files
committed
Add SyncClientOptions, Logger util; refactor evals/run.ts to use new Logger; create foundations of CLI
1 parent d101fb1 commit 350fef5

File tree

9 files changed

+839
-694
lines changed

9 files changed

+839
-694
lines changed

.fernignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ src/humanloop.client.ts
1010
src/overload.ts
1111
src/error.ts
1212
src/context.ts
13-
src/sync
13+
src/cli.ts
1414
src/cache
15+
src/sync
16+
src/utils
1517

1618
# Tests
1719

package.json

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,59 @@
33
"version": "0.8.21",
44
"private": false,
55
"repository": "https://github.com/humanloop/humanloop-node",
6-
"main": "./index.js",
7-
"types": "./index.d.ts",
6+
"main": "./dist/index.js",
7+
"types": "./dist/index.d.ts",
88
"scripts": {
99
"format": "prettier . --write --ignore-unknown",
1010
"build": "tsc",
1111
"prepack": "cp -rv dist/. .",
1212
"test": "jest"
1313
},
1414
"dependencies": {
15-
"url-join": "4.0.1",
16-
"form-data": "^4.0.0",
17-
"formdata-node": "^6.0.3",
18-
"node-fetch": "^2.7.0",
19-
"qs": "^6.13.1",
20-
"readable-stream": "^4.5.2",
21-
"form-data-encoder": "^4.0.2",
2215
"@opentelemetry/api": "<=1.9.0",
2316
"@opentelemetry/resources": "<=2.0.0",
2417
"@opentelemetry/sdk-trace-node": "<=2.0.0",
18+
"@traceloop/ai-semantic-conventions": ">=0.11.6",
2519
"@traceloop/instrumentation-anthropic": ">=0.11.1",
2620
"@traceloop/instrumentation-cohere": ">=0.11.1",
2721
"@traceloop/instrumentation-openai": ">=0.11.3",
28-
"@traceloop/ai-semantic-conventions": ">=0.11.6",
22+
"chalk": "^5.4.1",
2923
"cli-progress": "^3.12.0",
30-
"lodash": "^4.17.21"
24+
"commander": "^13.1.0",
25+
"form-data": "^4.0.0",
26+
"form-data-encoder": "^4.0.2",
27+
"formdata-node": "^6.0.3",
28+
"lodash": "^4.17.21",
29+
"node-fetch": "^2.7.0",
30+
"qs": "^6.13.1",
31+
"readable-stream": "^4.5.2",
32+
"url-join": "4.0.1"
3133
},
3234
"devDependencies": {
33-
"@types/url-join": "4.0.1",
34-
"@types/qs": "^6.9.17",
35+
"@anthropic-ai/sdk": "^0.32.1",
36+
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
37+
"@types/cli-progress": "^3.11.6",
38+
"@types/jest": "^29.5.14",
39+
"@types/lodash": "4.14.74",
40+
"@types/node": "^18.19.70",
3541
"@types/node-fetch": "^2.6.12",
42+
"@types/qs": "^6.9.17",
3643
"@types/readable-stream": "^4.0.18",
37-
"webpack": "^5.97.1",
38-
"ts-loader": "^9.5.1",
44+
"@types/url-join": "4.0.1",
45+
"cohere-ai": "^7.15.0",
46+
"dotenv": "^16.5.0",
3947
"jest": "^29.7.0",
40-
"@types/jest": "^29.5.14",
41-
"ts-jest": "^29.1.1",
4248
"jest-environment-jsdom": "^29.7.0",
43-
"@types/node": "^18.19.70",
49+
"jsonschema": "^1.4.1",
50+
"openai": "^4.74.0",
4451
"prettier": "^3.4.2",
52+
"ts-jest": "^29.1.1",
53+
"ts-loader": "^9.5.1",
4554
"typescript": "~5.7.2",
46-
"openai": "^4.74.0",
47-
"@anthropic-ai/sdk": "^0.32.1",
48-
"cohere-ai": "^7.15.0",
49-
"dotenv": "^16.4.6",
50-
"jsonschema": "^1.4.1",
51-
"@types/cli-progress": "^3.11.6",
52-
"@types/lodash": "4.14.74",
53-
"@trivago/prettier-plugin-sort-imports": "^4.3.0"
55+
"webpack": "^5.97.1"
56+
},
57+
"bin": {
58+
"humanloop": "dist/cli.js"
5459
},
5560
"browser": {
5661
"fs": false,

src/cli.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env node
2+
import * as dotenv from "dotenv";
3+
import chalk from "chalk";
4+
import { Command } from "commander";
5+
6+
import { HumanloopClient } from "./humanloop.client";
7+
8+
const { version } = require("../package.json");
9+
10+
// Load environment variables
11+
dotenv.config();
12+
13+
const program = new Command();
14+
program
15+
.name("humanloop")
16+
.description("Humanloop CLI for managing sync operations")
17+
.version(version);
18+
19+
// Common auth options
20+
const addAuthOptions = (command: Command) =>
21+
command
22+
.option("--api-key <apiKey>", "Humanloop API key")
23+
.option("--env-file <envFile>", "Path to .env file")
24+
.option("--base-url <baseUrl>", "Base URL for Humanloop API");
25+
26+
// Helper to get client
27+
function getClient(options: {
28+
envFile?: string;
29+
apiKey?: string;
30+
baseUrl?: string;
31+
baseDir?: string;
32+
}): HumanloopClient {
33+
if (options.envFile) dotenv.config({ path: options.envFile });
34+
const apiKey = options.apiKey || process.env.HUMANLOOP_API_KEY;
35+
if (!apiKey) {
36+
console.error(
37+
chalk.red(
38+
"No API key found. Set HUMANLOOP_API_KEY in .env file or use --api-key",
39+
),
40+
);
41+
process.exit(1);
42+
}
43+
return new HumanloopClient({
44+
apiKey,
45+
baseUrl: options.baseUrl,
46+
sync: { baseDir: options.baseDir },
47+
});
48+
}
49+
50+
// Pull command
51+
addAuthOptions(
52+
program
53+
.command("pull")
54+
.description("Pull files from Humanloop to local filesystem")
55+
.option("-p, --path <path>", "Path to pull (file or directory)")
56+
.option("-e, --environment <env>", "Environment to pull from")
57+
.option("--base-dir <baseDir>", "Base directory for synced files", "humanloop"),
58+
).action(async (options) => {
59+
try {
60+
console.log(chalk.blue("Pulling files from Humanloop..."));
61+
const client = getClient(options);
62+
const files = await client.pull(options.path, options.environment);
63+
console.log(chalk.green(`Successfully synced ${files.length} files`));
64+
} catch (error) {
65+
console.error(chalk.red(`Error: ${error}`));
66+
process.exit(1);
67+
}
68+
});
69+
70+
program.parse(process.argv);

0 commit comments

Comments
 (0)