mixdog 0.9.44 → 0.9.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "0.9.44",
3
+ "version": "0.9.45",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone mixdog coding-agent CLI/TUI workspace.",
@@ -13,8 +13,8 @@
13
13
  * the child exits, reporting the resolved version on success.
14
14
  */
15
15
 
16
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
17
- import { dirname, join } from 'node:path';
16
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
17
+ import { basename, delimiter, dirname, join } from 'node:path';
18
18
  import { fileURLToPath } from 'node:url';
19
19
  import { spawn } from 'node:child_process';
20
20
  import { resolvePluginData } from './plugin-paths.mjs';
@@ -199,19 +199,49 @@ export async function checkLatestVersion({ force = false, dataDir } = {}) {
199
199
  * `-WindowStyle Hidden` style flags that antivirus heuristics flag).
200
200
  */
201
201
  export function npmCliJsPath() {
202
- const execDir = dirname(process.execPath);
203
- const candidates = [
204
- // Windows: npm ships beside node.exe.
205
- join(execDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'),
206
- // Unix layout: <prefix>/bin/node → <prefix>/lib/node_modules/npm.
207
- join(execDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
208
- ];
209
202
  // When launched via npm itself, npm_execpath is authoritative.
210
203
  const envPath = process.env.npm_execpath;
211
- if (envPath && /npm-cli\.js$/i.test(envPath)) candidates.unshift(envPath);
204
+ const candidates = envPath && /npm-cli\.js$/i.test(envPath) ? [envPath] : [];
205
+ const execDirs = [dirname(process.execPath)];
206
+ try {
207
+ const realExecDir = dirname(realpathSync(process.execPath));
208
+ if (!execDirs.includes(realExecDir)) execDirs.push(realExecDir);
209
+ } catch { /* retain the raw executable path */ }
210
+
211
+ for (const execDir of execDirs) {
212
+ // Windows: npm ships beside node.exe.
213
+ candidates.push(join(execDir, 'node_modules', 'npm', 'bin', 'npm-cli.js'));
214
+ // Unix layout: <prefix>/bin/node → <prefix>/lib/node_modules/npm.
215
+ candidates.push(join(execDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'));
216
+ // Homebrew: <prefix>/bin/node → <prefix>/libexec/lib/node_modules/npm.
217
+ candidates.push(join(execDir, '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'));
218
+ }
212
219
  for (const candidate of candidates) {
213
220
  try { if (existsSync(candidate)) return candidate; } catch { /* keep looking */ }
214
221
  }
222
+
223
+ // Last resort: npm shims on PATH commonly resolve into npm's package bin dir.
224
+ const pathDirs = (process.env.PATH || process.env.Path || '').split(delimiter);
225
+ for (const pathDir of pathDirs) {
226
+ if (!pathDir) continue;
227
+ const npmPaths = process.platform === 'win32'
228
+ ? [join(pathDir, 'npm'), join(pathDir, 'npm.cmd')]
229
+ : [join(pathDir, 'npm')];
230
+ for (const npmPath of npmPaths) {
231
+ try {
232
+ if (!existsSync(npmPath)) continue;
233
+ const resolvedNpm = realpathSync(npmPath);
234
+ const npmBinDir = dirname(resolvedNpm);
235
+ if (
236
+ basename(npmBinDir) !== 'bin'
237
+ || basename(dirname(npmBinDir)) !== 'npm'
238
+ || basename(dirname(dirname(npmBinDir))) !== 'node_modules'
239
+ ) continue;
240
+ const cliJs = join(npmBinDir, 'npm-cli.js');
241
+ if (existsSync(cliJs)) return cliJs;
242
+ } catch { /* keep looking */ }
243
+ }
244
+ }
215
245
  return null;
216
246
  }
217
247
 
package/src/tui/App.jsx CHANGED
@@ -263,12 +263,9 @@ export function App({ store, initialStatusLine = '', forceOnboarding = false })
263
263
  const [resizeState, setResizeState] = useState(() => ({ ...terminalSize(stdout), epoch: 0 }));
264
264
  const [panelTransitionEpoch, setPanelTransitionEpoch] = useState(0);
265
265
  const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState(0);
266
- // Windows Terminal/conhost scrolls the alt-screen (auto-wrap/DECAWM) when the
267
- // bottom-right cell is written. WT_SESSION is also set when the UI runs under
268
- // a Unix-ish shell hosted by Windows Terminal, where process.platform is not
269
- // necessarily win32 but the terminal behavior is still Windows-like.
270
- const windowsLikeTerminal = process.platform === 'win32' || Boolean(process.env.WT_SESSION);
271
- const rightSafetyColumns = windowsLikeTerminal ? 1 : 0;
266
+ // Keep a universal one-cell margin at the right edge: terminals may clip or
267
+ // wrap their final cell, including macOS terminals rendering rounded borders.
268
+ const rightSafetyColumns = 1;
272
269
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
273
270
  // scrollOffset = how many transcript ROWS we've scrolled UP from the bottom
274
271
  // (0 = pinned to the latest, showing the newest content). Mouse wheel adjusts
@@ -3140,8 +3140,8 @@ function formatAggregateDetail(summaries) {
3140
3140
  }
3141
3141
 
3142
3142
  // src/runtime/shared/update-checker.mjs
3143
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3144
- import { dirname as dirname2, join as join2 } from "node:path";
3143
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
3144
+ import { basename, delimiter, dirname as dirname2, join as join2 } from "node:path";
3145
3145
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3146
3146
 
3147
3147
  // src/runtime/shared/plugin-paths.mjs
@@ -7128,7 +7128,7 @@ import { randomBytes } from "node:crypto";
7128
7128
  import { existsSync as existsSync2, unlinkSync } from "node:fs";
7129
7129
  import { readFile as readFileAsync, stat as statAsync } from "node:fs/promises";
7130
7130
  import { tmpdir } from "node:os";
7131
- import { basename, extname, isAbsolute, resolve } from "node:path";
7131
+ import { basename as basename2, extname, isAbsolute, resolve } from "node:path";
7132
7132
 
7133
7133
  // src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs
7134
7134
  var API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
@@ -7396,7 +7396,7 @@ async function readImageAttachmentFromPath(rawPath, cwd = process.cwd()) {
7396
7396
  if (!st.isFile()) return null;
7397
7397
  const buffer = await readFileAsync(fullPath);
7398
7398
  return imageAttachmentFromBuffer(buffer, mimeType, {
7399
- filename: basename(fullPath),
7399
+ filename: basename2(fullPath),
7400
7400
  sourcePath: fullPath
7401
7401
  });
7402
7402
  }
@@ -7467,7 +7467,7 @@ async function readClipboardText() {
7467
7467
  // src/standalone/projects.mjs
7468
7468
  import { homedir as homedir2 } from "node:os";
7469
7469
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
7470
- import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve2 } from "node:path";
7470
+ import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve2 } from "node:path";
7471
7471
  var MIXDOG_HOME = process.env.MIXDOG_HOME || join3(homedir2(), ".mixdog");
7472
7472
  var PROJECTS_FILE = join3(MIXDOG_HOME, "projects.json");
7473
7473
  function toAbsolute(rawPath) {
@@ -7487,7 +7487,7 @@ function readStore() {
7487
7487
  const projects = Array.isArray(parsed?.projects) ? parsed.projects : [];
7488
7488
  return {
7489
7489
  projects: projects.filter((entry) => entry && typeof entry.path === "string" && entry.path.trim()).map((entry) => ({
7490
- name: String(entry.name || basename2(entry.path) || entry.path),
7490
+ name: String(entry.name || basename3(entry.path) || entry.path),
7491
7491
  path: String(entry.path),
7492
7492
  addedAt: Number(entry.addedAt) || 0,
7493
7493
  ...Number(entry.lastSelectedAt) > 0 ? { lastSelectedAt: Number(entry.lastSelectedAt) } : {}
@@ -7517,7 +7517,7 @@ function ensureProjectIdMarker(absPath, name) {
7517
7517
  }
7518
7518
  const markerPath = join3(absPath, ".mixdog", "project.id");
7519
7519
  if (existsSync3(markerPath)) return;
7520
- const value = String(name || basename2(absPath) || "").trim();
7520
+ const value = String(name || basename3(absPath) || "").trim();
7521
7521
  if (!value || value.toLowerCase() === "common") return;
7522
7522
  const markerDir = join3(absPath, ".mixdog");
7523
7523
  mkdirSync2(markerDir, { recursive: true });
@@ -7555,7 +7555,7 @@ function addProject(rawPath) {
7555
7555
  return existing;
7556
7556
  }
7557
7557
  const entry = {
7558
- name: basename2(absPath) || absPath,
7558
+ name: basename3(absPath) || absPath,
7559
7559
  path: absPath,
7560
7560
  addedAt: Date.now()
7561
7561
  };
@@ -7584,7 +7584,7 @@ function renameProject(rawPath, nextName) {
7584
7584
  const entry = store.projects.find((item) => normalizeKey(item.path) === key);
7585
7585
  if (!entry) return null;
7586
7586
  const trimmed = String(nextName || "").trim();
7587
- entry.name = trimmed || basename2(absPath) || absPath;
7587
+ entry.name = trimmed || basename3(absPath) || absPath;
7588
7588
  writeStore(store);
7589
7589
  return entry;
7590
7590
  }
@@ -14387,7 +14387,7 @@ import {
14387
14387
  unlinkSync as unlinkSync2,
14388
14388
  writeFileSync as writeFileSync3
14389
14389
  } from "fs";
14390
- import { dirname as dirname4, basename as basename3, join as join4 } from "path";
14390
+ import { dirname as dirname4, basename as basename4, join as join4 } from "path";
14391
14391
  import { randomBytes as randomBytes2 } from "crypto";
14392
14392
  import { execFile as execFile2, execFileSync } from "child_process";
14393
14393
  import { promisify } from "util";
@@ -14843,7 +14843,7 @@ function writeFileAtomicSync(filePath, data, opts = {}) {
14843
14843
  const run = () => {
14844
14844
  const dir = dirname4(filePath);
14845
14845
  mkdirSync3(dir, { recursive: true });
14846
- const tmp = join4(dir, `.${basename3(filePath)}.${randomBytes2(12).toString("hex")}.tmp`);
14846
+ const tmp = join4(dir, `.${basename4(filePath)}.${randomBytes2(12).toString("hex")}.tmp`);
14847
14847
  try {
14848
14848
  const writeOpts = { encoding: opts.encoding || "utf8", flag: "wx", mode: opts.mode !== void 0 ? opts.mode : 384 };
14849
14849
  writeFileSync3(tmp, data, writeOpts);
@@ -19528,8 +19528,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
19528
19528
  const [resizeState, setResizeState] = useState8(() => ({ ...terminalSize(stdout2), epoch: 0 }));
19529
19529
  const [panelTransitionEpoch, setPanelTransitionEpoch] = useState8(0);
19530
19530
  const [panelInkMaskEpoch, setPanelInkMaskEpoch] = useState8(0);
19531
- const windowsLikeTerminal = process.platform === "win32" || Boolean(process.env.WT_SESSION);
19532
- const rightSafetyColumns = windowsLikeTerminal ? 1 : 0;
19531
+ const rightSafetyColumns = 1;
19533
19532
  const frameColumns = Math.max(1, resizeState.columns - rightSafetyColumns);
19534
19533
  const [scrollOffset, setScrollOffset] = useState8(0);
19535
19534
  const scrollPositionRef = useRef10(0);