Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 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
36cce5e
refactor(cli): model onboard flags with oclif
cv May 3, 2026
702afb1
docs: sync oclif UX command reference
cv May 3, 2026
3224350
refactor(cli): extract public argv normalizer
cv May 3, 2026
cd4cdb8
refactor(cli): rename oclif dispatch module
cv May 3, 2026
9499ca6
refactor(cli): normalize policy command ids
cv May 3, 2026
42028ef
test(cli): require oclif command metadata
cv May 3, 2026
a05c6b3
refactor(cli): return typed debug parse results
cv May 3, 2026
1875fe9
refactor(cli): add public command display ids
cv May 3, 2026
36f1dbe
refactor(cli): use oclif summaries in root help
cv May 3, 2026
78bfd5a
refactor(cli): table-drive sandbox dispatch
cv May 3, 2026
96ce61f
refactor(cli): normalize gateway token command id
cv May 3, 2026
266ebc9
refactor(cli): render public oclif help
cv May 3, 2026
dc98994
refactor(cli): add shared oclif command base
cv May 3, 2026
d0d2a70
refactor(cli): use oclif flag relationships
cv May 3, 2026
8396c06
refactor(cli): pass lifecycle typed options
cv May 3, 2026
1532b19
refactor(cli): parse durations with oclif flags
cv May 3, 2026
7c0445a
refactor(cli): project public help through oclif
cv May 3, 2026
3978c32
test(cli): cover oclif metadata routing helpers
cv May 3, 2026
591eabb
test(cli): cover global oclif command adapters
cv May 3, 2026
8a6ecbc
test(cli): cover sandbox oclif command adapters
cv May 3, 2026
e5aa22f
refactor(cli): split share oclif commands
cv May 3, 2026
e179336
test(cli): narrow sandbox logs coverage ignores
cv May 3, 2026
a629813
test(cli): cover remaining global oclif adapters
cv May 3, 2026
c5954e7
test(cli): cover credentials oclif adapter
cv May 3, 2026
3380de9
test(cli): cover runtime utility helpers
cv May 3, 2026
f60a190
test(cli): improve global adapter coverage
cv May 3, 2026
78a16d1
merge: sync simple global adapter coverage
cv May 3, 2026
a58dc90
merge: sync credentials adapter coverage
cv May 3, 2026
034454f
merge: include credentials adapter coverage
cv May 3, 2026
28bc497
merge: sync combined global adapter coverage
cv May 3, 2026
e9ed6ba
test(cli): cover global action facade
cv May 3, 2026
00b288c
merge: sync global action facade coverage
cv May 3, 2026
7bd5f32
test(cli): stabilize coverage dist sourcemaps
cv May 4, 2026
d4b55d9
test(cli): rebaseline clean-dist function coverage
cv May 4, 2026
b872474
refactor(cli): extract maintenance image helpers
cv May 4, 2026
4965762
refactor(cli): extract upgrade sandbox helpers
cv May 4, 2026
9acd660
refactor(cli): extract sandbox destroy helpers
cv May 4, 2026
cc0eaa1
refactor(cli): extract sandbox logs helpers
cv May 4, 2026
847e115
refactor(cli): extract policy channel helpers
cv May 4, 2026
b6c0f5a
test(cli): allow clean coverage variance
cv May 4, 2026
5c98bd1
merge: sync coverage stabilization
cv May 4, 2026
4754f3e
merge: sync maintenance helper extraction
cv May 4, 2026
96f0758
merge: sync upgrade helper extraction
cv May 4, 2026
b6bd105
merge: sync destroy helper extraction
cv May 4, 2026
98fb75d
merge: sync logs helper extraction
cv May 4, 2026
5920d5b
test(cli): keep destroy helpers outside coverage ratchet
cv May 4, 2026
64d1646
merge: sync destroy helper coverage boundary
cv May 4, 2026
717c482
test(cli): keep logs helpers outside coverage ratchet
cv May 4, 2026
688074f
merge: sync logs helper coverage boundary
cv May 4, 2026
1314270
test(cli): keep policy channel helpers outside coverage ratchet
cv May 4, 2026
79d81c2
refactor(cli): group oclif core modules
cv May 4, 2026
5453a89
refactor(cli): split oclif commands by command tree
cv May 4, 2026
bbc297f
test(cli): reset credential command helper cache
cv May 4, 2026
25224c1
test(cli): avoid generic warning assertion in debug output
cv May 4, 2026
1ed9256
refactor(cli): group pure domain helpers
cv May 4, 2026
79e05ff
merge(main): reconcile domain helper grouping
cv May 6, 2026
3bb17fb
Merge branch 'main' into refactor/layer-domain-helpers
prekshivyas May 6, 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
4 changes: 2 additions & 2 deletions src/lib/commands/sandbox/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import { Args, Command, Flags } from "@oclif/core";

import { logsSinceDurationFlag } from "../../duration-flags";
import type { SandboxLogsOptions } from "../../sandbox-logs-options";
import { DEFAULT_SANDBOX_LOG_LINES } from "../../sandbox-logs-options";
import type { SandboxLogsOptions } from "../../domain/sandbox/log-options";
import { DEFAULT_SANDBOX_LOG_LINES } from "../../domain/sandbox/log-options";
import { showSandboxLogs } from "../../sandbox-runtime-actions";

type SandboxLogsRuntimeBridge = {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/coverage-hotspots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";

import { parseDuration } from "./duration";
import { parseDuration } from "./domain/duration";
import { parseGatewayTokenArgs, runGatewayTokenCommand } from "./gateway-token-command";
import { resolveDefaultSandboxName, runStartCommand, runStopCommand } from "./services-command";
import { getVersion } from "./version";
Expand Down
2 changes: 1 addition & 1 deletion test/duration.test.ts → src/lib/domain/duration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { describe, it, expect } from "vitest";
import { parseDuration, MAX_SECONDS, DEFAULT_SECONDS } from "../src/lib/duration.js";
import { parseDuration, MAX_SECONDS, DEFAULT_SECONDS } from "./duration";

describe("parseDuration", () => {
it("parses minutes", () => {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
normalizeGarbageCollectImagesOptions,
normalizeRebuildSandboxOptions,
normalizeUpgradeSandboxesOptions,
} from "./lifecycle-options";
} from "./options";

describe("lifecycle option normalization", () => {
it("preserves typed destroy options and still accepts compatibility argv", () => {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
findOrphanedSandboxImages,
getRegisteredImageTags,
parseSandboxImageRows,
} from "./maintenance-image-helpers";
} from "./images";

describe("maintenance image helpers", () => {
it("parses Docker image rows and fills missing sizes", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
shouldSkipUpgradeConfirmation,
splitRebuildableSandboxes,
type SandboxVersionCheck,
} from "./upgrade-sandboxes-helpers";
} from "./upgrade";

describe("upgrade sandboxes helpers", () => {
it("detects upgrade confirmation bypass modes", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import type { UpgradeSandboxesOptions } from "./lifecycle-options";
import type { UpgradeSandboxesOptions } from "../lifecycle/options";

export type SandboxVersionCheck = {
isStale: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
parseCustomPolicySource,
parsePolicyAddArgs,
shouldSkipPolicyConfirmation,
} from "./policy-channel-helpers";
} from "./policy-channel";

describe("policy channel helpers", () => {
it("parses custom policy source flags", () => {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
isMissingSandboxDeleteOutput,
shouldCleanupGatewayAfterDestroy,
shouldStopHostServicesAfterDestroy,
} from "./sandbox-destroy-helpers";
} from "./destroy";

describe("sandbox destroy helpers", () => {
it("detects missing sandbox delete output", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

/* v8 ignore start -- pure helper tests exercise this module; orchestration coverage still runs through dist. */

import { stripAnsi } from "./openshell";
const ANSI_RE = /\x1b\[[0-9;]*m/g;

function stripAnsi(value = ""): string {
return String(value).replace(ANSI_RE, "");
}

export type SpawnLikeResult = {
status: number | null;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
exitCodeFromSignal,
getLogsProbeTimeoutMs,
normalizeSandboxLogsOptions,
} from "./sandbox-logs-helpers";
} from "./logs";

describe("sandbox logs helpers", () => {
it("normalizes boolean and partial logs options", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

import os from "node:os";

import type { SandboxLogsOptions } from "./sandbox-logs-options";
import { DEFAULT_SANDBOX_LOG_LINES } from "./sandbox-logs-options";
import type { SandboxLogsOptions } from "./log-options";
import { DEFAULT_SANDBOX_LOG_LINES } from "./log-options";

export const DEFAULT_LOGS_PROBE_TIMEOUT_MS = 5000;
export const LOGS_PROBE_TIMEOUT_ENV = "NEMOCLAW_LOGS_PROBE_TIMEOUT_MS";
Expand Down
2 changes: 1 addition & 1 deletion src/lib/duration-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

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

import { parseDuration } from "./duration";
import { parseDuration } from "./domain/duration";

const LOGS_SINCE_DURATION_RE = /^[1-9]\d*(?:ms|s|m|h|d)$/i;

Expand Down
2 changes: 1 addition & 1 deletion src/lib/global-cli-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { runDeployAction as executeDeployAction } from "./deploy-action";
import {
type GarbageCollectImagesOptions,
type UpgradeSandboxesOptions,
} from "./lifecycle-options";
} from "./domain/lifecycle/options";
import {
backupAll as executeBackupAllAction,
garbageCollectImages as executeGarbageCollectImagesAction,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/maintenance-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { prompt as askPrompt } from "./credentials";
import {
type GarbageCollectImagesOptions,
normalizeGarbageCollectImagesOptions,
} from "./lifecycle-options";
} from "./domain/lifecycle/options";
import { dockerListImagesFormat, dockerRmi } from "./docker";
import { findOrphanedSandboxImages, parseSandboxImageRows } from "./maintenance-image-helpers";
import { findOrphanedSandboxImages, parseSandboxImageRows } from "./domain/maintenance/images";
import { captureOpenshell } from "./openshell-runtime";
import * as registry from "./registry";
import { parseLiveSandboxNames } from "./runtime-recovery";
Expand Down
2 changes: 1 addition & 1 deletion src/lib/policy-channel-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { recoverNamedGatewayRuntime } from "./gateway-runtime-action";
const { isNonInteractive } = require("./onboard") as { isNonInteractive: () => boolean };
const onboardProviders = require("./onboard-providers");
import * as policies from "./policies";
import { parsePolicyAddArgs } from "./policy-channel-helpers";
import { parsePolicyAddArgs } from "./domain/policy-channel";
import * as registry from "./registry";
import { runOpenshell } from "./openshell-runtime";
import { rebuildSandbox } from "./sandbox-runtime-actions";
Expand Down
4 changes: 2 additions & 2 deletions src/lib/sandbox-destroy-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { prompt as askPrompt } from "./credentials";
import {
type DestroySandboxOptions,
normalizeDestroySandboxOptions,
} from "./lifecycle-options";
} from "./domain/lifecycle/options";
import * as onboardSession from "./onboard-session";
import type { Session } from "./onboard-session";
import { OPENSHELL_PROBE_TIMEOUT_MS } from "./openshell-timeouts";
Expand All @@ -26,7 +26,7 @@ import {
getSandboxDeleteOutcome,
shouldCleanupGatewayAfterDestroy,
shouldStopHostServicesAfterDestroy,
} from "./sandbox-destroy-helpers";
} from "./domain/sandbox/destroy";
import { G, R, YW } from "./terminal-style";

type DockerRmi = (tag: string, opts?: { ignoreError?: boolean }) => { status: number | null };
Expand Down
4 changes: 2 additions & 2 deletions src/lib/sandbox-logs-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
getLogsProbeTimeoutMs,
normalizeSandboxLogsOptions,
type LogProbeResult,
} from "./sandbox-logs-helpers";
import type { SandboxLogsOptions } from "./sandbox-logs-options";
} from "./domain/sandbox/logs";
import type { SandboxLogsOptions } from "./domain/sandbox/log-options";

/* v8 ignore next -- process exit mapping is covered through CLI subprocess log tests. */
function exitWithSpawnResult(result: LogProbeResult) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/sandbox-rebuild-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { prompt as askPrompt } from "./credentials";
import {
normalizeRebuildSandboxOptions,
type RebuildSandboxOptions,
} from "./lifecycle-options";
} from "./domain/lifecycle/options";

const { hydrateCredentialEnv } = require("./onboard") as {
hydrateCredentialEnv: (name: string) => string | null;
Expand All @@ -26,7 +26,7 @@ import * as policies from "./policies";
import * as registry from "./registry";
import { resolveOpenshell } from "./resolve-openshell";
import { parseLiveSandboxNames } from "./runtime-recovery";
import { getSandboxDeleteOutcome } from "./sandbox-destroy-helpers";
import { getSandboxDeleteOutcome } from "./domain/sandbox/destroy";
import { removeSandboxRegistryEntry } from "./sandbox-destroy-action";
import { executeSandboxCommand } from "./sandbox-process-recovery-action";
import {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/sandbox-runtime-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

/* v8 ignore start -- transitional action facade until implementations leave src/nemoclaw.ts. */

import type { DestroySandboxOptions, RebuildSandboxOptions } from "./lifecycle-options";
import type { DestroySandboxOptions, RebuildSandboxOptions } from "./domain/lifecycle/options";
import type { SandboxConnectOptions } from "./sandbox-connect-action";
import type { SandboxLogsOptions } from "./sandbox-logs-options";
import type { SandboxLogsOptions } from "./domain/sandbox/log-options";

export async function connectSandbox(
sandboxName: string,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/shields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const {
parseCurrentPolicy,
PERMISSIVE_POLICY_PATH,
} = require("./policies");
const { parseDuration, MAX_SECONDS, DEFAULT_SECONDS } = require("./duration");
const { parseDuration, MAX_SECONDS, DEFAULT_SECONDS } = require("./domain/duration");
const { appendAuditEntry } = require("./shields-audit");
const { resolveAgentConfig } = require("./sandbox-config");

Expand Down
4 changes: 2 additions & 2 deletions src/lib/upgrade-sandboxes-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { prompt as askPrompt } from "./credentials";
import {
normalizeUpgradeSandboxesOptions,
type UpgradeSandboxesOptions,
} from "./lifecycle-options";
} from "./domain/lifecycle/options";
import { captureOpenshell } from "./openshell-runtime";
import * as registry from "./registry";
import { parseLiveSandboxNames } from "./runtime-recovery";
Expand All @@ -19,7 +19,7 @@ import {
classifyUpgradeableSandboxes,
shouldSkipUpgradeConfirmation,
splitRebuildableSandboxes,
} from "./upgrade-sandboxes-helpers";
} from "./domain/maintenance/upgrade";

// ── Upgrade sandboxes (#1904) ────────────────────────────────────
// Detect sandboxes running stale agent versions and offer to rebuild them.
Expand Down
4 changes: 2 additions & 2 deletions test/image-cleanup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
removeSandboxImage,
removeSandboxRegistryEntry,
} from "../src/lib/sandbox-destroy-action";
import { getSandboxDeleteOutcome } from "../src/lib/sandbox-destroy-helpers";
import { normalizeGarbageCollectImagesOptions } from "../src/lib/lifecycle-options";
import { getSandboxDeleteOutcome } from "../src/lib/domain/sandbox/destroy";
import { normalizeGarbageCollectImagesOptions } from "../src/lib/domain/lifecycle/options";
import { help as renderRootHelp } from "../src/lib/root-help-action";

const ROOT = path.resolve(import.meta.dirname, "..");
Expand Down
10 changes: 5 additions & 5 deletions test/shields.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,29 +76,29 @@ describe("shields — unit logic", () => {
// Since the CJS require resolution issue makes direct import flaky,
// test the TypeScript duration module instead.
it("parses minutes", async () => {
const { parseDuration } = await import("../src/lib/duration.js");
const { parseDuration } = await import("../src/lib/domain/duration.js");
expect(parseDuration("5m")).toBe(300);
expect(parseDuration("30m")).toBe(1800);
});

it("parses seconds", async () => {
const { parseDuration } = await import("../src/lib/duration.js");
const { parseDuration } = await import("../src/lib/domain/duration.js");
expect(parseDuration("90s")).toBe(90);
});

it("treats bare numbers as seconds", async () => {
const { parseDuration } = await import("../src/lib/duration.js");
const { parseDuration } = await import("../src/lib/domain/duration.js");
expect(parseDuration("300")).toBe(300);
});

it("rejects durations exceeding 30 minutes", async () => {
const { parseDuration } = await import("../src/lib/duration.js");
const { parseDuration } = await import("../src/lib/domain/duration.js");
expect(() => parseDuration("31m")).toThrow("exceeds maximum");
expect(() => parseDuration("1h")).toThrow("exceeds maximum");
});

it("rejects invalid input", async () => {
const { parseDuration } = await import("../src/lib/duration.js");
const { parseDuration } = await import("../src/lib/domain/duration.js");
expect(() => parseDuration("abc")).toThrow("Invalid duration");
});
});
Expand Down
Loading