@cmgmyr/hive 1.12.0 → 1.12.1

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.
@@ -1 +1 @@
1
- {"version":"1.12.0","sha":"aea4e1b","dirty":false,"build_id":"29032035781c51496a882c8bca3ea8edc17cab379acdac96b255751bf5bd67a1"}
1
+ {"version":"1.12.1","sha":"10a48d4","dirty":false,"build_id":"bf1c5acc24e6752e59a0f10acf0e8d07d633a3cf7709bfb701aa0900028aee56"}
package/dist/cli.js CHANGED
@@ -34,7 +34,7 @@ import { probeSessionInterpreter, reexecTarget, sessionStartVerdict, } from "./s
34
34
  import { backupHealth, backupNow, backupsDir, formatBytes, listSnapshots, previewRestore, restoreSnapshot, totalSizeBytes, } from "./backup.js";
35
35
  import { describeTeardownWindow, readTeardowns, teardownLogPath, } from "./teardown.js";
36
36
  import { asNameClash, buildEnvFlags, closeAgentRow, isReservedAgentName, launchAgent, LEAD_KIND, LEAD_NAME, mintLeadActorId, relayoutAfterPaneLeft, upsertActor, withWindowClaim, } from "./spawn.js";
37
- import { adoptableWindow, applyLayout, claimInitialWindow, configureHiveWindow, controlModeFor, createWindow, DEFAULT_LAYOUT, describePaneChoice, ensureSession, findProjectWindow, foreignSocket, isViewSessionName, listOwnedWindows, liveTargets, observationFailed, observeRowOwnership, ORPHAN_MIN_AGE_MS, orphanScratchServers, orphansWorthWarningAbout, paneIsAloneInWindow, paneWindow, paneVisibility, panePidForRecord, PROCESSES_LAYOUT, processesPaneTitle, processesWindowName, projectWindows, RAW_ATTACH_TMUX_CONFIG, renderAttachCommand, resolveAttachTarget, resolveInTmuxTarget, rowLive, rowOwnership, SESSION_PREFIX, appendGlobalHook, globalHooks, replaceGlobalHooks, sessionName, setPaneTitle, shellQuote, shownPaneTitle, makeProcessesWindow, tmux, TMUX_DOC, tmuxSaysNothingThere, tmuxTimeoutOverride, tmuxSocketPath, untrustedTmuxServer, waitForPaneEstablished, windowLayout, } from "./tmux.js";
37
+ import { adoptableWindow, applyLayout, claimInitialWindow, configureHiveWindow, controlModeFor, createWindow, DEFAULT_LAYOUT, describePaneChoice, ensureSession, findProjectWindow, foreignSocket, isViewSessionName, listOwnedWindows, liveTargets, observationFailed, observeRowOwnership, ORPHAN_MIN_AGE_MS, orphanScratchServers, orphansWorthWarningAbout, paneIsAloneInWindow, paneWindow, paneVisibility, panePidForRecord, PROCESSES_LAYOUT, processesPaneTitle, processesWindowName, projectWindows, RAW_ATTACH_TMUX_CONFIG, renderAttachCommand, resolveAttachTarget, resolveInTmuxTarget, rowLive, rowOwnership, SESSION_PREFIX, appendGlobalHook, globalHooks, replaceGlobalHooks, sessionName, setPaneTitle, shellQuote, shownPaneTitle, makeProcessesWindow, tmux, TMUX_DOC, tmuxNotInstalled, tmuxSaysNothingThere, tmuxTimeoutOverride, tmuxSocketPath, untrustedTmuxServer, waitForPaneEstablished, windowLayout, } from "./tmux.js";
38
38
  import { collectCrew, crewStoreProblem } from "./crew.js";
39
39
  import { resumeWorker, validateResumeWorker } from "./agentResume.js";
40
40
  import { markWorkerLost } from "./workerRecovery.js";
@@ -2474,6 +2474,17 @@ function cmdDoctor(argv) {
2474
2474
  const override = tmuxTimeoutOverride();
2475
2475
  return override === null ? version : `${version} (HIVE_TMUX_TIMEOUT_MS=${override}ms override; testing only)`;
2476
2476
  });
2477
+ try {
2478
+ const serverEnv = tmux("show-environment", "-g", "NO_COLOR");
2479
+ if (serverEnv.startsWith("NO_COLOR=")) {
2480
+ warn("tmux NO_COLOR", "Claude Code drops the dim styling on placeholders and suggestions, so hive reads them as typed input; agent_send refuses and wakes hold.", "clear it with `tmux set-environment -g -u NO_COLOR`, then restart affected workers");
2481
+ }
2482
+ }
2483
+ catch (e) {
2484
+ if (!tmuxNotInstalled(e) && tmuxSaysNothingThere(e) && process.env.NO_COLOR !== undefined) {
2485
+ warn("tmux NO_COLOR", "NO_COLOR is set in this shell; a tmux server started here would pass it to every worker, causing Claude Code placeholders and suggestions to read as typed input; agent_send refuses and wakes hold.", "unset NO_COLOR before starting tmux, or clear it with `tmux set-environment -g -u NO_COLOR` on a running server, then restart affected workers");
2486
+ }
2487
+ }
2477
2488
  const orphans = orphanScratchServers();
2478
2489
  reportPtyHeadroom(orphans);
2479
2490
  reportOrphanTmuxServers(orphans);
package/dist/spawn.js CHANGED
@@ -6,7 +6,7 @@ import { gitOut } from "./git.js";
6
6
  import { dataDir, db } from "./db.js";
7
7
  import { loadProjectYml } from "./projectYml.js";
8
8
  import { WORKER_RECOVERY_RETENTION_SECONDS } from "./workerRecovery.js";
9
- import { applyLayout, claimInitialWindow, createWindow, DEFAULT_LAYOUT, ensureSession, crossServerRefusal, findProcessesWindow, findProjectWindow, isPaneTarget, paneProcessExited, paneWindow, PROCESSES_LAYOUT, processesPaneTitle, processesWindowName, retainOnExitArgs, rowLive, sessionName, setPaneTitle, setRemainOnExit, makeProcessesWindow, tmux, tmuxSocketPath, untrustedTmuxServer, waitForPaneEstablished, windowLayout, windowOwner, windowTitle, rowOwnership, } from "./tmux.js";
9
+ import { applyLayout, claimInitialWindow, createWindow, DEFAULT_LAYOUT, ensureSession, crossServerRefusal, findProcessesWindow, findProjectWindow, isPaneTarget, paneProcessExited, paneWindow, PROCESSES_LAYOUT, processesPaneTitle, processesWindowName, retainOnExitArgs, rowLive, sessionName, setPaneTitle, setRemainOnExit, makeProcessesWindow, tmux, paneEnvPath, tmuxWithClientPath, tmuxSocketPath, untrustedTmuxServer, waitForPaneEstablished, windowLayout, windowOwner, windowTitle, rowOwnership, } from "./tmux.js";
10
10
  export function withWindowClaim(claim) {
11
11
  if (db.inTransaction) {
12
12
  throw new Error("withWindowClaim was called from inside an already-open transaction. better-sqlite3 nests a " +
@@ -137,7 +137,7 @@ function placeAgentPane(session, spec, envFlags, commandString, title, onRetainA
137
137
  return claimInitialWindow(started, windowName, windowOwnerId).pane;
138
138
  }
139
139
  const splitInto = (window, layout) => {
140
- const [pane, created = ""] = tmux("split-window", "-d", "-P", "-F", "#{pane_id}\t#{pane_pid}", "-t", window, "-c", spec.cwd, ...envFlags, commandString, ...(spec.retainOnExit ? retainOnExitArgs(window) : [])).split("\t");
140
+ const [pane, created = ""] = tmuxWithClientPath(paneEnvPath(), "split-window", "-d", "-P", "-F", "#{pane_id}\t#{pane_pid}", "-t", window, "-c", spec.cwd, ...envFlags, commandString, ...(spec.retainOnExit ? retainOnExitArgs(window) : [])).split("\t");
141
141
  pid = created;
142
142
  if (spec.retainOnExit)
143
143
  onRetainArmed(window);
package/dist/tmux.js CHANGED
@@ -193,7 +193,7 @@ export function ensureSession(name, cwd, initial) {
193
193
  if (untrustedTmuxServer())
194
194
  throw crossServerRefusal("create a tmux session");
195
195
  try {
196
- const [pane, window, pid = ""] = tmux("new-session", "-d", "-P", "-F", CREATED_PANE_FORMAT, "-s", name, "-c", cwd, ...(initial && "command" in initial ? [...initial.envFlags, initial.command] : [])).split("\t");
196
+ const [pane, window, pid = ""] = tmuxWithClientPath(paneEnvPath(), "new-session", "-d", "-P", "-F", CREATED_PANE_FORMAT, "-s", name, "-c", cwd, ...(initial && "command" in initial ? [...initial.envFlags, initial.command] : [])).split("\t");
197
197
  if (initial && "command" in initial)
198
198
  unsetAtSessionScope(name, initial.envFlags);
199
199
  return { created: true, pane, window, pid };
@@ -703,7 +703,7 @@ export function captureFinalScreen(target, lines) {
703
703
  }
704
704
  }
705
705
  export function createWindow(session, windowName, cwd, envFlags, command, projectId, detach = false, retainOnExit = false) {
706
- const created = tmux("new-window", ...(detach ? ["-d"] : []), "-P", "-F", CREATED_PANE_FORMAT, "-t", `=${session}`, "-n", windowName, "-c", cwd, ...envFlags, command, ...(retainOnExit ? retainOnExitArgs(`=${session}:${windowName}`) : []));
706
+ const created = tmuxWithClientPath(paneEnvPath(), "new-window", ...(detach ? ["-d"] : []), "-P", "-F", CREATED_PANE_FORMAT, "-t", `=${session}`, "-n", windowName, "-c", cwd, ...envFlags, command, ...(retainOnExit ? retainOnExitArgs(`=${session}:${windowName}`) : []));
707
707
  const [pane, window, pid = ""] = created.split("\t");
708
708
  configureHiveWindow(window, true, projectId);
709
709
  return { pane, window, pid };
@@ -1446,3 +1446,26 @@ export async function sendText(target, text, submit = true, onPasted, onBuffered
1446
1446
  tmux("send-keys", "-t", target, "Enter");
1447
1447
  }
1448
1448
  }
1449
+ export function tmuxWithClientPath(path, ...args) {
1450
+ if (path === null)
1451
+ return tmux(...args);
1452
+ const previousPath = process.env.PATH;
1453
+ process.env.PATH = path;
1454
+ try {
1455
+ return tmux(...args);
1456
+ }
1457
+ finally {
1458
+ if (previousPath === undefined)
1459
+ delete process.env.PATH;
1460
+ else
1461
+ process.env.PATH = previousPath;
1462
+ }
1463
+ }
1464
+ export function paneEnvPath() {
1465
+ if (process.env.npm_command !== "exec" || process.env.PATH === undefined)
1466
+ return null;
1467
+ const entries = process.env.PATH.split(":");
1468
+ // npm exec's first node-gyp-bin entry closes its injected PATH prefix; preserve everything after it.
1469
+ const boundary = entries.findIndex((entry) => entry.endsWith("/@npmcli/run-script/lib/node-gyp-bin"));
1470
+ return boundary === -1 ? null : entries.slice(boundary + 1).join(":");
1471
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmgmyr/hive",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "description": "Run a crew of Claude Code and Codex workers from one lead session: visible tmux panes, exact state from hooks, one local SQLite store.",
5
5
  "type": "module",
6
6
  "bin": {