@opencomputer/cli 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/README.md +16 -0
- package/dist/api.d.ts +85 -0
- package/dist/api.js +108 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +7 -0
- package/dist/auth.js +122 -0
- package/dist/auth.js.map +1 -0
- package/dist/commands.d.ts +6 -0
- package/dist/commands.js +189 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +66 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/config.test.js +32 -0
- package/dist/config.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# OpenComputer CLI
|
|
2
|
+
|
|
3
|
+
The agent-only OpenComputer CLI deploys managed agents from templates and runs
|
|
4
|
+
them through the public OpenComputer API.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install --global @opencomputer/cli
|
|
8
|
+
opencomputer login
|
|
9
|
+
opencomputer templates
|
|
10
|
+
opencomputer deploy email-triage
|
|
11
|
+
opencomputer run email-triage "Triage today's inbox."
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Authentication is stored separately from the legacy `oc` CLI in
|
|
15
|
+
`~/.opencomputer/config.json`. `OPENCOMPUTER_API_KEY` and
|
|
16
|
+
`OPENCOMPUTER_API_URL` can be used in CI.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ResolvedConfig } from "./config.js";
|
|
2
|
+
export interface OpenComputerIdentity {
|
|
3
|
+
user_id: string | null;
|
|
4
|
+
email: string | null;
|
|
5
|
+
org_id: string;
|
|
6
|
+
org_name: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface ManagedAgentTemplate {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
category: string;
|
|
13
|
+
integrations: string[];
|
|
14
|
+
suggestedPrompts: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface ManagedAgentSummary {
|
|
17
|
+
id: string;
|
|
18
|
+
activeAlias: string;
|
|
19
|
+
deploymentCount: number;
|
|
20
|
+
createdAt: string;
|
|
21
|
+
updatedAt: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ManagedAgentDeployment {
|
|
24
|
+
id: string;
|
|
25
|
+
agentId: string;
|
|
26
|
+
alias: string;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ManagedAgentEvent {
|
|
30
|
+
id: string;
|
|
31
|
+
seq: number;
|
|
32
|
+
type: string;
|
|
33
|
+
data: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
interface SessionSnapshot {
|
|
36
|
+
id: string;
|
|
37
|
+
status: string;
|
|
38
|
+
}
|
|
39
|
+
interface CreateSessionResult {
|
|
40
|
+
session: SessionSnapshot;
|
|
41
|
+
deployment?: ManagedAgentDeployment;
|
|
42
|
+
}
|
|
43
|
+
export declare class APIError extends Error {
|
|
44
|
+
readonly status: number;
|
|
45
|
+
constructor(message: string, status: number);
|
|
46
|
+
}
|
|
47
|
+
export declare class OpenComputerClient {
|
|
48
|
+
private readonly config;
|
|
49
|
+
constructor(config: ResolvedConfig);
|
|
50
|
+
private request;
|
|
51
|
+
startLogin(): Promise<{
|
|
52
|
+
device_code: string;
|
|
53
|
+
user_code: string;
|
|
54
|
+
verification_uri: string;
|
|
55
|
+
verification_uri_complete: string;
|
|
56
|
+
expires_in: number;
|
|
57
|
+
interval: number;
|
|
58
|
+
}>;
|
|
59
|
+
exchangeLogin(deviceCode: string, credentialName: string): Promise<{
|
|
60
|
+
status: "authorization_pending" | "authorized";
|
|
61
|
+
retry_after?: number;
|
|
62
|
+
credential?: {
|
|
63
|
+
id: string;
|
|
64
|
+
key: string;
|
|
65
|
+
key_prefix: string;
|
|
66
|
+
name: string;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
whoami(): Promise<OpenComputerIdentity>;
|
|
70
|
+
revokeCredential(): Promise<void>;
|
|
71
|
+
templates(): Promise<ManagedAgentTemplate[]>;
|
|
72
|
+
agents(): Promise<ManagedAgentSummary[]>;
|
|
73
|
+
deploy(templateId: string, agentId?: string, alias?: string): Promise<{
|
|
74
|
+
template: ManagedAgentTemplate;
|
|
75
|
+
deployment: ManagedAgentDeployment;
|
|
76
|
+
}>;
|
|
77
|
+
createSession(agentId: string): Promise<CreateSessionResult>;
|
|
78
|
+
createTurn(sessionId: string, input: string): Promise<{
|
|
79
|
+
turnId: string;
|
|
80
|
+
duplicate: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
events(sessionId: string, after: number): Promise<ManagedAgentEvent[]>;
|
|
83
|
+
suspendSession(sessionId: string): Promise<SessionSnapshot>;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export class APIError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
constructor(message, status) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function errorMessage(body, status) {
|
|
9
|
+
if (body && typeof body === "object") {
|
|
10
|
+
const record = body;
|
|
11
|
+
if (typeof record.error === "string")
|
|
12
|
+
return record.error;
|
|
13
|
+
if (record.error && typeof record.error === "object") {
|
|
14
|
+
const message = record.error.message;
|
|
15
|
+
if (typeof message === "string")
|
|
16
|
+
return message;
|
|
17
|
+
}
|
|
18
|
+
if (typeof record.message === "string")
|
|
19
|
+
return record.message;
|
|
20
|
+
}
|
|
21
|
+
return `OpenComputer request failed (${status})`;
|
|
22
|
+
}
|
|
23
|
+
export class OpenComputerClient {
|
|
24
|
+
config;
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
}
|
|
28
|
+
async request(path, init = {}, authenticated = true) {
|
|
29
|
+
const headers = new Headers(init.headers);
|
|
30
|
+
if (init.body && !headers.has("content-type")) {
|
|
31
|
+
headers.set("content-type", "application/json");
|
|
32
|
+
}
|
|
33
|
+
if (authenticated) {
|
|
34
|
+
if (!this.config.apiKey) {
|
|
35
|
+
throw new Error("Not logged in. Run `opencomputer login` or set OPENCOMPUTER_API_KEY.");
|
|
36
|
+
}
|
|
37
|
+
headers.set("x-api-key", this.config.apiKey);
|
|
38
|
+
}
|
|
39
|
+
const response = await fetch(`${this.config.apiUrl}${path}`, {
|
|
40
|
+
...init,
|
|
41
|
+
headers,
|
|
42
|
+
redirect: "manual",
|
|
43
|
+
signal: AbortSignal.timeout(30_000),
|
|
44
|
+
});
|
|
45
|
+
if (response.status === 204)
|
|
46
|
+
return undefined;
|
|
47
|
+
const body = await response.json().catch(() => undefined);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new APIError(errorMessage(body, response.status), response.status);
|
|
50
|
+
}
|
|
51
|
+
return body;
|
|
52
|
+
}
|
|
53
|
+
startLogin() {
|
|
54
|
+
return this.request("/auth/cli/device", { method: "POST" }, false);
|
|
55
|
+
}
|
|
56
|
+
exchangeLogin(deviceCode, credentialName) {
|
|
57
|
+
return this.request("/auth/cli/device/exchange", {
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
device_code: deviceCode,
|
|
61
|
+
credential_name: credentialName,
|
|
62
|
+
}),
|
|
63
|
+
}, false);
|
|
64
|
+
}
|
|
65
|
+
whoami() {
|
|
66
|
+
return this.request("/api/whoami");
|
|
67
|
+
}
|
|
68
|
+
revokeCredential() {
|
|
69
|
+
return this.request("/auth/cli/credential", { method: "DELETE" });
|
|
70
|
+
}
|
|
71
|
+
async templates() {
|
|
72
|
+
const result = await this.request("/api/managed-agents/templates");
|
|
73
|
+
return result.templates;
|
|
74
|
+
}
|
|
75
|
+
async agents() {
|
|
76
|
+
const result = await this.request("/api/managed-agents/agents");
|
|
77
|
+
return result.agents;
|
|
78
|
+
}
|
|
79
|
+
deploy(templateId, agentId, alias = "production") {
|
|
80
|
+
return this.request(`/api/managed-agents/templates/${encodeURIComponent(templateId)}/deploy`, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
body: JSON.stringify({ agentId, alias }),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
createSession(agentId) {
|
|
86
|
+
return this.request("/api/managed-agents/sessions", {
|
|
87
|
+
method: "POST",
|
|
88
|
+
body: JSON.stringify({ agentId }),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
createTurn(sessionId, input) {
|
|
92
|
+
return this.request(`/api/managed-agents/sessions/${encodeURIComponent(sessionId)}/turns`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
body: JSON.stringify({
|
|
95
|
+
input,
|
|
96
|
+
idempotencyKey: crypto.randomUUID(),
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async events(sessionId, after) {
|
|
101
|
+
const result = await this.request(`/api/managed-agents/sessions/${encodeURIComponent(sessionId)}/events?after=${after}`);
|
|
102
|
+
return result.events;
|
|
103
|
+
}
|
|
104
|
+
suspendSession(sessionId) {
|
|
105
|
+
return this.request(`/api/managed-agents/sessions/${encodeURIComponent(sessionId)}/suspend`, { method: "POST" });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type OpenComputerIdentity } from "./api.js";
|
|
2
|
+
import { type ResolvedConfig } from "./config.js";
|
|
3
|
+
export declare function login(config: ResolvedConfig, options: {
|
|
4
|
+
noBrowser: boolean;
|
|
5
|
+
force: boolean;
|
|
6
|
+
}): Promise<OpenComputerIdentity>;
|
|
7
|
+
export declare function logout(config: ResolvedConfig, localOnly: boolean): Promise<void>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { hostname, platform } from "node:os";
|
|
3
|
+
import { OpenComputerClient } from "./api.js";
|
|
4
|
+
import { loadStoredConfig, saveStoredConfig, } from "./config.js";
|
|
5
|
+
function credentialName() {
|
|
6
|
+
const cleanHost = hostname()
|
|
7
|
+
.replace(/[\u0000-\u001f\u007f]/g, "")
|
|
8
|
+
.trim();
|
|
9
|
+
return `opencomputer CLI${cleanHost ? ` on ${cleanHost}` : ""}`.slice(0, 100);
|
|
10
|
+
}
|
|
11
|
+
function openBrowser(url) {
|
|
12
|
+
const command = platform() === "darwin"
|
|
13
|
+
? ["open", url]
|
|
14
|
+
: platform() === "win32"
|
|
15
|
+
? ["rundll32", "url.dll,FileProtocolHandler", url]
|
|
16
|
+
: ["xdg-open", url];
|
|
17
|
+
try {
|
|
18
|
+
const child = spawn(command[0], command.slice(1), {
|
|
19
|
+
detached: true,
|
|
20
|
+
stdio: "ignore",
|
|
21
|
+
});
|
|
22
|
+
child.once("error", () => undefined);
|
|
23
|
+
child.unref();
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function sleep(milliseconds) {
|
|
31
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
32
|
+
}
|
|
33
|
+
export async function login(config, options) {
|
|
34
|
+
if (process.env.OPENCOMPUTER_API_KEY && !options.force) {
|
|
35
|
+
throw new Error("OPENCOMPUTER_API_KEY currently controls authentication; unset it or use --force.");
|
|
36
|
+
}
|
|
37
|
+
const stored = await loadStoredConfig();
|
|
38
|
+
if (stored.apiKey && !options.force) {
|
|
39
|
+
try {
|
|
40
|
+
return await new OpenComputerClient({
|
|
41
|
+
apiUrl: stored.apiUrl ?? config.apiUrl,
|
|
42
|
+
apiKey: stored.apiKey,
|
|
43
|
+
}).whoami();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// An expired saved login is replaced below.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const client = new OpenComputerClient({
|
|
50
|
+
apiUrl: config.apiUrl,
|
|
51
|
+
});
|
|
52
|
+
const receipt = await client.startLogin();
|
|
53
|
+
if (!receipt.device_code ||
|
|
54
|
+
!receipt.user_code ||
|
|
55
|
+
!receipt.verification_uri_complete ||
|
|
56
|
+
receipt.expires_in <= 0 ||
|
|
57
|
+
receipt.interval <= 0) {
|
|
58
|
+
throw new Error("OpenComputer returned an incomplete login response.");
|
|
59
|
+
}
|
|
60
|
+
const verificationURL = new URL(receipt.verification_uri_complete);
|
|
61
|
+
if (verificationURL.protocol !== "https:") {
|
|
62
|
+
throw new Error("OpenComputer returned an unsafe login URL.");
|
|
63
|
+
}
|
|
64
|
+
process.stderr.write(`\nConfirm this code in your browser:\n\n ${receipt.user_code}\n\n` +
|
|
65
|
+
` ${receipt.verification_uri_complete}\n`);
|
|
66
|
+
if (!options.noBrowser && !openBrowser(receipt.verification_uri_complete)) {
|
|
67
|
+
process.stderr.write("\nCould not open a browser automatically.\n");
|
|
68
|
+
}
|
|
69
|
+
process.stderr.write("\nWaiting for confirmation…\n");
|
|
70
|
+
const deadline = Date.now() + receipt.expires_in * 1_000;
|
|
71
|
+
let interval = receipt.interval;
|
|
72
|
+
let credential;
|
|
73
|
+
while (Date.now() + interval * 1_000 < deadline) {
|
|
74
|
+
await sleep(interval * 1_000);
|
|
75
|
+
const exchange = await client.exchangeLogin(receipt.device_code, credentialName());
|
|
76
|
+
if (exchange.status === "authorized") {
|
|
77
|
+
credential = exchange.credential;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
interval = Math.max(interval, exchange.retry_after ?? interval);
|
|
81
|
+
}
|
|
82
|
+
if (!credential?.key || !credential.id) {
|
|
83
|
+
throw new Error("Login confirmation expired. Run `opencomputer login` again.");
|
|
84
|
+
}
|
|
85
|
+
const authenticated = new OpenComputerClient({
|
|
86
|
+
apiUrl: config.apiUrl,
|
|
87
|
+
apiKey: credential.key,
|
|
88
|
+
});
|
|
89
|
+
const identity = await authenticated.whoami();
|
|
90
|
+
const previous = options.force && stored.apiKey
|
|
91
|
+
? { apiKey: stored.apiKey, apiUrl: stored.apiUrl ?? config.apiUrl }
|
|
92
|
+
: null;
|
|
93
|
+
await saveStoredConfig({
|
|
94
|
+
apiUrl: config.apiUrl,
|
|
95
|
+
apiKey: credential.key,
|
|
96
|
+
login: {
|
|
97
|
+
credentialId: credential.id,
|
|
98
|
+
keyPrefix: credential.key_prefix,
|
|
99
|
+
name: credential.name,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (previous) {
|
|
103
|
+
await new OpenComputerClient(previous).revokeCredential().catch(() => {
|
|
104
|
+
process.stderr.write("Warning: the previous CLI credential could not be revoked. Remove it in the dashboard.\n");
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return identity;
|
|
108
|
+
}
|
|
109
|
+
export async function logout(config, localOnly) {
|
|
110
|
+
const stored = await loadStoredConfig();
|
|
111
|
+
if (!stored.apiKey || !stored.login) {
|
|
112
|
+
throw new Error("There is no CLI-managed login to revoke.");
|
|
113
|
+
}
|
|
114
|
+
if (!localOnly) {
|
|
115
|
+
await new OpenComputerClient({
|
|
116
|
+
apiUrl: stored.apiUrl ?? config.apiUrl,
|
|
117
|
+
apiKey: stored.apiKey,
|
|
118
|
+
}).revokeCredential();
|
|
119
|
+
}
|
|
120
|
+
await saveStoredConfig({ apiUrl: stored.apiUrl ?? config.apiUrl });
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { OpenComputerClient } from "./api.js";
|
|
2
|
+
import { login, logout } from "./auth.js";
|
|
3
|
+
import { resolveConfig } from "./config.js";
|
|
4
|
+
function printJSON(value) {
|
|
5
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
6
|
+
}
|
|
7
|
+
function option(args, name) {
|
|
8
|
+
const index = args.indexOf(name);
|
|
9
|
+
if (index < 0)
|
|
10
|
+
return undefined;
|
|
11
|
+
const value = args[index + 1];
|
|
12
|
+
if (!value || value.startsWith("--")) {
|
|
13
|
+
throw new Error(`${name} requires a value`);
|
|
14
|
+
}
|
|
15
|
+
args.splice(index, 2);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function flag(args, name) {
|
|
19
|
+
const index = args.indexOf(name);
|
|
20
|
+
if (index < 0)
|
|
21
|
+
return false;
|
|
22
|
+
args.splice(index, 1);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
async function waitForEvent(client, sessionId, after, terminal, onEvent, timeoutMs) {
|
|
26
|
+
const deadline = Date.now() + timeoutMs;
|
|
27
|
+
let cursor = after;
|
|
28
|
+
while (Date.now() < deadline) {
|
|
29
|
+
for (const event of await client.events(sessionId, cursor)) {
|
|
30
|
+
cursor = Math.max(cursor, event.seq);
|
|
31
|
+
onEvent(event);
|
|
32
|
+
if (event.type === "runtime.disconnected") {
|
|
33
|
+
throw new Error(typeof event.data.reason === "string"
|
|
34
|
+
? event.data.reason
|
|
35
|
+
: "The agent runtime disconnected.");
|
|
36
|
+
}
|
|
37
|
+
if (terminal(event))
|
|
38
|
+
return { event, cursor };
|
|
39
|
+
}
|
|
40
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
41
|
+
}
|
|
42
|
+
throw new Error("Timed out waiting for the agent.");
|
|
43
|
+
}
|
|
44
|
+
async function runAgent(client, agent, prompt, keep, json) {
|
|
45
|
+
const created = await client.createSession(agent);
|
|
46
|
+
process.stderr.write(`Starting ${agent}…\n`);
|
|
47
|
+
const connected = await waitForEvent(client, created.session.id, 0, (event) => event.type === "runtime.connected", () => undefined, 90_000);
|
|
48
|
+
const turn = await client.createTurn(created.session.id, prompt);
|
|
49
|
+
let streamed = false;
|
|
50
|
+
let streamedText = "";
|
|
51
|
+
let completedText = "";
|
|
52
|
+
const completed = await waitForEvent(client, created.session.id, connected.cursor, (event) => event.type === "turn.completed" || event.type === "turn.failed", (event) => {
|
|
53
|
+
if (event.type === "message.delta") {
|
|
54
|
+
streamed = true;
|
|
55
|
+
const text = String(event.data.text ?? "");
|
|
56
|
+
streamedText += text;
|
|
57
|
+
if (!json)
|
|
58
|
+
process.stdout.write(text);
|
|
59
|
+
}
|
|
60
|
+
else if (event.type === "message.completed" &&
|
|
61
|
+
typeof event.data.text === "string") {
|
|
62
|
+
completedText = event.data.text;
|
|
63
|
+
}
|
|
64
|
+
}, 180_000);
|
|
65
|
+
if (!json && !streamed && completedText)
|
|
66
|
+
process.stdout.write(completedText);
|
|
67
|
+
if (!json && (!process.stdout.isTTY || streamed || completedText)) {
|
|
68
|
+
process.stdout.write("\n");
|
|
69
|
+
}
|
|
70
|
+
if (completed.event.type === "turn.failed") {
|
|
71
|
+
throw new Error(String(completed.event.data.message ?? "Agent turn failed"));
|
|
72
|
+
}
|
|
73
|
+
if (!keep) {
|
|
74
|
+
await client.suspendSession(created.session.id).catch(() => undefined);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
sessionId: created.session.id,
|
|
78
|
+
turnId: turn.turnId,
|
|
79
|
+
agentId: created.deployment?.agentId ?? agent,
|
|
80
|
+
deploymentId: created.deployment?.id,
|
|
81
|
+
status: "completed",
|
|
82
|
+
output: streamedText || completedText || undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export async function runCommand(command, rawArgs, globals) {
|
|
86
|
+
const args = [...rawArgs];
|
|
87
|
+
const config = await resolveConfig(globals);
|
|
88
|
+
const client = new OpenComputerClient(config);
|
|
89
|
+
if (command === "login") {
|
|
90
|
+
const identity = await login(config, {
|
|
91
|
+
noBrowser: flag(args, "--no-browser"),
|
|
92
|
+
force: flag(args, "--force"),
|
|
93
|
+
});
|
|
94
|
+
if (args.length)
|
|
95
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
96
|
+
if (globals.json)
|
|
97
|
+
printJSON(identity);
|
|
98
|
+
else {
|
|
99
|
+
process.stdout.write(`Logged in as ${identity.email ?? identity.user_id ?? "user"}\n` +
|
|
100
|
+
`Organization: ${identity.org_name ?? identity.org_id}\n`);
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (command === "logout") {
|
|
105
|
+
const localOnly = flag(args, "--local");
|
|
106
|
+
if (args.length)
|
|
107
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
108
|
+
await logout(config, localOnly);
|
|
109
|
+
if (globals.json)
|
|
110
|
+
printJSON({ status: "logged_out", localOnly });
|
|
111
|
+
else
|
|
112
|
+
process.stdout.write(localOnly ? "Local login cleared.\n" : "Logged out.\n");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (command === "whoami") {
|
|
116
|
+
const identity = await client.whoami();
|
|
117
|
+
if (globals.json)
|
|
118
|
+
printJSON(identity);
|
|
119
|
+
else {
|
|
120
|
+
process.stdout.write(`User ${identity.email ?? identity.user_id ?? "—"}\n` +
|
|
121
|
+
`Organization ${identity.org_name ?? "—"}\n` +
|
|
122
|
+
`Org ID ${identity.org_id}\n` +
|
|
123
|
+
`API ${config.apiUrl}\n`);
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (command === "templates") {
|
|
128
|
+
const templates = await client.templates();
|
|
129
|
+
if (globals.json)
|
|
130
|
+
printJSON(templates);
|
|
131
|
+
else {
|
|
132
|
+
for (const template of templates) {
|
|
133
|
+
process.stdout.write(`${template.id.padEnd(22)} ${template.name}\n` +
|
|
134
|
+
`${"".padEnd(23)}${template.description}\n` +
|
|
135
|
+
`${"".padEnd(23)}${template.integrations.join(", ")}\n`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (command === "agents") {
|
|
141
|
+
const agents = await client.agents();
|
|
142
|
+
if (globals.json)
|
|
143
|
+
printJSON(agents);
|
|
144
|
+
else if (!agents.length) {
|
|
145
|
+
process.stdout.write("No agents deployed. Run `opencomputer templates` to get started.\n");
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
for (const agent of agents) {
|
|
149
|
+
process.stdout.write(`${agent.id.padEnd(24)} ${agent.activeAlias.padEnd(12)} ${agent.deploymentCount} deployment${agent.deploymentCount === 1 ? "" : "s"}\n`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (command === "deploy") {
|
|
155
|
+
const name = option(args, "--name");
|
|
156
|
+
const alias = option(args, "--alias") ?? "production";
|
|
157
|
+
const template = args.shift();
|
|
158
|
+
if (!template) {
|
|
159
|
+
throw new Error("Usage: opencomputer deploy <template> [--name <agent>]");
|
|
160
|
+
}
|
|
161
|
+
if (args.length)
|
|
162
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
163
|
+
const result = await client.deploy(template, name, alias);
|
|
164
|
+
if (globals.json)
|
|
165
|
+
printJSON(result);
|
|
166
|
+
else {
|
|
167
|
+
process.stdout.write(`Deployed ${result.template.name}\n` +
|
|
168
|
+
`Agent: ${result.deployment.agentId}\n` +
|
|
169
|
+
`Alias: ${result.deployment.alias}\n` +
|
|
170
|
+
`Deployment: ${result.deployment.id}\n\n` +
|
|
171
|
+
`Run it:\n opencomputer run ${result.deployment.agentId} "Your prompt"\n`);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (command === "run") {
|
|
176
|
+
const keep = flag(args, "--keep");
|
|
177
|
+
const agent = args.shift();
|
|
178
|
+
const prompt = args.join(" ").trim();
|
|
179
|
+
if (!agent || !prompt) {
|
|
180
|
+
throw new Error("Usage: opencomputer run <agent> <prompt>");
|
|
181
|
+
}
|
|
182
|
+
const result = await runAgent(client, agent, prompt, keep, globals.json);
|
|
183
|
+
if (globals.json)
|
|
184
|
+
printJSON(result);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
throw new Error(`Unknown command: ${command}`);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const DEFAULT_API_URL = "https://app.opencomputer.dev";
|
|
2
|
+
export interface LoginMetadata {
|
|
3
|
+
credentialId: string;
|
|
4
|
+
keyPrefix: string;
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
export interface StoredConfig {
|
|
8
|
+
apiUrl?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
login?: LoginMetadata;
|
|
11
|
+
}
|
|
12
|
+
export interface ResolvedConfig {
|
|
13
|
+
apiUrl: string;
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function configPath(): string;
|
|
17
|
+
export declare function loadStoredConfig(): Promise<StoredConfig>;
|
|
18
|
+
export declare function resolveConfig(overrides: {
|
|
19
|
+
apiUrl?: string;
|
|
20
|
+
apiKey?: string;
|
|
21
|
+
}): Promise<ResolvedConfig>;
|
|
22
|
+
export declare function normalizeAPIURL(value: string): string;
|
|
23
|
+
export declare function saveStoredConfig(config: StoredConfig): Promise<void>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { chmod, mkdir, open, readFile, rename, rm } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
export const DEFAULT_API_URL = "https://app.opencomputer.dev";
|
|
5
|
+
export function configPath() {
|
|
6
|
+
return (process.env.OPENCOMPUTER_CONFIG ??
|
|
7
|
+
join(homedir(), ".opencomputer", "config.json"));
|
|
8
|
+
}
|
|
9
|
+
export async function loadStoredConfig() {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(await readFile(configPath(), "utf8"));
|
|
12
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function resolveConfig(overrides) {
|
|
22
|
+
const stored = await loadStoredConfig();
|
|
23
|
+
return {
|
|
24
|
+
apiUrl: normalizeAPIURL(overrides.apiUrl ??
|
|
25
|
+
process.env.OPENCOMPUTER_API_URL ??
|
|
26
|
+
stored.apiUrl ??
|
|
27
|
+
DEFAULT_API_URL),
|
|
28
|
+
apiKey: overrides.apiKey ?? process.env.OPENCOMPUTER_API_KEY ?? stored.apiKey,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function normalizeAPIURL(value) {
|
|
32
|
+
const url = new URL(value);
|
|
33
|
+
if (url.protocol !== "https:" &&
|
|
34
|
+
!(url.protocol === "http:" &&
|
|
35
|
+
["localhost", "127.0.0.1", "::1"].includes(url.hostname))) {
|
|
36
|
+
throw new Error("The OpenComputer API URL must use HTTPS");
|
|
37
|
+
}
|
|
38
|
+
url.pathname = url.pathname.replace(/\/api\/?$/, "").replace(/\/+$/, "");
|
|
39
|
+
url.search = "";
|
|
40
|
+
url.hash = "";
|
|
41
|
+
return url.toString().replace(/\/$/, "");
|
|
42
|
+
}
|
|
43
|
+
export async function saveStoredConfig(config) {
|
|
44
|
+
const path = configPath();
|
|
45
|
+
const directory = dirname(path);
|
|
46
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
47
|
+
await chmod(directory, 0o700);
|
|
48
|
+
const temporary = join(directory, `.config-${process.pid}-${crypto.randomUUID()}.tmp`);
|
|
49
|
+
const handle = await open(temporary, "wx", 0o600);
|
|
50
|
+
try {
|
|
51
|
+
await handle.writeFile(`${JSON.stringify(config, null, 2)}\n`);
|
|
52
|
+
await handle.sync();
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
await handle.close();
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
await rename(temporary, path);
|
|
59
|
+
await chmod(path, 0o600);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
await rm(temporary, { force: true });
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,CAAC,MAAM,eAAe,GAAG,8BAA8B,CAAC;AAmB9D,MAAM,UAAU,UAAU;IACxB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,aAAa,CAAC,CAChD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,MAAsB,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAGnC;IACC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,OAAO;QACL,MAAM,EAAE,eAAe,CACrB,SAAS,CAAC,MAAM;YACd,OAAO,CAAC,GAAG,CAAC,oBAAoB;YAChC,MAAM,CAAC,MAAM;YACb,eAAe,CAClB;QACD,MAAM,EACJ,SAAS,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,MAAM,CAAC,MAAM;KACxE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,IACE,GAAG,CAAC,QAAQ,KAAK,QAAQ;QACzB,CAAC,CACC,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CACzD,EACD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzE,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAoB;IACzD,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,CACpB,SAAS,EACT,WAAW,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,MAAM,CACpD,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC9B,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { loadStoredConfig, normalizeAPIURL, saveStoredConfig, } from "./config.js";
|
|
7
|
+
test("normalizes the public API URL and rejects insecure remotes", () => {
|
|
8
|
+
assert.equal(normalizeAPIURL("https://app.opencomputer.dev/api/"), "https://app.opencomputer.dev");
|
|
9
|
+
assert.throws(() => normalizeAPIURL("http://example.com"));
|
|
10
|
+
assert.equal(normalizeAPIURL("http://localhost:8787"), "http://localhost:8787");
|
|
11
|
+
});
|
|
12
|
+
test("stores agent CLI credentials in a mode-0600 file", async () => {
|
|
13
|
+
const directory = await mkdtemp(join(tmpdir(), "opencomputer-cli-"));
|
|
14
|
+
const path = join(directory, "nested", "config.json");
|
|
15
|
+
process.env.OPENCOMPUTER_CONFIG = path;
|
|
16
|
+
try {
|
|
17
|
+
await saveStoredConfig({
|
|
18
|
+
apiUrl: "https://app.opencomputer.dev",
|
|
19
|
+
apiKey: "osb_test",
|
|
20
|
+
});
|
|
21
|
+
assert.equal((await stat(path)).mode & 0o777, 0o600);
|
|
22
|
+
assert.deepEqual(await loadStoredConfig(), {
|
|
23
|
+
apiUrl: "https://app.opencomputer.dev",
|
|
24
|
+
apiKey: "osb_test",
|
|
25
|
+
});
|
|
26
|
+
assert.match(await readFile(path, "utf8"), /"apiKey": "osb_test"/);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
delete process.env.OPENCOMPUTER_CONFIG;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;IACtE,MAAM,CAAC,KAAK,CACV,eAAe,CAAC,mCAAmC,CAAC,EACpD,8BAA8B,CAC/B,CAAC;IACF,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CACV,eAAe,CAAC,uBAAuB,CAAC,EACxC,uBAAuB,CACxB,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;IAClE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,IAAI,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,gBAAgB,CAAC;YACrB,MAAM,EAAE,8BAA8B;YACtC,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,CAAC,SAAS,CAAC,MAAM,gBAAgB,EAAE,EAAE;YACzC,MAAM,EAAE,8BAA8B;YACtC,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACrE,CAAC;YAAS,CAAC;QACT,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACzC,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runCommand } from "./commands.js";
|
|
3
|
+
const VERSION = "0.1.0";
|
|
4
|
+
function takeOption(args, name) {
|
|
5
|
+
const index = args.indexOf(name);
|
|
6
|
+
if (index < 0)
|
|
7
|
+
return undefined;
|
|
8
|
+
const value = args[index + 1];
|
|
9
|
+
if (!value || value.startsWith("--")) {
|
|
10
|
+
throw new Error(`${name} requires a value`);
|
|
11
|
+
}
|
|
12
|
+
args.splice(index, 2);
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function takeFlag(args, name) {
|
|
16
|
+
const index = args.indexOf(name);
|
|
17
|
+
if (index < 0)
|
|
18
|
+
return false;
|
|
19
|
+
args.splice(index, 1);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
function help() {
|
|
23
|
+
process.stdout.write(`OpenComputer — deploy and run managed agents
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
opencomputer login [--no-browser] [--force]
|
|
27
|
+
opencomputer logout [--local]
|
|
28
|
+
opencomputer whoami
|
|
29
|
+
opencomputer templates
|
|
30
|
+
opencomputer agents
|
|
31
|
+
opencomputer deploy <template> [--name <agent>] [--alias <alias>]
|
|
32
|
+
opencomputer run <agent> <prompt> [--keep]
|
|
33
|
+
|
|
34
|
+
Global options:
|
|
35
|
+
--api-url <url> OpenComputer API (default: https://app.opencomputer.dev)
|
|
36
|
+
--api-key <key> API key (or OPENCOMPUTER_API_KEY)
|
|
37
|
+
--json Print machine-readable output
|
|
38
|
+
--help Show this help
|
|
39
|
+
--version Show the CLI version
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
async function main() {
|
|
43
|
+
const args = process.argv.slice(2);
|
|
44
|
+
if (takeFlag(args, "--version")) {
|
|
45
|
+
process.stdout.write(`${VERSION}\n`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!args.length || takeFlag(args, "--help")) {
|
|
49
|
+
help();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const globals = {
|
|
53
|
+
apiUrl: takeOption(args, "--api-url"),
|
|
54
|
+
apiKey: takeOption(args, "--api-key"),
|
|
55
|
+
json: takeFlag(args, "--json"),
|
|
56
|
+
};
|
|
57
|
+
const command = args.shift();
|
|
58
|
+
if (!command) {
|
|
59
|
+
help();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
await runCommand(command, args, globals);
|
|
63
|
+
}
|
|
64
|
+
main().catch((error) => {
|
|
65
|
+
process.stderr.write(`opencomputer: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAsB,MAAM,eAAe,CAAC;AAE/D,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,SAAS,UAAU,CAAC,IAAc,EAAE,IAAY;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,mBAAmB,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,IAAc,EAAE,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,IAAI;IACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;CAiBtB,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO;IACT,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC7C,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAkB;QAC7B,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC;QACrC,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC;QACrC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;KAC/B,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IACD,MAAM,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iBAAiB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAC5E,CAAC;IACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opencomputer/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deploy and run managed OpenComputer agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"opencomputer": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"test": "npm run build && node --test dist/config.test.js",
|
|
16
|
+
"prepack": "npm test"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/diggerhq/opencomputer.git",
|
|
27
|
+
"directory": "cli"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"agents",
|
|
31
|
+
"ai",
|
|
32
|
+
"opencomputer"
|
|
33
|
+
],
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^24.0.0",
|
|
36
|
+
"typescript": "^5.9.0"
|
|
37
|
+
}
|
|
38
|
+
}
|