@locusai/cli 0.17.13 → 0.17.14

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.
Files changed (2) hide show
  1. package/bin/locus.js +308 -56
  2. package/package.json +1 -1
package/bin/locus.js CHANGED
@@ -105,20 +105,11 @@ function padEnd(str, width) {
105
105
  return str;
106
106
  return str + " ".repeat(width - currentWidth);
107
107
  }
108
- function clearLine() {
109
- if (getCapabilities().isTTY) {
110
- process.stdout.write("\x1B[2K\r");
111
- }
112
- }
113
- function hideCursor() {
114
- if (getCapabilities().isTTY) {
115
- process.stdout.write("\x1B[?25l");
116
- }
117
- }
118
- function showCursor() {
119
- if (getCapabilities().isTTY) {
120
- process.stdout.write("\x1B[?25h");
121
- }
108
+ function truncate(str, maxWidth) {
109
+ const stripped = stripAnsi(str);
110
+ if (stripped.length <= maxWidth)
111
+ return str;
112
+ return `${stripped.slice(0, maxWidth - 1)}…`;
122
113
  }
123
114
  function beginSync() {
124
115
  if (getCapabilities().isTTY) {
@@ -821,9 +812,10 @@ class Spinner {
821
812
  this.message = message;
822
813
  this.frame = 0;
823
814
  this.timer = setInterval(() => {
815
+ if (!process.stderr.isTTY)
816
+ return;
824
817
  const char = cyan(SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length]);
825
- clearLine();
826
- process.stderr.write(`${char} ${this.message}`);
818
+ process.stderr.write(`\x1B[2K\r${char} ${this.message}`);
827
819
  this.frame++;
828
820
  }, 80);
829
821
  if (this.timer.unref) {
@@ -838,7 +830,9 @@ class Spinner {
838
830
  clearInterval(this.timer);
839
831
  this.timer = null;
840
832
  }
841
- clearLine();
833
+ if (process.stderr.isTTY) {
834
+ process.stderr.write("\x1B[2K\r");
835
+ }
842
836
  if (finalMessage) {
843
837
  process.stderr.write(`${finalMessage}
844
838
  `);
@@ -1640,9 +1634,103 @@ ${bold(green("Locus initialized!"))}
1640
1634
  reInit: isReInit
1641
1635
  });
1642
1636
  }
1643
- var LOCUS_MD_TEMPLATE = `# Locus — Project Instructions
1637
+ var LOCUS_MD_TEMPLATE = `## Planning First
1638
+
1639
+ Complex tasks must be planned before writing code. Create ".locus/plans/<task-name>.md" with:
1640
+ - **Goal**: What we're trying to achieve and why
1641
+ - **Approach**: Step-by-step strategy with technical decisions
1642
+ - **Affected files**: List of files to create/modify/delete
1643
+ - **Acceptance criteria**: Specific, testable conditions for completion
1644
+ - **Dependencies**: Required packages, APIs, or external services
1645
+
1646
+ Delete the planning .md files after successful execution.
1647
+
1648
+ ## Code Quality
1649
+
1650
+ - **Follow existing patterns**: Run formatters and linters before finishing (check "package.json" scripts or project config)
1651
+ - **Minimize changes**: Keep modifications atomic. Separate refactors from behavioral changes into different tasks
1652
+ - **Never commit secrets**: No API keys, passwords, or credentials in code. Use environment variables or secret management
1653
+ - **Test as you go**: If tests exist, run relevant ones. If breaking changes occur, update tests accordingly
1654
+ - **Comment complex logic**: Explain *why*, not *what*. Focus on business logic and non-obvious decisions
1655
+
1656
+ ## Artifacts
1657
+
1658
+ When a task produces knowledge, analysis, or research output rather than (or in addition to) code changes, you **must** save results as Markdown in ".locus/artifacts/<descriptive-name>.md":
1659
+
1660
+ **Always create artifacts for:**
1661
+ - Code quality audits, security reviews, vulnerability assessments
1662
+ - Architecture analyses, system design proposals, or recommendations
1663
+ - Dependency reports, performance profiling, benchmarking results
1664
+ - Research summaries, technology comparisons, or feasibility studies
1665
+ - Migration plans, deployment strategies, or rollback procedures
1666
+ - Post-mortems, incident analysis, or debugging investigations
1667
+
1668
+ **Artifact structure:**
1669
+ - Clear title and date
1670
+ - Executive summary (2-3 sentences)
1671
+ - Detailed findings/analysis
1672
+ - Actionable recommendations (if applicable)
1673
+
1674
+ ## Git Operations
1675
+
1676
+ - **Do NOT run**: git add, git commit, git push, git checkout, git branch, or any git commands
1677
+ - **Why**: The Locus orchestrator handles all version control automatically after execution
1678
+ - **Your role**: Focus solely on making file changes. The system commits, pushes, and creates PRs
1679
+
1680
+ ## Continuous Learning
1681
+
1682
+ Read ".locus/LEARNINGS.md" **before starting any task** to avoid repeating mistakes.
1683
+
1684
+ **The quality bar:** Ask yourself — "Would a new agent working on a completely different task benefit from knowing this?" If yes, record it. If it only matters for the current task or file, skip it.
1685
+
1686
+ **When to update:**
1687
+ - User corrects your approach, rejects a choice, or states a preference explicitly
1688
+ - You discover where something lives architecturally (e.g., which package owns shared types)
1689
+ - A structural or design decision would not be obvious from reading the code
1690
+ - You encounter a non-obvious constraint that applies project-wide
1691
+
1692
+ **What to record (high-value):**
1693
+ - Where things live: package ownership, shared utilities, config locations
1694
+ - Architectural decisions and their rationale ("we use X not Y because Z")
1695
+ - Explicit user preference overrides — when the user corrects or rejects an approach
1696
+ - Project-wide conventions that aren't visible from a single file
1644
1697
 
1645
- This file provides context to AI agents when executing tasks.
1698
+ **What NOT to record (low-value):**
1699
+ - One-time fixes or workarounds specific to a single file or function
1700
+ - Implementation details that are obvious from reading the code
1701
+ - Startup sequences, signal handlers, or local patterns — unless they represent a project-wide rule
1702
+ - Anything the next agent could discover in 30 seconds by reading the relevant file
1703
+
1704
+ **Good examples:**
1705
+ - \`[Architecture]\`: Shared types for all packages live in \`@locusai/shared\` — never redefine them locally in CLI or API packages.
1706
+ - \`[User Preferences]\`: User prefers not to track low-level interrupt/signal handling patterns in learnings — focus on architectural and decision-level entries.
1707
+ - \`[Packages]\`: Validation uses Zod throughout — do not introduce a second validation library.
1708
+
1709
+ **Bad examples (do not write these):**
1710
+ - \`[Patterns]\`: \`run.ts\` must call \`registerShutdownHandlers()\` at startup. ← too local, obvious from the file.
1711
+ - \`[Debugging]\`: Fixed a regex bug in \`image-detect.ts\`. ← one-time fix, irrelevant to future tasks.
1712
+
1713
+ **Format (append-only, never delete):**
1714
+
1715
+ \`\`\`
1716
+ - **[Category]**: Concise description (1-2 lines max). *Rationale if non-obvious.*
1717
+ \`\`\`
1718
+
1719
+ **Categories:** Architecture, Packages, User Preferences, Conventions, Debugging
1720
+
1721
+ ## Error Handling
1722
+
1723
+ - **Read error messages carefully**: Don't guess. Parse the actual error before proposing fixes
1724
+ - **Check dependencies first**: Missing packages, wrong versions, and environment issues are common
1725
+ - **Verify assumptions**: If something "should work," confirm it actually does in this environment
1726
+ - **Ask for context**: If you need environment details, configuration, or logs, request them explicitly
1727
+
1728
+ ## Communication
1729
+
1730
+ - **Be precise**: When uncertain, state what you know and what you're assuming
1731
+ - **Show your work**: For complex changes, briefly explain the approach before executing
1732
+ - **Highlight trade-offs**: If multiple approaches exist, note why you chose one over others
1733
+ - **Request feedback**: For ambiguous requirements, propose an approach and ask for confirmation
1646
1734
 
1647
1735
  ## Project Overview
1648
1736
 
@@ -1655,16 +1743,13 @@ This file provides context to AI agents when executing tasks.
1655
1743
  ## Development Workflow
1656
1744
 
1657
1745
  <!-- How to run, test, build, and deploy the project -->
1658
-
1659
- ## Important Notes
1660
-
1661
- <!-- Anything the AI agent should know: gotchas, design decisions, constraints -->
1662
1746
  `, LEARNINGS_MD_TEMPLATE = `# Learnings
1663
1747
 
1664
1748
  This file captures important lessons, decisions, and corrections made during development.
1665
1749
  It is read by AI agents before every task to avoid repeating mistakes and to follow established patterns.
1666
1750
 
1667
1751
  <!-- Add learnings below this line. Format: - **[Category]**: Description -->
1752
+ - **[User Preferences]**: Do not record low-level implementation details or one-time fixes in learnings. Focus on architectural decisions, package ownership, and explicit user preference overrides — entries that help any future agent on any task, not just the current one.
1668
1753
  `, GITIGNORE_ENTRIES;
1669
1754
  var init_init = __esm(() => {
1670
1755
  init_config();
@@ -2533,7 +2618,9 @@ var init_status_indicator = __esm(() => {
2533
2618
  this.startTime = Date.now();
2534
2619
  this.activity = options?.activity ?? "";
2535
2620
  this.frame = 0;
2536
- hideCursor();
2621
+ if (process.stderr.isTTY) {
2622
+ process.stderr.write("\x1B[?25l");
2623
+ }
2537
2624
  this.timer = setInterval(() => {
2538
2625
  this.render(message);
2539
2626
  this.frame++;
@@ -2547,8 +2634,9 @@ var init_status_indicator = __esm(() => {
2547
2634
  clearInterval(this.timer);
2548
2635
  this.timer = null;
2549
2636
  }
2550
- clearLine();
2551
- showCursor();
2637
+ if (process.stderr.isTTY) {
2638
+ process.stderr.write("\x1B[2K\r\x1B[?25h");
2639
+ }
2552
2640
  }
2553
2641
  isActive() {
2554
2642
  return this.timer !== null;
@@ -2569,12 +2657,13 @@ var init_status_indicator = __esm(() => {
2569
2657
  line += ` ${dim("—")} ${dim(this.activity)}`;
2570
2658
  }
2571
2659
  line += ` ${dim("— esc to interrupt")}`;
2572
- const maxWidth = caps.columns - 1;
2573
- if (line.length > maxWidth + 50) {
2574
- line = line.slice(0, maxWidth + 50);
2660
+ const cols = process.stderr.columns ?? process.stdout.columns ?? 80;
2661
+ if (visualWidth(line) > cols - 1) {
2662
+ line = truncate(line, cols - 1);
2575
2663
  }
2576
- clearLine();
2577
- process.stderr.write(line);
2664
+ if (!process.stderr.isTTY)
2665
+ return;
2666
+ process.stderr.write("\x1B[2K\r" + line);
2578
2667
  }
2579
2668
  renderShimmer() {
2580
2669
  const t = Date.now() / 1000;
@@ -2959,8 +3048,6 @@ class InputHandler {
2959
3048
  isLocked() {
2960
3049
  return this.locked;
2961
3050
  }
2962
- enableProtocols() {}
2963
- disableProtocols() {}
2964
3051
  async readline() {
2965
3052
  await this.waitUntilUnlocked();
2966
3053
  return new Promise((resolve2) => {
@@ -3739,6 +3826,9 @@ class ClaudeRunner {
3739
3826
  if (options.model) {
3740
3827
  args.push("--model", options.model);
3741
3828
  }
3829
+ if (options.verbose) {
3830
+ args.push("--verbose", "--output-format", "stream-json");
3831
+ }
3742
3832
  log.debug("Spawning claude", { args: args.join(" "), cwd: options.cwd });
3743
3833
  return new Promise((resolve2) => {
3744
3834
  let output = "";
@@ -3751,11 +3841,46 @@ class ClaudeRunner {
3751
3841
  stdio: ["pipe", "pipe", "pipe"],
3752
3842
  env
3753
3843
  });
3754
- this.process.stdout?.on("data", (chunk) => {
3755
- const text = chunk.toString();
3756
- output += text;
3757
- options.onOutput?.(text);
3758
- });
3844
+ if (options.verbose) {
3845
+ let lineBuffer = "";
3846
+ const seenToolIds = new Set;
3847
+ this.process.stdout?.on("data", (chunk) => {
3848
+ lineBuffer += chunk.toString();
3849
+ const lines = lineBuffer.split(`
3850
+ `);
3851
+ lineBuffer = lines.pop() ?? "";
3852
+ for (const line of lines) {
3853
+ if (!line.trim())
3854
+ continue;
3855
+ try {
3856
+ const event = JSON.parse(line);
3857
+ if (event.type === "assistant" && event.message?.content) {
3858
+ for (const item of event.message.content) {
3859
+ if (item.type === "tool_use" && item.id && !seenToolIds.has(item.id)) {
3860
+ seenToolIds.add(item.id);
3861
+ options.onToolActivity?.(formatToolCall(item.name ?? "", item.input ?? {}));
3862
+ }
3863
+ }
3864
+ } else if (event.type === "result") {
3865
+ const text = event.result ?? "";
3866
+ output = text;
3867
+ options.onOutput?.(text);
3868
+ }
3869
+ } catch {
3870
+ const newLine = `${line}
3871
+ `;
3872
+ output += newLine;
3873
+ options.onOutput?.(newLine);
3874
+ }
3875
+ }
3876
+ });
3877
+ } else {
3878
+ this.process.stdout?.on("data", (chunk) => {
3879
+ const text = chunk.toString();
3880
+ output += text;
3881
+ options.onOutput?.(text);
3882
+ });
3883
+ }
3759
3884
  this.process.stderr?.on("data", (chunk) => {
3760
3885
  const text = chunk.toString();
3761
3886
  errorOutput += text;
@@ -3823,6 +3948,33 @@ class ClaudeRunner {
3823
3948
  }
3824
3949
  }
3825
3950
  }
3951
+ function formatToolCall(name, input) {
3952
+ switch (name) {
3953
+ case "Read":
3954
+ return `reading ${input.file_path ?? ""}`;
3955
+ case "Write":
3956
+ return `writing ${input.file_path ?? ""}`;
3957
+ case "Edit":
3958
+ case "MultiEdit":
3959
+ return `editing ${input.file_path ?? ""}`;
3960
+ case "Bash":
3961
+ return `running: ${String(input.command ?? "").slice(0, 60)}`;
3962
+ case "Glob":
3963
+ return `glob ${input.pattern ?? ""}`;
3964
+ case "Grep":
3965
+ return `grep ${input.pattern ?? ""}`;
3966
+ case "LS":
3967
+ return `ls ${input.path ?? ""}`;
3968
+ case "WebFetch":
3969
+ return `fetching ${String(input.url ?? "").slice(0, 50)}`;
3970
+ case "WebSearch":
3971
+ return `searching: ${input.query ?? ""}`;
3972
+ case "Task":
3973
+ return `spawning agent`;
3974
+ default:
3975
+ return name;
3976
+ }
3977
+ }
3826
3978
  var init_claude = __esm(() => {
3827
3979
  init_logger();
3828
3980
  });
@@ -3830,7 +3982,7 @@ var init_claude = __esm(() => {
3830
3982
  // src/ai/codex.ts
3831
3983
  import { execSync as execSync5, spawn as spawn3 } from "node:child_process";
3832
3984
  function buildCodexArgs(model) {
3833
- const args = ["exec", "--full-auto", "--skip-git-repo-check"];
3985
+ const args = ["exec", "--full-auto", "--skip-git-repo-check", "--json"];
3834
3986
  if (model) {
3835
3987
  args.push("--model", model);
3836
3988
  }
@@ -3870,17 +4022,64 @@ class CodexRunner {
3870
4022
  const args = buildCodexArgs(options.model);
3871
4023
  log.debug("Spawning codex", { args: args.join(" "), cwd: options.cwd });
3872
4024
  return new Promise((resolve2) => {
3873
- let output = "";
4025
+ let rawOutput = "";
3874
4026
  let errorOutput = "";
3875
4027
  this.process = spawn3("codex", args, {
3876
4028
  cwd: options.cwd,
3877
4029
  stdio: ["pipe", "pipe", "pipe"],
3878
4030
  env: { ...process.env }
3879
4031
  });
4032
+ let agentMessages = [];
4033
+ const flushAgentMessages = () => {
4034
+ if (agentMessages.length > 0) {
4035
+ options.onOutput?.(agentMessages.join(`
4036
+
4037
+ `));
4038
+ agentMessages = [];
4039
+ }
4040
+ };
4041
+ let lineBuffer = "";
3880
4042
  this.process.stdout?.on("data", (chunk) => {
3881
- const text = chunk.toString();
3882
- output += text;
3883
- options.onOutput?.(text);
4043
+ lineBuffer += chunk.toString();
4044
+ const lines = lineBuffer.split(`
4045
+ `);
4046
+ lineBuffer = lines.pop() ?? "";
4047
+ for (const line of lines) {
4048
+ if (!line.trim())
4049
+ continue;
4050
+ rawOutput += `${line}
4051
+ `;
4052
+ log.debug("codex stdout line", { line });
4053
+ try {
4054
+ const event = JSON.parse(line);
4055
+ const { type, item } = event;
4056
+ if (type === "item.started" && item?.type === "command_execution") {
4057
+ const cmd = (item.command ?? "").slice(0, 80);
4058
+ options.onToolActivity?.(`running: ${cmd}`);
4059
+ } else if (type === "item.completed" && item?.type === "command_execution") {
4060
+ const code = item.exit_code;
4061
+ options.onToolActivity?.(code === 0 ? "done" : `exit ${code}`);
4062
+ } else if (type === "item.completed" && item?.type === "reasoning") {
4063
+ const text = (item.text ?? "").trim().replace(/\*\*([^*]+)\*\*/g, "$1").replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, "$1");
4064
+ if (text)
4065
+ options.onToolActivity?.(text);
4066
+ } else if (type === "item.completed" && item?.type === "agent_message") {
4067
+ const text = item.text ?? "";
4068
+ if (text) {
4069
+ agentMessages.push(text);
4070
+ options.onToolActivity?.(text.split(`
4071
+ `)[0].slice(0, 80));
4072
+ }
4073
+ } else if (type === "turn.completed") {
4074
+ flushAgentMessages();
4075
+ }
4076
+ } catch {
4077
+ const newLine = `${line}
4078
+ `;
4079
+ rawOutput += newLine;
4080
+ options.onOutput?.(newLine);
4081
+ }
4082
+ }
3884
4083
  });
3885
4084
  this.process.stderr?.on("data", (chunk) => {
3886
4085
  const text = chunk.toString();
@@ -3889,10 +4088,11 @@ class CodexRunner {
3889
4088
  });
3890
4089
  this.process.on("close", (code) => {
3891
4090
  this.process = null;
4091
+ flushAgentMessages();
3892
4092
  if (this.aborted) {
3893
4093
  resolve2({
3894
4094
  success: false,
3895
- output,
4095
+ output: rawOutput,
3896
4096
  error: "Aborted by user",
3897
4097
  exitCode: code ?? 143
3898
4098
  });
@@ -3901,13 +4101,13 @@ class CodexRunner {
3901
4101
  if (code === 0) {
3902
4102
  resolve2({
3903
4103
  success: true,
3904
- output,
4104
+ output: rawOutput,
3905
4105
  exitCode: 0
3906
4106
  });
3907
4107
  } else {
3908
4108
  resolve2({
3909
4109
  success: false,
3910
- output,
4110
+ output: rawOutput,
3911
4111
  error: errorOutput || `codex exited with code ${code}`,
3912
4112
  exitCode: code ?? 1
3913
4113
  });
@@ -3917,7 +4117,7 @@ class CodexRunner {
3917
4117
  this.process = null;
3918
4118
  resolve2({
3919
4119
  success: false,
3920
- output,
4120
+ output: rawOutput,
3921
4121
  error: `Failed to spawn codex: ${err.message}`,
3922
4122
  exitCode: 1
3923
4123
  });
@@ -4025,6 +4225,7 @@ ${red("✗")} ${dim("Force exit.")}\r
4025
4225
  model: options.model,
4026
4226
  cwd: options.cwd,
4027
4227
  signal: abortController.signal,
4228
+ verbose: options.verbose,
4028
4229
  onOutput: (chunk) => {
4029
4230
  if (wasAborted)
4030
4231
  return;
@@ -4034,7 +4235,19 @@ ${red("✗")} ${dim("Force exit.")}\r
4034
4235
  }
4035
4236
  renderer?.push(chunk);
4036
4237
  output += chunk;
4037
- }
4238
+ },
4239
+ onToolActivity: (() => {
4240
+ let lastActivityTime = 0;
4241
+ return (summary) => {
4242
+ if (wasAborted)
4243
+ return;
4244
+ const now = Date.now();
4245
+ if (now - lastActivityTime >= 2000) {
4246
+ lastActivityTime = now;
4247
+ indicator.setActivity(summary);
4248
+ }
4249
+ };
4250
+ })()
4038
4251
  });
4039
4252
  renderer?.stop();
4040
4253
  indicator.stop();
@@ -5939,6 +6152,12 @@ function getSlashCommands() {
5939
6152
  description: "Force-save current session",
5940
6153
  handler: cmdSave
5941
6154
  },
6155
+ {
6156
+ name: "/verbose",
6157
+ aliases: ["/v"],
6158
+ description: "Toggle verbose mode (show agent stderr streams)",
6159
+ handler: cmdVerbose
6160
+ },
5942
6161
  {
5943
6162
  name: "/exit",
5944
6163
  aliases: ["/quit", "/q"],
@@ -5999,8 +6218,30 @@ function cmdReset(_args, ctx) {
5999
6218
  process.stderr.write(`${green("✓")} Conversation context reset.
6000
6219
  `);
6001
6220
  }
6002
- function cmdHistory(_args, _ctx) {
6003
- process.stderr.write(`${dim("Recent input history is shown above the prompt.")}
6221
+ function cmdHistory(_args, ctx) {
6222
+ const entries = ctx.getHistory();
6223
+ if (entries.length === 0) {
6224
+ process.stderr.write(`${dim("No input history.")}
6225
+ `);
6226
+ return;
6227
+ }
6228
+ process.stderr.write(`
6229
+ ${bold("Input History:")} ${dim(`(${entries.length} entries)`)}
6230
+
6231
+ `);
6232
+ const display = entries.slice(0, 50);
6233
+ for (let i = 0;i < display.length; i++) {
6234
+ const num = dim(`${String(i + 1).padStart(3)}.`);
6235
+ const entry = display[i].replace(/\n/g, dim("↵"));
6236
+ process.stderr.write(` ${num} ${entry}
6237
+ `);
6238
+ }
6239
+ if (entries.length > 50) {
6240
+ process.stderr.write(`
6241
+ ${dim(`… and ${entries.length - 50} more`)}
6242
+ `);
6243
+ }
6244
+ process.stderr.write(`
6004
6245
  `);
6005
6246
  }
6006
6247
  function cmdSession(_args, ctx) {
@@ -6109,6 +6350,12 @@ function cmdSave(_args, ctx) {
6109
6350
  process.stderr.write(`${green("✓")} Session saved.
6110
6351
  `);
6111
6352
  }
6353
+ function cmdVerbose(_args, ctx) {
6354
+ ctx.onVerboseToggle();
6355
+ const isOn = ctx.getVerbose();
6356
+ process.stderr.write(`${isOn ? green("✓") : dim("○")} Verbose mode ${isOn ? bold("on") : "off"} — agent streams ${isOn ? "visible" : "hidden"}.
6357
+ `);
6358
+ }
6112
6359
  function cmdExit(_args, ctx) {
6113
6360
  ctx.onExit();
6114
6361
  }
@@ -6526,11 +6773,11 @@ async function runInteractiveRepl(session, sessionManager, options) {
6526
6773
  getHistory: () => history.getEntries(),
6527
6774
  onTab: (text) => completion.complete(text)
6528
6775
  });
6529
- input.enableProtocols();
6530
6776
  printWelcome(session);
6531
6777
  let shouldExit = false;
6532
6778
  let currentProvider = inferProviderFromModel(config.ai.model) || config.ai.provider;
6533
6779
  let currentModel = config.ai.model;
6780
+ let verbose = true;
6534
6781
  const slashCtx = {
6535
6782
  projectRoot,
6536
6783
  session,
@@ -6556,7 +6803,12 @@ async function runInteractiveRepl(session, sessionManager, options) {
6556
6803
  },
6557
6804
  onExit: () => {
6558
6805
  shouldExit = true;
6559
- }
6806
+ },
6807
+ getHistory: () => history.getEntries(),
6808
+ onVerboseToggle: () => {
6809
+ verbose = !verbose;
6810
+ },
6811
+ getVerbose: () => verbose
6560
6812
  };
6561
6813
  while (!shouldExit) {
6562
6814
  const result = await input.readline();
@@ -6586,7 +6838,7 @@ async function runInteractiveRepl(session, sessionManager, options) {
6586
6838
  ...config,
6587
6839
  ai: { provider: currentProvider, model: currentModel }
6588
6840
  }
6589
- });
6841
+ }, verbose);
6590
6842
  sessionManager.addMessage(session, {
6591
6843
  role: "assistant",
6592
6844
  content: response,
@@ -6611,7 +6863,6 @@ ${red("✗")} ${msg}
6611
6863
  break;
6612
6864
  }
6613
6865
  }
6614
- input.disableProtocols();
6615
6866
  const shouldPersistOnExit = session.messages.length > 0 || sessionManager.isPersisted(session);
6616
6867
  if (shouldPersistOnExit) {
6617
6868
  sessionManager.save(session);
@@ -6627,13 +6878,14 @@ ${red("✗")} ${msg}
6627
6878
  process.stdin.pause();
6628
6879
  process.exit(0);
6629
6880
  }
6630
- async function executeAITurn(prompt, session, options) {
6881
+ async function executeAITurn(prompt, session, options, verbose = false) {
6631
6882
  const { config, projectRoot } = options;
6632
6883
  const aiResult = await runAI({
6633
6884
  prompt,
6634
6885
  provider: config.ai.provider,
6635
6886
  model: config.ai.model,
6636
- cwd: projectRoot
6887
+ cwd: projectRoot,
6888
+ verbose
6637
6889
  });
6638
6890
  if (aiResult.interrupted) {
6639
6891
  if (aiResult.output) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.17.13",
3
+ "version": "0.17.14",
4
4
  "description": "GitHub-native AI engineering assistant",
5
5
  "type": "module",
6
6
  "bin": {