Skip to content
Closed
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
5 changes: 5 additions & 0 deletions packages/sdk-python/src/qwen_code_sdk/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,9 @@ def build_cli_arguments(options: QueryOptions) -> list[str]:
elif options.session_id:
args.extend(["--session-id", options.session_id])

if options.disabled_slash_commands:
args.extend(
["--disabled-slash-commands", ",".join(options.disabled_slash_commands)]
)

return args
3 changes: 3 additions & 0 deletions packages/sdk-python/src/qwen_code_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class QueryOptionsDict(TypedDict, total=False):
timeout: TimeoutOptionsDict
mcp_servers: dict[str, dict[str, Any]]
stderr: Callable[[str], None]
disabled_slash_commands: list[str]


@dataclass
Expand All @@ -139,6 +140,7 @@ class QueryOptions:
timeout: TimeoutOptions = TimeoutOptions()
mcp_servers: dict[str, dict[str, Any]] | None = None
stderr: Callable[[str], None] | None = None
disabled_slash_commands: list[str] | None = None

@classmethod
def from_mapping(cls, value: Mapping[str, Any] | None) -> QueryOptions:
Expand Down Expand Up @@ -183,6 +185,7 @@ def from_mapping(cls, value: Mapping[str, Any] | None) -> QueryOptions:
Callable[[str], None] | None,
_as_optional_callable(data, "stderr"),
),
disabled_slash_commands=_as_optional_str_list(data, "disabled_slash_commands"),
)


Expand Down
10 changes: 10 additions & 0 deletions packages/sdk-python/tests/unit/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ def test_cli_argument_precedence_prefers_resume_then_continue_then_session_id()
assert "--session-id" not in args


def test_build_cli_arguments_includes_disabled_slash_commands() -> None:
args = build_cli_arguments(
QueryOptions(disabled_slash_commands=["/init", "/vim"])
)

assert "--disabled-slash-commands" in args
idx = args.index("--disabled-slash-commands")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Test values ["/init", "/vim"] use slash-prefixed names, but the CLI expects bare names ('init', 'vim'). This propagates the incorrect format as test-as-documentation — developers reading this test will copy the slash-prefixed format.

Suggested change
idx = args.index("--disabled-slash-commands")
QueryOptions(disabled_slash_commands=["init", "vim"])

Also update the assertion:

    assert args[idx + 1] == "init,vim"

— qwen3.7-max via Qwen Code /review

assert args[idx + 1] == "/init,/vim"


def test_prepare_spawn_info_uses_runtime_for_python_scripts(tmp_path: Path) -> None:
script_path = tmp_path / "fake-qwen.py"
script_path.write_text("print('ok')\n", encoding="utf-8")
Expand Down
1 change: 1 addition & 0 deletions packages/sdk-typescript/src/query/createQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function query({
includePartialMessages: options.includePartialMessages,
resume: options.resume,
sessionId,
disabledSlashCommands: options.disabledSlashCommands,
});

const queryOptions: QueryOptions = {
Expand Down
10 changes: 10 additions & 0 deletions packages/sdk-typescript/src/transport/ProcessTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,16 @@ export class ProcessTransport implements Transport {
args.push('--session-id', this.options.sessionId);
}

if (
this.options.disabledSlashCommands &&
this.options.disabledSlashCommands.length > 0
) {
args.push(
'--disabled-slash-commands',
this.options.disabledSlashCommands.join(','),
);
}

return args;
}

Expand Down
1 change: 1 addition & 0 deletions packages/sdk-typescript/src/types/queryOptionsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export const QueryOptionsSchema = z
includePartialMessages: z.boolean().optional(),
resume: z.string().optional(),
sessionId: z.string().optional(),
disabledSlashCommands: z.array(z.string()).optional(),
timeout: TimeoutConfigSchema.optional(),
})
.strict();
9 changes: 9 additions & 0 deletions packages/sdk-typescript/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type TransportOptions = {
* When resume is provided, this should match the resume ID.
*/
sessionId?: string;
disabledSlashCommands?: string[];
};

export interface QuerySystemPromptPreset {
Expand Down Expand Up @@ -465,6 +466,14 @@ export interface QueryOptions {
*/
sessionId?: string;

/**
* Slash command names to hide/disable.
* Equivalent to CLI's `--disabled-slash-commands` flag.
* Matched case-insensitively against the final command name.
* @example ['/init', '/vim']
*/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] The @example ['/init', '/vim'] uses slash-prefixed names, but the CLI matches against bare command names ('init', 'vim'). The yargs coerce and addDisabled functions never strip a leading /, so '/init' will never match 'init' — commands will silently remain enabled.

Verified at both matching sites (CommandService.create and nonInteractiveCliCommands.ts): they compare against cmd.name.toLowerCase() where cmd.name is the bare name (e.g., 'init' in initCommand.ts, 'vim' in vimCommand.ts). The official CLI docs in docs/users/configuration/settings.md correctly use bare names: "disabled": ["auth", "mcp"].

Suggested change
*/
* @example ['init', 'vim']

Alternatively, strip the leading / in both SDK transports before joining, since users will naturally think in /command terms.

— qwen3.7-max via Qwen Code /review

disabledSlashCommands?: string[];

/**
* Timeout configuration for various SDK operations.
* All values are in milliseconds.
Expand Down
23 changes: 23 additions & 0 deletions packages/sdk-typescript/test/unit/ProcessTransport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,29 @@ describe('ProcessTransport', () => {
);
});

it('should include --disabled-slash-commands when provided', () => {
mockPrepareSpawnInfo.mockReturnValue({
command: 'qwen',
args: [],
type: 'native',
originalInput: 'qwen',
});
mockSpawn.mockReturnValue(mockChildProcess);

const options: TransportOptions = {
pathToQwenExecutable: 'qwen',
disabledSlashCommands: ['/init', '/vim'],
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Test values ['/init', '/vim'] use slash-prefixed names, but the CLI expects bare names ('init', 'vim'). This propagates the incorrect format as test-as-documentation.

Suggested change
disabledSlashCommands: ['init', 'vim'],

Also update the assertion:

        expect.arrayContaining(['--disabled-slash-commands', 'init,vim']),

— qwen3.7-max via Qwen Code /review

new ProcessTransport(options);

expect(mockSpawn).toHaveBeenCalledWith(
'qwen',
expect.arrayContaining(['--disabled-slash-commands', '/init,/vim']),
expect.any(Object),
);
});

it('should throw if aborted before initialization', () => {
mockPrepareSpawnInfo.mockReturnValue({
command: 'qwen',
Expand Down
Loading