promptpilot 0.1.7 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts CHANGED
@@ -21,6 +21,7 @@ interface CliDependencies {
21
21
  columns?: number;
22
22
  user?: string;
23
23
  };
24
+ spawnClaude?: (prompt: string) => Promise<number>;
24
25
  }
25
26
  declare function runCli(argv: string[], io?: CliIO, dependencies?: CliDependencies): Promise<number>;
26
27
 
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/cli.ts
4
4
  import { readFileSync, realpathSync } from "fs";
5
5
  import { fileURLToPath } from "url";
6
- import { execSync } from "child_process";
6
+ import { execSync, spawn } from "child_process";
7
7
 
8
8
  // src/errors.ts
9
9
  var InvalidPromptError = class extends Error {
@@ -1417,6 +1417,18 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1417
1417
  };
1418
1418
  }
1419
1419
  if (!this.client.listModels) {
1420
+ if (isClaudeTiersOnlyTargetSet(availableTargets)) {
1421
+ const selected = selectClaudeTierHeuristic(options.input, options.routingPriority, availableTargets);
1422
+ if (selected) {
1423
+ return {
1424
+ selectedTarget: stripInternalTargetFields(selected),
1425
+ rankedTargets: [{ ...stripInternalTargetFields(selected), rank: 1, reason: "Selected by Claude tier heuristic (no local Qwen router available)." }],
1426
+ routingReason: "Selected by Claude tier heuristic (no local Qwen router available).",
1427
+ routingWarnings: [],
1428
+ routingProvider: "heuristic"
1429
+ };
1430
+ }
1431
+ }
1420
1432
  return {
1421
1433
  selectedTarget: null,
1422
1434
  rankedTargets: [],
@@ -1441,12 +1453,23 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1441
1453
  routingProvider: null
1442
1454
  };
1443
1455
  }
1456
+ const claudeTiersOnly = isClaudeTiersOnlyTargetSet(availableTargets);
1457
+ const routingCandidates = claudeTiersOnly ? filterClaudeTierCandidates(availableTargets, options.input, options.routingPriority) : availableTargets;
1458
+ if (routingCandidates.length === 1) {
1459
+ return {
1460
+ selectedTarget: stripInternalTargetFields(routingCandidates[0]),
1461
+ rankedTargets: [{ ...stripInternalTargetFields(routingCandidates[0]), rank: 1, reason: "Selected by Claude tier pre-filter based on prompt signals." }],
1462
+ routingReason: "Selected by Claude tier pre-filter based on prompt signals.",
1463
+ routingWarnings: [],
1464
+ routingProvider: "heuristic"
1465
+ };
1466
+ }
1444
1467
  const response = await this.client.generateJson({
1445
1468
  model: routerModel,
1446
1469
  timeoutMs: options.input.timeoutMs ?? this.config.timeoutMs,
1447
1470
  temperature: 0,
1448
1471
  format: "json",
1449
- systemPrompt: buildDownstreamRoutingSystemPrompt(options.routingPriority, options.workloadBias),
1472
+ systemPrompt: buildDownstreamRoutingSystemPrompt(options.routingPriority, options.workloadBias, claudeTiersOnly),
1450
1473
  prompt: JSON.stringify(
1451
1474
  {
1452
1475
  objective: "Rank the caller-supplied downstream targets for this prompt and choose the best top target.",
@@ -1458,7 +1481,7 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1458
1481
  targetHints: options.input.targetHints ?? [],
1459
1482
  workloadBias: options.workloadBias,
1460
1483
  routingPriority: options.routingPriority,
1461
- candidateTargets: availableTargets.map((target) => ({
1484
+ candidateTargets: routingCandidates.map((target) => ({
1462
1485
  id: target.id,
1463
1486
  provider: target.provider,
1464
1487
  model: target.model,
@@ -1477,7 +1500,7 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1477
1500
  new Set((response.rankedTargetIds ?? []).map((value) => value.trim()).filter(Boolean))
1478
1501
  ).slice(0, Math.max(1, options.routingTopK));
1479
1502
  const rankedTargets = rankedTargetIds.map((id, index) => {
1480
- const target = availableTargets.find((candidate) => candidate.id === id);
1503
+ const target = routingCandidates.find((candidate) => candidate.id === id);
1481
1504
  if (!target) {
1482
1505
  return null;
1483
1506
  }
@@ -1488,7 +1511,7 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1488
1511
  };
1489
1512
  }).filter((value) => value !== null);
1490
1513
  const selectedTargetId = response.selectedTargetId?.trim();
1491
- const selectedTargetCandidate = (selectedTargetId && availableTargets.find((candidate) => candidate.id === selectedTargetId)) ?? (rankedTargets[0] ? availableTargets.find(
1514
+ const selectedTargetCandidate = (selectedTargetId && routingCandidates.find((candidate) => candidate.id === selectedTargetId)) ?? (rankedTargets[0] ? routingCandidates.find(
1492
1515
  (candidate) => candidate.provider === rankedTargets[0].provider && candidate.model === rankedTargets[0].model && candidate.label === rankedTargets[0].label
1493
1516
  ) ?? null : null);
1494
1517
  if (!selectedTargetCandidate || rankedTargets.length === 0) {
@@ -1510,6 +1533,18 @@ Mode: Ultra compression. Minimize tokens aggressively.` : getOptimizationSystemP
1510
1533
  routingProvider: routerModel
1511
1534
  };
1512
1535
  } catch {
1536
+ if (isClaudeTiersOnlyTargetSet(availableTargets)) {
1537
+ const selected = selectClaudeTierHeuristic(options.input, options.routingPriority, availableTargets);
1538
+ if (selected) {
1539
+ return {
1540
+ selectedTarget: stripInternalTargetFields(selected),
1541
+ rankedTargets: [{ ...stripInternalTargetFields(selected), rank: 1, reason: "Selected by Claude tier heuristic (Qwen routing failed)." }],
1542
+ routingReason: "Selected by Claude tier heuristic (Qwen routing failed).",
1543
+ routingWarnings: ["Qwen downstream routing failed; fell back to Claude tier heuristic."],
1544
+ routingProvider: "heuristic"
1545
+ };
1546
+ }
1547
+ }
1513
1548
  return {
1514
1549
  selectedTarget: null,
1515
1550
  rankedTargets: [],
@@ -1658,8 +1693,8 @@ function stripInternalTargetFields(target) {
1658
1693
  latencyRank: target.latencyRank
1659
1694
  };
1660
1695
  }
1661
- function buildDownstreamRoutingSystemPrompt(priority, workloadBias) {
1662
- return [
1696
+ function buildDownstreamRoutingSystemPrompt(priority, workloadBias, claudeTiersOnly = false) {
1697
+ const lines = [
1663
1698
  "You are a downstream model router for PromptPilot.",
1664
1699
  "Return strict JSON only with this shape:",
1665
1700
  '{"selectedTargetId":"string","rankedTargetIds":["string"],"reason":"string"}',
@@ -1670,7 +1705,108 @@ function buildDownstreamRoutingSystemPrompt(priority, workloadBias) {
1670
1705
  "Code-first means ambiguous prompts should default toward coding-capable or agentic-capable targets.",
1671
1706
  "Explicit email, support, chat, and lightweight writing prompts may prefer cheaper lighter targets.",
1672
1707
  "Do not invent targets. Do not output prose outside JSON."
1673
- ].join("\n");
1708
+ ];
1709
+ if (claudeTiersOnly) {
1710
+ lines.push(
1711
+ "You are choosing between Claude model tiers (Haiku, Sonnet, Opus).",
1712
+ "Haiku: fastest and cheapest. ONLY suitable for email, chat, support, summarization, and trivial one-sentence rewrites. Do NOT use Haiku for any coding, debugging, refactoring, or technical tasks.",
1713
+ "Sonnet: balanced cost and capability. The DEFAULT for all coding, debugging, refactoring, writing, and general-purpose tasks. If the prompt mentions code, a file, a module, a bug, or any technical work, choose Sonnet at minimum.",
1714
+ "Opus: most capable and most expensive. Use for complex architecture decisions, multi-constraint agentic planning, system design, long-horizon reasoning, or when the prompt explicitly requires the strongest model.",
1715
+ "When routing priority is cheapest_adequate: Haiku for non-technical lightweight tasks only, Sonnet for anything involving code or technical content, Opus only when clearly necessary.",
1716
+ "When routing priority is best_quality: Opus for all code and reasoning tasks, Sonnet for writing and non-technical tasks.",
1717
+ "When routing priority is fastest_adequate: Haiku only for lightweight non-technical tasks, Sonnet otherwise.",
1718
+ "IMPORTANT: refactor, debug, fix, auth, module, CI, test, and TypeScript are all coding signals \u2014 always choose Sonnet or Opus for these, never Haiku."
1719
+ );
1720
+ }
1721
+ return lines.join("\n");
1722
+ }
1723
+ var CLAUDE_TIER_TARGETS = [
1724
+ {
1725
+ provider: "anthropic",
1726
+ model: "claude-haiku-4-5",
1727
+ label: "anthropic:claude-haiku-4-5",
1728
+ capabilities: ["writing", "email", "support", "chat", "summarization"],
1729
+ costRank: 1,
1730
+ latencyRank: 1
1731
+ },
1732
+ {
1733
+ provider: "anthropic",
1734
+ model: "claude-sonnet-4-6",
1735
+ label: "anthropic:claude-sonnet-4-6",
1736
+ capabilities: ["coding", "writing", "agentic", "tool_use", "refactor", "debugging"],
1737
+ costRank: 2,
1738
+ latencyRank: 2
1739
+ },
1740
+ {
1741
+ provider: "anthropic",
1742
+ model: "claude-opus-4-6",
1743
+ label: "anthropic:claude-opus-4-6",
1744
+ capabilities: ["coding", "agentic", "tool_use", "refactor", "debugging", "architecture", "writing"],
1745
+ costRank: 3,
1746
+ latencyRank: 3
1747
+ }
1748
+ ];
1749
+ function isClaudeTiersOnlyTargetSet(targets) {
1750
+ return targets.length >= 2 && targets.every(
1751
+ (t) => t.provider === "anthropic" && /haiku|sonnet|opus/i.test(t.model)
1752
+ );
1753
+ }
1754
+ function isCodeSignal(input) {
1755
+ const task = (input.task ?? "").toLowerCase();
1756
+ const preset = (input.preset ?? "").toLowerCase();
1757
+ const hints = input.targetHints ?? [];
1758
+ return task === "code" || preset === "code" || hints.some((h) => ["coding", "agentic", "tool_use", "refactor", "debugging", "architecture"].includes(h)) || /\b(refactor|debug|fix|auth|module|ci|test|typescript|javascript|function|class|api|endpoint|build|deploy|lint|migration)\b/i.test(input.prompt);
1759
+ }
1760
+ function isArchitectureSignal(input) {
1761
+ const hints = input.targetHints ?? [];
1762
+ return hints.includes("architecture") || /\b(architect|architecture|design system|migration plan|multi.?step|long.?horizon|agentic.*plan|system design|microservice|monolith)\b/i.test(input.prompt);
1763
+ }
1764
+ function filterClaudeTierCandidates(targets, input, priority) {
1765
+ if (priority === "best_quality") {
1766
+ const filtered = targets.filter((t) => /opus|sonnet/i.test(t.model));
1767
+ return filtered.length > 0 ? filtered : targets;
1768
+ }
1769
+ if (priority === "cheapest_adequate") {
1770
+ if (isArchitectureSignal(input)) {
1771
+ const filtered2 = targets.filter((t) => /opus|sonnet/i.test(t.model));
1772
+ return filtered2.length > 0 ? filtered2 : targets;
1773
+ }
1774
+ if (isCodeSignal(input)) {
1775
+ const sonnet = targets.find((t) => /sonnet/i.test(t.model));
1776
+ return sonnet ? [sonnet] : targets.filter((t) => !/haiku/i.test(t.model));
1777
+ }
1778
+ const filtered = targets.filter((t) => /haiku|sonnet/i.test(t.model));
1779
+ return filtered.length > 0 ? filtered : targets;
1780
+ }
1781
+ if (priority === "fastest_adequate") {
1782
+ const filtered = targets.filter((t) => !/opus/i.test(t.model));
1783
+ return filtered.length > 0 ? filtered : targets;
1784
+ }
1785
+ return targets;
1786
+ }
1787
+ function selectClaudeTierHeuristic(input, priority, targets) {
1788
+ const haiku = targets.find((t) => /haiku/i.test(t.model)) ?? null;
1789
+ const sonnet = targets.find((t) => /sonnet/i.test(t.model)) ?? null;
1790
+ const opus = targets.find((t) => /opus/i.test(t.model)) ?? null;
1791
+ const task = (input.task ?? "").toLowerCase();
1792
+ const preset = (input.preset ?? "").toLowerCase();
1793
+ const hints = input.targetHints ?? [];
1794
+ const prompt = input.prompt;
1795
+ const isLightweight = ["email", "chat", "support", "summarization"].includes(task) || ["email", "chat", "support", "summarization"].includes(preset) || hints.some((h) => ["email", "support", "chat", "summarization"].includes(h));
1796
+ const needsOpus = /\b(architect|architecture|design system|migration plan|multi.?step|complex.*refactor|long.?horizon|agentic.*plan)\b/i.test(prompt) || hints.includes("architecture") || priority === "best_quality";
1797
+ const isCodeTask = ["code"].includes(task) || ["code"].includes(preset) || hints.some((h) => ["coding", "agentic", "tool_use", "refactor", "debugging", "architecture"].includes(h)) || /\b(refactor|debug|fix|auth|module|ci|test|typescript|javascript|function|class|api|endpoint)\b/i.test(prompt);
1798
+ if (priority === "fastest_adequate") {
1799
+ if (needsOpus) return opus ?? sonnet;
1800
+ if (isCodeTask) return sonnet ?? opus;
1801
+ return haiku ?? sonnet;
1802
+ }
1803
+ if (priority === "best_quality") {
1804
+ return opus ?? sonnet ?? haiku;
1805
+ }
1806
+ if (needsOpus) return opus ?? sonnet;
1807
+ if (isCodeTask) return sonnet ?? opus;
1808
+ if (isLightweight) return haiku ?? sonnet;
1809
+ return sonnet ?? haiku ?? opus;
1674
1810
  }
1675
1811
  function inferCapabilities(target) {
1676
1812
  const lower = `${target.provider} ${target.model} ${target.label ?? ""}`.toLowerCase();
@@ -1819,6 +1955,109 @@ function createOptimizer(config = {}) {
1819
1955
  return new PromptOptimizer(config);
1820
1956
  }
1821
1957
 
1958
+ // src/cliMenu.ts
1959
+ var ARROW_UP = "\x1B[A";
1960
+ var ARROW_DOWN = "\x1B[B";
1961
+ var ENTER = "\r";
1962
+ var CTRL_C = "";
1963
+ var ESCAPE = "\x1B";
1964
+ var CLAUDE_TIER_OPTIONS = [
1965
+ {
1966
+ key: "auto",
1967
+ label: "Auto",
1968
+ badge: "recommended",
1969
+ description: "PromptPilot picks the best tier for your prompt"
1970
+ },
1971
+ {
1972
+ key: "haiku",
1973
+ label: "Haiku",
1974
+ badge: "fastest \xB7 cheapest",
1975
+ description: "email, chat, summarization, simple rewrites"
1976
+ },
1977
+ {
1978
+ key: "sonnet",
1979
+ label: "Sonnet",
1980
+ badge: "balanced",
1981
+ description: "coding, debugging, writing, general-purpose"
1982
+ },
1983
+ {
1984
+ key: "opus",
1985
+ label: "Opus",
1986
+ badge: "most capable",
1987
+ description: "architecture, complex reasoning, agentic planning"
1988
+ }
1989
+ ];
1990
+ function renderClaudeMenu(options, selected) {
1991
+ const lines = ["Select Claude model tier:\n"];
1992
+ for (let index = 0; index < options.length; index++) {
1993
+ const opt = options[index];
1994
+ const isSelected = index === selected;
1995
+ const cursor = isSelected ? "\u276F" : " ";
1996
+ const label = isSelected ? `\x1B[1m${opt.label}\x1B[0m` : opt.label;
1997
+ const badge = `\x1B[2m${opt.badge}\x1B[0m`;
1998
+ const desc = `\x1B[2m${opt.description}\x1B[0m`;
1999
+ lines.push(` ${cursor} ${label.padEnd(isSelected ? 14 : 6)} ${badge}`);
2000
+ lines.push(` ${desc}`);
2001
+ }
2002
+ lines.push("\n \x1B[2m\u2191/\u2193 move Enter confirm q cancel\x1B[0m");
2003
+ return lines.join("\n");
2004
+ }
2005
+ async function promptClaudeTierMenu(stderr, stdin) {
2006
+ return new Promise((resolve) => {
2007
+ let selected = 0;
2008
+ const options = CLAUDE_TIER_OPTIONS;
2009
+ const lineCount = options.length * 2 + 3;
2010
+ const draw = (first) => {
2011
+ if (!first) {
2012
+ stderr.write(`\x1B[${lineCount}A`);
2013
+ }
2014
+ stderr.write(`\x1B[?25l${renderClaudeMenu(options, selected)}
2015
+ `);
2016
+ };
2017
+ const cleanup = () => {
2018
+ stderr.write("\x1B[?25h");
2019
+ stdin.setRawMode(false);
2020
+ stdin.pause();
2021
+ stdin.removeListener("data", onData);
2022
+ };
2023
+ const onData = (chunk) => {
2024
+ if (chunk === CTRL_C) {
2025
+ cleanup();
2026
+ process.exit(0);
2027
+ }
2028
+ if (chunk === "q" || chunk === ESCAPE) {
2029
+ cleanup();
2030
+ stderr.write("\n");
2031
+ resolve(null);
2032
+ return;
2033
+ }
2034
+ if (chunk === ARROW_UP) {
2035
+ selected = (selected - 1 + options.length) % options.length;
2036
+ draw(false);
2037
+ return;
2038
+ }
2039
+ if (chunk === ARROW_DOWN) {
2040
+ selected = (selected + 1) % options.length;
2041
+ draw(false);
2042
+ return;
2043
+ }
2044
+ if (chunk === ENTER) {
2045
+ cleanup();
2046
+ stderr.write(`
2047
+ Selected: \x1B[1m${options[selected].label}\x1B[0m
2048
+
2049
+ `);
2050
+ resolve(options[selected].key);
2051
+ }
2052
+ };
2053
+ stdin.setRawMode(true);
2054
+ stdin.resume();
2055
+ stdin.setEncoding("utf8");
2056
+ stdin.on("data", onData);
2057
+ draw(true);
2058
+ });
2059
+ }
2060
+
1822
2061
  // src/cliWelcome.ts
1823
2062
  import { basename } from "path";
1824
2063
  var MIN_WIDE_COLUMNS = 76;
@@ -2036,7 +2275,7 @@ async function runCli(argv, io = { stdout: process.stdout, stderr: process.stder
2036
2275
  `);
2037
2276
  return 0;
2038
2277
  }
2039
- if (command !== "optimize") {
2278
+ if (command !== "optimize" && command !== "claude") {
2040
2279
  io.stderr.write(`Unknown command: ${command}
2041
2280
  `);
2042
2281
  io.stderr.write(`${getHelpText()}
@@ -2079,6 +2318,20 @@ async function runCli(argv, io = { stdout: process.stdout, stderr: process.stder
2079
2318
  io.stderr.write("A prompt is required.\n");
2080
2319
  return 1;
2081
2320
  }
2321
+ const wantTierMenu = command === "claude" || parsed.autoClaudeTiers;
2322
+ let claudeTierChoice = null;
2323
+ if (wantTierMenu && io.stderr.isTTY && io.stdin) {
2324
+ claudeTierChoice = await promptClaudeTierMenu(io.stderr, io.stdin);
2325
+ if (claudeTierChoice === null) {
2326
+ return 0;
2327
+ }
2328
+ }
2329
+ const resolvedTargets = (() => {
2330
+ if (!wantTierMenu) return parsed.targets;
2331
+ if (!claudeTierChoice || claudeTierChoice === "auto") return [...CLAUDE_TIER_TARGETS, ...parsed.targets];
2332
+ const picked = CLAUDE_TIER_TARGETS.find((t) => t.model.toLowerCase().includes(claudeTierChoice));
2333
+ return picked ? [picked, ...parsed.targets] : [...CLAUDE_TIER_TARGETS, ...parsed.targets];
2334
+ })();
2082
2335
  const spinner = createSpinner(io.stderr, io.stderr.isTTY ?? false);
2083
2336
  try {
2084
2337
  spinner.start("optimizing");
@@ -2096,7 +2349,7 @@ async function runCli(argv, io = { stdout: process.stdout, stderr: process.stder
2096
2349
  maxLength: parsed.maxLength,
2097
2350
  tags: parsed.tags,
2098
2351
  pinnedConstraints: parsed.pinnedConstraints,
2099
- availableTargets: parsed.targets,
2352
+ availableTargets: resolvedTargets,
2100
2353
  routingEnabled: parsed.routingEnabled,
2101
2354
  routingPriority: parsed.routingPriority,
2102
2355
  routingTopK: parsed.routingTopK,
@@ -2111,6 +2364,11 @@ async function runCli(argv, io = { stdout: process.stdout, stderr: process.stder
2111
2364
  bypassOptimization: parsed.bypassOptimization
2112
2365
  });
2113
2366
  spinner.stop();
2367
+ if (command === "claude") {
2368
+ const doSpawn = dependencies.spawnClaude ?? spawnClaudeProcess;
2369
+ const exitCode = await doSpawn(result.finalPrompt);
2370
+ return exitCode;
2371
+ }
2114
2372
  if (parsed.json) {
2115
2373
  io.stdout.write(`${toPrettyJson(result)}
2116
2374
  `);
@@ -2168,6 +2426,7 @@ function parseOptimizeArgs(args) {
2168
2426
  clearSession: false,
2169
2427
  useContext: true,
2170
2428
  bypassOptimization: false,
2429
+ autoClaudeTiers: false,
2171
2430
  help: false,
2172
2431
  tags: [],
2173
2432
  pinnedConstraints: [],
@@ -2278,6 +2537,9 @@ function parseOptimizeArgs(args) {
2278
2537
  case "--bypass-optimization":
2279
2538
  parsed.bypassOptimization = true;
2280
2539
  break;
2540
+ case "--claude":
2541
+ parsed.autoClaudeTiers = true;
2542
+ break;
2281
2543
  case "--help":
2282
2544
  case "-h":
2283
2545
  parsed.help = true;
@@ -2291,9 +2553,16 @@ function parseOptimizeArgs(args) {
2291
2553
  }
2292
2554
  function getHelpText() {
2293
2555
  return [
2294
- "promptpilot optimize <prompt> [options]",
2556
+ "Usage:",
2295
2557
  "",
2296
- "Options:",
2558
+ " promptpilot claude <prompt> [options]",
2559
+ " Optimize your prompt and pipe it directly to the claude CLI.",
2560
+ " Shows a tier picker (Haiku / Sonnet / Opus / Auto) in interactive mode.",
2561
+ "",
2562
+ " promptpilot optimize <prompt> [options]",
2563
+ " Optimize and print the result to stdout.",
2564
+ "",
2565
+ "Options (shared):",
2297
2566
  " --session <id>",
2298
2567
  " --model <name> Override auto-selected local Ollama model",
2299
2568
  " --mode <mode>",
@@ -2315,9 +2584,6 @@ function getHelpText() {
2315
2584
  " --store <local|sqlite>",
2316
2585
  " --storage-dir <path>",
2317
2586
  " --sqlite-path <path>",
2318
- " --plain",
2319
- " --json",
2320
- " --clipboard Copy optimized prompt to clipboard",
2321
2587
  " --debug",
2322
2588
  " --save-context",
2323
2589
  " --no-context",
@@ -2326,7 +2592,13 @@ function getHelpText() {
2326
2592
  " --max-context-tokens <n>",
2327
2593
  " --max-input-tokens <n>",
2328
2594
  " --timeout <ms>",
2329
- " --bypass-optimization"
2595
+ " --bypass-optimization",
2596
+ "",
2597
+ "Options (optimize only):",
2598
+ " --plain",
2599
+ " --json",
2600
+ " --clipboard Copy optimized prompt to clipboard",
2601
+ " --claude Route between Haiku, Sonnet, and Opus automatically"
2330
2602
  ].join("\n");
2331
2603
  }
2332
2604
  function parseTargetCandidate(raw, index) {
@@ -2387,6 +2659,19 @@ function readPackageVersion() {
2387
2659
  return "dev";
2388
2660
  }
2389
2661
  }
2662
+ function spawnClaudeProcess(prompt) {
2663
+ return new Promise((resolve, reject) => {
2664
+ const child = spawn("claude", [], { stdio: ["pipe", "inherit", "inherit"] });
2665
+ if (!child.stdin) {
2666
+ reject(new Error("Failed to open stdin pipe to claude process"));
2667
+ return;
2668
+ }
2669
+ child.stdin.write(prompt);
2670
+ child.stdin.end();
2671
+ child.on("close", (code) => resolve(code ?? 1));
2672
+ child.on("error", reject);
2673
+ });
2674
+ }
2390
2675
  function copyToClipboard(text) {
2391
2676
  const commands = [
2392
2677
  { cmd: "xclip", args: ["-selection", "clipboard"], platform: "linux" },