Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4b7a4a2
refactor(cli): extract sandbox live state helpers
cv May 2, 2026
2ce87dd
refactor(cli): extract sandbox skill install action
cv May 2, 2026
4cd3cf3
refactor(cli): extract sandbox connect action
cv May 3, 2026
e9dd46e
refactor(cli): extract sandbox status action
cv May 3, 2026
aab6c86
refactor(cli): extract sandbox doctor action
cv May 3, 2026
8908521
refactor(cli): extract sandbox destroy action
cv May 3, 2026
56e4f05
refactor(cli): extract sandbox rebuild action
cv May 3, 2026
8bf1958
refactor(cli): extract upgrade sandboxes action
cv May 3, 2026
38eb84d
refactor(cli): remove runtime bridge
cv May 3, 2026
b2ad5da
refactor(cli): remove legacy dispatch fallbacks
cv May 3, 2026
edd2650
refactor(cli): expose explicit main entrypoint
cv May 3, 2026
a15da95
refactor(cli): add oclif examples for utility commands
cv May 3, 2026
4f57ebb
refactor(cli): validate logs flags with oclif
cv May 3, 2026
8b2d077
refactor(cli): improve sandbox diagnostic command metadata
cv May 3, 2026
a09cc51
refactor(cli): tighten policy and channel parser validation
cv May 3, 2026
75857dc
refactor(cli): improve snapshot command metadata
cv May 3, 2026
11c0676
refactor(cli): require skill install path in oclif
cv May 3, 2026
05f9eca
refactor(cli): add lifecycle confirmation flag aliases
cv May 3, 2026
4ebeae4
refactor(cli): split share into oclif subcommands
cv May 3, 2026
7d72437
Revert "refactor(cli): split share into oclif subcommands"
cv May 3, 2026
0ee5ca5
refactor(cli): split share into oclif subcommands
cv May 3, 2026
928219c
refactor(cli): model debug flags with oclif
cv May 3, 2026
d6cb358
merge(main): reconcile debug flag metadata
cv May 5, 2026
52eb5a1
Merge branch 'main' into refactor/oclif-ux-debug-flags
prekshivyas May 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions src/lib/debug-cli-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@

/* v8 ignore start -- thin oclif adapter covered through CLI integration tests. */

import { Command } from "@oclif/core";
import { Command, Flags } from "@oclif/core";

import type { CaptureOpenshellResult } from "./openshell";
import type { RunDebugCommandDeps } from "./debug-command";
import { CLI_NAME } from "./branding";
import { runDebug } from "./debug";
import { runDebugCommand } from "./debug-command";
import { OPENSHELL_PROBE_TIMEOUT_MS } from "./openshell-timeouts";
import type { DebugOptions } from "./debug";
import type { RunDebugCommandDeps } from "./debug-command";
import { runDebugCommandWithOptions } from "./debug-command";
import type { CaptureOpenshellResult } from "./openshell";
import { captureOpenshellCommand } from "./openshell";
import { parseLiveSandboxNames } from "./runtime-recovery";
import { OPENSHELL_PROBE_TIMEOUT_MS } from "./openshell-timeouts";
import * as registry from "./registry";
import { resolveOpenshell } from "./resolve-openshell";
import { parseLiveSandboxNames } from "./runtime-recovery";

const useColor = !process.env.NO_COLOR && !!process.stderr.isTTY;
const B = useColor ? "\x1b[1m" : "";
Expand Down Expand Up @@ -70,13 +71,28 @@ function buildDebugCommandDeps(rootDir: string): RunDebugCommandDeps {

export default class DebugCliCommand extends Command {
static id = "debug";
static strict = false;
static strict = true;
static summary = "Collect diagnostics for bug reports";
static description = "Collect NemoClaw diagnostic information.";
static usage = ["debug [--quick] [--output FILE] [--sandbox NAME]"];
static usage = ["debug [--quick|-q] [--output FILE|-o FILE] [--sandbox NAME]"];
static examples = [
"<%= config.bin %> debug --quick",
"<%= config.bin %> debug --sandbox alpha",
"<%= config.bin %> debug --output /tmp/nemoclaw-debug.tar.gz",
];
static flags = {
help: Flags.help({ char: "h" }),
quick: Flags.boolean({ char: "q", description: "Only collect minimal diagnostics" }),
output: Flags.string({ char: "o", description: "Write a tarball to FILE" }),
sandbox: Flags.string({ description: "Target sandbox name" }),
};

public async run(): Promise<void> {
this.parsed = true;
runDebugCommand(this.argv, buildDebugCommandDeps(this.config.root));
const { flags } = await this.parse(DebugCliCommand);
const options: DebugOptions = {};
if (flags.quick) options.quick = true;
if (flags.output) options.output = flags.output;
if (flags.sandbox) options.sandboxName = flags.sandbox;
runDebugCommandWithOptions(options, buildDebugCommandDeps(this.config.root));
}
}
23 changes: 22 additions & 1 deletion src/lib/debug-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@

import { describe, expect, it, vi } from "vitest";

import { parseDebugArgs, printDebugHelp, runDebugCommand } from "../../dist/lib/debug-command";
import {
parseDebugArgs,
printDebugHelp,
runDebugCommand,
runDebugCommandWithOptions,
} from "../../dist/lib/debug-command";

function exitWithCode(code: number): never {
throw new Error(`exit:${code}`);
Expand Down Expand Up @@ -40,6 +45,22 @@ describe("debug command", () => {
expect(runDebug).toHaveBeenCalledWith({ sandboxName: "beta" });
});

it("runs parsed debug options and falls back to the default sandbox", () => {
const runDebug = vi.fn();
runDebugCommandWithOptions({ quick: true, output: "/tmp/out.tgz" }, {
getDefaultSandbox: () => "alpha",
runDebug,
log: () => {},
error: () => {},
exit: exitWithCode,
});
expect(runDebug).toHaveBeenCalledWith({
quick: true,
output: "/tmp/out.tgz",
sandboxName: "alpha",
});
});

it("--sandbox overrides the default sandbox", () => {
const runDebug = vi.fn();
runDebugCommand(["--sandbox", "mybox"], {
Expand Down
8 changes: 8 additions & 0 deletions src/lib/debug-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ export function parseDebugArgs(
return opts;
}

export function runDebugCommandWithOptions(options: DebugOptions, deps: RunDebugCommandDeps): void {
const opts = { ...options };
if (!opts.sandboxName) {
opts.sandboxName = deps.getDefaultSandbox();
}
deps.runDebug(opts);
}

export function runDebugCommand(args: string[], deps: RunDebugCommandDeps): void {
const opts = parseDebugArgs(args, deps);
deps.runDebug(opts);
Expand Down
5 changes: 3 additions & 2 deletions test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1148,8 +1148,8 @@ describe("CLI dispatch", () => {

it("debug exits 1 on unknown option", () => {
const r = run("debug --quik");
expect(r.code).toBe(1);
expect(r.out.includes("Unknown option")).toBeTruthy();
expect(r.code).not.toBe(0);
expect(r.out).toContain("Nonexistent flag: --quik");
});

it("help mentions debug command", () => {
Expand All @@ -1172,6 +1172,7 @@ describe("CLI dispatch", () => {
it("debug --sandbox without a name exits 1", () => {
const r = run("debug --sandbox");
expect(r.code).not.toBe(0);
expect(r.out).toContain("--sandbox");
});

it("debug warns when default sandbox is stale", testTimeoutOptions(), () => {
Expand Down
Loading