mixdog 0.7.14 → 0.7.16
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/hooks/session-start.cjs +10 -2
- package/hooks/shim-launcher.cjs +15 -1
- package/lib/keychain-cjs.cjs +32 -5
- package/lib/plugin-paths.cjs +10 -2
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +1 -1
- package/setup/config-merge.mjs +1 -8
- package/setup/launch-core.mjs +184 -73
- package/setup/locate-claude.mjs +22 -4
- package/setup/setup-server.mjs +37 -21
- package/src/agent/orchestrator/config.mjs +7 -11
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +36 -10
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +13 -4
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +11 -1
- package/src/agent/orchestrator/tools/graph-manifest.json +7 -7
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +11 -1
- package/src/agent/orchestrator/tools/patch-manifest.json +7 -7
- package/src/channels/index.mjs +10 -1
- package/src/channels/lib/executor.mjs +59 -24
- package/src/channels/lib/hook-pipe-server.mjs +8 -1
- package/src/memory/lib/runtime-fetcher.mjs +19 -3
- package/src/search/lib/web-tools.mjs +13 -1
- package/src/shared/config.mjs +26 -4
- package/src/shared/open-url.mjs +35 -10
- package/src/shared/user-cwd.mjs +14 -2
- package/src/shared/wsl.mjs +35 -0
package/src/shared/open-url.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { isWSL } from './wsl.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Open a URL in the user's default browser. Best-effort and non-blocking —
|
|
@@ -11,27 +12,51 @@ import { spawn } from 'child_process';
|
|
|
11
12
|
* treats the first quoted string as the WINDOW TITLE, so the URL is dropped
|
|
12
13
|
* and nothing opens.
|
|
13
14
|
* - macOS: `open <url>`.
|
|
15
|
+
* - WSL: xdg-open usually fails (no Linux GUI), so reach the Windows-HOST
|
|
16
|
+
* browser — prefer `wslview` (wslu), else `powershell.exe Start-Process`.
|
|
17
|
+
* cmd.exe `start` is deliberately NOT used: cmd re-parses URL metacharacters
|
|
18
|
+
* so a query-string `&` (e.g. `?a=1&b=2`) is treated as a command separator
|
|
19
|
+
* and the URL truncates. PowerShell's Start-Process takes the URL as one
|
|
20
|
+
* argument and does not reparse `&`; the URL is passed inside a single-quoted
|
|
21
|
+
* PowerShell literal (single quotes doubled) so `&`, spaces and quotes
|
|
22
|
+
* survive and no injection is possible. Falls back through the chain when an
|
|
23
|
+
* opener is missing.
|
|
14
24
|
* - Linux/other: `xdg-open <url>`.
|
|
15
25
|
*/
|
|
16
26
|
export function openInBrowser(url) {
|
|
17
27
|
const u = String(url);
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
// Ordered [cmd, args] candidates. Every platform but WSL has exactly one;
|
|
29
|
+
// WSL has a fallback chain since the first opener may be absent.
|
|
30
|
+
let candidates;
|
|
20
31
|
if (process.platform === 'win32') {
|
|
21
|
-
|
|
22
|
-
args = ['url.dll,FileProtocolHandler', u];
|
|
32
|
+
candidates = [['rundll32', ['url.dll,FileProtocolHandler', u]]];
|
|
23
33
|
} else if (process.platform === 'darwin') {
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
candidates = [['open', [u]]];
|
|
35
|
+
} else if (isWSL()) {
|
|
36
|
+
// Single-quoted PowerShell literal: double any embedded single quote.
|
|
37
|
+
// Everything else (incl. `&`) is literal inside a single-quoted string.
|
|
38
|
+
const psUrl = `'${u.replace(/'/g, "''")}'`;
|
|
39
|
+
candidates = [
|
|
40
|
+
['wslview', [u]],
|
|
41
|
+
['powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `Start-Process -FilePath ${psUrl}`]],
|
|
42
|
+
];
|
|
26
43
|
} else {
|
|
27
|
-
|
|
28
|
-
args = [u];
|
|
44
|
+
candidates = [['xdg-open', [u]]];
|
|
29
45
|
}
|
|
46
|
+
tryOpenCandidates(candidates, 0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Spawn candidates[index]; on spawn error (opener missing) advance to the next.
|
|
50
|
+
// Always non-blocking — the caller prints the URL, so exhausting the chain is
|
|
51
|
+
// never fatal.
|
|
52
|
+
function tryOpenCandidates(candidates, index) {
|
|
53
|
+
if (index >= candidates.length) return;
|
|
54
|
+
const [cmd, args] = candidates[index];
|
|
30
55
|
try {
|
|
31
56
|
const child = spawn(cmd, args, { stdio: 'ignore', detached: true, windowsHide: true });
|
|
32
|
-
child.on('error', () => {
|
|
57
|
+
child.on('error', () => { tryOpenCandidates(candidates, index + 1); });
|
|
33
58
|
child.unref();
|
|
34
59
|
} catch {
|
|
35
|
-
|
|
60
|
+
tryOpenCandidates(candidates, index + 1);
|
|
36
61
|
}
|
|
37
62
|
}
|
package/src/shared/user-cwd.mjs
CHANGED
|
@@ -54,8 +54,20 @@ export function _safeProcessCwd() {
|
|
|
54
54
|
function _normalizePlatformCwd(p) {
|
|
55
55
|
if (!p || typeof p !== 'string') return p
|
|
56
56
|
if (process.platform !== 'win32') return resolve(p)
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
// Map all three POSIX drive-prefix shapes to native Windows paths before
|
|
58
|
+
// resolution, aligned with path-utils.mjs posixPathToWindowsPath:
|
|
59
|
+
// /cygdrive/c/... (Cygwin), /mnt/c/... (WSL), /c/... (MSYS/Git-Bash) → C:\...
|
|
60
|
+
// Cygwin/WSL prefixes must be tested before the bare single-letter form
|
|
61
|
+
// because their slice offsets differ.
|
|
62
|
+
const cyg = p.match(/^\/cygdrive\/([a-zA-Z])\//)
|
|
63
|
+
const wsl = p.match(/^\/mnt\/([a-zA-Z])\//)
|
|
64
|
+
let native = p
|
|
65
|
+
if (cyg) native = `${cyg[1].toUpperCase()}:\\${p.slice(11).replace(/\//g, '\\')}`
|
|
66
|
+
else if (wsl) native = `${wsl[1].toUpperCase()}:\\${p.slice(7).replace(/\//g, '\\')}`
|
|
67
|
+
else {
|
|
68
|
+
const m = p.match(/^[\/\\]([a-zA-Z])[\/\\](.*)$/)
|
|
69
|
+
if (m) native = `${m[1].toUpperCase()}:\\${m[2].replace(/\//g, '\\')}`
|
|
70
|
+
}
|
|
59
71
|
return resolve(native)
|
|
60
72
|
}
|
|
61
73
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// WSL (Windows Subsystem for Linux) detection.
|
|
2
|
+
//
|
|
3
|
+
// process.platform reports 'linux' inside WSL, so any caller that needs
|
|
4
|
+
// Windows-HOST behavior — opening the Windows default browser, reaching the
|
|
5
|
+
// Windows credential store, translating Windows drive paths — must branch on
|
|
6
|
+
// this explicitly rather than on process.platform alone. Plain-Linux behavior
|
|
7
|
+
// stays the default; this only flags the WSL special case.
|
|
8
|
+
//
|
|
9
|
+
// Detection order (cheapest / most reliable first):
|
|
10
|
+
// 1. WSL_DISTRO_NAME / WSL_INTEROP env vars (set by the WSL init for every
|
|
11
|
+
// interactive and most non-interactive sessions).
|
|
12
|
+
// 2. /proc/version containing "microsoft"/"wsl" (the kernel is a Microsoft
|
|
13
|
+
// build under WSL1/WSL2). Read once and memoized.
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
let _isWSL;
|
|
17
|
+
|
|
18
|
+
export function isWSL() {
|
|
19
|
+
if (_isWSL !== undefined) return _isWSL;
|
|
20
|
+
if (process.platform !== 'linux') {
|
|
21
|
+
_isWSL = false;
|
|
22
|
+
return _isWSL;
|
|
23
|
+
}
|
|
24
|
+
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) {
|
|
25
|
+
_isWSL = true;
|
|
26
|
+
return _isWSL;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const v = readFileSync('/proc/version', 'utf8').toLowerCase();
|
|
30
|
+
_isWSL = v.includes('microsoft') || v.includes('wsl');
|
|
31
|
+
} catch {
|
|
32
|
+
_isWSL = false;
|
|
33
|
+
}
|
|
34
|
+
return _isWSL;
|
|
35
|
+
}
|