Skip to content
Merged
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
93 changes: 93 additions & 0 deletions src/cli/repl-commands/adapter-cli-reference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { Adapter } from "../../core/pipeline/types.js";
import { colors } from "../colors.js";

export interface AdapterLoginCommandSpec {
command: string;
args: string[];
}

interface AdapterCliReferenceSection {
title: string;
commands: string[];
note?: string;
}

export const getAdapterLoginCommandSpec = (
adapter: Adapter,
): AdapterLoginCommandSpec => {
if (adapter === "codex") {
return { command: "codex", args: ["login"] };
}

if (adapter === "gemini") {
return { command: "gemini", args: [] };
}

return { command: "claude", args: ["auth", "login"] };
};

export const getLoginHint = (adapter: Adapter): string => {
const spec = getAdapterLoginCommandSpec(adapter);
return [spec.command, ...spec.args].join(" ").trim();
};

export const getLogoutHint = (adapter: Adapter): string =>
adapter === "claude" ? "claude auth logout" : `${adapter} logout`;

const getAdapterCliReferenceSections = (): AdapterCliReferenceSection[] => [
{
title: "Codex CLI",
commands: [
"codex login",
"codex login status",
"codex debug models",
"codex /goal <objective>",
"codex /goal pause | resume | clear",
"codex logout",
],
note: "로그인 / 상태 / 모델 조회 / 목표 관리(/goal)는 Codex 원본 CLI에서 처리합니다.",
},
{
title: "Gemini CLI",
commands: ["gemini"],
note: "인증 진입은 gemini로 하고, 모델 선택은 detoks /gms가 맡습니다.",
},
{
title: "Claude Code",
commands: [
"claude auth login",
"claude auth status --json",
"claude --model <model>",
"claude auth logout",
],
note: "Claude는 auth 후 detoks /claude-models가 모델 선택을 맡고, 실행 시 --model로 전달됩니다.",
},
];

export const formatAdapterCliReference = (): string => {
const lines: string[] = [
"",
`${colors.title("외부 adapter CLI 참고")}`,
"",
];

for (const section of getAdapterCliReferenceSections()) {
lines.push(` ${colors.boldText(section.title)}`);
for (const command of section.commands) {
lines.push(` ${colors.muted(command)}`);
}
if (section.note) {
lines.push(` ${colors.muted(section.note)}`);
}
lines.push("");
}

lines.push(
colors.muted(
" detoks 명령은 REPL 안에서, adapter CLI 원본 명령은 외부 터미널에서 사용하세요.",
),
);
lines.push("");

return `${lines.join("\n")}\n`;
};
93 changes: 7 additions & 86 deletions src/cli/repl-commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ import {
import { loadLastCustomModel, saveCustomModel } from "../model-setup/custom-store.js";
import { parseHfRepoInput, listGgufFiles, HfRepoError } from "../model-setup/hf-repo.js";
import { promptLine } from "../interactive/prompt-line.js";
import {
formatAdapterCliReference,
getAdapterLoginCommandSpec,
getLoginHint,
getLogoutHint,
} from "./adapter-cli-reference.js";
export { formatAdapterCliReference, getAdapterLoginCommandSpec } from "./adapter-cli-reference.js";

export interface SlashCommand {
name: string;
Expand Down Expand Up @@ -211,92 +218,6 @@ export const isSlashCommand = (
return input.startsWith("/") && getSlashCommand(input, adapter) !== null;
};

export const getAdapterLoginCommandSpec = (
adapter: Adapter,
): { command: string; args: string[] } => {
if (adapter === "codex") {
return { command: "codex", args: ["login"] };
}

if (adapter === "gemini") {
return { command: "gemini", args: [] };
}

return { command: "claude", args: ["auth", "login"] };
};

const getLoginHint = (adapter: Adapter): string => {
const spec = getAdapterLoginCommandSpec(adapter);
return [spec.command, ...spec.args].join(" ").trim();
};

const getLogoutHint = (adapter: Adapter): string =>
adapter === "claude" ? "claude auth logout" : `${adapter} logout`;

interface AdapterCliReferenceSection {
title: string;
commands: string[];
note?: string;
}

const getAdapterCliReferenceSections = (): AdapterCliReferenceSection[] => [
{
title: "Codex CLI",
commands: [
"codex login",
"codex login status",
"codex debug models",
"codex /goal <objective>",
"codex /goal pause | resume | clear",
"codex logout",
],
note: "로그인 / 상태 / 모델 조회 / 목표 관리(/goal)는 Codex 원본 CLI에서 처리합니다.",
},
{
title: "Gemini CLI",
commands: ["gemini"],
note: "인증 진입은 gemini로 하고, 모델 선택은 detoks /gms가 맡습니다.",
},
{
title: "Claude Code",
commands: [
"claude auth login",
"claude auth status --json",
"claude --model <model>",
"claude auth logout",
],
note: "Claude는 auth 후 detoks /claude-models가 모델 선택을 맡고, 실행 시 --model로 전달됩니다.",
},
];

export const formatAdapterCliReference = (): string => {
const lines: string[] = [
"",
`${colors.title("외부 adapter CLI 참고")}`,
"",
];

for (const section of getAdapterCliReferenceSections()) {
lines.push(` ${colors.boldText(section.title)}`);
for (const command of section.commands) {
lines.push(` ${colors.muted(command)}`);
}
if (section.note) {
lines.push(` ${colors.muted(section.note)}`);
}
lines.push("");
}

lines.push(
colors.muted(
" detoks 명령은 REPL 안에서, adapter CLI 원본 명령은 외부 터미널에서 사용하세요.",
),
);
lines.push("");

return `${lines.join("\n")}\n`;
};

const buildSlashCommandMenuOptions = (
adapter: Adapter,
): SelectOption[] =>
Expand Down
45 changes: 45 additions & 0 deletions tests/ts/unit/cli/repl-commands/adapter-cli-reference.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it } from "vitest";
import {
formatAdapterCliReference,
getAdapterLoginCommandSpec,
getLoginHint,
getLogoutHint,
} from "../../../../../src/cli/repl-commands/adapter-cli-reference.js";

describe("adapter CLI reference helpers", () => {
it("maps adapters to login and logout hints", () => {
expect(getAdapterLoginCommandSpec("codex")).toEqual({
command: "codex",
args: ["login"],
});
expect(getAdapterLoginCommandSpec("gemini")).toEqual({
command: "gemini",
args: [],
});
expect(getAdapterLoginCommandSpec("claude")).toEqual({
command: "claude",
args: ["auth", "login"],
});

expect(getLoginHint("codex")).toBe("codex login");
expect(getLoginHint("gemini")).toBe("gemini");
expect(getLoginHint("claude")).toBe("claude auth login");

expect(getLogoutHint("codex")).toBe("codex logout");
expect(getLogoutHint("gemini")).toBe("gemini logout");
expect(getLogoutHint("claude")).toBe("claude auth logout");
});

it("formats the external adapter CLI reference", () => {
const reference = formatAdapterCliReference();

expect(reference).toContain("외부 adapter CLI 참고");
expect(reference).toContain("Codex CLI");
expect(reference).toContain("codex debug models");
expect(reference).toContain("Gemini CLI");
expect(reference).toContain("gemini");
expect(reference).toContain("Claude Code");
expect(reference).toContain("claude auth status --json");
expect(reference).toContain("detoks 명령은 REPL 안에서");
});
});
Loading