lacy 1.8.25 → 1.8.28

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 (3) hide show
  1. package/README.md +2 -2
  2. package/index.mjs +48 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@ npx lacy
11
11
  - Installs the latest Lacy Shell release into `~/.lacy` and adds it to your zsh, Bash or fish config
12
12
  - Uses your AI CLI tool without asking when exactly one is installed
13
13
  - Asks which one to use when several are installed
14
- - Offers to install lash when none is found
14
+ - Offers to install Claude Code when none is found
15
15
  - Asks nothing when there is no terminal (CI, Docker)
16
16
 
17
17
  Run `npx lacy` again after installing to change the tool or mode, edit the config, update, reinstall, or uninstall. Without a terminal it updates to the latest release instead.
@@ -49,7 +49,7 @@ $ git status runs in shell
49
49
  ? fix the build error AI answers
50
50
  ```
51
51
 
52
- Works with lash, claude, opencode, gemini, codex, hermes, copilot, goose, amp, aider, or a custom command.
52
+ Works with lash, claude, opencode, gemini, codex, hermes, copilot, goose, aider, or a custom command.
53
53
 
54
54
  ## Other install methods
55
55
 
package/index.mjs CHANGED
@@ -39,21 +39,33 @@ const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: "0" };
39
39
  const STATE_FILES = ["config.yaml", "current_mode", "logs", ".last_session", ".server.pid"];
40
40
 
41
41
  // Keep in sync with LACY_TOOL_LIST in lib/core/constants.sh (tests check).
42
- const TOOL_LIST = ["lash", "claude", "opencode", "gemini", "codex", "hermes", "copilot", "goose", "amp", "aider"];
42
+ const TOOL_LIST = ["claude", "lash", "opencode", "gemini", "codex", "hermes", "copilot", "goose", "aider"];
43
43
 
44
44
  const TOOL_HINTS = {
45
- lash: "AI coding agent, lash.lacy.sh (recommended)",
46
- claude: "Claude Code CLI",
45
+ lash: "AI coding agent, lash.lacy.sh",
46
+ claude: "Claude Code CLI (recommended)",
47
47
  opencode: "OpenCode CLI",
48
48
  gemini: "Google Gemini CLI",
49
49
  codex: "OpenAI Codex CLI",
50
50
  hermes: "Hermes Agent by Nous Research",
51
51
  copilot: "GitHub Copilot CLI",
52
52
  goose: "Goose agent by Block",
53
- amp: "Sourcegraph Amp CLI",
54
53
  aider: "Aider pair programming",
55
54
  };
56
55
 
56
+ // Keep in sync with lacy_tool_install_cmd in lib/core/mcp.sh (tests check).
57
+ const INSTALL_CMDS = {
58
+ lash: "npm install -g lashcode",
59
+ claude: "npm install -g @anthropic-ai/claude-code",
60
+ opencode: "npm install -g opencode-ai",
61
+ gemini: "npm install -g @google/gemini-cli",
62
+ codex: "npm install -g @openai/codex",
63
+ hermes: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash",
64
+ copilot: "npm install -g @github/copilot",
65
+ goose: "brew install block-goose-cli",
66
+ aider: "pipx install aider-chat",
67
+ };
68
+
57
69
  const MODES = [
58
70
  { value: "auto", label: "Auto", hint: "smart detection (recommended)" },
59
71
  { value: "shell", label: "Shell", hint: "all commands execute directly" },
@@ -282,7 +294,7 @@ function defaultConfig(active = "", customCommand = "") {
282
294
  : ' # custom_command: "your-command --flags"';
283
295
  return `# Lacy Shell configuration
284
296
  agent_tools:
285
- # lash, claude, opencode, gemini, codex, hermes, copilot, goose, amp, aider, custom
297
+ # lash, claude, opencode, gemini, codex, hermes, copilot, goose, aider, custom
286
298
  # Leave empty to auto-detect.
287
299
  ${activeLine}
288
300
  ${customLine}
@@ -293,6 +305,7 @@ modes:
293
305
  # preheat:
294
306
  # eager: false
295
307
  # server_port: 4096
308
+ # claude_idle_minutes: 15 # keep claude running between questions; 0 turns it off
296
309
 
297
310
  # logging:
298
311
  # queries: false # true writes ~/.lacy/logs/queries.log (owner-only)
@@ -515,27 +528,27 @@ function checkPrerequisites(shell) {
515
528
  return missing;
516
529
  }
517
530
 
518
- function installLash() {
531
+ function installClaude() {
519
532
  const s = spinner();
520
- s.start("Installing lash");
533
+ s.start("Installing Claude Code");
521
534
  try {
522
535
  if (commandExists("npm")) {
523
- execSync("npm install -g lashcode", { stdio: "pipe" });
536
+ execSync(INSTALL_CMDS.claude, { stdio: "pipe" });
524
537
  } else if (commandExists("brew")) {
525
- execSync("brew tap lacymorrow/tap && brew install lash", { stdio: "pipe" });
538
+ execSync("brew install --cask claude-code", { stdio: "pipe" });
526
539
  } else {
527
- s.stop("Could not install lash: npm or Homebrew is needed");
540
+ s.stop("Could not install Claude Code: npm or Homebrew is needed");
528
541
  return false;
529
542
  }
530
543
  } catch {
531
- s.stop("lash did not install");
544
+ s.stop("Claude Code did not install");
532
545
  return false;
533
546
  }
534
- s.stop("lash installed");
535
- return commandExists("lash");
547
+ s.stop("Claude Code installed. Sign in once by running: claude");
548
+ return commandExists("claude");
536
549
  }
537
550
 
538
- // One tool installed: use it. None: offer lash. Several: ask which.
551
+ // One tool installed: use it. None: offer Claude Code. Several: ask which.
539
552
  // Without a terminal nothing is asked and the default is used.
540
553
  async function chooseTool() {
541
554
  const detected = detectTools();
@@ -556,18 +569,18 @@ async function chooseTool() {
556
569
  }
557
570
 
558
571
  if (!isInteractive()) {
559
- p.log.warn("No AI CLI tool found. Install one later, for example: npm install -g lashcode");
572
+ p.log.warn(`No AI CLI tool found. Install one later, for example: ${INSTALL_CMDS.claude}`);
560
573
  return "";
561
574
  }
562
575
 
563
576
  p.log.warn("No AI CLI tool found. Lacy needs one to answer questions.");
564
577
  const yes = await p.confirm({
565
- message: `Install ${pc.green("lash")} (lash.lacy.sh)?`,
578
+ message: `Install ${pc.green("Claude Code")} (claude)?`,
566
579
  initialValue: true,
567
580
  });
568
581
  if (p.isCancel(yes)) cancelled("Installation cancelled");
569
- if (yes && installLash()) return "lash";
570
- p.log.info("Install one later, for example: npm install -g lashcode");
582
+ if (yes && installClaude()) return "claude";
583
+ p.log.info(`Install one later, for example: ${INSTALL_CMDS.claude}`);
571
584
  return "";
572
585
  }
573
586
 
@@ -727,6 +740,23 @@ async function dashboard() {
727
740
  writeConfigValue("active", "");
728
741
  p.log.success(`Tool set to: ${pc.cyan("auto-detect")}`);
729
742
  } else {
743
+ // Every query would fail with a missing tool: offer to install it
744
+ if (!commandExists(selectedTool)) {
745
+ const cmd = INSTALL_CMDS[selectedTool];
746
+ const install = await p.confirm({
747
+ message: `${selectedTool} is not installed. Install it now? (${cmd})`,
748
+ });
749
+ if (p.isCancel(install) || !install) {
750
+ p.log.error(`${selectedTool} is not installed, so the tool was not changed.`);
751
+ continue;
752
+ }
753
+ const result = spawnSync("sh", ["-c", cmd], { stdio: "inherit" });
754
+ if (result.status !== 0 || !commandExists(selectedTool)) {
755
+ p.log.error(`Installing ${selectedTool} failed, so the tool was not changed. To try it yourself: ${cmd}`);
756
+ continue;
757
+ }
758
+ p.log.success(`${selectedTool} installed. If it asks you to sign in, run: ${selectedTool}`);
759
+ }
730
760
  writeConfigValue("active", selectedTool);
731
761
  p.log.success(`Tool set to: ${pc.cyan(selectedTool)}`);
732
762
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lacy",
3
- "version": "1.8.25",
3
+ "version": "1.8.28",
4
4
  "description": "Installer for lacy. Talk to your shell: commands run, questions go to your AI coding tool.",
5
5
  "type": "module",
6
6
  "bin": {