Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 57 additions & 0 deletions src/argv.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { describe, expect, it } from 'vitest';
import { detectInitInvocation, firstOperand } from './argv.js';

const argv = (...args: string[]): string[] => ['/node', '/bitrefill', ...args];

describe('firstOperand', () => {
it('returns the first non-option token', () => {
expect(firstOperand(argv('--json', 'search-products'))).toBe(
'search-products'
);
});

it('returns undefined when there is no operand', () => {
expect(firstOperand(argv('--json'))).toBeUndefined();
expect(firstOperand(argv())).toBeUndefined();
});
});

describe('detectInitInvocation', () => {
it('detects the init subcommand', () => {
expect(detectInitInvocation(argv('init')).isInit).toBe(true);
expect(detectInitInvocation(argv('init', '--openclaw')).isInit).toBe(
true
);
expect(detectInitInvocation(argv('--json', 'init')).isInit).toBe(true);
});

it('reports --help and -h on the init subcommand', () => {
expect(detectInitInvocation(argv('init', '--help'))).toEqual({
isInit: true,
hasHelp: true,
});
expect(detectInitInvocation(argv('init', '-h'))).toEqual({
isInit: true,
hasHelp: true,
});
expect(detectInitInvocation(argv('init')).hasHelp).toBe(false);
});

it('does not treat an option value of "init" as the subcommand', () => {
expect(
detectInitInvocation(argv('search-products', '--query', 'init'))
.isInit
).toBe(false);
expect(
detectInitInvocation(argv('llm-context', '-o', 'init')).isInit
).toBe(false);
});

it('leaves `help init` to the help command', () => {
expect(detectInitInvocation(argv('help', 'init')).isInit).toBe(false);
});

it('returns false without arguments', () => {
expect(detectInitInvocation(argv()).isInit).toBe(false);
});
});
21 changes: 21 additions & 0 deletions src/argv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Subcommand detection for the pre-connect dispatch in `index.ts`, kept here
* so it can be unit tested without importing the CLI entry point.
*/
export interface InitInvocation {
isInit: boolean;
hasHelp: boolean;
}

/** The subcommand is the first operand; an option value is never one. */
export function firstOperand(argv: readonly string[]): string | undefined {
return argv.slice(2).find((arg) => !arg.startsWith('-'));
}

export function detectInitInvocation(argv: readonly string[]): InitInvocation {
const args = argv.slice(2);
return {
isInit: firstOperand(argv) === 'init',
hasHelp: args.includes('--help') || args.includes('-h'),
};
}
10 changes: 2 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { buildOptionsForTool, parseToolArgs } from './tools.js';
import { generateLlmContextMarkdown } from './llm-context.js';
import { buildManifest } from './manifest.js';
import { runInit } from './init.js';
import { detectInitInvocation } from './argv.js';
import { BASE_MCP_URL, IS_DEFAULT_BASE_MCP_URL } from './config.js';

import { VERSION } from './version.js';
Expand Down Expand Up @@ -248,13 +249,6 @@ Options:
--openclaw Force OpenClaw integration even if not auto-detected
-h, --help Display help for command`;

function detectInitInvocation(): { isInit: boolean; hasHelp: boolean } {
const isInit = process.argv.some((arg, i) => arg === 'init' && i >= 2);
const hasHelp =
process.argv.includes('--help') || process.argv.includes('-h');
return { isInit, hasHelp };
}

async function handleInit(): Promise<void> {
const formatter = createOutputFormatter(resolveJsonMode());
try {
Expand Down Expand Up @@ -484,7 +478,7 @@ function getClientId(serverUrl: string): string | undefined {
// --- Main ---

async function main(): Promise<void> {
const init = detectInitInvocation();
const init = detectInitInvocation(process.argv);
if (init.isInit && init.hasHelp) {
console.log(INIT_HELP);
return;
Expand Down