@otto-code/cli 0.8.12 → 0.8.14
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.js +1 -5
- package/dist/commands/daemon/index.js +1 -0
- package/dist/commands/daemon/local-daemon.js +3 -0
- package/dist/commands/daemon/pair.d.ts +27 -1
- package/dist/commands/daemon/pair.js +133 -46
- package/dist/commands/daemon/start.js +1 -0
- package/dist/commands/daemon/status.d.ts +11 -0
- package/dist/commands/daemon/status.js +47 -22
- package/dist/commands/hub/authority.d.ts +17 -0
- package/dist/commands/hub/authority.js +18 -0
- package/dist/commands/hub/connect.d.ts +21 -0
- package/dist/commands/hub/connect.js +34 -0
- package/dist/commands/hub/credentials.d.ts +21 -0
- package/dist/commands/hub/credentials.js +143 -0
- package/dist/commands/hub/daemon-client.d.ts +27 -0
- package/dist/commands/hub/daemon-client.js +14 -0
- package/dist/commands/hub/deploy-bundle.d.ts +16 -0
- package/dist/commands/hub/deploy-bundle.js +248 -0
- package/dist/commands/hub/deploy.d.ts +40 -0
- package/dist/commands/hub/deploy.js +90 -0
- package/dist/commands/hub/disconnect.d.ts +16 -0
- package/dist/commands/hub/disconnect.js +24 -0
- package/dist/commands/hub/error.d.ts +6 -0
- package/dist/commands/hub/error.js +9 -0
- package/dist/commands/hub/help.d.ts +3 -0
- package/dist/commands/hub/help.js +5 -0
- package/dist/commands/hub/hub-client/index.d.ts +19 -0
- package/dist/commands/hub/hub-client/index.js +99 -0
- package/dist/commands/hub/hub-client/internal/contracts.d.ts +86 -0
- package/dist/commands/hub/hub-client/internal/contracts.js +62 -0
- package/dist/commands/hub/hub-client/internal/problem.d.ts +3 -0
- package/dist/commands/hub/hub-client/internal/problem.js +85 -0
- package/dist/commands/hub/hub-client/internal/transport.d.ts +15 -0
- package/dist/commands/hub/hub-client/internal/transport.js +30 -0
- package/dist/commands/hub/index.d.ts +15 -25
- package/dist/commands/hub/index.js +67 -73
- package/dist/commands/hub/init-plan.d.ts +50 -0
- package/dist/commands/hub/init-plan.js +136 -0
- package/dist/commands/hub/init.d.ts +20 -0
- package/dist/commands/hub/init.js +415 -0
- package/dist/commands/hub/{device-authorization.d.ts → login-flow.d.ts} +12 -15
- package/dist/commands/hub/login-flow.js +78 -0
- package/dist/commands/hub/login.d.ts +21 -0
- package/dist/commands/hub/login.js +34 -0
- package/dist/commands/hub/logout.d.ts +32 -0
- package/dist/commands/hub/logout.js +71 -0
- package/dist/commands/hub/origin.d.ts +2 -0
- package/dist/commands/hub/origin.js +27 -0
- package/dist/commands/hub/projects.d.ts +24 -0
- package/dist/commands/hub/projects.js +49 -0
- package/dist/commands/hub/reporter.d.ts +10 -0
- package/dist/commands/hub/reporter.js +11 -0
- package/dist/commands/hub/status-output.d.ts +13 -0
- package/dist/commands/hub/status-output.js +30 -0
- package/dist/commands/onboard.js +20 -40
- package/dist/commands/provider/diagnostic.d.ts +12 -0
- package/dist/commands/provider/diagnostic.js +31 -0
- package/dist/commands/provider/index.js +5 -0
- package/dist/commands/schedule/types.d.ts +1 -4
- package/dist/commands/workspace/index.js +10 -0
- package/dist/commands/workspace/rename.d.ts +22 -0
- package/dist/commands/workspace/rename.js +61 -0
- package/dist/output/types.d.ts +1 -1
- package/dist/run.js +8 -1
- package/dist/utils/client.js +4 -1
- package/package.json +5 -5
- package/dist/commands/chat/create.d.ts +0 -9
- package/dist/commands/chat/create.js +0 -23
- package/dist/commands/chat/delete.d.ts +0 -6
- package/dist/commands/chat/delete.js +0 -20
- package/dist/commands/chat/index.d.ts +0 -3
- package/dist/commands/chat/index.js +0 -47
- package/dist/commands/chat/inspect.d.ts +0 -6
- package/dist/commands/chat/inspect.js +0 -20
- package/dist/commands/chat/ls.d.ts +0 -6
- package/dist/commands/chat/ls.js +0 -20
- package/dist/commands/chat/post.d.ts +0 -9
- package/dist/commands/chat/post.js +0 -28
- package/dist/commands/chat/read.d.ts +0 -11
- package/dist/commands/chat/read.js +0 -40
- package/dist/commands/chat/schema.d.ts +0 -36
- package/dist/commands/chat/schema.js +0 -81
- package/dist/commands/chat/shared.d.ts +0 -19
- package/dist/commands/chat/shared.js +0 -118
- package/dist/commands/chat/wait.d.ts +0 -9
- package/dist/commands/chat/wait.js +0 -45
- package/dist/commands/hub/cloud-device-authorization.d.ts +0 -45
- package/dist/commands/hub/cloud-device-authorization.js +0 -92
- package/dist/commands/hub/device-authorization.js +0 -87
- package/dist/commands/loop/index.d.ts +0 -3
- package/dist/commands/loop/index.js +0 -18
- package/dist/commands/loop/inspect.d.ts +0 -13
- package/dist/commands/loop/inspect.js +0 -100
- package/dist/commands/loop/logs.d.ts +0 -8
- package/dist/commands/loop/logs.js +0 -69
- package/dist/commands/loop/ls.d.ts +0 -18
- package/dist/commands/loop/ls.js +0 -62
- package/dist/commands/loop/run.d.ts +0 -30
- package/dist/commands/loop/run.js +0 -162
- package/dist/commands/loop/stop.d.ts +0 -15
- package/dist/commands/loop/stop.js +0 -56
- package/dist/commands/loop/types.d.ts +0 -138
- package/dist/commands/loop/types.js +0 -2
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const START_TIMEOUT_MS = 15000;
|
|
3
|
-
const activationUrlSchema = z.url({ protocol: /^https?$/u });
|
|
4
|
-
const authorizationSchema = z.object({
|
|
5
|
-
deviceCode: z.string().min(32),
|
|
6
|
-
userCode: z.string().min(1),
|
|
7
|
-
verificationUri: activationUrlSchema,
|
|
8
|
-
verificationUriComplete: activationUrlSchema,
|
|
9
|
-
expiresAt: z.string().datetime(),
|
|
10
|
-
interval: z.number().int().min(5),
|
|
11
|
-
});
|
|
12
|
-
const pollSchema = z.discriminatedUnion("status", [
|
|
13
|
-
z.object({ status: z.literal("pending"), interval: z.number().int().min(5) }),
|
|
14
|
-
z.object({ status: z.literal("slow_down"), interval: z.number().int().min(5) }),
|
|
15
|
-
z.object({
|
|
16
|
-
status: z.literal("approved"),
|
|
17
|
-
interval: z.number().int().min(5),
|
|
18
|
-
enrollmentToken: z.string().min(32),
|
|
19
|
-
}),
|
|
20
|
-
z.object({ status: z.literal("denied"), interval: z.number().int().min(5) }),
|
|
21
|
-
z.object({ status: z.literal("expired"), interval: z.number().int().min(5) }),
|
|
22
|
-
z.object({ status: z.literal("enrolled"), interval: z.number().int().min(5) }),
|
|
23
|
-
z.object({ status: z.literal("retry_later") }),
|
|
24
|
-
]);
|
|
25
|
-
export class CloudDeviceAuthorizationClient {
|
|
26
|
-
constructor(startTimeoutMilliseconds = START_TIMEOUT_MS) {
|
|
27
|
-
this.startTimeoutMilliseconds = startTimeoutMilliseconds;
|
|
28
|
-
}
|
|
29
|
-
async start(hubUrl, displayName) {
|
|
30
|
-
const signal = AbortSignal.timeout(this.startTimeoutMilliseconds);
|
|
31
|
-
try {
|
|
32
|
-
const response = await fetch(endpoint(hubUrl, "/api/device-authorizations/"), {
|
|
33
|
-
method: "POST",
|
|
34
|
-
headers: { "content-type": "application/json" },
|
|
35
|
-
body: JSON.stringify({ displayName }),
|
|
36
|
-
signal,
|
|
37
|
-
});
|
|
38
|
-
if (!response.ok)
|
|
39
|
-
throw new Error(`Cloud registration failed (${response.status})`);
|
|
40
|
-
return authorizationSchema.parse(await response.json());
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
if (signal.aborted) {
|
|
44
|
-
throw new Error("Cloud registration start timed out", { cause: error });
|
|
45
|
-
}
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async poll(hubUrl, deviceCode, timeoutMilliseconds) {
|
|
50
|
-
const signal = AbortSignal.timeout(timeoutMilliseconds);
|
|
51
|
-
let response;
|
|
52
|
-
try {
|
|
53
|
-
response = await fetch(endpoint(hubUrl, "/api/device-authorizations/poll"), {
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers: { "content-type": "application/json" },
|
|
56
|
-
body: JSON.stringify({ deviceCode }),
|
|
57
|
-
signal,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
return { status: "retry_later" };
|
|
62
|
-
}
|
|
63
|
-
if ([408, 425, 429].includes(response.status) || response.status >= 500) {
|
|
64
|
-
return { status: "retry_later" };
|
|
65
|
-
}
|
|
66
|
-
if (!response.ok)
|
|
67
|
-
throw new Error(`Cloud registration poll failed (${response.status})`);
|
|
68
|
-
let body;
|
|
69
|
-
try {
|
|
70
|
-
body = await response.json();
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
if (signal.aborted || error instanceof TypeError)
|
|
74
|
-
return { status: "retry_later" };
|
|
75
|
-
throw error;
|
|
76
|
-
}
|
|
77
|
-
return pollSchema.parse(body);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function endpoint(hubUrl, pathname) {
|
|
81
|
-
const url = new URL(hubUrl);
|
|
82
|
-
if (!["http:", "https:"].includes(url.protocol) ||
|
|
83
|
-
url.username ||
|
|
84
|
-
url.password ||
|
|
85
|
-
url.search ||
|
|
86
|
-
url.hash) {
|
|
87
|
-
throw new Error("Hub URL must be an HTTP or HTTPS origin without credentials or a query");
|
|
88
|
-
}
|
|
89
|
-
url.pathname = `${url.pathname.replace(/\/$/u, "")}${pathname}`;
|
|
90
|
-
return url.toString();
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=cloud-device-authorization.js.map
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { platform } from "node:os";
|
|
3
|
-
import { CloudDeviceAuthorizationClient, } from "./cloud-device-authorization.js";
|
|
4
|
-
export class SystemBrowser {
|
|
5
|
-
constructor(options = {}) {
|
|
6
|
-
this.hostPlatform = options.hostPlatform ?? platform();
|
|
7
|
-
this.launch = options.launch ?? launchDetached;
|
|
8
|
-
}
|
|
9
|
-
async open(url) {
|
|
10
|
-
if (this.hostPlatform === "win32") {
|
|
11
|
-
await this.launch("rundll32.exe", ["url.dll,FileProtocolHandler", url]);
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
await this.launch(this.hostPlatform === "darwin" ? "open" : "xdg-open", [url]);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export class DeviceAuthorizationWorkflow {
|
|
18
|
-
constructor(options) {
|
|
19
|
-
this.options = options;
|
|
20
|
-
}
|
|
21
|
-
async authorize(hubUrl, displayName) {
|
|
22
|
-
const authorization = await this.options.cloud.start(hubUrl, displayName);
|
|
23
|
-
this.options.reporter.instructions(authorization.verificationUri, authorization.userCode);
|
|
24
|
-
if (this.options.openBrowser !== false) {
|
|
25
|
-
await this.options.browser.open(authorization.verificationUriComplete).catch(() => undefined);
|
|
26
|
-
}
|
|
27
|
-
let interval = authorization.interval;
|
|
28
|
-
const expiresAt = Date.parse(authorization.expiresAt);
|
|
29
|
-
while (true) {
|
|
30
|
-
const remaining = expiresAt - this.options.waiter.now();
|
|
31
|
-
if (remaining <= 0)
|
|
32
|
-
throw new Error("Daemon registration expired");
|
|
33
|
-
await this.options.waiter.wait(Math.min(interval * 1000, remaining));
|
|
34
|
-
if (this.options.waiter.now() >= expiresAt)
|
|
35
|
-
throw new Error("Daemon registration expired");
|
|
36
|
-
const pollLifetime = expiresAt - this.options.waiter.now();
|
|
37
|
-
if (pollLifetime <= 0)
|
|
38
|
-
throw new Error("Daemon registration expired");
|
|
39
|
-
const outcome = await this.options.cloud.poll(hubUrl, authorization.deviceCode, pollLifetime);
|
|
40
|
-
if (this.options.waiter.now() >= expiresAt)
|
|
41
|
-
throw new Error("Daemon registration expired");
|
|
42
|
-
if (outcome.status === "retry_later")
|
|
43
|
-
continue;
|
|
44
|
-
interval = outcome.interval;
|
|
45
|
-
if (outcome.status === "approved")
|
|
46
|
-
return outcome.enrollmentToken;
|
|
47
|
-
if (outcome.status === "denied")
|
|
48
|
-
throw new Error("Daemon registration was denied");
|
|
49
|
-
if (outcome.status === "expired")
|
|
50
|
-
throw new Error("Daemon registration expired");
|
|
51
|
-
if (outcome.status === "enrolled") {
|
|
52
|
-
throw new Error("Daemon registration was already used");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export function createDeviceAuthorizationWorkflow() {
|
|
58
|
-
return new DeviceAuthorizationWorkflow({
|
|
59
|
-
cloud: new CloudDeviceAuthorizationClient(),
|
|
60
|
-
waiter: {
|
|
61
|
-
wait: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
62
|
-
now: Date.now,
|
|
63
|
-
},
|
|
64
|
-
browser: new SystemBrowser(),
|
|
65
|
-
reporter: {
|
|
66
|
-
instructions(verificationUri, userCode) {
|
|
67
|
-
process.stderr.write(`Open ${verificationUri} and enter code ${userCode}\n`);
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
openBrowser: process.stderr.isTTY === true,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
async function launchDetached(command, args) {
|
|
74
|
-
await new Promise((resolve, reject) => {
|
|
75
|
-
const child = spawn(command, args, {
|
|
76
|
-
detached: true,
|
|
77
|
-
shell: false,
|
|
78
|
-
stdio: "ignore",
|
|
79
|
-
});
|
|
80
|
-
child.once("spawn", () => {
|
|
81
|
-
child.unref();
|
|
82
|
-
resolve();
|
|
83
|
-
});
|
|
84
|
-
child.once("error", reject);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
//# sourceMappingURL=device-authorization.js.map
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import { withOutput } from "../../output/index.js";
|
|
3
|
-
import { addJsonAndDaemonHostOptions, addDaemonHostOption } from "../../utils/command-options.js";
|
|
4
|
-
import { addLoopRunOptions, runLoopRunCommand } from "./run.js";
|
|
5
|
-
import { addLoopLsOptions, runLoopLsCommand } from "./ls.js";
|
|
6
|
-
import { addLoopInspectOptions, runLoopInspectCommand } from "./inspect.js";
|
|
7
|
-
import { addLoopLogsOptions, runLoopLogsCommand } from "./logs.js";
|
|
8
|
-
import { addLoopStopOptions, runLoopStopCommand } from "./stop.js";
|
|
9
|
-
export function createLoopCommand() {
|
|
10
|
-
const loop = new Command("loop").description("Run iterative worker loops");
|
|
11
|
-
addJsonAndDaemonHostOptions(addLoopRunOptions(loop.command("run"))).action(withOutput(runLoopRunCommand));
|
|
12
|
-
addJsonAndDaemonHostOptions(addLoopLsOptions(loop.command("ls"))).action(withOutput(runLoopLsCommand));
|
|
13
|
-
addJsonAndDaemonHostOptions(addLoopInspectOptions(loop.command("inspect"))).action(withOutput(runLoopInspectCommand));
|
|
14
|
-
addDaemonHostOption(addLoopLogsOptions(loop.command("logs"))).action(runLoopLogsCommand);
|
|
15
|
-
addJsonAndDaemonHostOptions(addLoopStopOptions(loop.command("stop"))).action(withOutput(runLoopStopCommand));
|
|
16
|
-
return loop;
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import type { CommandOptions, ListResult } from "../../output/index.js";
|
|
3
|
-
interface InspectRow {
|
|
4
|
-
key: string;
|
|
5
|
-
value: string;
|
|
6
|
-
}
|
|
7
|
-
export interface LoopInspectOptions extends CommandOptions {
|
|
8
|
-
}
|
|
9
|
-
export declare function addLoopInspectOptions(command: Command): Command;
|
|
10
|
-
export type LoopInspectResult = ListResult<InspectRow>;
|
|
11
|
-
export declare function runLoopInspectCommand(id: string, options: LoopInspectOptions, _command: Command): Promise<LoopInspectResult>;
|
|
12
|
-
export {};
|
|
13
|
-
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
-
export function addLoopInspectOptions(command) {
|
|
3
|
-
return command.description("Show loop details and iteration history").argument("<id>", "Loop ID");
|
|
4
|
-
}
|
|
5
|
-
function createInspectSchema(loop) {
|
|
6
|
-
return {
|
|
7
|
-
idField: "key",
|
|
8
|
-
columns: [
|
|
9
|
-
{ header: "KEY", field: "key", width: 18 },
|
|
10
|
-
{ header: "VALUE", field: "value", width: 80 },
|
|
11
|
-
],
|
|
12
|
-
serialize: () => loop,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function toRows(loop) {
|
|
16
|
-
return [
|
|
17
|
-
{ key: "Id", value: loop.id },
|
|
18
|
-
{ key: "Name", value: loop.name ?? "null" },
|
|
19
|
-
{ key: "Status", value: loop.status },
|
|
20
|
-
{ key: "Cwd", value: loop.cwd },
|
|
21
|
-
{ key: "Provider", value: loop.provider },
|
|
22
|
-
{ key: "Model", value: loop.model ?? "null" },
|
|
23
|
-
{ key: "WorkerProvider", value: loop.workerProvider ?? "null" },
|
|
24
|
-
{ key: "WorkerModel", value: loop.workerModel ?? "null" },
|
|
25
|
-
{ key: "VerifierProvider", value: loop.verifierProvider ?? "null" },
|
|
26
|
-
{ key: "VerifierModel", value: loop.verifierModel ?? "null" },
|
|
27
|
-
{ key: "Prompt", value: loop.prompt },
|
|
28
|
-
{ key: "VerifyPrompt", value: loop.verifyPrompt ?? "null" },
|
|
29
|
-
{
|
|
30
|
-
key: "VerifyChecks",
|
|
31
|
-
value: loop.verifyChecks.length > 0 ? loop.verifyChecks.join(" | ") : "[]",
|
|
32
|
-
},
|
|
33
|
-
{ key: "Archive", value: String(loop.archive) },
|
|
34
|
-
{ key: "SleepMs", value: String(loop.sleepMs) },
|
|
35
|
-
{
|
|
36
|
-
key: "MaxIterations",
|
|
37
|
-
value: loop.maxIterations === null ? "null" : String(loop.maxIterations),
|
|
38
|
-
},
|
|
39
|
-
{ key: "MaxTimeMs", value: loop.maxTimeMs === null ? "null" : String(loop.maxTimeMs) },
|
|
40
|
-
{ key: "CreatedAt", value: loop.createdAt },
|
|
41
|
-
{ key: "UpdatedAt", value: loop.updatedAt },
|
|
42
|
-
{ key: "CompletedAt", value: loop.completedAt ?? "null" },
|
|
43
|
-
{
|
|
44
|
-
key: "Iterations",
|
|
45
|
-
value: loop.iterations.length === 0
|
|
46
|
-
? "[]"
|
|
47
|
-
: loop.iterations
|
|
48
|
-
.map((iteration) => {
|
|
49
|
-
const summary = [
|
|
50
|
-
`#${iteration.index}`,
|
|
51
|
-
iteration.status,
|
|
52
|
-
iteration.workerAgentId ? `worker=${iteration.workerAgentId}` : null,
|
|
53
|
-
iteration.verifierAgentId ? `verifier=${iteration.verifierAgentId}` : null,
|
|
54
|
-
iteration.failureReason ? `reason=${iteration.failureReason}` : null,
|
|
55
|
-
]
|
|
56
|
-
.filter(Boolean)
|
|
57
|
-
.join(" ");
|
|
58
|
-
return summary;
|
|
59
|
-
})
|
|
60
|
-
.join(" | "),
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
export async function runLoopInspectCommand(id, options, _command) {
|
|
65
|
-
const host = getDaemonHost({ host: options.host });
|
|
66
|
-
let client;
|
|
67
|
-
try {
|
|
68
|
-
client = (await connectToDaemon({
|
|
69
|
-
host: options.host,
|
|
70
|
-
}));
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
74
|
-
throw {
|
|
75
|
-
code: "DAEMON_NOT_RUNNING",
|
|
76
|
-
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
77
|
-
details: "Start the daemon with: otto daemon start",
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
const payload = await client.loopInspect(id);
|
|
82
|
-
await client.close();
|
|
83
|
-
if (payload.error || !payload.loop) {
|
|
84
|
-
throw new Error(payload.error ?? `Loop not found: ${id}`);
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
type: "list",
|
|
88
|
-
data: toRows(payload.loop),
|
|
89
|
-
schema: createInspectSchema(payload.loop),
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
await client.close().catch(() => { });
|
|
94
|
-
throw {
|
|
95
|
-
code: "LOOP_INSPECT_FAILED",
|
|
96
|
-
message: error instanceof Error ? error.message : String(error),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
//# sourceMappingURL=inspect.js.map
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import type { CommandOptions } from "../../output/index.js";
|
|
3
|
-
export interface LoopLogsOptions extends CommandOptions {
|
|
4
|
-
pollInterval?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function addLoopLogsOptions(command: Command): Command;
|
|
7
|
-
export declare function runLoopLogsCommand(id: string, options: LoopLogsOptions, _command: Command): Promise<void>;
|
|
8
|
-
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
-
export function addLoopLogsOptions(command) {
|
|
3
|
-
return command
|
|
4
|
-
.description("Stream loop logs")
|
|
5
|
-
.argument("<id>", "Loop ID")
|
|
6
|
-
.option("--poll-interval <ms>", "Polling interval in milliseconds", "1000");
|
|
7
|
-
}
|
|
8
|
-
function parsePollInterval(value) {
|
|
9
|
-
const parsed = Number.parseInt(value, 10);
|
|
10
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
11
|
-
throw {
|
|
12
|
-
code: "INVALID_POLL_INTERVAL",
|
|
13
|
-
message: "--poll-interval must be a positive integer",
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
return parsed;
|
|
17
|
-
}
|
|
18
|
-
function renderLogEntry(entry) {
|
|
19
|
-
const prefix = [
|
|
20
|
-
entry.timestamp,
|
|
21
|
-
entry.source,
|
|
22
|
-
entry.iteration === null ? null : `iteration=${entry.iteration}`,
|
|
23
|
-
entry.level === "error" ? "ERROR" : null,
|
|
24
|
-
]
|
|
25
|
-
.filter(Boolean)
|
|
26
|
-
.join(" ");
|
|
27
|
-
return `${prefix}\n${entry.text}`;
|
|
28
|
-
}
|
|
29
|
-
export async function runLoopLogsCommand(id, options, _command) {
|
|
30
|
-
const host = getDaemonHost({ host: options.host });
|
|
31
|
-
const pollInterval = parsePollInterval(options.pollInterval ?? "1000");
|
|
32
|
-
let client;
|
|
33
|
-
try {
|
|
34
|
-
client = (await connectToDaemon({
|
|
35
|
-
host: options.host,
|
|
36
|
-
}));
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
-
console.error(`Error: Cannot connect to daemon at ${host}: ${message}`);
|
|
41
|
-
console.error("Start the daemon with: otto daemon start");
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
async function streamLogs(cursor) {
|
|
45
|
-
const payload = await client.loopLogs(id, cursor);
|
|
46
|
-
if (payload.error || !payload.loop) {
|
|
47
|
-
throw new Error(payload.error ?? `Loop not found: ${id}`);
|
|
48
|
-
}
|
|
49
|
-
for (const entry of payload.entries) {
|
|
50
|
-
console.log(renderLogEntry(entry));
|
|
51
|
-
}
|
|
52
|
-
if (payload.loop.status !== "running") {
|
|
53
|
-
await client.close();
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
57
|
-
return streamLogs(payload.nextCursor);
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
await streamLogs(0);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
await client.close().catch(() => { });
|
|
64
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
-
console.error(`Error: Failed to stream loop logs: ${message}`);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=logs.js.map
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import type { CommandOptions, OutputSchema, ListResult } from "../../output/index.js";
|
|
3
|
-
interface LoopListRow {
|
|
4
|
-
id: string;
|
|
5
|
-
name: string | null;
|
|
6
|
-
status: string;
|
|
7
|
-
cwd: string;
|
|
8
|
-
updated: string;
|
|
9
|
-
activeIteration: string;
|
|
10
|
-
}
|
|
11
|
-
export interface LoopLsOptions extends CommandOptions {
|
|
12
|
-
}
|
|
13
|
-
export declare const loopLsSchema: OutputSchema<LoopListRow>;
|
|
14
|
-
export declare function addLoopLsOptions(command: Command): Command;
|
|
15
|
-
export type LoopLsResult = ListResult<LoopListRow>;
|
|
16
|
-
export declare function runLoopLsCommand(options: LoopLsOptions, _command: Command): Promise<LoopLsResult>;
|
|
17
|
-
export {};
|
|
18
|
-
//# sourceMappingURL=ls.d.ts.map
|
package/dist/commands/loop/ls.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
-
export const loopLsSchema = {
|
|
3
|
-
idField: "id",
|
|
4
|
-
columns: [
|
|
5
|
-
{ header: "LOOP ID", field: "id", width: 10 },
|
|
6
|
-
{ header: "NAME", field: "name", width: 20 },
|
|
7
|
-
{ header: "STATUS", field: "status", width: 10 },
|
|
8
|
-
{ header: "ITER", field: "activeIteration", width: 8 },
|
|
9
|
-
{ header: "CWD", field: "cwd", width: 40 },
|
|
10
|
-
{ header: "UPDATED", field: "updated", width: 24 },
|
|
11
|
-
],
|
|
12
|
-
};
|
|
13
|
-
export function addLoopLsOptions(command) {
|
|
14
|
-
return command.description("List loops");
|
|
15
|
-
}
|
|
16
|
-
function toRow(loop) {
|
|
17
|
-
return {
|
|
18
|
-
id: loop.id,
|
|
19
|
-
name: loop.name,
|
|
20
|
-
status: loop.status,
|
|
21
|
-
cwd: loop.cwd,
|
|
22
|
-
updated: loop.updatedAt,
|
|
23
|
-
activeIteration: loop.activeIteration === null ? "-" : String(loop.activeIteration),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
export async function runLoopLsCommand(options, _command) {
|
|
27
|
-
const host = getDaemonHost({ host: options.host });
|
|
28
|
-
let client;
|
|
29
|
-
try {
|
|
30
|
-
client = (await connectToDaemon({
|
|
31
|
-
host: options.host,
|
|
32
|
-
}));
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
36
|
-
throw {
|
|
37
|
-
code: "DAEMON_NOT_RUNNING",
|
|
38
|
-
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
39
|
-
details: "Start the daemon with: otto daemon start",
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
try {
|
|
43
|
-
const payload = await client.loopList();
|
|
44
|
-
await client.close();
|
|
45
|
-
if (payload.error) {
|
|
46
|
-
throw new Error(payload.error);
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
type: "list",
|
|
50
|
-
data: payload.loops.map(toRow),
|
|
51
|
-
schema: loopLsSchema,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
await client.close().catch(() => { });
|
|
56
|
-
throw {
|
|
57
|
-
code: "LOOP_LIST_FAILED",
|
|
58
|
-
message: error instanceof Error ? error.message : String(error),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=ls.js.map
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
2
|
-
import type { CommandOptions, OutputSchema, SingleResult } from "../../output/index.js";
|
|
3
|
-
import type { LoopRunInput } from "./types.js";
|
|
4
|
-
export interface LoopRunRow {
|
|
5
|
-
id: string;
|
|
6
|
-
status: string;
|
|
7
|
-
name: string | null;
|
|
8
|
-
cwd: string;
|
|
9
|
-
}
|
|
10
|
-
export interface LoopRunOptions extends CommandOptions {
|
|
11
|
-
provider?: string;
|
|
12
|
-
model?: string;
|
|
13
|
-
mode?: string;
|
|
14
|
-
verifyProvider?: string;
|
|
15
|
-
verifyModel?: string;
|
|
16
|
-
verifyMode?: string;
|
|
17
|
-
verify?: string;
|
|
18
|
-
verifyCheck?: string[];
|
|
19
|
-
archive?: boolean;
|
|
20
|
-
name?: string;
|
|
21
|
-
sleep?: string;
|
|
22
|
-
maxIterations?: string;
|
|
23
|
-
maxTime?: string;
|
|
24
|
-
}
|
|
25
|
-
export declare const loopRunSchema: OutputSchema<LoopRunRow>;
|
|
26
|
-
export declare function addLoopRunOptions(command: Command): Command;
|
|
27
|
-
export declare function buildLoopRunInput(prompt: string, options: LoopRunOptions): LoopRunInput;
|
|
28
|
-
export type LoopRunResult = SingleResult<LoopRunRow>;
|
|
29
|
-
export declare function runLoopRunCommand(prompt: string, options: LoopRunOptions, _command: Command): Promise<LoopRunResult>;
|
|
30
|
-
//# sourceMappingURL=run.d.ts.map
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { connectToDaemon, getDaemonHost } from "../../utils/client.js";
|
|
2
|
-
import { collectMultiple } from "../../utils/command-options.js";
|
|
3
|
-
import { parseDuration } from "../../utils/duration.js";
|
|
4
|
-
import { resolveProviderAndModel } from "../../utils/provider-model.js";
|
|
5
|
-
export const loopRunSchema = {
|
|
6
|
-
idField: "id",
|
|
7
|
-
columns: [
|
|
8
|
-
{ header: "LOOP ID", field: "id", width: 10 },
|
|
9
|
-
{ header: "STATUS", field: "status", width: 10 },
|
|
10
|
-
{ header: "NAME", field: "name", width: 20 },
|
|
11
|
-
{ header: "CWD", field: "cwd", width: 40 },
|
|
12
|
-
],
|
|
13
|
-
};
|
|
14
|
-
export function addLoopRunOptions(command) {
|
|
15
|
-
return command
|
|
16
|
-
.description("Start a loop")
|
|
17
|
-
.argument("<prompt>", "Prompt for each fresh worker iteration")
|
|
18
|
-
.option("--provider <provider>", "Default provider for worker and verifier agents")
|
|
19
|
-
.option("--model <model>", "Default model for worker and verifier agents")
|
|
20
|
-
.option("--mode <mode>", "Provider-specific mode for the worker agent (e.g. claude bypassPermissions, opencode build)")
|
|
21
|
-
.option("--verify-provider <provider>", "Provider for the verifier agent")
|
|
22
|
-
.option("--verify-model <model>", "Model for the verifier agent")
|
|
23
|
-
.option("--verify-mode <mode>", "Provider-specific mode for the verifier agent")
|
|
24
|
-
.option("--verify <prompt>", "Verifier agent prompt")
|
|
25
|
-
.option("--verify-check <command>", "Shell command that must exit 0 (repeatable)", collectMultiple, [])
|
|
26
|
-
.option("--archive", "Archive worker and verifier agents after each iteration")
|
|
27
|
-
.option("--name <name>", "Optional loop name")
|
|
28
|
-
.option("--sleep <duration>", "Delay between iterations (for example: 30s, 5m)")
|
|
29
|
-
.option("--max-iterations <n>", "Maximum number of iterations")
|
|
30
|
-
.option("--max-time <duration>", "Maximum total runtime (for example: 1h, 30m)");
|
|
31
|
-
}
|
|
32
|
-
function toRow(loop) {
|
|
33
|
-
return {
|
|
34
|
-
id: loop.id,
|
|
35
|
-
status: loop.status,
|
|
36
|
-
name: loop.name,
|
|
37
|
-
cwd: loop.cwd,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function parseMaxIterations(value) {
|
|
41
|
-
if (value === undefined) {
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
const parsed = Number.parseInt(value, 10);
|
|
45
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
46
|
-
throw {
|
|
47
|
-
code: "INVALID_MAX_ITERATIONS",
|
|
48
|
-
message: "--max-iterations must be a positive integer",
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return parsed;
|
|
52
|
-
}
|
|
53
|
-
// oxlint-disable complexity
|
|
54
|
-
export function buildLoopRunInput(prompt, options) {
|
|
55
|
-
const verifyPrompt = options.verify?.trim();
|
|
56
|
-
if (options.verify !== undefined && !verifyPrompt) {
|
|
57
|
-
throw {
|
|
58
|
-
code: "INVALID_VERIFY_PROMPT",
|
|
59
|
-
message: "--verify cannot be empty",
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
const result = {
|
|
63
|
-
prompt,
|
|
64
|
-
cwd: process.cwd(),
|
|
65
|
-
};
|
|
66
|
-
// Resolve provider/model
|
|
67
|
-
if (options.provider) {
|
|
68
|
-
const { provider, model } = resolveProviderAndModel({ provider: options.provider });
|
|
69
|
-
if (provider)
|
|
70
|
-
result.provider = provider;
|
|
71
|
-
// Explicit --model takes precedence over parsed model
|
|
72
|
-
if (options.model?.trim()) {
|
|
73
|
-
result.model = options.model.trim();
|
|
74
|
-
}
|
|
75
|
-
else if (model) {
|
|
76
|
-
result.model = model;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else if (options.model?.trim()) {
|
|
80
|
-
result.model = options.model.trim();
|
|
81
|
-
}
|
|
82
|
-
if (options.mode?.trim()) {
|
|
83
|
-
result.modeId = options.mode.trim();
|
|
84
|
-
}
|
|
85
|
-
// Resolve verifier provider/model
|
|
86
|
-
if (options.verifyProvider) {
|
|
87
|
-
const { provider, model } = resolveProviderAndModel({ provider: options.verifyProvider });
|
|
88
|
-
if (provider)
|
|
89
|
-
result.verifierProvider = provider;
|
|
90
|
-
// Explicit --verify-model takes precedence over parsed model
|
|
91
|
-
if (options.verifyModel?.trim()) {
|
|
92
|
-
result.verifierModel = options.verifyModel.trim();
|
|
93
|
-
}
|
|
94
|
-
else if (model) {
|
|
95
|
-
result.verifierModel = model;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else if (options.verifyModel?.trim()) {
|
|
99
|
-
result.verifierModel = options.verifyModel.trim();
|
|
100
|
-
}
|
|
101
|
-
if (options.verifyMode?.trim()) {
|
|
102
|
-
result.verifierModeId = options.verifyMode.trim();
|
|
103
|
-
}
|
|
104
|
-
if (verifyPrompt)
|
|
105
|
-
result.verifyPrompt = verifyPrompt;
|
|
106
|
-
if (options.verifyCheck && options.verifyCheck.length > 0) {
|
|
107
|
-
result.verifyChecks = options.verifyCheck;
|
|
108
|
-
}
|
|
109
|
-
if (options.archive)
|
|
110
|
-
result.archive = true;
|
|
111
|
-
if (options.name?.trim())
|
|
112
|
-
result.name = options.name.trim();
|
|
113
|
-
if (options.sleep)
|
|
114
|
-
result.sleepMs = parseDuration(options.sleep);
|
|
115
|
-
if (options.maxIterations) {
|
|
116
|
-
result.maxIterations = parseMaxIterations(options.maxIterations);
|
|
117
|
-
}
|
|
118
|
-
if (options.maxTime)
|
|
119
|
-
result.maxTimeMs = parseDuration(options.maxTime);
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
export async function runLoopRunCommand(prompt, options, _command) {
|
|
123
|
-
const host = getDaemonHost({ host: options.host });
|
|
124
|
-
const input = buildLoopRunInput(prompt, options);
|
|
125
|
-
let client;
|
|
126
|
-
try {
|
|
127
|
-
client = (await connectToDaemon({
|
|
128
|
-
host: options.host,
|
|
129
|
-
}));
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
133
|
-
throw {
|
|
134
|
-
code: "DAEMON_NOT_RUNNING",
|
|
135
|
-
message: `Cannot connect to daemon at ${host}: ${message}`,
|
|
136
|
-
details: "Start the daemon with: otto daemon start",
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
const payload = await client.loopRun(input);
|
|
141
|
-
await client.close();
|
|
142
|
-
if (payload.error || !payload.loop) {
|
|
143
|
-
throw new Error(payload.error ?? "Loop creation failed");
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
type: "single",
|
|
147
|
-
data: toRow(payload.loop),
|
|
148
|
-
schema: loopRunSchema,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
await client.close().catch(() => { });
|
|
153
|
-
if (error && typeof error === "object" && "code" in error) {
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
throw {
|
|
157
|
-
code: "LOOP_RUN_FAILED",
|
|
158
|
-
message: error instanceof Error ? error.message : String(error),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=run.js.map
|