mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 17:20:43 +00:00
feat: add Crestodian setup helper
This commit is contained in:
@@ -51,6 +51,11 @@ const coreEntrySpecs: readonly CommandGroupDescriptorSpec<
|
||||
>[] = [
|
||||
...withProgramOnlySpecs(
|
||||
defineImportedProgramCommandGroupSpecs([
|
||||
{
|
||||
commandNames: ["crestodian"],
|
||||
loadModule: () => import("./register.crestodian.js"),
|
||||
exportName: "registerCrestodianCommand",
|
||||
},
|
||||
{
|
||||
commandNames: ["setup"],
|
||||
loadModule: () => import("./register.setup.js"),
|
||||
|
||||
@@ -37,6 +37,12 @@ vi.mock("./register.status-health-sessions.js", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("./register.crestodian.js", () => ({
|
||||
registerCrestodianCommand: (program: Command) => {
|
||||
program.command("crestodian");
|
||||
},
|
||||
}));
|
||||
|
||||
import {
|
||||
getCoreCliCommandNames,
|
||||
getCoreCliCommandsWithSubcommands,
|
||||
@@ -67,6 +73,7 @@ describe("command-registry", () => {
|
||||
|
||||
it("includes both agent and agents in core CLI command names", () => {
|
||||
const names = getCoreCliCommandNames();
|
||||
expect(names).toContain("crestodian");
|
||||
expect(names).toContain("mcp");
|
||||
expect(names).toContain("agent");
|
||||
expect(names).toContain("agents");
|
||||
@@ -81,6 +88,7 @@ describe("command-registry", () => {
|
||||
expect(names).toContain("sessions");
|
||||
expect(names).toContain("tasks");
|
||||
expect(names).not.toContain("agent");
|
||||
expect(names).not.toContain("crestodian");
|
||||
expect(names).not.toContain("status");
|
||||
expect(names).not.toContain("doctor");
|
||||
});
|
||||
|
||||
@@ -4,6 +4,11 @@ import type { NamedCommandDescriptor } from "./command-group-descriptors.js";
|
||||
export type CoreCliCommandDescriptor = NamedCommandDescriptor;
|
||||
|
||||
const coreCliCommandCatalog = defineCommandDescriptorCatalog([
|
||||
{
|
||||
name: "crestodian",
|
||||
description: "Open the ring-zero setup and repair helper",
|
||||
hasSubcommands: false,
|
||||
},
|
||||
{
|
||||
name: "setup",
|
||||
description: "Initialize local config and agent workspace",
|
||||
|
||||
37
src/cli/program/register.crestodian.ts
Normal file
37
src/cli/program/register.crestodian.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Command } from "commander";
|
||||
import { runCrestodian } from "../../crestodian/crestodian.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { theme } from "../../terminal/theme.js";
|
||||
import { runCommandWithRuntime } from "../cli-utils.js";
|
||||
import { formatHelpExamples } from "../help-format.js";
|
||||
|
||||
export function registerCrestodianCommand(program: Command) {
|
||||
program
|
||||
.command("crestodian")
|
||||
.description("Open the ring-zero setup and repair helper")
|
||||
.option("-m, --message <text>", "Run one Crestodian request")
|
||||
.option("--yes", "Approve persistent config writes for this request", false)
|
||||
.option("--json", "Output startup overview as JSON", false)
|
||||
.addHelpText(
|
||||
"after",
|
||||
() =>
|
||||
`\n${theme.heading("Examples:")}\n${formatHelpExamples([
|
||||
["openclaw", "Start Crestodian."],
|
||||
["openclaw crestodian", "Start Crestodian explicitly."],
|
||||
['openclaw crestodian -m "status"', "Run one status request."],
|
||||
[
|
||||
'openclaw crestodian -m "set default model openai/gpt-5.2" --yes',
|
||||
"Apply a typed config write.",
|
||||
],
|
||||
])}`,
|
||||
)
|
||||
.action(async (opts) => {
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
await runCrestodian({
|
||||
message: opts.message as string | undefined,
|
||||
yes: Boolean(opts.yes),
|
||||
json: Boolean(opts.json),
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerOnboardCommand } from "./register.onboard.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
runCrestodian: vi.fn(),
|
||||
setupWizardCommandMock: vi.fn(),
|
||||
runtime: {
|
||||
log: vi.fn(),
|
||||
@@ -14,10 +15,6 @@ const mocks = vi.hoisted(() => ({
|
||||
const setupWizardCommandMock = mocks.setupWizardCommandMock;
|
||||
const runtime = mocks.runtime;
|
||||
|
||||
vi.mock("../../commands/auth-choice-options.static.js", () => ({
|
||||
formatStaticAuthChoiceChoicesForCli: () => "token|oauth",
|
||||
}));
|
||||
|
||||
vi.mock("../../commands/auth-choice-options.js", () => ({
|
||||
formatAuthChoiceChoicesForCli: () => "token|oauth|openai-api-key",
|
||||
}));
|
||||
@@ -46,6 +43,10 @@ vi.mock("../../commands/onboard.js", () => ({
|
||||
setupWizardCommand: mocks.setupWizardCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../crestodian/crestodian.js", () => ({
|
||||
runCrestodian: mocks.runCrestodian,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: mocks.runtime,
|
||||
}));
|
||||
@@ -59,6 +60,7 @@ describe("registerOnboardCommand", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mocks.runCrestodian.mockResolvedValue(undefined);
|
||||
setupWizardCommandMock.mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
@@ -71,6 +73,7 @@ describe("registerOnboardCommand", () => {
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
expect(mocks.runCrestodian).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets installDaemon from explicit install flags and prioritizes --skip-daemon", async () => {
|
||||
@@ -171,4 +174,28 @@ describe("registerOnboardCommand", () => {
|
||||
expect(runtime.error).toHaveBeenCalledWith("Error: setup failed");
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("routes --modern to Crestodian", async () => {
|
||||
await runCli(["onboard", "--modern", "--json"]);
|
||||
|
||||
expect(setupWizardCommandMock).not.toHaveBeenCalled();
|
||||
expect(mocks.runCrestodian).toHaveBeenCalledWith({
|
||||
message: undefined,
|
||||
yes: false,
|
||||
json: true,
|
||||
interactive: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses a noninteractive overview for modern noninteractive onboarding", async () => {
|
||||
await runCli(["onboard", "--modern", "--non-interactive"]);
|
||||
|
||||
expect(setupWizardCommandMock).not.toHaveBeenCalled();
|
||||
expect(mocks.runCrestodian).toHaveBeenCalledWith({
|
||||
message: "overview",
|
||||
yes: false,
|
||||
json: false,
|
||||
interactive: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,6 +76,7 @@ export function registerOnboardCommand(program: Command) {
|
||||
)
|
||||
.option("--reset-scope <scope>", "Reset scope: config|config+creds+sessions|full")
|
||||
.option("--non-interactive", "Run without prompts", false)
|
||||
.option("--modern", "Use the Crestodian conversational onboarding preview", false)
|
||||
.option(
|
||||
"--accept-risk",
|
||||
"Acknowledge that agents are powerful and full system access is risky (required for --non-interactive)",
|
||||
@@ -142,6 +143,16 @@ export function registerOnboardCommand(program: Command) {
|
||||
|
||||
command.action(async (opts, commandRuntime) => {
|
||||
await runCommandWithRuntime(defaultRuntime, async () => {
|
||||
if (opts.modern) {
|
||||
const { runCrestodian } = await import("../../crestodian/crestodian.js");
|
||||
await runCrestodian({
|
||||
message: opts.nonInteractive ? "overview" : undefined,
|
||||
yes: false,
|
||||
json: Boolean(opts.json),
|
||||
interactive: !opts.nonInteractive,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const installDaemon = resolveInstallDaemonFlag(commandRuntime, {
|
||||
installDaemon: Boolean(opts.installDaemon),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user