opencara 0.100.0 → 0.100.1

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.
Files changed (2) hide show
  1. package/dist/bin.js +176 -172
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -1,23 +1,76 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/commands/run.ts
4
+ import {
5
+ arch,
6
+ cpus,
7
+ freemem,
8
+ hostname,
9
+ networkInterfaces,
10
+ platform,
11
+ release,
12
+ totalmem,
13
+ uptime
14
+ } from "node:os";
15
+ import { readFileSync as readFileSync2, statfsSync } from "node:fs";
16
+ import { dirname, join as join2 } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+
19
+ // src/config/store.ts
20
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "node:fs";
21
+ import { z } from "zod";
22
+
23
+ // src/config/paths.ts
24
+ import { homedir } from "node:os";
25
+ import { join } from "node:path";
26
+ var CONFIG_DIR = join(homedir(), ".opencara");
27
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
28
+ var DEFAULT_ORCHESTRATOR_URL = "https://opencara.com";
29
+
30
+ // src/config/store.ts
31
+ var ConfigSchema = z.object({
32
+ orchestratorUrl: z.string().url(),
33
+ token: z.string(),
34
+ agentHostId: z.string(),
35
+ deviceName: z.string()
36
+ });
37
+ function readConfig() {
38
+ if (!existsSync(CONFIG_FILE)) return null;
39
+ try {
40
+ return ConfigSchema.parse(JSON.parse(readFileSync(CONFIG_FILE, "utf8")));
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+ function writeConfig(cfg) {
46
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
47
+ writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), { mode: 384 });
48
+ }
49
+ function clearConfig() {
50
+ if (existsSync(CONFIG_FILE)) unlinkSync(CONFIG_FILE);
51
+ }
52
+ function defaultOrchestratorUrl() {
53
+ return process.env["OPENCARA_URL"] ?? DEFAULT_ORCHESTRATOR_URL;
54
+ }
55
+
3
56
  // src/commands/register.ts
4
57
  import { createHash, randomBytes } from "node:crypto";
5
58
  import { spawn } from "node:child_process";
6
59
 
7
60
  // ../shared/dist/events.js
8
- import { z } from "zod";
9
- var PlatformSchema = z.enum(["github"]);
10
- var PlatformEventSchema = z.object({
11
- id: z.string(),
61
+ import { z as z2 } from "zod";
62
+ var PlatformSchema = z2.enum(["github"]);
63
+ var PlatformEventSchema = z2.object({
64
+ id: z2.string(),
12
65
  platform: PlatformSchema,
13
- type: z.string(),
14
- receivedAt: z.string().datetime(),
15
- payload: z.unknown()
66
+ type: z2.string(),
67
+ receivedAt: z2.string().datetime(),
68
+ payload: z2.unknown()
16
69
  });
17
70
 
18
71
  // ../shared/dist/agent.js
19
- import { z as z2 } from "zod";
20
- var AgentRunStatusSchema = z2.enum([
72
+ import { z as z3 } from "zod";
73
+ var AgentRunStatusSchema = z3.enum([
21
74
  "queued",
22
75
  "assigned",
23
76
  "running",
@@ -25,171 +78,134 @@ var AgentRunStatusSchema = z2.enum([
25
78
  "failed",
26
79
  "cancelled"
27
80
  ]);
28
- var AgentSpecSchema = z2.object({
29
- kind: z2.string(),
30
- command: z2.string(),
31
- args: z2.array(z2.string()).default([]),
32
- env: z2.record(z2.string()).default({}),
33
- cwd: z2.string().optional()
81
+ var AgentSpecSchema = z3.object({
82
+ kind: z3.string(),
83
+ command: z3.string(),
84
+ args: z3.array(z3.string()).default([]),
85
+ env: z3.record(z3.string()).default({}),
86
+ cwd: z3.string().optional()
34
87
  });
35
- var AgentRunSchema = z2.object({
36
- id: z2.string(),
88
+ var AgentRunSchema = z3.object({
89
+ id: z3.string(),
37
90
  spec: AgentSpecSchema,
38
- triggerEventId: z2.string().optional(),
91
+ triggerEventId: z3.string().optional(),
39
92
  status: AgentRunStatusSchema,
40
- hostId: z2.string().nullable(),
41
- createdAt: z2.string().datetime(),
42
- startedAt: z2.string().datetime().nullable(),
43
- finishedAt: z2.string().datetime().nullable(),
44
- exitCode: z2.number().int().nullable()
93
+ hostId: z3.string().nullable(),
94
+ createdAt: z3.string().datetime(),
95
+ startedAt: z3.string().datetime().nullable(),
96
+ finishedAt: z3.string().datetime().nullable(),
97
+ exitCode: z3.number().int().nullable()
45
98
  });
46
99
 
47
100
  // ../shared/dist/host-protocol.js
48
- import { z as z3 } from "zod";
49
- var PairingCreateRequestSchema = z3.object({
50
- device_secret_hash: z3.string()
101
+ import { z as z4 } from "zod";
102
+ var PairingCreateRequestSchema = z4.object({
103
+ device_secret_hash: z4.string()
51
104
  });
52
- var PairingCreateResponseSchema = z3.object({
53
- code: z3.string(),
54
- expires_at: z3.string().datetime()
105
+ var PairingCreateResponseSchema = z4.object({
106
+ code: z4.string(),
107
+ expires_at: z4.string().datetime()
55
108
  });
56
- var PairingStatusResponseSchema = z3.union([
57
- z3.object({ status: z3.literal("pending") }),
58
- z3.object({
59
- status: z3.literal("confirmed"),
60
- token: z3.string(),
61
- agent_host_id: z3.string(),
62
- device_name: z3.string()
109
+ var PairingStatusResponseSchema = z4.union([
110
+ z4.object({ status: z4.literal("pending") }),
111
+ z4.object({
112
+ status: z4.literal("confirmed"),
113
+ token: z4.string(),
114
+ agent_host_id: z4.string(),
115
+ device_name: z4.string()
63
116
  }),
64
- z3.object({ status: z3.literal("expired") })
117
+ z4.object({ status: z4.literal("expired") })
65
118
  ]);
66
- var PairingConfirmRequestSchema = z3.object({
67
- device_name: z3.string().min(1)
119
+ var PairingConfirmRequestSchema = z4.object({
120
+ device_name: z4.string().min(1)
68
121
  });
69
- var SystemInfoSchema = z3.object({
70
- os: z3.string(),
122
+ var SystemInfoSchema = z4.object({
123
+ os: z4.string(),
71
124
  // os.platform()
72
- release: z3.string(),
125
+ release: z4.string(),
73
126
  // os.release()
74
- arch: z3.string(),
127
+ arch: z4.string(),
75
128
  // os.arch()
76
- hostname: z3.string(),
77
- cpu: z3.object({
78
- model: z3.string(),
79
- cores: z3.number().int().nonnegative(),
80
- speedMhz: z3.number().int().nonnegative()
129
+ hostname: z4.string(),
130
+ cpu: z4.object({
131
+ model: z4.string(),
132
+ cores: z4.number().int().nonnegative(),
133
+ speedMhz: z4.number().int().nonnegative()
81
134
  }),
82
- memory: z3.object({
83
- totalBytes: z3.number().nonnegative(),
84
- freeBytes: z3.number().nonnegative()
135
+ memory: z4.object({
136
+ totalBytes: z4.number().nonnegative(),
137
+ freeBytes: z4.number().nonnegative()
85
138
  }),
86
- disk: z3.object({
87
- path: z3.string(),
88
- totalBytes: z3.number().nonnegative(),
89
- freeBytes: z3.number().nonnegative()
139
+ disk: z4.object({
140
+ path: z4.string(),
141
+ totalBytes: z4.number().nonnegative(),
142
+ freeBytes: z4.number().nonnegative()
90
143
  }).optional(),
91
- ipAddrs: z3.array(z3.string()).default([]),
92
- uptimeSec: z3.number().nonnegative()
144
+ ipAddrs: z4.array(z4.string()).default([]),
145
+ uptimeSec: z4.number().nonnegative()
93
146
  });
94
- var HelloMessageSchema = z3.object({
95
- type: z3.literal("hello"),
96
- platform: z3.string(),
97
- version: z3.string(),
98
- capabilities: z3.array(z3.string()).default([]),
147
+ var HelloMessageSchema = z4.object({
148
+ type: z4.literal("hello"),
149
+ platform: z4.string(),
150
+ version: z4.string(),
151
+ capabilities: z4.array(z4.string()).default([]),
99
152
  systemInfo: SystemInfoSchema.optional()
100
153
  });
101
- var JobAssignmentSchema = z3.object({
102
- type: z3.literal("job"),
154
+ var JobAssignmentSchema = z4.object({
155
+ type: z4.literal("job"),
103
156
  run: AgentRunSchema,
104
157
  spec: AgentSpecSchema,
105
- stdinJson: z3.unknown().optional()
158
+ stdinJson: z4.unknown().optional()
106
159
  });
107
- var LogFrameSchema = z3.object({
108
- type: z3.literal("log"),
109
- runId: z3.string(),
110
- seq: z3.number().int().min(0),
111
- stream: z3.enum(["stdout", "stderr"]),
112
- chunk: z3.string()
160
+ var LogFrameSchema = z4.object({
161
+ type: z4.literal("log"),
162
+ runId: z4.string(),
163
+ seq: z4.number().int().min(0),
164
+ stream: z4.enum(["stdout", "stderr"]),
165
+ chunk: z4.string()
113
166
  });
114
- var RunDoneSchema = z3.object({
115
- type: z3.literal("done"),
116
- runId: z3.string(),
117
- status: z3.enum(["succeeded", "failed", "cancelled"]),
118
- exitCode: z3.number().int().nullable().optional(),
119
- errorMessage: z3.string().optional()
167
+ var RunDoneSchema = z4.object({
168
+ type: z4.literal("done"),
169
+ runId: z4.string(),
170
+ status: z4.enum(["succeeded", "failed", "cancelled"]),
171
+ exitCode: z4.number().int().nullable().optional(),
172
+ errorMessage: z4.string().optional()
120
173
  });
121
- var HelloAckSchema = z3.object({
122
- type: z3.literal("hello-ack"),
123
- agentHostId: z3.string(),
124
- deviceName: z3.string()
174
+ var HelloAckSchema = z4.object({
175
+ type: z4.literal("hello-ack"),
176
+ agentHostId: z4.string(),
177
+ deviceName: z4.string()
125
178
  });
126
- var PingSchema = z3.object({ type: z3.literal("ping") });
127
- var PongSchema = z3.object({ type: z3.literal("pong") });
128
- var ServerToDeviceMessageSchema = z3.discriminatedUnion("type", [
179
+ var PingSchema = z4.object({ type: z4.literal("ping") });
180
+ var PongSchema = z4.object({ type: z4.literal("pong") });
181
+ var ServerToDeviceMessageSchema = z4.discriminatedUnion("type", [
129
182
  JobAssignmentSchema,
130
183
  HelloAckSchema,
131
184
  PingSchema
132
185
  ]);
133
- var DeviceToServerMessageSchema = z3.discriminatedUnion("type", [
186
+ var DeviceToServerMessageSchema = z4.discriminatedUnion("type", [
134
187
  HelloMessageSchema,
135
188
  LogFrameSchema,
136
189
  RunDoneSchema,
137
190
  PongSchema
138
191
  ]);
139
- var HostRegisterRequestSchema = z3.object({
140
- hostId: z3.string(),
141
- hostName: z3.string(),
142
- capabilities: z3.array(z3.string()).default([]),
143
- token: z3.string()
192
+ var HostRegisterRequestSchema = z4.object({
193
+ hostId: z4.string(),
194
+ hostName: z4.string(),
195
+ capabilities: z4.array(z4.string()).default([]),
196
+ token: z4.string()
144
197
  });
145
- var HostRegisterResponseSchema = z3.object({
146
- ok: z3.literal(true),
147
- pollIntervalMs: z3.number().int().positive()
198
+ var HostRegisterResponseSchema = z4.object({
199
+ ok: z4.literal(true),
200
+ pollIntervalMs: z4.number().int().positive()
148
201
  });
149
202
 
150
- // src/config/store.ts
151
- import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "node:fs";
152
- import { z as z4 } from "zod";
153
-
154
- // src/config/paths.ts
155
- import { homedir } from "node:os";
156
- import { join } from "node:path";
157
- var CONFIG_DIR = join(homedir(), ".opencara");
158
- var CONFIG_FILE = join(CONFIG_DIR, "config.json");
159
- var DEFAULT_ORCHESTRATOR_URL = "https://opencara.com";
160
-
161
- // src/config/store.ts
162
- var ConfigSchema = z4.object({
163
- orchestratorUrl: z4.string().url(),
164
- token: z4.string(),
165
- agentHostId: z4.string(),
166
- deviceName: z4.string()
167
- });
168
- function readConfig() {
169
- if (!existsSync(CONFIG_FILE)) return null;
170
- try {
171
- return ConfigSchema.parse(JSON.parse(readFileSync(CONFIG_FILE, "utf8")));
172
- } catch {
173
- return null;
174
- }
175
- }
176
- function writeConfig(cfg) {
177
- if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
178
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), { mode: 384 });
179
- }
180
- function clearConfig() {
181
- if (existsSync(CONFIG_FILE)) unlinkSync(CONFIG_FILE);
182
- }
183
- function defaultOrchestratorUrl() {
184
- return process.env["OPENCARA_URL"] ?? DEFAULT_ORCHESTRATOR_URL;
185
- }
186
-
187
203
  // src/commands/register.ts
188
204
  var POLL_INTERVAL_MS = 2e3;
189
205
  async function register(opts = {}) {
190
206
  const orchestratorUrl = opts.url ?? defaultOrchestratorUrl();
191
- if (!opts.force && readConfig()) {
192
- console.log("Already paired. Use --force to re-pair.");
207
+ if (!opts.forcePair && readConfig()) {
208
+ console.log("Already paired. Use --force-pair to re-pair.");
193
209
  return;
194
210
  }
195
211
  const deviceSecret = randomBytes(32).toString("base64url");
@@ -237,7 +253,6 @@ async function register(opts = {}) {
237
253
  console.log(`
238
254
 
239
255
  \u2713 Paired as "${result.device_name}".`);
240
- console.log(` Run 'opencara run' to start accepting jobs.`);
241
256
  return;
242
257
  }
243
258
  throw new Error("pairing timed out");
@@ -255,22 +270,6 @@ function sleep(ms) {
255
270
  return new Promise((r) => setTimeout(r, ms));
256
271
  }
257
272
 
258
- // src/commands/run.ts
259
- import {
260
- arch,
261
- cpus,
262
- freemem,
263
- hostname,
264
- networkInterfaces,
265
- platform,
266
- release,
267
- totalmem,
268
- uptime
269
- } from "node:os";
270
- import { readFileSync as readFileSync2, statfsSync } from "node:fs";
271
- import { dirname, join as join2 } from "node:path";
272
- import { fileURLToPath } from "node:url";
273
-
274
273
  // src/transport/ws-client.ts
275
274
  import WebSocket from "ws";
276
275
  var HEARTBEAT_MS = 3e4;
@@ -373,10 +372,12 @@ var __dirname = dirname(fileURLToPath(import.meta.url));
373
372
  var PKG_VERSION = readPkgVersion();
374
373
  var LOG_FLUSH_MS = 800;
375
374
  var MAX_CHUNK_SIZE = 4 * 1024;
376
- async function run() {
377
- const cfg = readConfig();
378
- if (!cfg) {
379
- throw new Error("Not paired. Run 'opencara register' first.");
375
+ async function run(opts = {}) {
376
+ let cfg = readConfig();
377
+ if (!cfg || opts.forcePair) {
378
+ await register({ url: opts.url, forcePair: opts.forcePair });
379
+ cfg = readConfig();
380
+ if (!cfg) throw new Error("pairing did not save a config");
380
381
  }
381
382
  const wsUrl = cfg.orchestratorUrl.replace(/^http/, "ws") + "/api/devices/ws";
382
383
  const client = new WsClient({
@@ -512,7 +513,7 @@ function collectSystemInfo() {
512
513
  async function status() {
513
514
  const cfg = readConfig();
514
515
  if (!cfg) {
515
- console.log("Not paired. Run 'opencara register' to pair.");
516
+ console.log("Not paired. Run 'opencara' to pair and start accepting jobs.");
516
517
  return;
517
518
  }
518
519
  console.log(`Paired:`);
@@ -551,17 +552,11 @@ async function logout() {
551
552
 
552
553
  // src/bin.ts
553
554
  async function main() {
554
- const [, , cmd, ...rest] = process.argv;
555
+ const argv = process.argv.slice(2);
556
+ const cmd = argv[0];
555
557
  switch (cmd) {
556
- case "register":
557
- await register({
558
- force: rest.includes("--force"),
559
- url: pickFlag(rest, "--url")
560
- });
561
- return;
562
- case "run":
563
- await run();
564
- return;
558
+ case void 0:
559
+ break;
565
560
  case "status":
566
561
  await status();
567
562
  return;
@@ -570,14 +565,19 @@ async function main() {
570
565
  return;
571
566
  case "--help":
572
567
  case "-h":
573
- case void 0:
574
568
  printHelp();
575
569
  return;
576
570
  default:
577
- console.error(`unknown command: ${cmd}`);
578
- printHelp();
579
- process.exit(1);
571
+ if (!cmd.startsWith("-")) {
572
+ console.error(`unknown command: ${cmd}`);
573
+ printHelp();
574
+ process.exit(1);
575
+ }
580
576
  }
577
+ await run({
578
+ forcePair: argv.includes("--force-pair"),
579
+ url: pickFlag(argv, "--url")
580
+ });
581
581
  }
582
582
  function pickFlag(argv, name) {
583
583
  const i = argv.indexOf(name);
@@ -588,10 +588,14 @@ function printHelp() {
588
588
  console.log(`opencara \u2014 agent host CLI
589
589
 
590
590
  Usage:
591
- opencara register [--url URL] [--force]
592
- opencara run
593
- opencara status
594
- opencara logout
591
+ opencara [--url URL] [--force-pair] Pair (if needed) and start accepting jobs.
592
+ opencara status Show pairing state.
593
+ opencara logout Forget the saved pairing.
594
+
595
+ Options:
596
+ --url URL Orchestrator URL (default: https://opencara.com,
597
+ or $OPENCARA_URL).
598
+ --force-pair Re-pair even if already paired.
595
599
  `);
596
600
  }
597
601
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.100.0",
3
+ "version": "0.100.1",
4
4
  "description": "OpenCara agent-host CLI: register a machine as an agent host and run dispatched agents.",
5
5
  "license": "MIT",
6
6
  "repository": {