Skip to content
Merged
29 changes: 29 additions & 0 deletions src/lib/legacy-oclif-dispatch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,33 @@ describe("resolveSandboxOclifDispatch", () => {
usage: "recover",
});
});

it("routes policy-add missing-value errors through a raw oclif adapter", () => {
expect(resolveSandboxOclifDispatch("alpha", "policy-add", ["--from-file"])).toEqual({
kind: "oclif",
commandId: "sandbox:policy-add:raw",
args: ["alpha", "--from-file"],
});
});

it("routes skill help and unknown subcommands through oclif", () => {
expect(resolveSandboxOclifDispatch("alpha", "skill", ["--help"])).toEqual({
kind: "oclif",
commandId: "sandbox:skill",
args: ["alpha", "--help"],
});
expect(resolveSandboxOclifDispatch("alpha", "skill", ["bogus"])).toEqual({
kind: "oclif",
commandId: "sandbox:skill",
args: ["alpha", "bogus"],
});
});

it("routes snapshot unknown subcommands through oclif", () => {
expect(resolveSandboxOclifDispatch("alpha", "snapshot", ["bogus"])).toEqual({
kind: "oclif",
commandId: "sandbox:snapshot",
args: ["alpha", "bogus"],
});
});
});
16 changes: 5 additions & 11 deletions src/lib/legacy-oclif-dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ export type UsageErrorDispatch = {
lines: string[];
};

export type LegacyDispatch = {
kind: "legacy";
target: "policy-add" | "skill" | "snapshot";
};

export type UnknownSubcommandDispatch = {
kind: "unknownSubcommand";
command: "credentials" | "channels";
Expand All @@ -39,7 +34,6 @@ export type DispatchResult =
| OclifDispatch
| HelpDispatch
| UsageErrorDispatch
| LegacyDispatch
| UnknownSubcommandDispatch
| UnknownActionDispatch;

Expand Down Expand Up @@ -126,7 +120,7 @@ export function resolveSandboxOclifDispatch(
};
}
if (hasMissingFlagValue(actionArgs, "--from-file") || hasMissingFlagValue(actionArgs, "--from-dir")) {
return { kind: "legacy", target: "policy-add" };
return { kind: "oclif", commandId: "sandbox:policy-add:raw", args: [sandboxName, ...actionArgs] };
}
return { kind: "oclif", commandId: "sandbox:policy-add", args: [sandboxName, ...actionArgs] };
case "policy-remove":
Expand All @@ -145,13 +139,13 @@ export function resolveSandboxOclifDispatch(
const skillSub = actionArgs[0];
const skillArgs = actionArgs.slice(1);
if (!skillSub || skillSub === "help" || skillSub === "--help" || skillSub === "-h") {
return { kind: "legacy", target: "skill" };
return { kind: "oclif", commandId: "sandbox:skill", args: [sandboxName, ...actionArgs] };
}
if (skillSub === "install") {
if (hasHelpFlag(skillArgs)) return { kind: "legacy", target: "skill" };
if (hasHelpFlag(skillArgs)) return { kind: "oclif", commandId: "sandbox:skill", args: [sandboxName, ...actionArgs] };
return { kind: "oclif", commandId: "sandbox:skill:install", args: [sandboxName, ...skillArgs] };
}
return { kind: "legacy", target: "skill" };
return { kind: "oclif", commandId: "sandbox:skill", args: [sandboxName, ...actionArgs] };
}
case "rebuild":
if (hasHelpFlag(actionArgs)) return { kind: "help", usage: "rebuild [--yes|--force] [--verbose|-v]" };
Expand All @@ -176,7 +170,7 @@ export function resolveSandboxOclifDispatch(
if (hasHelpFlag(snapshotArgs)) return { kind: "help", usage: "snapshot restore [selector] [--to <dst>]" };
return { kind: "oclif", commandId: "sandbox:snapshot:restore", args: [sandboxName, ...snapshotArgs] };
}
return { kind: "legacy", target: "snapshot" };
return { kind: "oclif", commandId: "sandbox:snapshot", args: [sandboxName, ...actionArgs] };
}
case "shields": {
const shieldsSub = actionArgs[0];
Expand Down
12 changes: 10 additions & 2 deletions src/lib/oclif-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
GarbageCollectImagesCommand,
UpgradeSandboxesCommand,
} from "./maintenance-cli-commands";
import { PolicyAddCommand, PolicyRemoveCommand } from "./policy-mutate-cli-commands";
import {
PolicyAddCommand,
PolicyAddRawCommand,
PolicyRemoveCommand,
} from "./policy-mutate-cli-commands";
import RebuildCliCommand from "./rebuild-cli-command";
import RecoverCliCommand from "./recover-cli-command";
import SandboxDoctorCliCommand from "./sandbox-doctor-cli-command";
Expand All @@ -46,8 +50,9 @@ import {
ShieldsUpCommand,
} from "./shields-cli-commands";
import ShareCommand from "./share-command";
import SkillInstallCliCommand from "./skill-install-cli-command";
import SkillInstallCliCommand, { SkillCliCommand } from "./skill-install-cli-command";
import {
SnapshotCommand,
SnapshotCreateCommand,
SnapshotListCommand,
SnapshotRestoreCommand,
Expand Down Expand Up @@ -83,14 +88,17 @@ export default {
"sandbox:doctor": SandboxDoctorCliCommand,
"sandbox:logs": SandboxLogsCommand,
"sandbox:policy-add": PolicyAddCommand,
"sandbox:policy-add:raw": PolicyAddRawCommand,
"sandbox:policy-list": SandboxPolicyListCommand,
"sandbox:policy-remove": PolicyRemoveCommand,
"sandbox:rebuild": RebuildCliCommand,
"sandbox:recover": RecoverCliCommand,
"sandbox:shields:down": ShieldsDownCommand,
"sandbox:shields:status": ShieldsStatusCommand,
"sandbox:shields:up": ShieldsUpCommand,
"sandbox:skill": SkillCliCommand,
"sandbox:skill:install": SkillInstallCliCommand,
"sandbox:snapshot": SnapshotCommand,
"sandbox:snapshot:create": SnapshotCreateCommand,
"sandbox:snapshot:list": SnapshotListCommand,
"sandbox:snapshot:restore": SnapshotRestoreCommand,
Expand Down
14 changes: 14 additions & 0 deletions src/lib/policy-mutate-cli-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ export class PolicyAddCommand extends Command {
}
}

export class PolicyAddRawCommand extends Command {
static id = "sandbox:policy-add:raw";
static strict = false;
static hidden = true;

public async run(): Promise<void> {
const [sandboxName, ...actionArgs] = this.argv;
if (!sandboxName || sandboxName.trim() === "") {
this.error("Missing required sandboxName for policy-add.", { exit: 2 });
}
await getRuntimeBridge().sandboxPolicyAdd(sandboxName, actionArgs);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

export class PolicyRemoveCommand extends Command {
static id = "sandbox:policy-remove";
static strict = true;
Expand Down
16 changes: 16 additions & 0 deletions src/lib/skill-install-cli-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ function getRuntimeBridge() {
return runtimeBridgeFactory();
}

export class SkillCliCommand extends Command {
static id = "sandbox:skill";
static strict = false;
static summary = "Show skill command usage";
static description = "Show skill install usage or report unknown skill subcommands.";
static usage = ["<name> skill install <path>"];

public async run(): Promise<void> {
const [sandboxName, ...actionArgs] = this.argv;
if (!sandboxName || sandboxName.trim() === "") {
this.error("Missing required sandboxName for skill.", { exit: 2 });
}
await getRuntimeBridge().sandboxSkillInstall(sandboxName, actionArgs);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

export default class SkillInstallCliCommand extends Command {
static id = "sandbox:skill:install";
static strict = true;
Expand Down
16 changes: 16 additions & 0 deletions src/lib/snapshot-cli-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ const sandboxNameArg = Args.string({
required: true,
});

export class SnapshotCommand extends Command {
static id = "sandbox:snapshot";
static strict = false;
static summary = "Show snapshot usage";
static description = "Show snapshot usage or report unknown snapshot subcommands.";
static usage = ["<name> snapshot <create|list|restore>"];

public async run(): Promise<void> {
const [sandboxName, ...actionArgs] = this.argv;
if (!sandboxName || sandboxName.trim() === "") {
this.error("Missing required sandboxName for snapshot.", { exit: 2 });
}
await getRuntimeBridge().sandboxSnapshot(sandboxName, actionArgs);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

export class SnapshotListCommand extends Command {
static id = "sandbox:snapshot:list";
static strict = true;
Expand Down
32 changes: 0 additions & 32 deletions src/nemoclaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,38 +249,6 @@ async function runDispatchResult(
console.error(` Unknown action: ${result.action}`);
console.error(` Valid actions: ${VALID_SANDBOX_ACTIONS}`);
process.exit(1);
case "legacy": {
const sandboxName = opts.sandboxName;
const actionArgs = opts.actionArgs ?? [];
if (!sandboxName) {
throw new Error(`Missing sandbox name for legacy dispatch target ${result.target}`);
}
switch (result.target) {
case "policy-add": {
const { addSandboxPolicy } = require("./lib/policy-channel-actions") as {
addSandboxPolicy: (sandboxName: string, args?: string[]) => Promise<void>;
};
await addSandboxPolicy(sandboxName, actionArgs);
return;
}
case "skill": {
const { installSandboxSkill } = require("./lib/sandbox-skill-install-action") as {
installSandboxSkill: (sandboxName: string, args?: string[]) => Promise<void>;
};
await installSandboxSkill(sandboxName, actionArgs);
return;
}
case "snapshot": {
const { runSandboxSnapshot } = require("./lib/snapshot-action") as {
runSandboxSnapshot: (sandboxName: string, args: string[]) => Promise<void>;
};
await runSandboxSnapshot(sandboxName, actionArgs);
return;
}
default:
throw new Error(`Unhandled legacy dispatch target ${result.target}`);
}
}
}
}

Expand Down
Loading