@openserv-labs/client 2.4.8 → 2.5.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,3 @@
1
+ #!/usr/bin/env node
2
+ import "./deploy/index.js";
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,mBAAmB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ require("./deploy/index.js");
@@ -0,0 +1,46 @@
1
+ export declare class ApiError extends Error {
2
+ readonly statusCode: number | undefined;
3
+ constructor(message: string, statusCode: number | undefined);
4
+ }
5
+ export interface ApiClientOptions {
6
+ apiKey: string;
7
+ agentId?: number;
8
+ orchestratorUrl?: string;
9
+ }
10
+ export interface ContainerInfo {
11
+ id: string;
12
+ appName: string;
13
+ machineId: string;
14
+ status: string;
15
+ }
16
+ export interface StatusInfo {
17
+ id: string;
18
+ appName: string;
19
+ machineId: string;
20
+ status: string;
21
+ machineState: string;
22
+ metadata: Record<string, unknown>;
23
+ }
24
+ export interface ExecResult {
25
+ stdout: string;
26
+ stderr: string;
27
+ exitCode: number;
28
+ }
29
+ export interface GoLiveResult {
30
+ publicUrl: string;
31
+ }
32
+ export declare class ApiClient {
33
+ private client;
34
+ constructor(opts: ApiClientOptions);
35
+ createContainer(): Promise<ContainerInfo>;
36
+ getStatus(id: string): Promise<StatusInfo>;
37
+ findContainerByAgent(agentId: number): Promise<ContainerInfo | null>;
38
+ upload(id: string, tarBuffer: Buffer): Promise<void>;
39
+ exec(id: string, command: string[], timeout?: number): Promise<ExecResult>;
40
+ start(id: string, entrypoint?: string): Promise<void>;
41
+ restart(id: string): Promise<void>;
42
+ goLive(id: string, mode?: string): Promise<GoLiveResult>;
43
+ updateEndpointUrl(agentId: number, agentApiKey: string, endpointUrl: string): Promise<void>;
44
+ private request;
45
+ }
46
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/deploy/api-client.ts"],"names":[],"mappings":"AAIA,qBAAa,QAAS,SAAQ,KAAK;aAGf,UAAU,EAAE,MAAM,GAAG,SAAS;gBAD9C,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,GAAG,SAAS;CAKjD;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAgB;gBAElB,IAAI,EAAE,gBAAgB;IAgB5B,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAIzC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI1C,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAepE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,IAAI,CACR,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC;IAOhB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,SAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAM7D,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;YAUF,OAAO;CAyBtB"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ApiClient = exports.ApiError = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const DEFAULT_ORCHESTRATOR_URL = "https://agent-orchestrator.openserv.ai";
9
+ class ApiError extends Error {
10
+ statusCode;
11
+ constructor(message, statusCode) {
12
+ super(message);
13
+ this.statusCode = statusCode;
14
+ this.name = "ApiError";
15
+ }
16
+ }
17
+ exports.ApiError = ApiError;
18
+ class ApiClient {
19
+ client;
20
+ constructor(opts) {
21
+ const headers = {
22
+ "x-openserv-key": opts.apiKey,
23
+ };
24
+ if (opts.agentId != null) {
25
+ headers["x-openserv-agent-id"] = String(opts.agentId);
26
+ }
27
+ this.client = axios_1.default.create({
28
+ baseURL: opts.orchestratorUrl || DEFAULT_ORCHESTRATOR_URL,
29
+ headers,
30
+ maxBodyLength: 100 * 1024 * 1024,
31
+ maxContentLength: 100 * 1024 * 1024,
32
+ });
33
+ }
34
+ async createContainer() {
35
+ return this.request("POST", "/container/create");
36
+ }
37
+ async getStatus(id) {
38
+ return this.request("GET", `/container/${id}/status`);
39
+ }
40
+ async findContainerByAgent(agentId) {
41
+ try {
42
+ const status = await this.getStatus(String(agentId));
43
+ return {
44
+ id: status.id,
45
+ appName: status.appName,
46
+ machineId: status.machineId,
47
+ status: status.status,
48
+ };
49
+ }
50
+ catch (err) {
51
+ if (err instanceof ApiError && err.statusCode === 404)
52
+ return null;
53
+ throw err;
54
+ }
55
+ }
56
+ async upload(id, tarBuffer) {
57
+ await this.request("POST", `/container/${id}/upload`, tarBuffer, {
58
+ headers: { "Content-Type": "application/gzip" },
59
+ });
60
+ }
61
+ async exec(id, command, timeout) {
62
+ return this.request("POST", `/container/${id}/exec`, {
63
+ command,
64
+ timeout,
65
+ });
66
+ }
67
+ async start(id, entrypoint) {
68
+ await this.request("POST", `/container/${id}/start`, {
69
+ entrypoint: entrypoint || "npx tsx src/agent.ts",
70
+ });
71
+ }
72
+ async restart(id) {
73
+ await this.request("POST", `/container/${id}/restart`);
74
+ }
75
+ async goLive(id, mode = "on-demand") {
76
+ return this.request("POST", `/container/${id}/go-live`, {
77
+ mode,
78
+ });
79
+ }
80
+ async updateEndpointUrl(agentId, agentApiKey, endpointUrl) {
81
+ const platformUrl = process.env.OPENSERV_API_URL || "https://api.openserv.ai";
82
+ await axios_1.default.put(`${platformUrl}/agents/${agentId}/endpoint-url`, { endpoint_url: endpointUrl }, { headers: { "x-openserv-key": agentApiKey } });
83
+ }
84
+ async request(method, path, body, config) {
85
+ try {
86
+ const res = await this.client.request({
87
+ method,
88
+ url: path,
89
+ data: body,
90
+ ...config,
91
+ });
92
+ return res.data;
93
+ }
94
+ catch (err) {
95
+ const axiosErr = err;
96
+ const statusCode = axiosErr.response?.status;
97
+ const data = axiosErr.response?.data ?? axiosErr.message;
98
+ const detail = typeof data === "string" ? data : JSON.stringify(data);
99
+ throw new ApiError(`${method} ${path} failed (${statusCode ?? "unknown"}): ${detail}`, statusCode);
100
+ }
101
+ }
102
+ }
103
+ exports.ApiClient = ApiClient;
@@ -0,0 +1,2 @@
1
+ export declare function deploy(targetPath: string): Promise<void>;
2
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/deploy/deploy.ts"],"names":[],"mappings":"AA8CA,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgH9D"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deploy = deploy;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const api_client_js_1 = require("./api-client.js");
9
+ const env_js_1 = require("./env.js");
10
+ const logger_js_1 = require("./logger.js");
11
+ const openserv_json_js_1 = require("./openserv-json.js");
12
+ const tar_js_1 = require("./tar.js");
13
+ async function resolveContainer(client, dir, containerId, agentId) {
14
+ if (containerId) {
15
+ logger_js_1.logger.info(`Using existing container: ${containerId}`);
16
+ return { id: containerId, isFirstDeploy: false };
17
+ }
18
+ if (agentId) {
19
+ logger_js_1.logger.info(`Agent ID found: ${agentId}. Checking for existing container...`);
20
+ const existing = await client.findContainerByAgent(agentId);
21
+ if (existing) {
22
+ (0, env_js_1.writeContainerId)(dir, existing.id);
23
+ logger_js_1.logger.info(` Found container: ${existing.id}`);
24
+ logger_js_1.logger.info(" Saved to .env\n");
25
+ return { id: existing.id, isFirstDeploy: false };
26
+ }
27
+ logger_js_1.logger.info(" No container found. Creating new container...");
28
+ }
29
+ else {
30
+ logger_js_1.logger.info("Creating new container...");
31
+ }
32
+ const container = await client.createContainer();
33
+ (0, env_js_1.writeContainerId)(dir, container.id);
34
+ logger_js_1.logger.info(` Container ID: ${container.id}`);
35
+ logger_js_1.logger.info(" Written to .env\n");
36
+ return { id: container.id, isFirstDeploy: true };
37
+ }
38
+ async function deploy(targetPath) {
39
+ const dir = node_path_1.default.resolve(targetPath);
40
+ logger_js_1.logger.info(`Deploying from ${dir}\n`);
41
+ const env = (0, env_js_1.readEnv)(dir);
42
+ const agentConfig = (0, openserv_json_js_1.readAgentConfig)(dir);
43
+ const agentId = agentConfig?.id;
44
+ if (!env.apiKey) {
45
+ throw new Error("OPENSERV_USER_API_KEY not found. Set it in your .env file or as an environment variable.");
46
+ }
47
+ const client = new api_client_js_1.ApiClient({
48
+ apiKey: env.apiKey,
49
+ agentId,
50
+ orchestratorUrl: env.orchestratorUrl,
51
+ });
52
+ const { id: targetId, isFirstDeploy } = await resolveContainer(client, dir, env.containerId, agentId);
53
+ let currentStatus;
54
+ let appName;
55
+ if (!isFirstDeploy) {
56
+ try {
57
+ const status = await client.getStatus(targetId);
58
+ currentStatus = status.status;
59
+ appName = status.appName;
60
+ logger_js_1.logger.info(` Current status: ${currentStatus}`);
61
+ }
62
+ catch {
63
+ // Container might not be reachable yet
64
+ }
65
+ }
66
+ logger_js_1.logger.info("\nCreating archive...");
67
+ const { buffer: tarBuffer, files } = await (0, tar_js_1.createTarBuffer)(dir);
68
+ for (const file of files) {
69
+ logger_js_1.logger.info(` ${file}`);
70
+ }
71
+ logger_js_1.logger.info(` ${files.length} files, ${(tarBuffer.length / 1024).toFixed(1)} KB`);
72
+ logger_js_1.logger.info("\nUploading files...");
73
+ await client.upload(targetId, tarBuffer);
74
+ logger_js_1.logger.info(" Done.");
75
+ const verify = await client.exec(targetId, ["ls", "-la", "/app"], 30);
76
+ if (verify.exitCode === 0) {
77
+ logger_js_1.logger.info(" Verified /app contents:");
78
+ for (const line of verify.stdout.split("\n").filter(Boolean)) {
79
+ logger_js_1.logger.info(` ${line}`);
80
+ }
81
+ }
82
+ else {
83
+ logger_js_1.logger.error(" Warning: could not verify upload");
84
+ if (verify.stderr)
85
+ logger_js_1.logger.error(` ${verify.stderr}`);
86
+ }
87
+ logger_js_1.logger.info("\nInstalling dependencies...");
88
+ const installResult = await client.exec(targetId, ["npm", "install"], 600);
89
+ if (installResult.exitCode !== 0) {
90
+ const parts = [`npm install failed (exit code ${installResult.exitCode})`];
91
+ if (installResult.stdout)
92
+ parts.push(`stdout: ${installResult.stdout.slice(0, 500)}`);
93
+ if (installResult.stderr)
94
+ parts.push(`stderr: ${installResult.stderr.slice(0, 500)}`);
95
+ throw new Error(parts.join("\n"));
96
+ }
97
+ logger_js_1.logger.info(" Done.");
98
+ const needsStart = isFirstDeploy || !currentStatus || currentStatus === "ready";
99
+ if (needsStart) {
100
+ logger_js_1.logger.info("\nStarting agent...");
101
+ await client.start(targetId);
102
+ logger_js_1.logger.info(" Agent started.");
103
+ }
104
+ else {
105
+ logger_js_1.logger.info("\nRestarting container...");
106
+ await client.restart(targetId);
107
+ logger_js_1.logger.info(" Container restarted.");
108
+ }
109
+ let publicUrl;
110
+ if (currentStatus !== "live") {
111
+ logger_js_1.logger.info("\nGoing live...");
112
+ const result = await client.goLive(targetId, "continuous");
113
+ publicUrl = result.publicUrl;
114
+ logger_js_1.logger.info(` Public URL: ${publicUrl}`);
115
+ }
116
+ else {
117
+ if (appName) {
118
+ publicUrl = `https://${appName}.fly.dev`;
119
+ }
120
+ logger_js_1.logger.info("\nAlready live.");
121
+ }
122
+ if (agentConfig?.apiKey && agentConfig.id && publicUrl) {
123
+ logger_js_1.logger.info("\nUpdating agent endpoint URL...");
124
+ await client.updateEndpointUrl(agentConfig.id, agentConfig.apiKey, publicUrl);
125
+ logger_js_1.logger.info(` Agent endpoint set to ${publicUrl}`);
126
+ }
127
+ logger_js_1.logger.info("\nDeploy complete!");
128
+ }
@@ -0,0 +1,8 @@
1
+ export interface EnvValues {
2
+ apiKey?: string;
3
+ containerId?: string;
4
+ orchestratorUrl?: string;
5
+ }
6
+ export declare function readEnv(dir: string): EnvValues;
7
+ export declare function writeContainerId(dir: string, containerId: string): void;
8
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/deploy/env.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAY9C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAoBvE"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readEnv = readEnv;
7
+ exports.writeContainerId = writeContainerId;
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const dotenv_1 = require("dotenv");
11
+ function readEnv(dir) {
12
+ const envPath = node_path_1.default.join(dir, ".env");
13
+ const parsed = (0, dotenv_1.config)({ path: envPath });
14
+ const env = parsed.parsed ?? {};
15
+ return {
16
+ apiKey: env.OPENSERV_USER_API_KEY || process.env.OPENSERV_USER_API_KEY,
17
+ containerId: env.OPENSERV_CONTAINER_ID || process.env.OPENSERV_CONTAINER_ID,
18
+ orchestratorUrl: env.OPENSERV_ORCHESTRATOR_URL || process.env.OPENSERV_ORCHESTRATOR_URL,
19
+ };
20
+ }
21
+ function writeContainerId(dir, containerId) {
22
+ const envPath = node_path_1.default.join(dir, ".env");
23
+ let content = "";
24
+ if (node_fs_1.default.existsSync(envPath)) {
25
+ content = node_fs_1.default.readFileSync(envPath, "utf8");
26
+ }
27
+ const key = "OPENSERV_CONTAINER_ID";
28
+ const line = `${key}=${containerId}`;
29
+ const regex = new RegExp(`^${key}=.*$`, "m");
30
+ if (regex.test(content)) {
31
+ content = content.replace(regex, line);
32
+ }
33
+ else {
34
+ const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
35
+ content = `${content}${separator}${line}\n`;
36
+ }
37
+ node_fs_1.default.writeFileSync(envPath, content, "utf8");
38
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/deploy/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const deploy_js_1 = require("./deploy.js");
4
+ const HELP = `
5
+ Usage: serv <command> [path]
6
+
7
+ Commands:
8
+ deploy [path] Deploy an agent to OpenServ (default path: .)
9
+
10
+ Options:
11
+ --help, -h Show this help message
12
+
13
+ Environment variables (set in .env or shell):
14
+ OPENSERV_USER_API_KEY Your OpenServ API key (required)
15
+ OPENSERV_CONTAINER_ID Container ID for redeployment (auto-set after first deploy)
16
+ OPENSERV_ORCHESTRATOR_URL Custom orchestrator URL (optional)
17
+ `.trim();
18
+ async function main() {
19
+ const args = process.argv.slice(2);
20
+ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
21
+ console.log(HELP);
22
+ process.exit(0);
23
+ }
24
+ const command = args[0];
25
+ switch (command) {
26
+ case "deploy": {
27
+ const targetPath = args[1] || ".";
28
+ await (0, deploy_js_1.deploy)(targetPath);
29
+ break;
30
+ }
31
+ default:
32
+ console.error(`Unknown command: ${command}\n`);
33
+ console.log(HELP);
34
+ process.exit(1);
35
+ }
36
+ }
37
+ main().catch((err) => {
38
+ console.error("\nFailed:", err instanceof Error ? err.message : err);
39
+ process.exit(1);
40
+ });
@@ -0,0 +1,6 @@
1
+ export declare const logger: {
2
+ info: (...args: unknown[]) => void;
3
+ warn: (...args: unknown[]) => void;
4
+ error: (...args: unknown[]) => void;
5
+ };
6
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/deploy/logger.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;oBACD,OAAO,EAAE;oBACT,OAAO,EAAE;qBACR,OAAO,EAAE;CAC3B,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ exports.logger = {
5
+ info: (...args) => console.log(...args),
6
+ warn: (...args) => console.warn(...args),
7
+ error: (...args) => console.error(...args),
8
+ };
@@ -0,0 +1,6 @@
1
+ export interface AgentConfig {
2
+ id: number;
3
+ apiKey?: string;
4
+ }
5
+ export declare function readAgentConfig(dir: string): AgentConfig | undefined;
6
+ //# sourceMappingURL=openserv-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openserv-json.d.ts","sourceRoot":"","sources":["../../src/deploy/openserv-json.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAmBpE"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readAgentConfig = readAgentConfig;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ function readAgentConfig(dir) {
10
+ const filePath = node_path_1.default.join(dir, ".openserv.json");
11
+ if (!node_fs_1.default.existsSync(filePath)) {
12
+ return undefined;
13
+ }
14
+ try {
15
+ const raw = node_fs_1.default.readFileSync(filePath, "utf8");
16
+ const data = JSON.parse(raw);
17
+ if (!data.agents)
18
+ return undefined;
19
+ const firstAgent = Object.values(data.agents)[0];
20
+ if (!firstAgent)
21
+ return undefined;
22
+ return { id: firstAgent.id, apiKey: firstAgent.apiKey };
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
@@ -0,0 +1,6 @@
1
+ export interface TarResult {
2
+ buffer: Buffer;
3
+ files: string[];
4
+ }
5
+ export declare function createTarBuffer(dir: string): Promise<TarResult>;
6
+ //# sourceMappingURL=tar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/deploy/tar.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAerE"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createTarBuffer = createTarBuffer;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const ignore_1 = __importDefault(require("ignore"));
10
+ const nanotar_1 = require("nanotar");
11
+ const ALWAYS_EXCLUDE = [
12
+ "node_modules",
13
+ ".git",
14
+ "dist",
15
+ ".next",
16
+ ".turbo",
17
+ ".env",
18
+ ".env.example",
19
+ ".env.local",
20
+ ".env.*.local",
21
+ ];
22
+ const ALWAYS_EXCLUDE_EXTENSIONS = [".tsbuildinfo"];
23
+ async function createTarBuffer(dir) {
24
+ const ig = (0, ignore_1.default)();
25
+ ig.add(ALWAYS_EXCLUDE);
26
+ const gitignorePath = node_path_1.default.join(dir, ".gitignore");
27
+ if (node_fs_1.default.existsSync(gitignorePath)) {
28
+ const content = node_fs_1.default.readFileSync(gitignorePath, "utf8");
29
+ ig.add(content);
30
+ }
31
+ const entries = collectEntries(dir, dir, ig);
32
+ const files = entries.map((e) => e.name);
33
+ const gzipped = await (0, nanotar_1.createTarGzip)(entries);
34
+ return { buffer: Buffer.from(gzipped), files };
35
+ }
36
+ function collectEntries(baseDir, currentDir, ig) {
37
+ const entries = [];
38
+ const items = node_fs_1.default.readdirSync(currentDir, { withFileTypes: true });
39
+ for (const item of items) {
40
+ const fullPath = node_path_1.default.join(currentDir, item.name);
41
+ const relativePath = node_path_1.default.relative(baseDir, fullPath);
42
+ if (ALWAYS_EXCLUDE_EXTENSIONS.some((ext) => item.name.endsWith(ext))) {
43
+ continue;
44
+ }
45
+ const testPath = item.isDirectory() ? `${relativePath}/` : relativePath;
46
+ if (ig.ignores(testPath)) {
47
+ continue;
48
+ }
49
+ if (item.isDirectory()) {
50
+ entries.push(...collectEntries(baseDir, fullPath, ig));
51
+ }
52
+ else {
53
+ entries.push({
54
+ name: relativePath,
55
+ data: new Uint8Array(node_fs_1.default.readFileSync(fullPath)),
56
+ });
57
+ }
58
+ }
59
+ return entries;
60
+ }
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@openserv-labs/client",
3
- "version": "2.4.8",
3
+ "version": "2.5.0",
4
4
  "description": "OpenServ Platform Client - Manage agents, workflows, tasks, and triggers via the OpenServ API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "serv": "./dist/cli.js"
9
+ },
7
10
  "scripts": {
8
11
  "build": "tsc",
9
12
  "dev": "tsc --watch",
@@ -15,7 +18,8 @@
15
18
  "format": "prettier --write \"**/*.{ts,json,md}\"",
16
19
  "format:check": "prettier --check \"**/*.{ts,json,md}\"",
17
20
  "test": "node --import tsx --test test/**/*.test.ts",
18
- "test:unit": "node --import tsx --test test/unit/**/*.test.ts"
21
+ "test:unit": "node --import tsx --test test/unit/**/*.test.ts",
22
+ "deploy": "tsx src/cli.ts deploy"
19
23
  },
20
24
  "repository": {
21
25
  "type": "git",
@@ -38,6 +42,9 @@
38
42
  "license": "MIT",
39
43
  "dependencies": {
40
44
  "axios": "^1.6.8",
45
+ "dotenv": "^16.4.5",
46
+ "ignore": "^7.0.3",
47
+ "nanotar": "^0.2.0",
41
48
  "pinata": "^2.5.1",
42
49
  "viem": "^2.45.1"
43
50
  },
@@ -45,7 +52,6 @@
45
52
  "@eslint/js": "^9.39.2",
46
53
  "@tsconfig/strictest": "^2.0.3",
47
54
  "@types/node": "^22.10.2",
48
- "dotenv": "^16.4.5",
49
55
  "eslint": "^9.39.2",
50
56
  "eslint-config-prettier": "^9.1.0",
51
57
  "eslint-plugin-prettier": "^5.1.3",