fix(platform): search mise shims dir so mise-installed CLIs are detected (#3319)

* fix(platform): search mise shims dir so mise-installed CLIs are detected

- Add ~/.local/share/mise/shims (and MISE_DATA_DIR override + legacy ~/.mise/shims) to wellKnownUserToolchainBins.
- This makes Pi, Kimi, and other mise-managed coding agents visible to the daemon even when launched from GUI contexts with stripped PATH.
- Added tests for default and MISE_DATA_DIR cases.
- Also pinned pnpm@10.33.2 in root mise.toml for better mise ergonomics.

Before/after: more local CLIs now appear in the runtime picker (Kimi, Pi, Antigravity, Kilo, etc.).

Refs: discussion in session around improving detection for common mise users.

* fix(platform): address Copilot review on mise shims logic

- Generalize the shims comment (no hard-coded CLI examples).
- Make per-version Node toolchain scanning respect MISE_DATA_DIR
  (use the same mise root for installs as for shims).
- Avoid duplicate shims entries when MISE_DATA_DIR makes legacy path
  identical to the primary one.

Addresses the three inline comments from copilot-pull-request-reviewer
on PR #3319.

* test(platform): extend MISE_DATA_DIR test to cover installs scanning

Addresses non-blocking review feedback from @nettee on PR #3319.

The previous test only asserted shims behavior under a custom
MISE_DATA_DIR. This extends it to also create fixture trees under
customMise/installs/node/... and customMise/installs/npm-openai-codex/...
and assert that the install paths are discovered while default-root
paths are excluded.

This makes the test robust against regressions in the installs
scanning logic (existingMiseNpmPackageBinDirs + node version dirs).

* fix(platform): only fall back to ~/.mise/shims when no MISE_DATA_DIR is set

Addresses the remaining non-blocking review comment from @nettee on PR #3319.

When an explicit MISE_DATA_DIR is provided, we no longer inject the
legacy ~/.mise/shims path. This prevents stale shims from a previous
mise layout from being re-introduced into detection.

Also added a regression assertion in the MISE_DATA_DIR test.

* fix(daemon): make claude-stream dedup robust when final assistant wrapper lacks msgId

Prevents duplicated text and thinking output (especially visible during
design system generation with AMR/Vela).

Root cause: the textStreamed guard fell back to  whenever the
final  message arrived without a string uid=501(ramarivera) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),399(com.apple.access_ssh),33(_appstore),98(_lpadmin),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),400(com.apple.access_remote_ae) (common in some
AMR flows and design system tasks), causing the full content to be
re-emitted even if it had already been delivered via streaming deltas.

Fix: track whether any text or thinking was streamed via deltas for the
current message and use that as a reliable fallback for the final wrapper
instead of only trusting  presence.

* revert: remove dedup from claude-stream (PR #3319 should stay clean)
This commit is contained in:
Ramiro 2026-05-30 05:21:04 +02:00 committed by GitHub
parent 51963cff78
commit e30a4a2202
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 2 deletions

3
mise.toml Normal file
View file

@ -0,0 +1,3 @@
[tools]
node = "24"
pnpm = "10.33.2"

View file

@ -942,16 +942,32 @@ export function wellKnownUserToolchainBins(
join(home, ".npm-global", "bin"), join(home, ".npm-global", "bin"),
join(home, ".npm-packages", "bin"), join(home, ".npm-packages", "bin"),
); );
// Mise shims: makes every tool installed with `mise install` visible to
// GUI-launched daemons even when the process inherits a stripped PATH.
// Respect MISE_DATA_DIR (the official way to relocate the whole mise tree).
// We only fall back to the legacy ~/.mise/shims path when no explicit
// MISE_DATA_DIR override is provided.
const miseDataOverride = resolveUserScopedHome(env.MISE_DATA_DIR, home);
const miseData = miseDataOverride || join(home, ".local", "share", "mise");
dirs.push(join(miseData, "shims"));
if (!miseDataOverride) {
dirs.push(join(home, ".mise", "shims"));
}
if (includeSystemBins) { if (includeSystemBins) {
dirs.push("/opt/homebrew/bin", "/usr/local/bin"); dirs.push("/opt/homebrew/bin", "/usr/local/bin");
} }
// Per-version Node toolchains: scan the install root and surface every // Per-version Node toolchains: scan the install root and surface every
// version directory's bin folder. Best-effort — missing roots simply // version directory's bin folder. Best-effort — missing roots simply
// contribute nothing. // contribute nothing.
dirs.push(...existingMiseNpmPackageBinDirs(join(home, ".local", "share", "mise", "installs"))); // When MISE_DATA_DIR is set we use the same root for consistency with shims.
const miseInstalls = join(miseData, "installs");
dirs.push(...existingMiseNpmPackageBinDirs(miseInstalls));
for (const installRoot of [ for (const installRoot of [
{ {
root: join(home, ".local", "share", "mise", "installs", "node"), root: join(miseInstalls, "node"),
segments: ["bin"], segments: ["bin"],
}, },
{ {

View file

@ -826,6 +826,56 @@ describe("wellKnownUserToolchainBins", () => {
} }
}); });
it("includes the default mise shims dir so mise-installed CLIs (pi, kimi, etc.) are visible to GUI daemons", () => {
const home = mkdtempSync(join(tmpdir(), "wkutb-mise-shims-"));
try {
const dirs = wellKnownUserToolchainBins({ home, env: {}, includeSystemBins: false });
expect(dirs).toContain(join(home, ".local", "share", "mise", "shims"));
// Legacy location too
expect(dirs).toContain(join(home, ".mise", "shims"));
} finally {
rmSync(home, { recursive: true, force: true });
}
});
it("respects $MISE_DATA_DIR for the shims location (custom mise root)", () => {
const home = mkdtempSync(join(tmpdir(), "wkutb-mise-data-"));
const customMise = mkdtempSync(join(tmpdir(), "wkutb-custom-mise-"));
try {
// Create fixture install trees under the custom root so the installs
// scanning logic is exercised (this catches regressions that only
// affect shims but not the Node / npm-openai-codex install paths).
const customNodeBin = join(customMise, "installs", "node", "24.16.0", "bin");
mkdirSync(customNodeBin, { recursive: true });
writeFileSync(join(customNodeBin, "marker"), "");
const customCodexBin = join(customMise, "installs", "npm-openai-codex", "latest", "bin");
mkdirSync(customCodexBin, { recursive: true });
writeFileSync(join(customCodexBin, "codex"), "");
const dirs = wellKnownUserToolchainBins({
home,
env: { MISE_DATA_DIR: customMise },
includeSystemBins: false,
});
expect(dirs).toContain(join(customMise, "shims"));
// Install paths under custom root should be discovered
expect(dirs).toContain(customNodeBin);
expect(dirs).toContain(customCodexBin);
// Default-root paths must not leak in when MISE_DATA_DIR is set
expect(dirs).not.toContain(join(home, ".local", "share", "mise", "shims"));
expect(dirs).not.toContain(join(home, ".local", "share", "mise", "installs", "node", "24.16.0", "bin"));
// Legacy ~/.mise/shims must also be excluded when an explicit override is present
expect(dirs).not.toContain(join(home, ".mise", "shims"));
} finally {
rmSync(home, { recursive: true, force: true });
rmSync(customMise, { recursive: true, force: true });
}
});
it("does not append a prefix entry when neither env var is set", () => { it("does not append a prefix entry when neither env var is set", () => {
const home = mkdtempSync(join(tmpdir(), "wkutb-noprefix-")); const home = mkdtempSync(join(tmpdir(), "wkutb-noprefix-"));
try { try {