@openserv-labs/client 2.5.0 → 2.5.2

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
@@ -719,6 +719,82 @@ triggers.manual({
719
719
  // { type: 'manual', name: '...', description: '...' }
720
720
  ```
721
721
 
722
+ ## Deploy to OpenServ Cloud
723
+
724
+ Deploy your agent to the OpenServ managed cloud with a single command:
725
+
726
+ ```bash
727
+ npx @openserv-labs/client deploy [path]
728
+ ```
729
+
730
+ Where `[path]` is the directory containing your agent code (defaults to current directory).
731
+
732
+ ### Prerequisites
733
+
734
+ 1. **`OPENSERV_USER_API_KEY` in `.env`** — The deploy CLI needs this key to authenticate with the platform. If you've already run `provision()` at least once, check your `.openserv.json` file — it contains a `userApiKey` field you can use:
735
+
736
+ ```bash
737
+ # Look for the userApiKey in .openserv.json
738
+ cat .openserv.json | grep userApiKey
739
+ ```
740
+
741
+ Copy that value into your `.env`:
742
+
743
+ ```env
744
+ OPENSERV_USER_API_KEY=<userApiKey from .openserv.json>
745
+ ```
746
+
747
+ If you haven't provisioned yet, get the key from the [OpenServ platform dashboard](https://platform.openserv.ai/profile/api-keys) instead.
748
+
749
+ 2. **Run `provision()` first** — Your agent must be provisioned at least once before deploying. `provision()` registers the agent on the platform and writes credentials to `.openserv.json`. Starting the agent locally (`npm run dev`) is enough if your code calls `provision()` before `run(agent)`.
750
+
751
+ ### How It Works
752
+
753
+ The deploy command:
754
+
755
+ 1. Reads `.openserv.json` to find the provisioned agent ID
756
+ 2. Creates or reuses a cloud container (saves `OPENSERV_CONTAINER_ID` to `.env`)
757
+ 3. Archives your source code (respects `.gitignore`, excludes `node_modules`, `.git`, `.env`, `dist`)
758
+ 4. Uploads and installs dependencies in the container
759
+ 5. Starts (or restarts) the agent and exposes a public URL
760
+
761
+ ### Deploy Workflow
762
+
763
+ ```bash
764
+ # 1. Run locally once to provision (registers agent + writes .openserv.json)
765
+ npm run dev
766
+
767
+ # 2. Set OPENSERV_USER_API_KEY in .env
768
+ # - If you already provisioned: grab userApiKey from .openserv.json
769
+ # - Otherwise: get it from the platform dashboard
770
+ echo "OPENSERV_USER_API_KEY=your-key" >> .env
771
+
772
+ # 3. Deploy to cloud
773
+ npx @openserv-labs/client deploy .
774
+ ```
775
+
776
+ On subsequent deploys, the CLI reuses the existing container — it uploads your latest code, reinstalls dependencies, and restarts the agent.
777
+
778
+ ### Environment Variables for Deploy
779
+
780
+ | Variable | Description | Required |
781
+ | --------------------------- | ---------------------------------------- | -------- |
782
+ | `OPENSERV_USER_API_KEY` | Your OpenServ user API key | Yes |
783
+ | `OPENSERV_CONTAINER_ID` | Container ID (auto-set after first deploy) | No |
784
+
785
+ ### CLI Reference
786
+
787
+ The package also exposes a `serv` binary:
788
+
789
+ ```bash
790
+ # Via npx
791
+ npx @openserv-labs/client deploy [path]
792
+
793
+ # Or if installed globally / as a dependency
794
+ serv deploy [path]
795
+ serv --help
796
+ ```
797
+
722
798
  ## Environment Variables
723
799
 
724
800
  | Variable | Description | Required |
@@ -4,7 +4,6 @@ export declare class ApiError extends Error {
4
4
  }
5
5
  export interface ApiClientOptions {
6
6
  apiKey: string;
7
- agentId?: number;
8
7
  orchestratorUrl?: string;
9
8
  }
10
9
  export interface ContainerInfo {
@@ -34,7 +33,6 @@ export declare class ApiClient {
34
33
  constructor(opts: ApiClientOptions);
35
34
  createContainer(): Promise<ContainerInfo>;
36
35
  getStatus(id: string): Promise<StatusInfo>;
37
- findContainerByAgent(agentId: number): Promise<ContainerInfo | null>;
38
36
  upload(id: string, tarBuffer: Buffer): Promise<void>;
39
37
  exec(id: string, command: string[], timeout?: number): Promise<ExecResult>;
40
38
  start(id: string, entrypoint?: string): Promise<void>;
@@ -1 +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"}
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,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;IAa5B,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAIzC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI1C,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"}
@@ -21,9 +21,6 @@ class ApiClient {
21
21
  const headers = {
22
22
  "x-openserv-key": opts.apiKey,
23
23
  };
24
- if (opts.agentId != null) {
25
- headers["x-openserv-agent-id"] = String(opts.agentId);
26
- }
27
24
  this.client = axios_1.default.create({
28
25
  baseURL: opts.orchestratorUrl || DEFAULT_ORCHESTRATOR_URL,
29
26
  headers,
@@ -37,22 +34,6 @@ class ApiClient {
37
34
  async getStatus(id) {
38
35
  return this.request("GET", `/container/${id}/status`);
39
36
  }
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
37
  async upload(id, tarBuffer) {
57
38
  await this.request("POST", `/container/${id}/upload`, tarBuffer, {
58
39
  headers: { "Content-Type": "application/gzip" },
@@ -1 +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"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/deploy/deploy.ts"],"names":[],"mappings":"AA8BA,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG9D"}
@@ -8,27 +8,13 @@ const node_path_1 = __importDefault(require("node:path"));
8
8
  const api_client_js_1 = require("./api-client.js");
9
9
  const env_js_1 = require("./env.js");
10
10
  const logger_js_1 = require("./logger.js");
11
- const openserv_json_js_1 = require("./openserv-json.js");
12
11
  const tar_js_1 = require("./tar.js");
13
- async function resolveContainer(client, dir, containerId, agentId) {
12
+ async function resolveContainer(client, dir, containerId) {
14
13
  if (containerId) {
15
14
  logger_js_1.logger.info(`Using existing container: ${containerId}`);
16
15
  return { id: containerId, isFirstDeploy: false };
17
16
  }
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
- }
17
+ logger_js_1.logger.info("Creating new container...");
32
18
  const container = await client.createContainer();
33
19
  (0, env_js_1.writeContainerId)(dir, container.id);
34
20
  logger_js_1.logger.info(` Container ID: ${container.id}`);
@@ -39,17 +25,14 @@ async function deploy(targetPath) {
39
25
  const dir = node_path_1.default.resolve(targetPath);
40
26
  logger_js_1.logger.info(`Deploying from ${dir}\n`);
41
27
  const env = (0, env_js_1.readEnv)(dir);
42
- const agentConfig = (0, openserv_json_js_1.readAgentConfig)(dir);
43
- const agentId = agentConfig?.id;
44
28
  if (!env.apiKey) {
45
29
  throw new Error("OPENSERV_USER_API_KEY not found. Set it in your .env file or as an environment variable.");
46
30
  }
47
31
  const client = new api_client_js_1.ApiClient({
48
32
  apiKey: env.apiKey,
49
- agentId,
50
33
  orchestratorUrl: env.orchestratorUrl,
51
34
  });
52
- const { id: targetId, isFirstDeploy } = await resolveContainer(client, dir, env.containerId, agentId);
35
+ const { id: targetId, isFirstDeploy } = await resolveContainer(client, dir, env.containerId);
53
36
  let currentStatus;
54
37
  let appName;
55
38
  if (!isFirstDeploy) {
@@ -119,10 +102,5 @@ async function deploy(targetPath) {
119
102
  }
120
103
  logger_js_1.logger.info("\nAlready live.");
121
104
  }
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
105
  logger_js_1.logger.info("\nDeploy complete!");
128
106
  }
@@ -1 +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"}
1
+ {"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../src/deploy/tar.ts"],"names":[],"mappings":"AAuBA,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"}
@@ -14,7 +14,6 @@ const ALWAYS_EXCLUDE = [
14
14
  "dist",
15
15
  ".next",
16
16
  ".turbo",
17
- ".env",
18
17
  ".env.example",
19
18
  ".env.local",
20
19
  ".env.*.local",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openserv-labs/client",
3
- "version": "2.5.0",
3
+ "version": "2.5.2",
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",
@@ -1,6 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,27 +0,0 @@
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
- }