@duvoai/cli 0.0.1 → 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 +61 -0
- package/dist/api/agent-schemas.d.ts +427 -0
- package/dist/api/agent-schemas.js +20 -0
- package/dist/api/run-schemas.d.ts +621 -0
- package/dist/api/run-schemas.js +91 -0
- package/dist/bin/create-program.js +8 -1
- package/dist/commands/agents/create.d.ts +2 -0
- package/dist/commands/agents/create.js +182 -0
- package/dist/commands/agents/get.js +5 -11
- package/dist/commands/agents/index.js +2 -0
- package/dist/commands/agents/list.js +5 -11
- package/dist/commands/api.js +5 -13
- package/dist/commands/runs/get.d.ts +2 -0
- package/dist/commands/runs/get.js +59 -0
- package/dist/commands/runs/index.d.ts +2 -0
- package/dist/commands/runs/index.js +17 -0
- package/dist/commands/runs/messages.d.ts +2 -0
- package/dist/commands/runs/messages.js +80 -0
- package/dist/commands/runs/respond.d.ts +2 -0
- package/dist/commands/runs/respond.js +105 -0
- package/dist/commands/runs/send-message.d.ts +2 -0
- package/dist/commands/runs/send-message.js +41 -0
- package/dist/commands/runs/start.d.ts +2 -0
- package/dist/commands/runs/start.js +54 -0
- package/dist/commands/runs/stop.d.ts +2 -0
- package/dist/commands/runs/stop.js +41 -0
- package/dist/commands/shared/require-auth.d.ts +12 -0
- package/dist/commands/shared/require-auth.js +18 -0
- package/dist/commands/whoami.js +2 -9
- package/dist/output/green.d.ts +5 -0
- package/dist/output/green.js +18 -0
- package/package.json +4 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { startRunResponseSchema } from "../../api/run-schemas.js";
|
|
2
|
+
import { httpRequest } from "../../client/client.js";
|
|
3
|
+
import { CliError } from "../../errors.js";
|
|
4
|
+
import { green } from "../../output/green.js";
|
|
5
|
+
import { printJson } from "../../output/json.js";
|
|
6
|
+
import { renderKeyValue } from "../../output/text.js";
|
|
7
|
+
import { requireAuthenticatedConfig } from "../shared/require-auth.js";
|
|
8
|
+
export function registerRunsStart(runs) {
|
|
9
|
+
runs
|
|
10
|
+
.command("start")
|
|
11
|
+
.description("Start a new agent run")
|
|
12
|
+
.requiredOption("--agent <id>", "ID of the agent to run")
|
|
13
|
+
.option("--message <text>", "optional initial message to start the run with")
|
|
14
|
+
.option("--sandbox-id <id>", "optional sandbox ID with pre-uploaded files")
|
|
15
|
+
.option("--webhook-url <url>", "optional webhook URL to POST run events to")
|
|
16
|
+
.option("--json", "output raw JSON from the API")
|
|
17
|
+
.action(async function startAction(options) {
|
|
18
|
+
const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
|
|
19
|
+
const body = {
|
|
20
|
+
agent_id: options.agent,
|
|
21
|
+
...(options.message !== undefined ? { message: options.message } : {}),
|
|
22
|
+
...(options.sandboxId !== undefined
|
|
23
|
+
? { sandbox_id: options.sandboxId }
|
|
24
|
+
: {}),
|
|
25
|
+
...(options.webhookUrl !== undefined
|
|
26
|
+
? { webhook_url: options.webhookUrl }
|
|
27
|
+
: {}),
|
|
28
|
+
};
|
|
29
|
+
const raw = await httpRequest({
|
|
30
|
+
method: "POST",
|
|
31
|
+
path: "/v1/runs",
|
|
32
|
+
apiKey,
|
|
33
|
+
apiBaseUrl,
|
|
34
|
+
body,
|
|
35
|
+
});
|
|
36
|
+
if (options.json) {
|
|
37
|
+
printJson(raw);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const parsed = startRunResponseSchema.safeParse(raw);
|
|
41
|
+
if (!parsed.success) {
|
|
42
|
+
throw new CliError(`Unexpected response from the API: ${parsed.error.message}`);
|
|
43
|
+
}
|
|
44
|
+
const { run } = parsed.data;
|
|
45
|
+
console.log(green("Run started!"));
|
|
46
|
+
console.log(renderKeyValue([
|
|
47
|
+
{ label: "ID", value: run.id },
|
|
48
|
+
{ label: "Agent", value: run.agent_id },
|
|
49
|
+
{ label: "Build", value: run.build_id },
|
|
50
|
+
{ label: "Status", value: run.status },
|
|
51
|
+
{ label: "Created", value: run.created_at },
|
|
52
|
+
]));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { stopRunResponseSchema } from "../../api/run-schemas.js";
|
|
2
|
+
import { httpRequest } from "../../client/client.js";
|
|
3
|
+
import { CliError } from "../../errors.js";
|
|
4
|
+
import { green } from "../../output/green.js";
|
|
5
|
+
import { printJson } from "../../output/json.js";
|
|
6
|
+
import { confirmDestructive } from "../shared/confirm.js";
|
|
7
|
+
import { requireAuthenticatedConfig } from "../shared/require-auth.js";
|
|
8
|
+
export function registerRunsStop(runs) {
|
|
9
|
+
runs
|
|
10
|
+
.command("stop <id>")
|
|
11
|
+
.description("Stop a running agent run")
|
|
12
|
+
.option("-y, --yes", "skip the confirmation prompt")
|
|
13
|
+
.option("--json", "output raw JSON from the API")
|
|
14
|
+
.action(async function stopAction(id, options) {
|
|
15
|
+
const { apiKey, apiBaseUrl } = await requireAuthenticatedConfig(this);
|
|
16
|
+
await confirmDestructive({
|
|
17
|
+
message: `Stop run "${id}"?`,
|
|
18
|
+
skip: options.yes ?? false,
|
|
19
|
+
});
|
|
20
|
+
const raw = await httpRequest({
|
|
21
|
+
method: "POST",
|
|
22
|
+
path: `/v1/runs/${encodeURIComponent(id)}/stop`,
|
|
23
|
+
apiKey,
|
|
24
|
+
apiBaseUrl,
|
|
25
|
+
});
|
|
26
|
+
if (options.json) {
|
|
27
|
+
printJson(raw);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const parsed = stopRunResponseSchema.safeParse(raw);
|
|
31
|
+
if (!parsed.success) {
|
|
32
|
+
throw new CliError(`Unexpected response from the API: ${parsed.error.message}`);
|
|
33
|
+
}
|
|
34
|
+
const { success, message } = parsed.data;
|
|
35
|
+
if (!success) {
|
|
36
|
+
throw new CliError(message ?? `Failed to stop run "${id}".`);
|
|
37
|
+
}
|
|
38
|
+
const label = message ?? `Run "${id}" stopped.`;
|
|
39
|
+
console.log(green(label));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Command } from "commander";
|
|
2
|
+
import { type ResolvedConfig } from "../../config/resolve.js";
|
|
3
|
+
export type AuthenticatedConfig = ResolvedConfig & {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the effective profile for this invocation and guarantees an
|
|
8
|
+
* API key is present. Intended for every command that hits the API —
|
|
9
|
+
* throws `AuthCliError` (exit code 2) if no key is stored or passed via
|
|
10
|
+
* env, so callers can assume `apiKey` is a non-null string.
|
|
11
|
+
*/
|
|
12
|
+
export declare function requireAuthenticatedConfig(command: Command): Promise<AuthenticatedConfig>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { resolveConfig } from "../../config/resolve.js";
|
|
2
|
+
import { AuthCliError } from "../../errors.js";
|
|
3
|
+
import { getProfileFlag } from "./profile-flag.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the effective profile for this invocation and guarantees an
|
|
6
|
+
* API key is present. Intended for every command that hits the API —
|
|
7
|
+
* throws `AuthCliError` (exit code 2) if no key is stored or passed via
|
|
8
|
+
* env, so callers can assume `apiKey` is a non-null string.
|
|
9
|
+
*/
|
|
10
|
+
export async function requireAuthenticatedConfig(command) {
|
|
11
|
+
const resolved = await resolveConfig({
|
|
12
|
+
profileFlag: getProfileFlag(command),
|
|
13
|
+
});
|
|
14
|
+
if (!resolved.apiKey) {
|
|
15
|
+
throw new AuthCliError("Not logged in. Run `duvo login` to save an API key.");
|
|
16
|
+
}
|
|
17
|
+
return { ...resolved, apiKey: resolved.apiKey };
|
|
18
|
+
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import { resolveConfig } from "../config/resolve.js";
|
|
2
|
-
import { AuthCliError } from "../errors.js";
|
|
3
1
|
import { truncateApiKey } from "../output/format.js";
|
|
4
|
-
import {
|
|
2
|
+
import { requireAuthenticatedConfig } from "./shared/require-auth.js";
|
|
5
3
|
export function registerWhoami(program) {
|
|
6
4
|
program
|
|
7
5
|
.command("whoami")
|
|
8
6
|
.description("Print the default profile, truncated API key, and base URL")
|
|
9
7
|
.action(async function whoamiAction() {
|
|
10
|
-
const resolved = await
|
|
11
|
-
profileFlag: getProfileFlag(this),
|
|
12
|
-
});
|
|
13
|
-
if (!resolved.apiKey) {
|
|
14
|
-
throw new AuthCliError("Not logged in. Run `duvo login` to save an API key.");
|
|
15
|
-
}
|
|
8
|
+
const resolved = await requireAuthenticatedConfig(this);
|
|
16
9
|
const profileLabel = resolved.profileName ?? "(env-only, no stored profile)";
|
|
17
10
|
console.log(`Profile ${profileLabel}`);
|
|
18
11
|
console.log(`API key ${truncateApiKey(resolved.apiKey)}`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const GREEN = "\x1b[32m";
|
|
2
|
+
const RESET = "\x1b[0m";
|
|
3
|
+
/**
|
|
4
|
+
* Wrap text in ANSI green. Honors `NO_COLOR` and skips styling when
|
|
5
|
+
* stdout is not a TTY so piped output stays clean.
|
|
6
|
+
*/
|
|
7
|
+
export function green(text) {
|
|
8
|
+
if (!shouldColor()) {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
return `${GREEN}${text}${RESET}`;
|
|
12
|
+
}
|
|
13
|
+
function shouldColor() {
|
|
14
|
+
if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "") {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return Boolean(process.stdout.isTTY);
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duvoai/cli",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Command-line interface for the Duvo public API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/bin/duvo.js",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"duvo": "./dist/bin/duvo.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"dist"
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json && node scripts/make-bin-executable.mjs",
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
22
23
|
"@clack/prompts": "^0.8.2",
|
|
24
|
+
"@taskcrew/shared": "workspace:*",
|
|
23
25
|
"commander": "^12.1.0",
|
|
24
26
|
"zod": "^3.25.76"
|
|
25
27
|
},
|