feat: mise/native tool install for engram + lean-ctx, agentflare run, abs-path MCP - #127
Conversation
agentflare init didn't reliably set up the agentflare/engram MCP servers. Bare command names (`agentflare`, `engram`) don't resolve for GUI-launched hosts that lack ~/.local/bin on PATH, and engram had no dependency-free install path on machines without Go/Homebrew/npm. - add mise bootstrap (src/mise_install.rs): cross-platform detect-or-install of mise, used as the uniform, dependency-free way to provide the engram binary - install engram through mise's github backend (prebuilt release binary, checksum-verified; no Go toolchain, no compile, no npm) — the only backend shipped; drop the old go install/brew path - register every host's engram + agentflare MCP server against the resolved absolute path, so GUI-launched clients resolve them regardless of PATH. For native engram hosts, run `engram setup` via the mise path so it writes that absolute path (and installs the memory persona) itself - engram check now requires the plugin AND a real mcpServers.engram entry, not just an enabled plugin - share paths::agentflare_binary() between init hooks and MCP registration
📝 WalkthroughWalkthroughThe PR adds cross-platform mise bootstrapping, mise-based engram and leanctx installation, absolute-path MCP registration, and a new ChangesMise-backed installation and registration
Environment-aware agent run command
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant DevVars
participant Agents
participant Mise
participant Agent
User->>CLI: run agent [options]
CLI->>DevVars: load(stage)
DevVars-->>CLI: environment variables
CLI->>Agents: cli_run(agent, env, model, mode, args)
Agents->>Mise: mise exec -- binary
Mise->>Agent: launch with environment and arguments
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components.rs (1)
445-474: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
mark_doneis called unconditionally — a failed (or undefined-host) registration is still marked "done".
mark_done(&marker)at Line 473 runs regardless of the match result, including thecline/opencodefailed to write …paths and the_ =>"no engram integration defined" arm. Because the non-claudecheckusesinstalled_via_mise() && host_marker("engram-setup", &host).exists(), the component will report satisfied on the next run even though MCP registration never succeeded. The native-host branch above (Line 433-438) correctly gatesmark_doneon success; this branch should too.🐛 Proposed fix: gate the marker on success
- let result = match host.as_str() { + let (result, ok) = match host.as_str() { "cline" => { let path = home().join(".cline").join("mcp.json"); if merge_json(&path, "engram", entry) { - format!("{} (engram registered)", path.display()) + (format!("{} (engram registered)", path.display()), true) } else { - format!("failed to write {}", path.display()) + (format!("failed to write {}", path.display()), false) } } "continue" => { let path = cwd().join(".continue").join("mcpServers").join("engram.json"); if write_if_absent(&path, &(serde_json::to_string_pretty(&entry).unwrap() + "\n")) { - format!("{} written", path.display()) + (format!("{} written", path.display()), true) } else { - format!("{} exists, skipped", path.display()) + (format!("{} exists, skipped", path.display()), true) } } "opencode" => { let path = home().join(".config").join("opencode").join("opencode.jsonc"); if merge_opencode_mcp(&path, "engram", entry) { - format!("{} (engram registered)", path.display()) + (format!("{} (engram registered)", path.display()), true) } else { - format!("failed to write {}", path.display()) + (format!("failed to write {}", path.display()), false) } } - _ => format!("no engram integration defined for host '{host}'"), + _ => (format!("no engram integration defined for host '{host}'"), false), }; - mark_done(&marker); + if ok { + mark_done(&marker); + } result🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components.rs` around lines 445 - 474, Gate mark_done(&marker) on successful registration in the host match branch: treat successful cline/continue/opencode writes as success, and leave the marker unset for failed writes or the undefined-host arm. Preserve the existing result messages while ensuring the marker is only created after a successful MCP registration, matching the native-host branch behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/mise_install.rs`:
- Around line 56-65: Update default_locations() to include the WinGet and Scoop
Windows executable paths in addition to %LOCALAPPDATA%\mise\bin\mise.exe, so
mise_bin() can find installations performed by install_windows() and avoid
reporting failure.
---
Outside diff comments:
In `@src/components.rs`:
- Around line 445-474: Gate mark_done(&marker) on successful registration in the
host match branch: treat successful cline/continue/opencode writes as success,
and leave the marker unset for failed writes or the undefined-host arm. Preserve
the existing result messages while ensuring the marker is only created after a
successful MCP registration, matching the native-host branch behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 282a0bee-b1a6-4145-bb3e-008c4cb67c22
📒 Files selected for processing (6)
src/components.rssrc/engram_install.rssrc/init.rssrc/main.rssrc/mise_install.rssrc/paths.rs
| fn default_locations() -> Vec<PathBuf> { | ||
| if cfg!(windows) { | ||
| let local = std::env::var("LOCALAPPDATA") | ||
| .map(PathBuf::from) | ||
| .unwrap_or_else(|_| home().join("AppData").join("Local")); | ||
| vec![local.join("mise").join("bin").join("mise.exe")] | ||
| } else { | ||
| vec![home().join(".local").join("bin").join("mise")] | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm default winget/scoop install locations for mise on Windows.Repository: getappz/agentflare
Length of output: 156
🌐 Web query:
mise winget scoop install location windows binary path
💡 Result:
On Windows, the installation locations for mise, Scoop, and WinGet depend on their default configurations, though these can be customized. mise Installation and Shims By default, mise installs tools into %LOCALAPPDATA%\mise\installs (or ~/.local/share/mise/installs) [1]. Because mise uses a shim-based approach on Windows rather than modifying the PATH directly, it requires the directory containing these shims to be included in your PATH [2][3][4]. By default, this shims directory is located at %LOCALAPPDATA%\mise\shims [2][5]. Scoop Installation Scoop, which is a recommended way to install mise on Windows, defaults to installing itself and its managed applications in the user's home directory [6][7]. - Root Directory: Defaults to %USERPROFILE%\scoop (can be overridden by the SCOOP environment variable) [6][8]. - Applications: Installed in %USERPROFILE%\scoop\apps [6]. - Shims: Scoop automatically creates shims for applications and adds them to your PATH [6][7]. These are stored in %USERPROFILE%\scoop\shims [6]. WinGet Installation WinGet (Windows Package Manager) typically installs applications into standard system or user-specific program directories, depending on the package manifest [2][9]. When using WinGet to install mise (winget install jdx.mise), it follows standard WinGet behavior, but users often need to manually ensure the mise shims directory (%LOCALAPPDATA%\mise\shims) is added to the PATH for mise to function correctly, as WinGet may not automatically configure this shim path [10][3][4]. Summary Table Package Manager | Default Root/Base Path | Binary/Shim Path --- | --- | --- mise | %LOCALAPPDATA%\mise | %LOCALAPPDATA%\mise\shims [2][4] Scoop | %USERPROFILE%\scoop [6][8] | %USERPROFILE%\scoop\shims [6] WinGet | Varies by package [2] | Varies; manual setup often required for shims [3] Note: You can override these defaults by setting environment variables (e.g., SCOOP or MISE_INSTALLS_DIR) [1][11][8].
Citations:
- 1: https://mise.en.dev/directories.html
- 2: https://github.com/jdx/mise/blob/30996304/docs/installing-mise.md
- 3: https://www.claudepluginhub.com/skills/ray-manaloto-mise-toolkit-mise-toolkit/mise-install-paths
- 4: https://mise.en.dev/installing-mise.html
- 5: https://mise.jdx.dev/installing-mise.html
- 6: https://github.com/ScoopInstaller/Scoop/wiki/Scoop-Folder-Layout
- 7: https://wyssmann.com/blog/2023/03/software-package-management-for-windows-with-scoop/
- 8: https://github.com/ScoopInstaller/Install?tab=readme-ov-file
- 9: https://github.com/jdx/mise/blob/1f68ad8e6c869604945149fecb0c14ec8bfad0b7/docs/installing-mise.md
- 10: Winget didn't create the link for mise-shim.exe, so mise fallback to "file" shim mode jdx/mise#8067
- 11: Windows: mise-shim fails in clean environments without PATHEXT / SystemRoot / MISE_INSTALLS_DIR jdx/mise#9528
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== file list ==\n'
git ls-files src/mise_install.rs src | sed -n '1,120p'
printf '\n== outline src/mise_install.rs ==\n'
ast-grep outline src/mise_install.rs --view expanded || true
printf '\n== locate relevant symbols ==\n'
rg -n "default_locations|ensure_mise|mise_bin|install_windows|winget|scoop|LOCALAPPDATA|PATH" src/mise_install.rs src -n -S || true
printf '\n== src/mise_install.rs excerpt ==\n'
nl -ba src/mise_install.rs | sed -n '1,240p'Repository: getappz/agentflare
Length of output: 8789
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== src/mise_install.rs lines 1-240 ==\n'
sed -n '1,240p' src/mise_install.rsRepository: getappz/agentflare
Length of output: 7683
🌐 Web query:
jdx.mise winget scoop Windows install path shims default location
💡 Result:
On Windows, the default location for mise shims is %LOCALAPPDATA%\mise\shims [1][2]. Mise supports both Scoop and Winget as installation methods on Windows [3]. When you install tools via mise, it populates this shims directory with small executables that act as symlinks to the mise binary, allowing for seamless command interception and version management [2]. To ensure that your shell can locate these tools, you should add the shims directory to your PATH environment variable [2]. If you use Scoop, it is generally designed to handle PATH configuration automatically [3]. For other installation methods or custom setups, you may need to add %LOCALAPPDATA%\mise\shims manually to your PATH or use the mise activate --shims command in your shell profile (such as your PowerShell profile) to manage the integration [2][4].
Citations:
- 1: https://mise.jdx.dev/installing-mise.html
- 2: https://mise.jdx.dev/dev-tools/shims.html
- 3: https://github.com/jdx/mise/blob/30996304/docs/installing-mise.md
- 4: https://github.com/jdx/mise/blob/main/docs/getting-started.md
🌐 Web query:
jdx.mise winget manifest install location scoop manifest path mise.exe
💡 Result:
The installation location for mise on Windows depends on the package manager used [1]. For WinGet, mise is typically installed in a subfolder within the WinGet package directory [2]: %LOCALAPPDATA%\Microsoft\WinGet\Packages\jdx.mise_Microsoft.Winget.Source_8wekyb3d8bbwe\mise\bin\mise.exe [2] WinGet also creates symlinks in: %LOCALAPPDATA%\Microsoft\WinGet\Links\mise.exe [2] For Scoop, mise is installed within the Scoop directory structure, typically under: %SCOOP%\apps\mise\current\bin\mise.exe Note that Scoop manages its own environment, and recent updates have decoupled the automatic activation of shims, requiring users to manually configure their PATH or use mise activate [3]. General installation behavior for mise on Windows: - Data and configuration: By default, mise uses %LOCALAPPDATA%\mise for data and shims [4][1][5]. - Shims: mise shims are typically located at %LOCALAPPDATA%\mise\shims [1][5]. - Customization: Users can override these defaults by setting environment variables such as MISE_DATA_DIR, MISE_CONFIG_DIR, and MISE_INSTALLS_DIR [4][6]. Setting MISE_INSTALLS_DIR to a shorter path (e.g., C:\mise) is sometimes recommended to avoid issues with long file paths on Windows [6].
Citations:
- 1: https://github.com/jdx/mise/blob/30996304/docs/installing-mise.md
- 2: feat(shim): add native .exe shim mode for Windows jdx/mise#8045
- 3: docs: remove outdated note about automatic shim activation with Scoop jdx/mise#4941
- 4: [Bug]: Mise doesn't work under the
scoopdir ScoopInstaller/Main#6477 - 5: https://github.com/jdx/mise/blob/3e3ff2f7/docs/getting-started.md
- 6: Windows: mise-shim fails in clean environments without PATHEXT / SystemRoot / MISE_INSTALLS_DIR jdx/mise#9528
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '300,335p' src/components.rsRepository: getappz/agentflare
Length of output: 2206
Windows install lookup misses WinGet/Scoop paths
default_locations() only checks %LOCALAPPDATA%\mise\bin\mise.exe, so a successful install_windows() can still fall through to MiseOutcome::Failed when mise_bin() rechecks PATH/defaults. Add the WinGet/Scoop install locations here, or return Installed after a successful package-manager install with a “open a new shell” note.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/mise_install.rs` around lines 56 - 65, Update default_locations() to
include the WinGet and Scoop Windows executable paths in addition to
%LOCALAPPDATA%\mise\bin\mise.exe, so mise_bin() can find installations performed
by install_windows() and avoid reporting failure.
… in its shell hook Replace the npm/mise path for lean-ctx with its official prebuilt-binary installer, declared in a small data-driven registry (src/tool_install.rs): each tool lists native install methods (curl | sh, brew) in priority order and the runner picks the first whose helper is present. No mise, no npm. lean-ctx's onboard installs a shell hook that gates non-allowlisted commands — including agentflare's own re-invocations — and also blocks `sh -c` outright. So after install agentflare runs `lean-ctx allow agentflare` as a direct process spawn (not via a shell), or it would lock itself out of every hooked shell. Also corrects the now-stale mise component comment (mise is only the installer for engram's prebuilt binary; lean-ctx no longer uses it).
…ed devel dir Drop the hardcoded dir = .worktrees/devel so the task installs whatever branch/worktree it is run from (mise runs a dir-less task in its own config_root, which for a per-worktree tracked config is that worktree).
…rs env injection Launches an agent (e.g. claude-code) via `mise exec` so all mise-managed tools are on PATH for the session and anything it spawns — makes mise tasks and tooling available inside the agent. Also injects wrangler-style .dev.vars: dotenv KEY=VALUE with # comments and quotes; --env <stage> loads .dev.vars.<stage>, which REPLACES the base .dev.vars (matching wrangler). - src/dev_vars.rs: .dev.vars loader + minimal dotenv parser (unit-tested) - src/agent_launch.rs: run_launch_env() injects env + wraps in `mise exec`; run_launch() delegates to it, so existing `agents launch` is unchanged - src/agents.rs: cli_run() loads .dev.vars from cwd and reports what it injects - src/cli/run.rs: the `run` subcommand
agentflare installs engram through mise and `agentflare run` launches via it, but mise isn't in lean-ctx's built-in default allowlist — so its onboarded gate would block mise (and thus agentflare's own mise usage) under the default enforce mode. Allow it alongside agentflare in the same post-install call.
The reason to run lean-ctx is denser model output; default it to the strongest compression during onboarding rather than leaving it at lite.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/agent_launch.rs (1)
29-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNo test coverage for
via_mise=trueorenvoverride injection.Existing tests only exercise the
via_mise=falsepath (viarun_launch). The new mise-wrapping and env-injection logic — the core behavior added by this PR — has no direct test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/agent_launch.rs` around lines 29 - 75, Add focused tests for run_launch_env covering via_mise=true and environment override injection: verify mise_bin is used with the expected “exec -- <binary>” arguments, and verify supplied env entries are applied to the spawned command. Use test doubles or a controlled executable/script to capture invocation and environment, while retaining coverage for the existing non-mise path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/agent_launch.rs`:
- Around line 59-75: Update the error handling around cmd.status() in the agent
launch function to report the actual executable being spawned: use “mise” when
via_mise is true and the agent binary otherwise, while retaining the original
error details. Reference the mise command construction and downstream Err
handler so the message accurately identifies the failing launcher.
In `@src/components.rs`:
- Around line 337-351: Only persist the lean-ctx installation marker after a
successful install: update the closure under the apply component in
src/components.rs to write the log within the Ok branch of the
tool_install::install result, while leaving failed outcomes unmarked so
subsequent agentflare init attempts can retry.
---
Nitpick comments:
In `@src/agent_launch.rs`:
- Around line 29-75: Add focused tests for run_launch_env covering via_mise=true
and environment override injection: verify mise_bin is used with the expected
“exec -- <binary>” arguments, and verify supplied env entries are applied to the
spawned command. Use test doubles or a controlled executable/script to capture
invocation and environment, while retaining coverage for the existing non-mise
path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5e1e185f-c97b-4ee0-9644-04d63eac8014
📒 Files selected for processing (9)
mise.local.tomlsrc/agent_launch.rssrc/agents.rssrc/cli/mod.rssrc/cli/run.rssrc/components.rssrc/dev_vars.rssrc/main.rssrc/tool_install.rs
| // `mise exec -- <binary> …` runs the agent inside mise's environment, so its | ||
| // tool paths are on PATH for the agent and its child shells. | ||
| let mise = if via_mise { crate::mise_install::mise_bin() } else { None }; | ||
| let mut cmd = match &mise { | ||
| Some(m) => { | ||
| let mut c = Command::new(m); | ||
| c.arg("exec").arg("--").arg(&binary); | ||
| c | ||
| } | ||
| None => Command::new(&binary), | ||
| }; | ||
| cmd.stdout(Stdio::inherit()); | ||
| cmd.stderr(Stdio::inherit()); | ||
| cmd.stdin(Stdio::inherit()); | ||
| for (k, v) in env { | ||
| cmd.env(k, v); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Error message misattributes failures when launched via mise.
Once the mise branch is taken, a spawn failure at cmd.status() may originate from invoking mise itself, but the downstream Err(e) handler still always reports "failed to launch {binary}: {e}", which is misleading for debugging.
🐛 Proposed fix
match cmd.status() {
Ok(s) if s.success() => LaunchOutcome::Launched,
Ok(s) => {
let code = s.code().unwrap_or(-1);
std::process::exit(code);
}
- Err(e) => LaunchOutcome::NotFound(format!(
- "failed to launch {}: {e}",
- binary.display()
- )),
+ Err(e) => {
+ let target = mise.as_ref().map(|m| m.display().to_string()).unwrap_or_else(|| binary.display().to_string());
+ LaunchOutcome::NotFound(format!("failed to launch {target}: {e}"))
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // `mise exec -- <binary> …` runs the agent inside mise's environment, so its | |
| // tool paths are on PATH for the agent and its child shells. | |
| let mise = if via_mise { crate::mise_install::mise_bin() } else { None }; | |
| let mut cmd = match &mise { | |
| Some(m) => { | |
| let mut c = Command::new(m); | |
| c.arg("exec").arg("--").arg(&binary); | |
| c | |
| } | |
| None => Command::new(&binary), | |
| }; | |
| cmd.stdout(Stdio::inherit()); | |
| cmd.stderr(Stdio::inherit()); | |
| cmd.stdin(Stdio::inherit()); | |
| for (k, v) in env { | |
| cmd.env(k, v); | |
| } | |
| Err(e) => { | |
| let target = mise | |
| .as_ref() | |
| .map(|m| m.display().to_string()) | |
| .unwrap_or_else(|| binary.display().to_string()); | |
| LaunchOutcome::NotFound(format!("failed to launch {target}: {e}")) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agent_launch.rs` around lines 59 - 75, Update the error handling around
cmd.status() in the agent launch function to report the actual executable being
spawned: use “mise” when via_mise is true and the agent binary otherwise, while
retaining the original error details. Reference the mise command construction
and downstream Err handler so the message accurately identifies the failing
launcher.
| apply: { | ||
| let log = leanctx_log.clone(); | ||
| Box::new(move || { | ||
| if log.exists() { | ||
| return format!("lean-ctx install already triggered — check {}", log.display()); | ||
| } | ||
| let _ = fs::create_dir_all(log.parent().unwrap()); | ||
| let cmd = "npm install -g lean-ctx-bin && lean-ctx onboard"; | ||
| let result = if cfg!(windows) { | ||
| Command::new("cmd").args(["/c", cmd]).status() | ||
| } else { | ||
| Command::new("sh").args(["-c", cmd]).status() | ||
| }; | ||
| let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX); | ||
| let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now())); | ||
| match result { | ||
| Ok(s) if s.success() => "lean-ctx installed and onboarded".to_string(), | ||
| _ => "lean-ctx install failed — run manually: npm install -g lean-ctx-bin && lean-ctx onboard".to_string(), | ||
| match outcome { | ||
| Ok(m) => format!("{m} + onboarded"), | ||
| Err(e) => e, | ||
| } | ||
| }) | ||
| }, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
A failed lean-ctx install can never be retried.
The log is written unconditionally after install(...) (Line 345), and the early guard returns on log.exists() (Lines 340-342). So if the installer fails once, every subsequent agentflare init short-circuits to "already triggered" while check (via tool_install::installed) still reports the tool absent — leaving the component permanently unsatisfiable until the user manually deletes the log. Write the marker only on success.
🔒️ Proposed fix: persist the marker only on success
let _ = fs::create_dir_all(log.parent().unwrap());
let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX);
- let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
match outcome {
- Ok(m) => format!("{m} + onboarded"),
+ Ok(m) => {
+ let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now()));
+ format!("{m} + onboarded")
+ }
Err(e) => e,
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| apply: { | |
| let log = leanctx_log.clone(); | |
| Box::new(move || { | |
| if log.exists() { | |
| return format!("lean-ctx install already triggered — check {}", log.display()); | |
| } | |
| let _ = fs::create_dir_all(log.parent().unwrap()); | |
| let cmd = "npm install -g lean-ctx-bin && lean-ctx onboard"; | |
| let result = if cfg!(windows) { | |
| Command::new("cmd").args(["/c", cmd]).status() | |
| } else { | |
| Command::new("sh").args(["-c", cmd]).status() | |
| }; | |
| let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX); | |
| let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now())); | |
| match result { | |
| Ok(s) if s.success() => "lean-ctx installed and onboarded".to_string(), | |
| _ => "lean-ctx install failed — run manually: npm install -g lean-ctx-bin && lean-ctx onboard".to_string(), | |
| match outcome { | |
| Ok(m) => format!("{m} + onboarded"), | |
| Err(e) => e, | |
| } | |
| }) | |
| }, | |
| apply: { | |
| let log = leanctx_log.clone(); | |
| Box::new(move || { | |
| if log.exists() { | |
| return format!("lean-ctx install already triggered — check {}", log.display()); | |
| } | |
| let _ = fs::create_dir_all(log.parent().unwrap()); | |
| let outcome = crate::tool_install::install(&crate::tool_install::LEAN_CTX); | |
| match outcome { | |
| Ok(m) => { | |
| let _ = fs::write(&log, format!("{:?}", std::time::SystemTime::now())); | |
| format!("{m} + onboarded") | |
| } | |
| Err(e) => e, | |
| } | |
| }) | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components.rs` around lines 337 - 351, Only persist the lean-ctx
installation marker after a successful install: update the closure under the
apply component in src/components.rs to write the log within the Ok branch of
the tool_install::install result, while leaving failed outcomes unmarked so
subsequent agentflare init attempts can retry.
* refactor(update): split self-update into module + MCP-safe binary swap
Split single-file src/update.rs into src/update/{mod,github,swap}.rs.
swap.rs is the reusable MCP-safe binary-replacement primitive:
- never signals/kills any process, so a live `agentflare mcp` server keeps
running its loaded image and picks up the new binary on next launch
- Windows: rename-aside + copy, with rollback on failure and a deferred
.bat fallback when the exe is hard-locked against renaming
- Unix: same-fs staged atomic rename
- find_killable_pids() reports (never kills) other running instances
github.rs isolates release discovery/download/checksum, with pure
parse_checksum/verify_checksum helpers now unit-tested.
Prepares update::swap::replace_binary for reuse by dev-install (#127).
* feat(dev-install): build-from-source + atomic install over running binary
New `agentflare dev-install` subcommand: cargo build (release by default),
resolve the built binary via `cargo metadata` (honors CARGO_TARGET_DIR and
workspace shared targets), verify it answers `--version` under a timeout, then
swap it over the running binary using the MCP-safe update::swap::replace_binary
primitive (#122) — so a live `agentflare mcp` server is never disturbed.
- refuses to overwrite the build output itself (guards against running from the
freshly built binary instead of the installed one)
- --debug builds debug; --dry-run reports the swap without performing it
- pure cargo-metadata target-dir parsing + same-file guard are unit-tested
* fix(dev-install): resolve built binary via cargo JSON, not target/<profile>
CodeRabbit (PR #206): built_binary_path assumed target_directory/<profile>/,
which is wrong when build.target / CARGO_BUILD_TARGET adds a <triple>/ segment
(or a custom profile renames the dir) -- the lookup would miss the binary.
Read the executable path from cargo's compiler-artifact JSON message instead of
reconstructing it, so any target/profile layout is handled. build_and_locate()
replaces the target-dir/profile-dir reconstruction and its parser.
* fix(update): address CodeRabbit review — swap rollback, staging race, net timeout
PR #206 CodeRabbit findings on the #122 swap/github code:
- swap.rs: surface Windows rollback failure (and the recoverable old-binary
path) instead of swallowing it, honoring the "never leave without a binary"
invariant.
- swap.rs: pid-scope the Unix staging filename so concurrent swaps against the
same target cannot clobber each other's staged file.
- github.rs: give the release HTTP client connect + per-read timeouts so a hung
network cannot block an update indefinitely (no overall timeout, to avoid
capping large asset downloads).
* fix(dev-install): reject non-host CARGO_BUILD_TARGET; reap cargo on read error
CodeRabbit (PR #206) on build_and_locate:
- Reject a non-host CARGO_BUILD_TARGET early with a clear message: dev-install
replaces the running binary, so a cross target would build something that
cannot run here. verify_runs() remains the backstop for a .cargo/config
build.target.
- Always child.wait() even when reading cargo stdout fails, so a failed read
never orphans the cargo process.
Agentflare-Agent: opencode Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c Agentflare-Item: 127
#127) (#508) * fix(jobs): bind claude-code's ~/.claude writable in bwrap sandbox (item #127) Agentflare-Agent: opencode Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c Agentflare-Item: 127 * fix(jobs): rustfmt the claude-dir bwrap tests (item #127) Agentflare-Agent: opencode Agentflare-Branch: task/127-bwrap-sandbox-has-no-writable-bind-for-c Agentflare-Item: 127 --------- Co-authored-by: shiva <shiva@gosysinfo.tech>
…dbox crate (#541) Move agentflare-jobs's bwrap sandbox module into its own crate, flare-sandbox, and make it agent-agnostic: instead of hardcoded is_opencode/is_claude_code/is_cursor checks and three near-identical mount blocks, it now takes a caller-supplied SandboxConfig (AgentProfile list + writable_home_dirs) and applies whichever agent-state mounts match the resolved command. agentflare-jobs's own sandbox.rs becomes the thin adapter that supplies agentflare's concrete policy. Cross-referenced akitaonrails/ai-jail's own per-agent state-dir table (cloned into .refs/ai-jail for reference) for which $HOME directories each CLI needs -- adopting its coverage of codex (.codex), gemini (.gemini), aider (.aider), grok (.grok), kimi (.kimi-code), and opencode's second directory (.config/opencode, alongside the existing .local/share/opencode) -- but keeping agentflare's own ephemeral-overlay write policy (items #106/#127) rather than ai-jail's persistent bind, since the two tools have different containment goals. No behavior change for claude-code/opencode/cursor; adds coverage for codex/gemini/aider/grok/kimi, none of which had any agent-specific mount before. Agentflare-Agent: claude-code Agentflare-Branch: feat/flare-sandbox-crate Co-authored-by: shiva <shiva@gosysinfo.tech>
Dependency-light install + launch tooling for agentflare's integrations, plus MCP-registration robustness.
engram — install via mise, register by absolute path (
5b0710b)agentflare,engram) don't resolve for GUI-launched hosts lacking~/.local/binon PATH; engram had no dependency-free install without Go/Homebrew/npm.src/mise_install.rs) and installs engram via mise'sgithub:backend (prebuilt release binary, checksum-verified — no toolchain). Registers every host's engram + agentflare MCP server against the resolved absolute path. For native engram hosts,engram setupis run via the mise path so it writes that absolute path (and installs the memory persona) itself. Honest engram check (plugin AND a realmcpServers.engram). Sharespaths::agentflare_binary().lean-ctx — native installer, not npm/mise (
e8b2b13,cdb9eee,0a2a05b)src/tool_install.rs): each tool lists native methods (curl | sh,brew) in priority order; the runner picks the first whose helper is present. No mise, no npm.onboardinstalls a shell hook that gates non-allowlisted commands (and blockssh -c). Post-install, agentflare (via direct process spawns) allowlists agentflare + mise and setscompression_level = max(power mode). Without this, the gate would block agentflare's own re-invocations and mise usage under the defaultenforcemode.agentflare run <agent>— mise env + wrangler-style.dev.vars(b0917c3)mise execso all mise-managed tools are on PATH for the session and anything it spawns — makes mise tasks/tooling available inside the agent..dev.vars(dotenvKEY=VALUE,#comments, quotes).--env <stage>loads.dev.vars.<stage>, which replaces the base file (matching wrangler).src/dev_vars.rs(loader),src/agent_launch.rs::run_launch_env(env + mise wrap;run_launchdelegates soagents launchis unchanged),src/cli/run.rs(subcommand).refresh-develmise task (6a1e1ce).worktrees/develdir so it builds whatever worktree it's run from.Verification
✔ Connected;agentflare runverified to inject.dev.varsvalues + all mise tool paths into a launched agent.agentflare initinstalls lean-ctx natively, onboards, allowlists agentflare+mise, sets power mode.Summary by CodeRabbit
miseand PATH-independent tool setup via absolute executables.agentflare runCLI support with optional env/model/mode and stage-based.dev.varsloading.misewhen available.engraminstall/verification and MCP server registration reliability across hosts (including Claude Code).agentflarepaths.misecomponent.