Просмотр исходного кода

feat(cli): open project TUI by default

Ma 7 месяцев назад
Родитель
Сommit
5137f4391a

+ 29 - 0
packages/cli/src/__tests__/tui-command.test.ts

@@ -0,0 +1,29 @@
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { createProgram } from "../program.js";
+
+describe("tui command", () => {
+  const originalArgv = process.argv;
+
+  afterEach(() => {
+    process.argv = originalArgv;
+    vi.restoreAllMocks();
+  });
+
+  it("launches the TUI when no subcommand is provided", async () => {
+    const launchTui = vi.fn(async () => {});
+    const program = createProgram({ launchTui });
+
+    await program.parseAsync([], { from: "user" });
+
+    expect(launchTui).toHaveBeenCalledTimes(1);
+  });
+
+  it("launches the TUI when the explicit tui command is used", async () => {
+    const launchTui = vi.fn(async () => {});
+    const program = createProgram({ launchTui });
+
+    await program.parseAsync(["tui"], { from: "user" });
+
+    expect(launchTui).toHaveBeenCalledTimes(1);
+  });
+});

+ 14 - 0
packages/cli/src/commands/tui.ts

@@ -0,0 +1,14 @@
+import { Command } from "commander";
+
+export interface TuiCommandHooks {
+  readonly launchTui?: (projectRoot: string) => Promise<void> | void;
+}
+
+export function createTuiCommand(hooks: TuiCommandHooks = {}): Command {
+  return new Command("tui")
+    .description("Open the InkOS project workspace TUI")
+    .action(async () => {
+      await hooks.launchTui?.(process.cwd());
+    });
+}
+

+ 2 - 67
packages/cli/src/index.ts

@@ -1,70 +1,5 @@
 #!/usr/bin/env node
 
-import { createRequire } from "node:module";
-import { Command } from "commander";
-import { initCommand } from "./commands/init.js";
-import { configCommand } from "./commands/config.js";
-import { bookCommand } from "./commands/book.js";
-import { writeCommand } from "./commands/write.js";
-import { reviewCommand } from "./commands/review.js";
-import { statusCommand } from "./commands/status.js";
-import { radarCommand } from "./commands/radar.js";
-import { upCommand, downCommand } from "./commands/daemon.js";
-import { doctorCommand } from "./commands/doctor.js";
-import { exportCommand } from "./commands/export.js";
-import { draftCommand } from "./commands/draft.js";
-import { auditCommand } from "./commands/audit.js";
-import { reviseCommand } from "./commands/revise.js";
-import { agentCommand } from "./commands/agent.js";
-import { planCommand } from "./commands/plan.js";
-import { composeCommand } from "./commands/compose.js";
-import { genreCommand } from "./commands/genre.js";
-import { updateCommand } from "./commands/update.js";
-import { detectCommand } from "./commands/detect.js";
-import { styleCommand } from "./commands/style.js";
-import { analyticsCommand } from "./commands/analytics.js";
-import { evalCommand } from "./commands/eval.js";
-import { importCommand } from "./commands/import.js";
-import { fanficCommand } from "./commands/fanfic.js";
-import { studioCommand } from "./commands/studio.js";
-import { consolidateCommand } from "./commands/consolidate.js";
+import { runProgram } from "./program.js";
 
-const require = createRequire(import.meta.url);
-const { version } = require("../package.json") as { version: string };
-
-const program = new Command();
-
-program
-  .name("inkos")
-  .description("InkOS — Multi-agent novel production system")
-  .version(version);
-
-program.addCommand(initCommand);
-program.addCommand(configCommand);
-program.addCommand(bookCommand);
-program.addCommand(writeCommand);
-program.addCommand(reviewCommand);
-program.addCommand(statusCommand);
-program.addCommand(radarCommand);
-program.addCommand(upCommand);
-program.addCommand(downCommand);
-program.addCommand(doctorCommand);
-program.addCommand(exportCommand);
-program.addCommand(draftCommand);
-program.addCommand(auditCommand);
-program.addCommand(reviseCommand);
-program.addCommand(agentCommand);
-program.addCommand(planCommand);
-program.addCommand(composeCommand);
-program.addCommand(genreCommand);
-program.addCommand(updateCommand);
-program.addCommand(detectCommand);
-program.addCommand(styleCommand);
-program.addCommand(analyticsCommand);
-program.addCommand(evalCommand);
-program.addCommand(importCommand);
-program.addCommand(fanficCommand);
-program.addCommand(studioCommand);
-program.addCommand(consolidateCommand);
-
-program.parse();
+await runProgram();

+ 87 - 0
packages/cli/src/program.ts

@@ -0,0 +1,87 @@
+import { createRequire } from "node:module";
+import { Command } from "commander";
+import { initCommand } from "./commands/init.js";
+import { configCommand } from "./commands/config.js";
+import { bookCommand } from "./commands/book.js";
+import { writeCommand } from "./commands/write.js";
+import { reviewCommand } from "./commands/review.js";
+import { statusCommand } from "./commands/status.js";
+import { radarCommand } from "./commands/radar.js";
+import { upCommand, downCommand } from "./commands/daemon.js";
+import { doctorCommand } from "./commands/doctor.js";
+import { exportCommand } from "./commands/export.js";
+import { draftCommand } from "./commands/draft.js";
+import { auditCommand } from "./commands/audit.js";
+import { reviseCommand } from "./commands/revise.js";
+import { agentCommand } from "./commands/agent.js";
+import { planCommand } from "./commands/plan.js";
+import { composeCommand } from "./commands/compose.js";
+import { genreCommand } from "./commands/genre.js";
+import { updateCommand } from "./commands/update.js";
+import { detectCommand } from "./commands/detect.js";
+import { styleCommand } from "./commands/style.js";
+import { analyticsCommand } from "./commands/analytics.js";
+import { evalCommand } from "./commands/eval.js";
+import { importCommand } from "./commands/import.js";
+import { fanficCommand } from "./commands/fanfic.js";
+import { studioCommand } from "./commands/studio.js";
+import { consolidateCommand } from "./commands/consolidate.js";
+import { createTuiCommand } from "./commands/tui.js";
+
+const require = createRequire(import.meta.url);
+const { version } = require("../package.json") as { version: string };
+
+export interface ProgramHooks {
+  readonly launchTui?: (projectRoot: string) => Promise<void> | void;
+}
+
+export function createProgram(hooks: ProgramHooks = {}): Command {
+  const program = new Command();
+
+  program
+    .name("inkos")
+    .description("InkOS — Multi-agent novel production system")
+    .version(version)
+    .action(async () => {
+      await hooks.launchTui?.(process.cwd());
+    });
+
+  program.addCommand(initCommand);
+  program.addCommand(configCommand);
+  program.addCommand(bookCommand);
+  program.addCommand(writeCommand);
+  program.addCommand(reviewCommand);
+  program.addCommand(statusCommand);
+  program.addCommand(radarCommand);
+  program.addCommand(upCommand);
+  program.addCommand(downCommand);
+  program.addCommand(doctorCommand);
+  program.addCommand(exportCommand);
+  program.addCommand(draftCommand);
+  program.addCommand(auditCommand);
+  program.addCommand(reviseCommand);
+  program.addCommand(agentCommand);
+  program.addCommand(planCommand);
+  program.addCommand(composeCommand);
+  program.addCommand(genreCommand);
+  program.addCommand(updateCommand);
+  program.addCommand(detectCommand);
+  program.addCommand(styleCommand);
+  program.addCommand(analyticsCommand);
+  program.addCommand(evalCommand);
+  program.addCommand(importCommand);
+  program.addCommand(fanficCommand);
+  program.addCommand(studioCommand);
+  program.addCommand(consolidateCommand);
+  program.addCommand(createTuiCommand({ launchTui: hooks.launchTui }));
+
+  return program;
+}
+
+export async function runProgram(
+  argv: string[] = process.argv,
+  hooks: ProgramHooks = {},
+): Promise<void> {
+  const program = createProgram(hooks);
+  await program.parseAsync(argv);
+}