ソースを参照

revert: remove v0.5 features for selective re-landing

Reverts: release pipeline, epub export, cost tracking.
Ma 7 ヶ月 前
親
コミット
d028ac7ba2

+ 0 - 108
.github/workflows/release.yml

@@ -1,108 +0,0 @@
-name: Release
-
-on:
-  push:
-    tags:
-      - "v*"
-
-permissions:
-  contents: write
-
-jobs:
-  test:
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        node-version: [20, 22]
-
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: pnpm/action-setup@v4
-        with:
-          version: 9
-
-      - uses: actions/setup-node@v4
-        with:
-          node-version: ${{ matrix.node-version }}
-          cache: pnpm
-
-      - run: pnpm install --frozen-lockfile
-      - run: pnpm build
-      - run: pnpm --filter @actalk/inkos-core typecheck
-      - run: pnpm --filter @actalk/inkos typecheck
-      - run: pnpm test
-
-  smoke-test:
-    runs-on: ubuntu-latest
-    needs: test
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: pnpm/action-setup@v4
-        with:
-          version: 9
-
-      - uses: actions/setup-node@v4
-        with:
-          node-version: 22
-          cache: pnpm
-
-      - run: pnpm install --frozen-lockfile
-      - run: pnpm build
-
-      - name: Smoke test — CLI help and version
-        run: |
-          node packages/cli/dist/index.js --help
-          node packages/cli/dist/index.js --version
-
-      - name: Smoke test — core import
-        run: node -e "import('@actalk/inkos-core').then(m => { if (!m.PipelineRunner) throw new Error('missing PipelineRunner'); console.log('core import OK') })"
-
-  publish:
-    runs-on: ubuntu-latest
-    needs: smoke-test
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: pnpm/action-setup@v4
-        with:
-          version: 9
-
-      - uses: actions/setup-node@v4
-        with:
-          node-version: 22
-          cache: pnpm
-          registry-url: https://registry.npmjs.org
-
-      - run: pnpm install --frozen-lockfile
-      - run: pnpm build
-      - run: pnpm -r publish --no-git-checks
-        env:
-          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
-
-  github-release:
-    runs-on: ubuntu-latest
-    needs: publish
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-
-      - name: Generate release notes
-        id: notes
-        run: |
-          PREV_TAG=$(git tag --sort=-creatordate | sed -n '2p' || echo "")
-          if [ -n "$PREV_TAG" ]; then
-            echo "notes<<EOF" >> "$GITHUB_OUTPUT"
-            git log --pretty=format:"- %s (%h)" "$PREV_TAG"..HEAD >> "$GITHUB_OUTPUT"
-            echo "" >> "$GITHUB_OUTPUT"
-            echo "EOF" >> "$GITHUB_OUTPUT"
-          else
-            echo "notes=Initial release" >> "$GITHUB_OUTPUT"
-          fi
-
-      - uses: softprops/action-gh-release@v2
-        with:
-          body: ${{ steps.notes.outputs.notes }}
-          generate_release_notes: true

+ 1 - 3
packages/cli/package.json

@@ -27,9 +27,7 @@
   "dependencies": {
     "@actalk/inkos-core": "workspace:*",
     "commander": "^13.0.0",
-    "dotenv": "^16.4.0",
-    "epub-gen-memory": "^1.0.10",
-    "marked": "^15.0.0"
+    "dotenv": "^16.4.0"
   },
   "devDependencies": {
     "typescript": "^5.8.0",

+ 1 - 56
packages/cli/src/commands/analytics.ts

@@ -2,14 +2,6 @@ import { Command } from "commander";
 import { StateManager } from "@actalk/inkos-core";
 import { loadConfig, findProjectRoot, resolveBookId, log, logError } from "../utils.js";
 
-interface TokenStats {
-  readonly totalPromptTokens: number;
-  readonly totalCompletionTokens: number;
-  readonly totalTokens: number;
-  readonly avgTokensPerChapter: number;
-  readonly recentTrend: ReadonlyArray<{ readonly chapter: number; readonly totalTokens: number }>;
-}
-
 interface AnalyticsData {
   readonly bookId: string;
   readonly totalChapters: number;
@@ -19,7 +11,6 @@ interface AnalyticsData {
   readonly topIssueCategories: ReadonlyArray<{ readonly category: string; readonly count: number }>;
   readonly chaptersWithMostIssues: ReadonlyArray<{ readonly chapter: number; readonly issueCount: number }>;
   readonly statusDistribution: Record<string, number>;
-  readonly tokenStats?: TokenStats;
 }
 
 export function computeAnalytics(
@@ -29,11 +20,6 @@ export function computeAnalytics(
     readonly status: string;
     readonly wordCount: number;
     readonly auditIssues: ReadonlyArray<string>;
-    readonly tokenUsage?: {
-      readonly promptTokens: number;
-      readonly completionTokens: number;
-      readonly totalTokens: number;
-    };
   }>,
 ): AnalyticsData {
   const totalChapters = chapters.length;
@@ -79,30 +65,6 @@ export function computeAnalytics(
     statusDistribution[ch.status] = (statusDistribution[ch.status] ?? 0) + 1;
   }
 
-  // Token stats
-  const chaptersWithUsage = chapters.filter((ch) => ch.tokenUsage);
-  let tokenStats: TokenStats | undefined;
-  if (chaptersWithUsage.length > 0) {
-    const totalPromptTokens = chaptersWithUsage.reduce((sum, ch) => sum + (ch.tokenUsage?.promptTokens ?? 0), 0);
-    const totalCompletionTokens = chaptersWithUsage.reduce((sum, ch) => sum + (ch.tokenUsage?.completionTokens ?? 0), 0);
-    const totalTokens = chaptersWithUsage.reduce((sum, ch) => sum + (ch.tokenUsage?.totalTokens ?? 0), 0);
-    const avgTokensPerChapter = Math.round(totalTokens / chaptersWithUsage.length);
-
-    // Recent 5 chapters trend (sorted by chapter number)
-    const recentTrend = [...chaptersWithUsage]
-      .sort((a, b) => a.number - b.number)
-      .slice(-5)
-      .map((ch) => ({ chapter: ch.number, totalTokens: ch.tokenUsage?.totalTokens ?? 0 }));
-
-    tokenStats = {
-      totalPromptTokens,
-      totalCompletionTokens,
-      totalTokens,
-      avgTokensPerChapter,
-      recentTrend,
-    };
-  }
-
   return {
     bookId,
     totalChapters,
@@ -112,13 +74,11 @@ export function computeAnalytics(
     topIssueCategories,
     chaptersWithMostIssues,
     statusDistribution,
-    tokenStats,
   };
 }
 
 export const analyticsCommand = new Command("analytics")
-  .alias("stats")
-  .description("Show analytics and token stats for a book")
+  .description("Show analytics for a book")
   .argument("[book-id]", "Book ID (auto-detected if only one book)")
   .option("--json", "Output JSON")
   .action(async (bookIdArg: string | undefined, opts) => {
@@ -150,21 +110,6 @@ export const analyticsCommand = new Command("analytics")
           log("");
         }
 
-        if (analytics.tokenStats) {
-          log("  Token usage:");
-          log(`    Total tokens: ${analytics.tokenStats.totalTokens.toLocaleString()}`);
-          log(`    Prompt tokens: ${analytics.tokenStats.totalPromptTokens.toLocaleString()}`);
-          log(`    Completion tokens: ${analytics.tokenStats.totalCompletionTokens.toLocaleString()}`);
-          log(`    Avg tokens/chapter: ${analytics.tokenStats.avgTokensPerChapter.toLocaleString()}`);
-          if (analytics.tokenStats.recentTrend.length > 0) {
-            log("    Recent trend:");
-            for (const { chapter, totalTokens } of analytics.tokenStats.recentTrend) {
-              log(`      Ch.${chapter}: ${totalTokens.toLocaleString()} tokens`);
-            }
-          }
-          log("");
-        }
-
         if (analytics.topIssueCategories.length > 0) {
           log("  Most common issue categories:");
           for (const { category, count } of analytics.topIssueCategories) {

+ 1 - 58
packages/cli/src/commands/export.ts

@@ -7,7 +7,7 @@ import { findProjectRoot, resolveBookId, log, logError } from "../utils.js";
 export const exportCommand = new Command("export")
   .description("Export book chapters to a single file")
   .argument("[book-id]", "Book ID (auto-detected if only one book)")
-  .option("--format <format>", "Output format (txt, md, epub)", "txt")
+  .option("--format <format>", "Output format (txt, md)", "txt")
   .option("--output <path>", "Output file path")
   .option("--approved-only", "Only export approved chapters")
   .option("--json", "Output JSON metadata")
@@ -30,11 +30,6 @@ export const exportCommand = new Command("export")
         throw new Error("No chapters to export.");
       }
 
-      if (opts.format === "epub") {
-        await exportEpub(book, chapters, chaptersDir, bookId, root, opts);
-        return;
-      }
-
       const parts: string[] = [];
 
       if (opts.format === "md") {
@@ -82,55 +77,3 @@ export const exportCommand = new Command("export")
       process.exit(1);
     }
   });
-
-async function exportEpub(
-  book: { readonly title: string },
-  chapters: ReadonlyArray<{ readonly number: number; readonly wordCount: number }>,
-  chaptersDir: string,
-  bookId: string,
-  root: string,
-  opts: { readonly output?: string; readonly json?: boolean },
-): Promise<void> {
-  const { marked } = await import("marked");
-  const { EPub } = await import("epub-gen-memory");
-
-  const epubChapters: Array<{ title: string; content: string }> = [];
-
-  for (const ch of chapters) {
-    const paddedNum = String(ch.number).padStart(4, "0");
-    const files = await readdir(chaptersDir);
-    const match = files.find((f) => f.startsWith(paddedNum));
-    if (!match) continue;
-
-    const markdown = await readFile(join(chaptersDir, match), "utf-8");
-    const html = await marked.parse(markdown);
-    // Extract title from first heading or fall back to filename
-    const titleMatch = markdown.match(/^#\s+(.+)/m);
-    const title = titleMatch?.[1] ?? match.replace(/\.md$/, "");
-
-    epubChapters.push({ title, content: html });
-  }
-
-  const epubInstance = new EPub(
-    { title: book.title, lang: "zh-CN" },
-    epubChapters,
-  );
-  const epubBuffer: Buffer = await epubInstance.genEpub();
-
-  const totalWords = chapters.reduce((sum, ch) => sum + ch.wordCount, 0);
-  const outputPath = opts.output ?? join(root, `${bookId}.epub`);
-  await writeFile(outputPath, epubBuffer);
-
-  if (opts.json) {
-    log(JSON.stringify({
-      bookId,
-      chaptersExported: chapters.length,
-      totalWords,
-      format: "epub",
-      outputPath,
-    }, null, 2));
-  } else {
-    log(`Exported ${chapters.length} chapters (${totalWords} words) to EPUB`);
-    log(`Output: ${outputPath}`);
-  }
-}

+ 1 - 7
packages/core/src/agents/continuity.ts

@@ -9,11 +9,6 @@ export interface AuditResult {
   readonly passed: boolean;
   readonly issues: ReadonlyArray<AuditIssue>;
   readonly summary: string;
-  readonly tokenUsage?: {
-    readonly promptTokens: number;
-    readonly completionTokens: number;
-    readonly totalTokens: number;
-  };
 }
 
 export interface AuditIssue {
@@ -301,8 +296,7 @@ ${chapterContent}`;
       ? await this.chatWithSearch(chatMessages, chatOptions)
       : await this.chat(chatMessages, chatOptions);
 
-    const result = this.parseAuditResult(response.content);
-    return { ...result, tokenUsage: response.usage };
+    return this.parseAuditResult(response.content);
   }
 
   private parseAuditResult(content: string): AuditResult {

+ 1 - 7
packages/core/src/agents/reviser.ts

@@ -15,11 +15,6 @@ export interface ReviseOutput {
   readonly updatedState: string;
   readonly updatedLedger: string;
   readonly updatedHooks: string;
-  readonly tokenUsage?: {
-    readonly promptTokens: number;
-    readonly completionTokens: number;
-    readonly totalTokens: number;
-  };
 }
 
 const MODE_DESCRIPTIONS: Record<ReviseMode, string> = {
@@ -157,8 +152,7 @@ ${chapterContent}`;
       { temperature: 0.3, maxTokens },
     );
 
-    const output = this.parseOutput(response.content, gp);
-    return { ...output, tokenUsage: response.usage };
+    return this.parseOutput(response.content, gp);
   }
 
   private parseOutput(content: string, gp: GenreProfile): ReviseOutput {

+ 4 - 24
packages/core/src/agents/writer.ts

@@ -21,12 +21,6 @@ export interface WriteChapterInput {
   readonly temperatureOverride?: number;
 }
 
-export interface TokenUsage {
-  readonly promptTokens: number;
-  readonly completionTokens: number;
-  readonly totalTokens: number;
-}
-
 export interface WriteChapterOutput {
   readonly chapterNumber: number;
   readonly title: string;
@@ -43,7 +37,6 @@ export interface WriteChapterOutput {
   readonly updatedCharacterMatrix: string;
   readonly postWriteErrors: ReadonlyArray<PostWriteViolation>;
   readonly postWriteWarnings: ReadonlyArray<PostWriteViolation>;
-  readonly tokenUsage?: TokenUsage;
 }
 
 export class WriterAgent extends BaseAgent {
@@ -129,14 +122,13 @@ export class WriterAgent extends BaseAgent {
       ],
       { maxTokens: creativeMaxTokens, temperature: creativeTemperature },
     );
-    const creativeUsage = creativeResponse.usage;
 
     const creative = parseCreativeOutput(chapterNumber, creativeResponse.content);
 
     // ── Phase 2: State settlement (temperature 0.3) ──
     process.stderr.write(`[writer] Phase 2: state settlement for chapter ${chapterNumber} (${creative.wordCount} chars)\n`);
 
-    const settleResult = await this.settle({
+    const settlement = await this.settle({
       book,
       genreProfile,
       bookRules,
@@ -152,8 +144,6 @@ export class WriterAgent extends BaseAgent {
       characterMatrix,
       volumeOutline,
     });
-    const settlement = settleResult.settlement;
-    const settleUsage = settleResult.usage;
 
     // ── Post-write validation (regex + rule-based, zero LLM cost) ──
     const ruleViolations = validatePostWrite(creative.content, genreProfile, bookRules);
@@ -179,13 +169,7 @@ export class WriterAgent extends BaseAgent {
       }
     }
 
-    // ── Merge into WriteChapterOutput ──
-    const tokenUsage: TokenUsage = {
-      promptTokens: creativeUsage.promptTokens + settleUsage.promptTokens,
-      completionTokens: creativeUsage.completionTokens + settleUsage.completionTokens,
-      totalTokens: creativeUsage.totalTokens + settleUsage.totalTokens,
-    };
-
+    // ── Merge into WriteChapterOutput (interface unchanged) ──
     return {
       chapterNumber,
       title: creative.title,
@@ -202,7 +186,6 @@ export class WriterAgent extends BaseAgent {
       updatedCharacterMatrix: settlement.updatedCharacterMatrix,
       postWriteErrors,
       postWriteWarnings,
-      tokenUsage,
     };
   }
 
@@ -221,7 +204,7 @@ export class WriterAgent extends BaseAgent {
     readonly emotionalArcs: string;
     readonly characterMatrix: string;
     readonly volumeOutline: string;
-  }): Promise<{ settlement: ReturnType<typeof parseSettlementOutput>; usage: TokenUsage }> {
+  }) {
     const settlerSystem = buildSettlerSystemPrompt(
       params.book, params.genreProfile, params.bookRules,
     );
@@ -251,10 +234,7 @@ export class WriterAgent extends BaseAgent {
       { maxTokens: settlerMaxTokens, temperature: 0.3 },
     );
 
-    return {
-      settlement: parseSettlementOutput(response.content, params.genreProfile),
-      usage: response.usage,
-    };
+    return parseSettlementOutput(response.content, params.genreProfile);
   }
 
   async saveChapter(

+ 2 - 2
packages/core/src/index.ts

@@ -14,7 +14,7 @@ export { createLLMClient, chatCompletion, chatWithTools, type LLMClient, type LL
 // Agents
 export { BaseAgent, type AgentContext } from "./agents/base.js";
 export { ArchitectAgent, type ArchitectOutput } from "./agents/architect.js";
-export { WriterAgent, type WriteChapterInput, type WriteChapterOutput, type TokenUsage } from "./agents/writer.js";
+export { WriterAgent, type WriteChapterInput, type WriteChapterOutput } from "./agents/writer.js";
 export { ContinuityAuditor, type AuditResult, type AuditIssue } from "./agents/continuity.js";
 export { ReviserAgent, type ReviseOutput, type ReviseMode } from "./agents/reviser.js";
 export { RadarAgent, type RadarResult, type RadarRecommendation } from "./agents/radar.js";
@@ -37,7 +37,7 @@ export { fetchUrl } from "./utils/web-search.js";
 export { splitChapters, type SplitChapter } from "./utils/chapter-splitter.js";
 
 // Pipeline
-export { PipelineRunner, type PipelineConfig, type ChapterPipelineResult, type DraftResult, type ReviseResult, type TruthFiles, type BookStatusInfo, type ImportChaptersInput, type ImportChaptersResult, type TokenUsageSummary } from "./pipeline/runner.js";
+export { PipelineRunner, type PipelineConfig, type ChapterPipelineResult, type DraftResult, type ReviseResult, type TruthFiles, type BookStatusInfo, type ImportChaptersInput, type ImportChaptersResult } from "./pipeline/runner.js";
 export { Scheduler, type SchedulerConfig } from "./pipeline/scheduler.js";
 export { runAgentLoop, AGENT_TOOLS as AGENT_TOOLS, type AgentLoopOptions } from "./pipeline/agent.js";
 export { detectChapter, detectAndRewrite, loadDetectionHistory, type DetectChapterResult, type DetectAndRewriteResult } from "./pipeline/detection-runner.js";

+ 0 - 5
packages/core/src/models/chapter.ts

@@ -28,11 +28,6 @@ export const ChapterMetaSchema = z.object({
   detectionScore: z.number().min(0).max(1).optional(),
   detectionProvider: z.string().optional(),
   detectedAt: z.string().datetime().optional(),
-  tokenUsage: z.object({
-    promptTokens: z.number().int().default(0),
-    completionTokens: z.number().int().default(0),
-    totalTokens: z.number().int().default(0),
-  }).optional(),
 });
 
 export type ChapterMeta = z.infer<typeof ChapterMetaSchema>;

+ 1 - 31
packages/core/src/pipeline/runner.ts

@@ -34,12 +34,6 @@ export interface PipelineConfig {
   readonly modelOverrides?: Record<string, string | AgentLLMOverride>;
 }
 
-export interface TokenUsageSummary {
-  readonly promptTokens: number;
-  readonly completionTokens: number;
-  readonly totalTokens: number;
-}
-
 export interface ChapterPipelineResult {
   readonly chapterNumber: number;
   readonly title: string;
@@ -47,7 +41,6 @@ export interface ChapterPipelineResult {
   readonly auditResult: AuditResult;
   readonly revised: boolean;
   readonly status: "ready-for-review" | "audit-failed";
-  readonly tokenUsage?: TokenUsageSummary;
 }
 
 // Atomic operation results
@@ -56,7 +49,6 @@ export interface DraftResult {
   readonly title: string;
   readonly wordCount: number;
   readonly filePath: string;
-  readonly tokenUsage?: TokenUsageSummary;
 }
 
 export interface ReviseResult {
@@ -232,7 +224,6 @@ export class PipelineRunner {
         createdAt: now,
         updatedAt: now,
         auditIssues: [],
-        ...(output.tokenUsage ? { tokenUsage: output.tokenUsage } : {}),
       };
       await this.state.saveChapterIndex(bookId, [...existingIndex, newEntry]);
 
@@ -244,7 +235,7 @@ export class PipelineRunner {
         wordCount: output.wordCount,
       });
 
-      return { chapterNumber, title: output.title, wordCount: output.wordCount, filePath, tokenUsage: output.tokenUsage };
+      return { chapterNumber, title: output.title, wordCount: output.wordCount, filePath };
     } finally {
       await releaseLock();
     }
@@ -473,9 +464,6 @@ export class PipelineRunner {
       ...(temperatureOverride ? { temperatureOverride } : {}),
     });
 
-    // Token usage accumulator
-    let totalUsage: TokenUsageSummary = output.tokenUsage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
-
     // 2a. Post-write error gate: if deterministic rules found errors, auto-fix before LLM audit
     let finalContent = output.content;
     let finalWordCount = output.wordCount;
@@ -500,7 +488,6 @@ export class PipelineRunner {
         "spot-fix",
         book.genre,
       );
-      totalUsage = PipelineRunner.addUsage(totalUsage, fixResult.tokenUsage);
       if (fixResult.revisedContent.length > 0) {
         finalContent = fixResult.revisedContent;
         finalWordCount = fixResult.wordCount;
@@ -516,7 +503,6 @@ export class PipelineRunner {
       chapterNumber,
       book.genre,
     );
-    totalUsage = PipelineRunner.addUsage(totalUsage, llmAudit.tokenUsage);
     const aiTellsResult = analyzeAITells(finalContent);
     const sensitiveWriteResult = analyzeSensitiveWords(finalContent);
     const hasBlockedWriteWords = sensitiveWriteResult.found.some((f) => f.severity === "block");
@@ -541,7 +527,6 @@ export class PipelineRunner {
           "spot-fix",
           book.genre,
         );
-        totalUsage = PipelineRunner.addUsage(totalUsage, reviseOutput.tokenUsage);
 
         if (reviseOutput.revisedContent.length > 0) {
           // Guard: reject revision if AI markers increased
@@ -566,7 +551,6 @@ export class PipelineRunner {
             book.genre,
             { temperature: 0 },
           );
-          totalUsage = PipelineRunner.addUsage(totalUsage, reAudit.tokenUsage);
           const reAITells = analyzeAITells(finalContent);
           const reSensitive = analyzeSensitiveWords(finalContent);
           const reHasBlocked = reSensitive.found.some((f) => f.severity === "block");
@@ -624,7 +608,6 @@ export class PipelineRunner {
       auditIssues: auditResult.issues.map(
         (i) => `[${i.severity}] ${i.description}`,
       ),
-      tokenUsage: totalUsage,
     };
     await this.state.saveChapterIndex(bookId, [...existingIndex, newEntry]);
 
@@ -663,7 +646,6 @@ export class PipelineRunner {
       auditResult,
       revised,
       status: auditResult.passed ? "ready-for-review" : "audit-failed",
-      tokenUsage: totalUsage,
     };
   }
 
@@ -973,18 +955,6 @@ ${matrix}`,
     }
   }
 
-  private static addUsage(
-    a: TokenUsageSummary,
-    b?: { readonly promptTokens: number; readonly completionTokens: number; readonly totalTokens: number },
-  ): TokenUsageSummary {
-    if (!b) return a;
-    return {
-      promptTokens: a.promptTokens + b.promptTokens,
-      completionTokens: a.completionTokens + b.completionTokens,
-      totalTokens: a.totalTokens + b.totalTokens,
-    };
-  }
-
   // ---------------------------------------------------------------------------
   // Helpers
   // ---------------------------------------------------------------------------

+ 0 - 318
pnpm-lock.yaml

@@ -19,12 +19,6 @@ importers:
       dotenv:
         specifier: ^16.4.0
         version: 16.6.1
-      epub-gen-memory:
-        specifier: ^1.0.10
-        version: 1.1.2
-      marked:
-        specifier: ^15.0.0
-        version: 15.0.12
     devDependencies:
       '@types/node':
         specifier: ^22.0.0
@@ -373,10 +367,6 @@ packages:
     cpu: [x64]
     os: [win32]
 
-  '@sindresorhus/is@4.6.0':
-    resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
-    engines: {node: '>=10'}
-
   '@types/chai@5.2.3':
     resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
 
@@ -442,21 +432,9 @@ packages:
     resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
     engines: {node: '>=12'}
 
-  async@3.2.6:
-    resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
-
   asynckit@0.4.0:
     resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
 
-  balanced-match@1.0.2:
-    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-
-  boolbase@1.0.0:
-    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
-
-  brace-expansion@2.0.2:
-    resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
-
   cac@6.7.14:
     resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
     engines: {node: '>=8'}
@@ -465,10 +443,6 @@ packages:
     resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
     engines: {node: '>= 0.4'}
 
-  callsites@3.1.0:
-    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
-    engines: {node: '>=6'}
-
   chai@5.3.3:
     resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
     engines: {node: '>=18'}
@@ -485,16 +459,6 @@ packages:
     resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
     engines: {node: '>=18'}
 
-  core-util-is@1.0.3:
-    resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
-
-  css-select@4.3.0:
-    resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
-
-  css-what@6.2.2:
-    resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
-    engines: {node: '>= 6'}
-
   debug@4.4.3:
     resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
     engines: {node: '>=6.0'}
@@ -512,26 +476,6 @@ packages:
     resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
     engines: {node: '>=0.4.0'}
 
-  diacritics@1.3.0:
-    resolution: {integrity: sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==}
-
-  dom-serializer@1.4.1:
-    resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
-
-  domelementtype@2.3.0:
-    resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
-
-  domhandler@4.3.1:
-    resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
-    engines: {node: '>= 4'}
-
-  domutils@2.8.0:
-    resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
-
-  dot-prop@6.0.1:
-    resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
-    engines: {node: '>=10'}
-
   dotenv@16.6.1:
     resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
     engines: {node: '>=12'}
@@ -540,22 +484,6 @@ packages:
     resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
     engines: {node: '>= 0.4'}
 
-  ejs@3.1.10:
-    resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
-    engines: {node: '>=0.10.0'}
-    hasBin: true
-
-  entities@2.2.0:
-    resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
-
-  entities@3.0.1:
-    resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
-    engines: {node: '>=0.12'}
-
-  epub-gen-memory@1.1.2:
-    resolution: {integrity: sha512-vwGM6MVNqKIskFzPZqhi4ZOs0ZTUXco9oDuHFX1vB2Il9pTAkaHWFBFgHrrl832dYmBPb/raGVUZXFvZYueRyw==}
-    engines: {node: '>=10.0.0'}
-
   es-define-property@1.0.1:
     resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
     engines: {node: '>= 0.4'}
@@ -600,9 +528,6 @@ packages:
       picomatch:
         optional: true
 
-  filelist@1.0.6:
-    resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==}
-
   form-data-encoder@1.7.2:
     resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
 
@@ -646,30 +571,9 @@ packages:
     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
     engines: {node: '>= 0.4'}
 
-  htmlparser2@7.2.0:
-    resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==}
-
   humanize-ms@1.2.1:
     resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
 
-  immediate@3.0.6:
-    resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
-
-  inherits@2.0.4:
-    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-
-  is-obj@2.0.0:
-    resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
-    engines: {node: '>=8'}
-
-  isarray@1.0.0:
-    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
-
-  jake@10.9.4:
-    resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
-    engines: {node: '>=10'}
-    hasBin: true
-
   js-tokens@9.0.1:
     resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
 
@@ -681,27 +585,12 @@ packages:
     resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
     engines: {node: '>=16'}
 
-  jszip@3.10.1:
-    resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
-
-  lie@3.3.0:
-    resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
-
-  lodash.isequal@4.5.0:
-    resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
-    deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
-
   loupe@3.2.1:
     resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
 
   magic-string@0.30.21:
     resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
 
-  marked@15.0.12:
-    resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
-    engines: {node: '>= 18'}
-    hasBin: true
-
   math-intrinsics@1.1.0:
     resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
     engines: {node: '>= 0.4'}
@@ -714,15 +603,6 @@ packages:
     resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
     engines: {node: '>= 0.6'}
 
-  mime@2.6.0:
-    resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
-    engines: {node: '>=4.0.0'}
-    hasBin: true
-
-  minimatch@5.1.9:
-    resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==}
-    engines: {node: '>=10'}
-
   ms@2.1.3:
     resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
 
@@ -745,9 +625,6 @@ packages:
       encoding:
         optional: true
 
-  nth-check@2.1.1:
-    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
-
   openai@4.104.0:
     resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==}
     hasBin: true
@@ -760,13 +637,6 @@ packages:
       zod:
         optional: true
 
-  ow@0.28.2:
-    resolution: {integrity: sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q==}
-    engines: {node: '>=12'}
-
-  pako@1.0.11:
-    resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
-
   pathe@2.0.3:
     resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
 
@@ -785,30 +655,14 @@ packages:
     resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
     engines: {node: ^10 || ^12 || >=14}
 
-  process-nextick-args@2.0.1:
-    resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
-
-  readable-stream@2.3.8:
-    resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
-
   rollup@4.59.0:
     resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
     hasBin: true
 
-  safe-buffer@5.1.2:
-    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
-
-  setimmediate@1.0.5:
-    resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
-
   siginfo@2.0.0:
     resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
 
-  slugify@1.6.8:
-    resolution: {integrity: sha512-HVk9X1E0gz3mSpoi60h/saazLKXKaZThMLU3u/aNwoYn8/xQyX2MGxL0ui2eaokkD7tF+Zo+cKTHUbe1mmmGzA==}
-    engines: {node: '>=8.0.0'}
-
   source-map-js@1.2.1:
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
     engines: {node: '>=0.10.0'}
@@ -819,9 +673,6 @@ packages:
   std-env@3.10.0:
     resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
 
-  string_decoder@1.1.1:
-    resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
-
   strip-literal@3.1.0:
     resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
 
@@ -864,13 +715,6 @@ packages:
   undici-types@6.21.0:
     resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
 
-  util-deprecate@1.0.2:
-    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-
-  vali-date@1.0.0:
-    resolution: {integrity: sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==}
-    engines: {node: '>=0.10.0'}
-
   vite-node@3.2.4:
     resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
     engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@@ -1127,8 +971,6 @@ snapshots:
   '@rollup/rollup-win32-x64-msvc@4.59.0':
     optional: true
 
-  '@sindresorhus/is@4.6.0': {}
-
   '@types/chai@5.2.3':
     dependencies:
       '@types/deep-eql': 4.0.2
@@ -1207,18 +1049,8 @@ snapshots:
 
   assertion-error@2.0.1: {}
 
-  async@3.2.6: {}
-
   asynckit@0.4.0: {}
 
-  balanced-match@1.0.2: {}
-
-  boolbase@1.0.0: {}
-
-  brace-expansion@2.0.2:
-    dependencies:
-      balanced-match: 1.0.2
-
   cac@6.7.14: {}
 
   call-bind-apply-helpers@1.0.2:
@@ -1226,8 +1058,6 @@ snapshots:
       es-errors: 1.3.0
       function-bind: 1.1.2
 
-  callsites@3.1.0: {}
-
   chai@5.3.3:
     dependencies:
       assertion-error: 2.0.1
@@ -1244,18 +1074,6 @@ snapshots:
 
   commander@13.1.0: {}
 
-  core-util-is@1.0.3: {}
-
-  css-select@4.3.0:
-    dependencies:
-      boolbase: 1.0.0
-      css-what: 6.2.2
-      domhandler: 4.3.1
-      domutils: 2.8.0
-      nth-check: 2.1.1
-
-  css-what@6.2.2: {}
-
   debug@4.4.3:
     dependencies:
       ms: 2.1.3
@@ -1264,30 +1082,6 @@ snapshots:
 
   delayed-stream@1.0.0: {}
 
-  diacritics@1.3.0: {}
-
-  dom-serializer@1.4.1:
-    dependencies:
-      domelementtype: 2.3.0
-      domhandler: 4.3.1
-      entities: 2.2.0
-
-  domelementtype@2.3.0: {}
-
-  domhandler@4.3.1:
-    dependencies:
-      domelementtype: 2.3.0
-
-  domutils@2.8.0:
-    dependencies:
-      dom-serializer: 1.4.1
-      domelementtype: 2.3.0
-      domhandler: 4.3.1
-
-  dot-prop@6.0.1:
-    dependencies:
-      is-obj: 2.0.0
-
   dotenv@16.6.1: {}
 
   dunder-proto@1.0.1:
@@ -1296,32 +1090,6 @@ snapshots:
       es-errors: 1.3.0
       gopd: 1.2.0
 
-  ejs@3.1.10:
-    dependencies:
-      jake: 10.9.4
-
-  entities@2.2.0: {}
-
-  entities@3.0.1: {}
-
-  epub-gen-memory@1.1.2:
-    dependencies:
-      abort-controller: 3.0.0
-      css-select: 4.3.0
-      diacritics: 1.3.0
-      dom-serializer: 1.4.1
-      domhandler: 4.3.1
-      domutils: 2.8.0
-      ejs: 3.1.10
-      htmlparser2: 7.2.0
-      jszip: 3.10.1
-      mime: 2.6.0
-      node-fetch: 2.7.0
-      ow: 0.28.2
-      slugify: 1.6.8
-    transitivePeerDependencies:
-      - encoding
-
   es-define-property@1.0.1: {}
 
   es-errors@1.3.0: {}
@@ -1380,10 +1148,6 @@ snapshots:
     optionalDependencies:
       picomatch: 4.0.3
 
-  filelist@1.0.6:
-    dependencies:
-      minimatch: 5.1.9
-
   form-data-encoder@1.7.2: {}
 
   form-data@4.0.5:
@@ -1434,31 +1198,10 @@ snapshots:
     dependencies:
       function-bind: 1.1.2
 
-  htmlparser2@7.2.0:
-    dependencies:
-      domelementtype: 2.3.0
-      domhandler: 4.3.1
-      domutils: 2.8.0
-      entities: 3.0.1
-
   humanize-ms@1.2.1:
     dependencies:
       ms: 2.1.3
 
-  immediate@3.0.6: {}
-
-  inherits@2.0.4: {}
-
-  is-obj@2.0.0: {}
-
-  isarray@1.0.0: {}
-
-  jake@10.9.4:
-    dependencies:
-      async: 3.2.6
-      filelist: 1.0.6
-      picocolors: 1.1.1
-
   js-tokens@9.0.1: {}
 
   js-yaml@4.1.1:
@@ -1470,27 +1213,12 @@ snapshots:
       '@babel/runtime': 7.28.6
       ts-algebra: 2.0.0
 
-  jszip@3.10.1:
-    dependencies:
-      lie: 3.3.0
-      pako: 1.0.11
-      readable-stream: 2.3.8
-      setimmediate: 1.0.5
-
-  lie@3.3.0:
-    dependencies:
-      immediate: 3.0.6
-
-  lodash.isequal@4.5.0: {}
-
   loupe@3.2.1: {}
 
   magic-string@0.30.21:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.5.5
 
-  marked@15.0.12: {}
-
   math-intrinsics@1.1.0: {}
 
   mime-db@1.52.0: {}
@@ -1499,12 +1227,6 @@ snapshots:
     dependencies:
       mime-db: 1.52.0
 
-  mime@2.6.0: {}
-
-  minimatch@5.1.9:
-    dependencies:
-      brace-expansion: 2.0.2
-
   ms@2.1.3: {}
 
   nanoid@3.3.11: {}
@@ -1515,10 +1237,6 @@ snapshots:
     dependencies:
       whatwg-url: 5.0.0
 
-  nth-check@2.1.1:
-    dependencies:
-      boolbase: 1.0.0
-
   openai@4.104.0(zod@3.25.76):
     dependencies:
       '@types/node': 18.19.130
@@ -1533,16 +1251,6 @@ snapshots:
     transitivePeerDependencies:
       - encoding
 
-  ow@0.28.2:
-    dependencies:
-      '@sindresorhus/is': 4.6.0
-      callsites: 3.1.0
-      dot-prop: 6.0.1
-      lodash.isequal: 4.5.0
-      vali-date: 1.0.0
-
-  pako@1.0.11: {}
-
   pathe@2.0.3: {}
 
   pathval@2.0.1: {}
@@ -1557,18 +1265,6 @@ snapshots:
       picocolors: 1.1.1
       source-map-js: 1.2.1
 
-  process-nextick-args@2.0.1: {}
-
-  readable-stream@2.3.8:
-    dependencies:
-      core-util-is: 1.0.3
-      inherits: 2.0.4
-      isarray: 1.0.0
-      process-nextick-args: 2.0.1
-      safe-buffer: 5.1.2
-      string_decoder: 1.1.1
-      util-deprecate: 1.0.2
-
   rollup@4.59.0:
     dependencies:
       '@types/estree': 1.0.8
@@ -1600,24 +1296,14 @@ snapshots:
       '@rollup/rollup-win32-x64-msvc': 4.59.0
       fsevents: 2.3.3
 
-  safe-buffer@5.1.2: {}
-
-  setimmediate@1.0.5: {}
-
   siginfo@2.0.0: {}
 
-  slugify@1.6.8: {}
-
   source-map-js@1.2.1: {}
 
   stackback@0.0.2: {}
 
   std-env@3.10.0: {}
 
-  string_decoder@1.1.1:
-    dependencies:
-      safe-buffer: 5.1.2
-
   strip-literal@3.1.0:
     dependencies:
       js-tokens: 9.0.1
@@ -1647,10 +1333,6 @@ snapshots:
 
   undici-types@6.21.0: {}
 
-  util-deprecate@1.0.2: {}
-
-  vali-date@1.0.0: {}
-
   vite-node@3.2.4(@types/node@22.19.15):
     dependencies:
       cac: 6.7.14