@locusai/cli 0.17.13 → 0.17.15

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 +310 -57
  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,65 @@ 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 ?? "").split(`
4058
+ `)[0].slice(0, 80);
4059
+ options.onToolActivity?.(`running: ${cmd}`);
4060
+ } else if (type === "item.completed" && item?.type === "command_execution") {
4061
+ const code = item.exit_code;
4062
+ options.onToolActivity?.(code === 0 ? "done" : `exit ${code}`);
4063
+ } else if (type === "item.completed" && item?.type === "reasoning") {
4064
+ const text = (item.text ?? "").trim().replace(/\*\*([^*]+)\*\*/g, "$1").replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, "$1");
4065
+ if (text)
4066
+ options.onToolActivity?.(text);
4067
+ } else if (type === "item.completed" && item?.type === "agent_message") {
4068
+ const text = item.text ?? "";
4069
+ if (text) {
4070
+ agentMessages.push(text);
4071
+ options.onToolActivity?.(text.split(`
4072
+ `)[0].slice(0, 80));
4073
+ }
4074
+ } else if (type === "turn.completed") {
4075
+ flushAgentMessages();
4076
+ }
4077
+ } catch {
4078
+ const newLine = `${line}
4079
+ `;
4080
+ rawOutput += newLine;
4081
+ options.onOutput?.(newLine);
4082
+ }
4083
+ }
3884
4084
  });
3885
4085
  this.process.stderr?.on("data", (chunk) => {
3886
4086
  const text = chunk.toString();
@@ -3889,10 +4089,11 @@ class CodexRunner {
3889
4089
  });
3890
4090
  this.process.on("close", (code) => {
3891
4091
  this.process = null;
4092
+ flushAgentMessages();
3892
4093
  if (this.aborted) {
3893
4094
  resolve2({
3894
4095
  success: false,
3895
- output,
4096
+ output: rawOutput,
3896
4097
  error: "Aborted by user",
3897
4098
  exitCode: code ?? 143
3898
4099
  });
@@ -3901,13 +4102,13 @@ class CodexRunner {
3901
4102
  if (code === 0) {
3902
4103
  resolve2({
3903
4104
  success: true,
3904
- output,
4105
+ output: rawOutput,
3905
4106
  exitCode: 0
3906
4107
  });
3907
4108
  } else {
3908
4109
  resolve2({
3909
4110
  success: false,
3910
- output,
4111
+ output: rawOutput,
3911
4112
  error: errorOutput || `codex exited with code ${code}`,
3912
4113
  exitCode: code ?? 1
3913
4114
  });
@@ -3917,7 +4118,7 @@ class CodexRunner {
3917
4118
  this.process = null;
3918
4119
  resolve2({
3919
4120
  success: false,
3920
- output,
4121
+ output: rawOutput,
3921
4122
  error: `Failed to spawn codex: ${err.message}`,
3922
4123
  exitCode: 1
3923
4124
  });
@@ -4025,6 +4226,7 @@ ${red("✗")} ${dim("Force exit.")}\r
4025
4226
  model: options.model,
4026
4227
  cwd: options.cwd,
4027
4228
  signal: abortController.signal,
4229
+ verbose: options.verbose,
4028
4230
  onOutput: (chunk) => {
4029
4231
  if (wasAborted)
4030
4232
  return;
@@ -4034,7 +4236,19 @@ ${red("✗")} ${dim("Force exit.")}\r
4034
4236
  }
4035
4237
  renderer?.push(chunk);
4036
4238
  output += chunk;
4037
- }
4239
+ },
4240
+ onToolActivity: (() => {
4241
+ let lastActivityTime = 0;
4242
+ return (summary) => {
4243
+ if (wasAborted)
4244
+ return;
4245
+ const now = Date.now();
4246
+ if (now - lastActivityTime >= 2000) {
4247
+ lastActivityTime = now;
4248
+ indicator.setActivity(summary);
4249
+ }
4250
+ };
4251
+ })()
4038
4252
  });
4039
4253
  renderer?.stop();
4040
4254
  indicator.stop();
@@ -5939,6 +6153,12 @@ function getSlashCommands() {
5939
6153
  description: "Force-save current session",
5940
6154
  handler: cmdSave
5941
6155
  },
6156
+ {
6157
+ name: "/verbose",
6158
+ aliases: ["/v"],
6159
+ description: "Toggle verbose mode (show agent stderr streams)",
6160
+ handler: cmdVerbose
6161
+ },
5942
6162
  {
5943
6163
  name: "/exit",
5944
6164
  aliases: ["/quit", "/q"],
@@ -5999,8 +6219,30 @@ function cmdReset(_args, ctx) {
5999
6219
  process.stderr.write(`${green("✓")} Conversation context reset.
6000
6220
  `);
6001
6221
  }
6002
- function cmdHistory(_args, _ctx) {
6003
- process.stderr.write(`${dim("Recent input history is shown above the prompt.")}
6222
+ function cmdHistory(_args, ctx) {
6223
+ const entries = ctx.getHistory();
6224
+ if (entries.length === 0) {
6225
+ process.stderr.write(`${dim("No input history.")}
6226
+ `);
6227
+ return;
6228
+ }
6229
+ process.stderr.write(`
6230
+ ${bold("Input History:")} ${dim(`(${entries.length} entries)`)}
6231
+
6232
+ `);
6233
+ const display = entries.slice(0, 50);
6234
+ for (let i = 0;i < display.length; i++) {
6235
+ const num = dim(`${String(i + 1).padStart(3)}.`);
6236
+ const entry = display[i].replace(/\n/g, dim("↵"));
6237
+ process.stderr.write(` ${num} ${entry}
6238
+ `);
6239
+ }
6240
+ if (entries.length > 50) {
6241
+ process.stderr.write(`
6242
+ ${dim(`… and ${entries.length - 50} more`)}
6243
+ `);
6244
+ }
6245
+ process.stderr.write(`
6004
6246
  `);
6005
6247
  }
6006
6248
  function cmdSession(_args, ctx) {
@@ -6109,6 +6351,12 @@ function cmdSave(_args, ctx) {
6109
6351
  process.stderr.write(`${green("✓")} Session saved.
6110
6352
  `);
6111
6353
  }
6354
+ function cmdVerbose(_args, ctx) {
6355
+ ctx.onVerboseToggle();
6356
+ const isOn = ctx.getVerbose();
6357
+ process.stderr.write(`${isOn ? green("✓") : dim("○")} Verbose mode ${isOn ? bold("on") : "off"} — agent streams ${isOn ? "visible" : "hidden"}.
6358
+ `);
6359
+ }
6112
6360
  function cmdExit(_args, ctx) {
6113
6361
  ctx.onExit();
6114
6362
  }
@@ -6526,11 +6774,11 @@ async function runInteractiveRepl(session, sessionManager, options) {
6526
6774
  getHistory: () => history.getEntries(),
6527
6775
  onTab: (text) => completion.complete(text)
6528
6776
  });
6529
- input.enableProtocols();
6530
6777
  printWelcome(session);
6531
6778
  let shouldExit = false;
6532
6779
  let currentProvider = inferProviderFromModel(config.ai.model) || config.ai.provider;
6533
6780
  let currentModel = config.ai.model;
6781
+ let verbose = true;
6534
6782
  const slashCtx = {
6535
6783
  projectRoot,
6536
6784
  session,
@@ -6556,7 +6804,12 @@ async function runInteractiveRepl(session, sessionManager, options) {
6556
6804
  },
6557
6805
  onExit: () => {
6558
6806
  shouldExit = true;
6559
- }
6807
+ },
6808
+ getHistory: () => history.getEntries(),
6809
+ onVerboseToggle: () => {
6810
+ verbose = !verbose;
6811
+ },
6812
+ getVerbose: () => verbose
6560
6813
  };
6561
6814
  while (!shouldExit) {
6562
6815
  const result = await input.readline();
@@ -6586,7 +6839,7 @@ async function runInteractiveRepl(session, sessionManager, options) {
6586
6839
  ...config,
6587
6840
  ai: { provider: currentProvider, model: currentModel }
6588
6841
  }
6589
- });
6842
+ }, verbose);
6590
6843
  sessionManager.addMessage(session, {
6591
6844
  role: "assistant",
6592
6845
  content: response,
@@ -6611,7 +6864,6 @@ ${red("✗")} ${msg}
6611
6864
  break;
6612
6865
  }
6613
6866
  }
6614
- input.disableProtocols();
6615
6867
  const shouldPersistOnExit = session.messages.length > 0 || sessionManager.isPersisted(session);
6616
6868
  if (shouldPersistOnExit) {
6617
6869
  sessionManager.save(session);
@@ -6627,13 +6879,14 @@ ${red("✗")} ${msg}
6627
6879
  process.stdin.pause();
6628
6880
  process.exit(0);
6629
6881
  }
6630
- async function executeAITurn(prompt, session, options) {
6882
+ async function executeAITurn(prompt, session, options, verbose = false) {
6631
6883
  const { config, projectRoot } = options;
6632
6884
  const aiResult = await runAI({
6633
6885
  prompt,
6634
6886
  provider: config.ai.provider,
6635
6887
  model: config.ai.model,
6636
- cwd: projectRoot
6888
+ cwd: projectRoot,
6889
+ verbose
6637
6890
  });
6638
6891
  if (aiResult.interrupted) {
6639
6892
  if (aiResult.output) {
@@ -8534,7 +8787,7 @@ ${bold("Plan saved:")} ${cyan(id)}
8534
8787
  `);
8535
8788
  return;
8536
8789
  }
8537
- process.stderr.write(` To create these issues: ${bold(`locus plan approve ${id.slice(0, 8)}`)}
8790
+ process.stderr.write(` To create these issues: ${bold(`locus plan approve ${id.slice(0, 8)} --sprint <sprint name>`)}
8538
8791
 
8539
8792
  `);
8540
8793
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.17.13",
3
+ "version": "0.17.15",
4
4
  "description": "GitHub-native AI engineering assistant",
5
5
  "type": "module",
6
6
  "bin": {