tmux-ide 2.9.3 → 2.9.4

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/bin/cli.js CHANGED
@@ -11958,8 +11958,8 @@ var require_package = __commonJS({
11958
11958
  "package.json"(exports, module) {
11959
11959
  module.exports = {
11960
11960
  name: "tmux-ide",
11961
- version: "2.9.3",
11962
- description: "A visual, agent-aware IDE for any tmux session, with optional workspace presets",
11961
+ version: "2.9.4",
11962
+ description: "The open-source workspace for coding agents: run Claude Code, Codex and other agents in tmux with live status",
11963
11963
  type: "module",
11964
11964
  bin: {
11965
11965
  "tmux-ide": "bin/cli.js"
@@ -12030,6 +12030,8 @@ var require_package = __commonJS({
12030
12030
  postinstall: "node scripts/postinstall.js",
12031
12031
  docs: "turbo run dev --filter=@tmux-ide/docs",
12032
12032
  "demo:tui": "bun --preload @opentui/solid/preload docs/scripts/render-tui-demo.tsx",
12033
+ "demo:font": "node docs/scripts/tui-demo-font/build.mjs",
12034
+ "readme:media": "node docs/scripts/readme-media.mjs",
12033
12035
  "test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/automatic-contrast-renderer.test.tsx ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/guided-tour-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/pane-interaction-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-new-agent-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/agent-team-renderer.test.tsx ./scripts/solid-conditional-props.test.tsx",
12034
12036
  "test:tui-smoke": "bun scripts/smoke-tui-missions.mjs",
12035
12037
  "test:tui-live": "node scripts/tui-testdrive.mjs smoke",
@@ -12070,7 +12072,11 @@ var require_package = __commonJS({
12070
12072
  },
12071
12073
  keywords: [
12072
12074
  "tmux",
12073
- "ide",
12075
+ "coding-agents",
12076
+ "claude-code",
12077
+ "codex",
12078
+ "ai-agents",
12079
+ "agent-teams",
12074
12080
  "terminal",
12075
12081
  "workspace",
12076
12082
  "developer-tools"
@@ -12082,7 +12088,7 @@ var require_package = __commonJS({
12082
12088
  type: "git",
12083
12089
  url: "git+https://github.com/wavyrai/tmux-ide.git"
12084
12090
  },
12085
- homepage: "https://github.com/wavyrai/tmux-ide#readme",
12091
+ homepage: "https://tmux-ide.com",
12086
12092
  bugs: {
12087
12093
  url: "https://github.com/wavyrai/tmux-ide/issues"
12088
12094
  },
@@ -19544,8 +19550,8 @@ function boundedName(value) {
19544
19550
  function commandBasename(value) {
19545
19551
  const command3 = boundedName(value);
19546
19552
  if (!command3) return null;
19547
- const basename22 = command3.split("/").at(-1)?.trim() ?? "";
19548
- return basename22.length > 0 ? basename22 : null;
19553
+ const basename23 = command3.split("/").at(-1)?.trim() ?? "";
19554
+ return basename23.length > 0 ? basename23 : null;
19549
19555
  }
19550
19556
  function stableHash(value) {
19551
19557
  let hash = 2166136261;
@@ -28275,9 +28281,9 @@ function deprecatedStandalonePaneIdentities(panes) {
28275
28281
  }
28276
28282
  function harnessForPane(pane) {
28277
28283
  if (pane.teamMemberName) return "claude-code";
28278
- const detected = pane.agentKind?.toLowerCase();
28279
- if (detected === "codex") return "codex";
28280
- if (detected === "claude" || detected === "claude-code") return "claude-code";
28284
+ const detected2 = pane.agentKind?.toLowerCase();
28285
+ if (detected2 === "codex") return "codex";
28286
+ if (detected2 === "claude" || detected2 === "claude-code") return "claude-code";
28281
28287
  const executable = `${pane.currentCommand} ${pane.type ?? ""} ${pane.name ?? ""}`.toLowerCase();
28282
28288
  if (executable.includes("codex")) return "codex";
28283
28289
  if (executable.includes("claude")) return "claude-code";
@@ -28763,8 +28769,8 @@ function launchCommandForHarness(harness) {
28763
28769
  }
28764
28770
  function paneStartHostsShell(startCommand) {
28765
28771
  const token2 = startCommand.trim().split(/\s+/u)[0] ?? "";
28766
- const basename22 = token2.replace(/^-/, "").replace(/\\/gu, "/").split("/").pop()?.toLowerCase() ?? "";
28767
- return basename22 === "" || SHELLS.has(basename22.replace(/\.exe$/u, ""));
28772
+ const basename23 = token2.replace(/^-/, "").replace(/\\/gu, "/").split("/").pop()?.toLowerCase() ?? "";
28773
+ return basename23 === "" || SHELLS.has(basename23.replace(/\.exe$/u, ""));
28768
28774
  }
28769
28775
  function interruptArgs2(paneId) {
28770
28776
  return ["send-keys", "-t", paneId, "C-c"];
@@ -30241,8 +30247,8 @@ var init_workspace_promotion2 = __esm({
30241
30247
  let name;
30242
30248
  if (isAgent) {
30243
30249
  const presentation = resolveAgentPresentation(facts, nowSec);
30244
- const detected = presentation.displayName ?? pane.currentCommand;
30245
- name = sanitizeLabel(detected, harnessForPane(facts));
30250
+ const detected2 = presentation.displayName ?? pane.currentCommand;
30251
+ name = sanitizeLabel(detected2, harnessForPane(facts));
30246
30252
  } else {
30247
30253
  name = "Terminal";
30248
30254
  }
@@ -61446,7 +61452,7 @@ var init_tmux_view_executor = __esm({
61446
61452
  tmuxCommandString(tmux5(["display-message", "-p", VIEW_PROOF_MISMATCH_SENTINEL]))
61447
61453
  ])
61448
61454
  );
61449
- const guarded = tmux5([
61455
+ const guarded2 = tmux5([
61450
61456
  "if-shell",
61451
61457
  "-F",
61452
61458
  "-t",
@@ -61458,7 +61464,7 @@ var init_tmux_view_executor = __esm({
61458
61464
  if (operation.operation === "create") {
61459
61465
  let result2;
61460
61466
  try {
61461
- result2 = this.#command(guarded);
61467
+ result2 = this.#command(guarded2);
61462
61468
  } catch {
61463
61469
  throw new TmuxAttachmentViewExecutorError("mutation-outcome-uncertain");
61464
61470
  }
@@ -61475,7 +61481,7 @@ var init_tmux_view_executor = __esm({
61475
61481
  let attempt;
61476
61482
  try {
61477
61483
  attempt = this.#clientCommand(
61478
- guarded,
61484
+ guarded2,
61479
61485
  operation.operation,
61480
61486
  plan,
61481
61487
  viewGuard,
@@ -62280,10 +62286,10 @@ function pinnedRunner(authority2, execute2, startupPolicy) {
62280
62286
  run(command3) {
62281
62287
  if (command3.executable !== "tmux") return { status: "failed" };
62282
62288
  try {
62283
- const guarded = authority2.nativeServerIdentity ? fenceNativeTmuxCommand(command3.argv, authority2.nativeServerIdentity) : null;
62289
+ const guarded2 = authority2.nativeServerIdentity ? fenceNativeTmuxCommand(command3.argv, authority2.nativeServerIdentity) : null;
62284
62290
  const stdout = execute2(
62285
62291
  authority2.executablePath,
62286
- [...currentSocketArgv(authority2), ...guarded?.argv ?? command3.argv],
62292
+ [...currentSocketArgv(authority2), ...guarded2?.argv ?? command3.argv],
62287
62293
  {
62288
62294
  cwd: authority2.trustedCwd,
62289
62295
  env: authority2.environment,
@@ -62291,7 +62297,7 @@ function pinnedRunner(authority2, execute2, startupPolicy) {
62291
62297
  timeoutMs: TERMINAL_ATTACHMENT_TMUX_COMMAND_TIMEOUT_MS
62292
62298
  }
62293
62299
  );
62294
- const value = guarded ? guarded.verify(String(stdout)) : String(stdout);
62300
+ const value = guarded2 ? guarded2.verify(String(stdout)) : String(stdout);
62295
62301
  if (authority2.namedSocketFence && !authority2.namedSocketFence.isPinned())
62296
62302
  authority2.namedSocketFence.resolve();
62297
62303
  if (value.includes("\0") || Buffer.byteLength(value, "utf8") > MAX_TMUX_OUTPUT_BYTES3) {
@@ -62336,12 +62342,12 @@ function pinnedReadRunner(authority2, execute2) {
62336
62342
  async run(command3, signal) {
62337
62343
  if (command3.executable !== "tmux" || signal?.aborted) return { status: "failed" };
62338
62344
  try {
62339
- const guarded = authority2.nativeServerIdentity ? fenceNativeTmuxCommand(command3.argv, authority2.nativeServerIdentity) : null;
62345
+ const guarded2 = authority2.nativeServerIdentity ? fenceNativeTmuxCommand(command3.argv, authority2.nativeServerIdentity) : null;
62340
62346
  const stdout = await execute2(
62341
62347
  authority2.executablePath,
62342
62348
  [
62343
62349
  ...authority2.namedSocketFence ? await authority2.namedSocketFence.resolveAsync(signal) : currentSocketArgv(authority2),
62344
- ...guarded?.argv ?? command3.argv
62350
+ ...guarded2?.argv ?? command3.argv
62345
62351
  ],
62346
62352
  {
62347
62353
  cwd: authority2.trustedCwd,
@@ -62351,7 +62357,7 @@ function pinnedReadRunner(authority2, execute2) {
62351
62357
  ...signal ? { signal } : {}
62352
62358
  }
62353
62359
  );
62354
- const value = guarded ? guarded.verify(String(stdout)) : String(stdout);
62360
+ const value = guarded2 ? guarded2.verify(String(stdout)) : String(stdout);
62355
62361
  if (authority2.namedSocketFence && !authority2.namedSocketFence.isPinned())
62356
62362
  await authority2.namedSocketFence.resolveAsync(signal);
62357
62363
  if (value.includes("\0") || Buffer.byteLength(value, "utf8") > MAX_TMUX_OUTPUT_BYTES3)
@@ -73838,16 +73844,16 @@ function defaultDeferRestart(restart2) {
73838
73844
  setImmediate(restart2);
73839
73845
  }
73840
73846
  async function appSetRemoteAccessHandler(input, deps2 = {}) {
73841
- const readSettings2 = deps2.readSettings ?? readAppSettings;
73842
- const writeSettings = deps2.writeSettings ?? writeAppSettings;
73847
+ const readSettings3 = deps2.readSettings ?? readAppSettings;
73848
+ const writeSettings2 = deps2.writeSettings ?? writeAppSettings;
73843
73849
  const nextEnabled = input.enabled;
73844
- const current = readSettings2();
73850
+ const current = readSettings3();
73845
73851
  const token2 = nextEnabled ? current.remoteAccess.token ?? (deps2.generateToken ?? generateAuthToken)() : null;
73846
73852
  const next = {
73847
73853
  ...current,
73848
73854
  remoteAccess: { enabled: nextEnabled, token: token2 }
73849
73855
  };
73850
- writeSettings(next);
73856
+ writeSettings2(next);
73851
73857
  const port = currentPort(deps2);
73852
73858
  const request3 = {
73853
73859
  enabled: nextEnabled,
@@ -82341,7 +82347,7 @@ function readJson(dir, name) {
82341
82347
  }
82342
82348
  }
82343
82349
  function detectStack(dir) {
82344
- const detected = {
82350
+ const detected2 = {
82345
82351
  packageManager: null,
82346
82352
  frameworks: [],
82347
82353
  devCommand: null,
@@ -82349,89 +82355,89 @@ function detectStack(dir) {
82349
82355
  reasons: []
82350
82356
  };
82351
82357
  if (fileExists(dir, "pnpm-lock.yaml")) {
82352
- detected.packageManager = "pnpm";
82353
- detected.reasons.push('Detected pnpm from "pnpm-lock.yaml".');
82358
+ detected2.packageManager = "pnpm";
82359
+ detected2.reasons.push('Detected pnpm from "pnpm-lock.yaml".');
82354
82360
  } else if (fileExists(dir, "bun.lockb") || fileExists(dir, "bun.lock")) {
82355
- detected.packageManager = "bun";
82356
- detected.reasons.push('Detected bun from "bun.lockb" or "bun.lock".');
82361
+ detected2.packageManager = "bun";
82362
+ detected2.reasons.push('Detected bun from "bun.lockb" or "bun.lock".');
82357
82363
  } else if (fileExists(dir, "yarn.lock")) {
82358
- detected.packageManager = "yarn";
82359
- detected.reasons.push('Detected yarn from "yarn.lock".');
82364
+ detected2.packageManager = "yarn";
82365
+ detected2.reasons.push('Detected yarn from "yarn.lock".');
82360
82366
  } else if (fileExists(dir, "package-lock.json")) {
82361
- detected.packageManager = "npm";
82362
- detected.reasons.push('Detected npm from "package-lock.json".');
82367
+ detected2.packageManager = "npm";
82368
+ detected2.reasons.push('Detected npm from "package-lock.json".');
82363
82369
  }
82364
82370
  const pkg = readJson(dir, "package.json");
82365
82371
  if (pkg) {
82366
- detected.language = "javascript";
82367
- detected.reasons.push('Detected JavaScript from "package.json".');
82372
+ detected2.language = "javascript";
82373
+ detected2.reasons.push('Detected JavaScript from "package.json".');
82368
82374
  const deps2 = {
82369
82375
  ...pkg.dependencies,
82370
82376
  ...pkg.devDependencies
82371
82377
  };
82372
- if (deps2["next"]) pushFramework(detected, "next", 'Found dependency "next".');
82373
- if (deps2["convex"]) pushFramework(detected, "convex", 'Found dependency "convex".');
82374
- if (deps2["vite"]) pushFramework(detected, "vite", 'Found dependency "vite".');
82378
+ if (deps2["next"]) pushFramework(detected2, "next", 'Found dependency "next".');
82379
+ if (deps2["convex"]) pushFramework(detected2, "convex", 'Found dependency "convex".');
82380
+ if (deps2["vite"]) pushFramework(detected2, "vite", 'Found dependency "vite".');
82375
82381
  if (deps2["remix"] || deps2["@remix-run/node"])
82376
- pushFramework(detected, "remix", "Found Remix dependency.");
82377
- if (deps2["nuxt"]) pushFramework(detected, "nuxt", 'Found dependency "nuxt".');
82378
- if (deps2["astro"]) pushFramework(detected, "astro", 'Found dependency "astro".');
82382
+ pushFramework(detected2, "remix", "Found Remix dependency.");
82383
+ if (deps2["nuxt"]) pushFramework(detected2, "nuxt", 'Found dependency "nuxt".');
82384
+ if (deps2["astro"]) pushFramework(detected2, "astro", 'Found dependency "astro".');
82379
82385
  if (deps2["svelte"] || deps2["@sveltejs/kit"])
82380
- pushFramework(detected, "svelte", "Found Svelte dependency.");
82381
- const pm = detected.packageManager ?? "npm";
82386
+ pushFramework(detected2, "svelte", "Found Svelte dependency.");
82387
+ const pm = detected2.packageManager ?? "npm";
82382
82388
  const run = pm === "npm" ? "npm run" : pm;
82383
82389
  const scripts = pkg.scripts;
82384
82390
  if (scripts?.dev) {
82385
- detected.devCommand = `${run} dev`;
82386
- detected.reasons.push(
82387
- `Using dev command "${detected.devCommand}" from package.json scripts.`
82391
+ detected2.devCommand = `${run} dev`;
82392
+ detected2.reasons.push(
82393
+ `Using dev command "${detected2.devCommand}" from package.json scripts.`
82388
82394
  );
82389
82395
  } else if (scripts?.start) {
82390
- detected.devCommand = `${run} start`;
82391
- detected.reasons.push(
82392
- `Using start command "${detected.devCommand}" from package.json scripts.`
82396
+ detected2.devCommand = `${run} start`;
82397
+ detected2.reasons.push(
82398
+ `Using start command "${detected2.devCommand}" from package.json scripts.`
82393
82399
  );
82394
82400
  }
82395
82401
  }
82396
82402
  if (fileExists(dir, "pyproject.toml") || fileExists(dir, "requirements.txt")) {
82397
- detected.language = detected.language ?? "python";
82398
- detected.reasons.push('Detected Python from "pyproject.toml" or "requirements.txt".');
82403
+ detected2.language = detected2.language ?? "python";
82404
+ detected2.reasons.push('Detected Python from "pyproject.toml" or "requirements.txt".');
82399
82405
  try {
82400
82406
  const pyproject = readFileSync31(resolve30(dir, "pyproject.toml"), "utf-8");
82401
82407
  if (pyproject.includes("fastapi"))
82402
- pushFramework(detected, "fastapi", 'Found "fastapi" in pyproject.toml.');
82408
+ pushFramework(detected2, "fastapi", 'Found "fastapi" in pyproject.toml.');
82403
82409
  else if (pyproject.includes("django"))
82404
- pushFramework(detected, "django", 'Found "django" in pyproject.toml.');
82410
+ pushFramework(detected2, "django", 'Found "django" in pyproject.toml.');
82405
82411
  else if (pyproject.includes("flask"))
82406
- pushFramework(detected, "flask", 'Found "flask" in pyproject.toml.');
82412
+ pushFramework(detected2, "flask", 'Found "flask" in pyproject.toml.');
82407
82413
  } catch {
82408
82414
  }
82409
82415
  }
82410
82416
  if (fileExists(dir, "Cargo.toml")) {
82411
- detected.language = detected.language ?? "rust";
82412
- detected.reasons.push('Detected Rust from "Cargo.toml".');
82413
- pushFramework(detected, "cargo", 'Using Cargo workflow from "Cargo.toml".');
82417
+ detected2.language = detected2.language ?? "rust";
82418
+ detected2.reasons.push('Detected Rust from "Cargo.toml".');
82419
+ pushFramework(detected2, "cargo", 'Using Cargo workflow from "Cargo.toml".');
82414
82420
  }
82415
82421
  if (fileExists(dir, "go.mod")) {
82416
- detected.language = detected.language ?? "go";
82417
- detected.reasons.push('Detected Go from "go.mod".');
82418
- pushFramework(detected, "go", 'Using Go workflow from "go.mod".');
82422
+ detected2.language = detected2.language ?? "go";
82423
+ detected2.reasons.push('Detected Go from "go.mod".');
82424
+ pushFramework(detected2, "go", 'Using Go workflow from "go.mod".');
82419
82425
  }
82420
82426
  if (fileExists(dir, "docker-compose.yml") || fileExists(dir, "docker-compose.yaml")) {
82421
82427
  pushFramework(
82422
- detected,
82428
+ detected2,
82423
82429
  "docker",
82424
82430
  'Detected Docker from "docker-compose.yml" or "docker-compose.yaml".'
82425
82431
  );
82426
82432
  }
82427
- if (detected.reasons.length === 0) {
82428
- detected.reasons.push("No framework-specific signals found; using the generic layout.");
82433
+ if (detected2.reasons.length === 0) {
82434
+ detected2.reasons.push("No framework-specific signals found; using the generic layout.");
82429
82435
  }
82430
- return detected;
82436
+ return detected2;
82431
82437
  }
82432
- function suggestConfig(dir, detected) {
82438
+ function suggestConfig(dir, detected2) {
82433
82439
  const name = basename15(dir);
82434
- const pm = detected.packageManager ?? "npm";
82440
+ const pm = detected2.packageManager ?? "npm";
82435
82441
  const run = pm === "npm" ? "npm run" : pm;
82436
82442
  const config2 = {
82437
82443
  name,
@@ -82449,7 +82455,7 @@ function suggestConfig(dir, detected) {
82449
82455
  ]
82450
82456
  };
82451
82457
  const bottom = config2.rows[1].panes;
82452
- const frameworks = detected.frameworks;
82458
+ const frameworks = detected2.frameworks;
82453
82459
  if (frameworks.length >= 2) {
82454
82460
  config2.rows[0].panes.push({ id: "agent-3", title: "Claude 3", command: "claude" });
82455
82461
  }
@@ -82475,8 +82481,8 @@ function suggestConfig(dir, detected) {
82475
82481
  bottom.push({ id: "dev", title: "Cargo", command: "cargo watch -x run" });
82476
82482
  } else if (frameworks.includes("go")) {
82477
82483
  bottom.push({ id: "dev", title: "Go", command: "go run ." });
82478
- } else if (detected.devCommand) {
82479
- bottom.push({ id: "dev", title: "Dev Server", command: detected.devCommand });
82484
+ } else if (detected2.devCommand) {
82485
+ bottom.push({ id: "dev", title: "Dev Server", command: detected2.devCommand });
82480
82486
  }
82481
82487
  if (frameworks.includes("convex")) {
82482
82488
  bottom.push({ id: "convex", title: "Convex", command: "npx convex dev" });
@@ -82488,44 +82494,44 @@ async function detect(targetDir, { json: json2, write: write2 } = {}) {
82488
82494
  const inputDir = resolve30(targetDir ?? ".");
82489
82495
  const context = write2 ? await resolveProjectConfigContext(inputDir) : null;
82490
82496
  const dir = context?.configWriteRoot ?? inputDir;
82491
- const detected = detectStack(dir);
82492
- const suggested = suggestConfig(dir, detected);
82497
+ const detected2 = detectStack(dir);
82498
+ const suggested = suggestConfig(dir, detected2);
82493
82499
  if (write2) {
82494
82500
  writeConfig(dir, suggested);
82495
82501
  if (json2) {
82496
- console.log(JSON.stringify({ detected, suggestedConfig: suggested, written: true }, null, 2));
82502
+ console.log(JSON.stringify({ detected: detected2, suggestedConfig: suggested, written: true }, null, 2));
82497
82503
  } else {
82498
- const desc = detected.frameworks.length > 0 ? detected.frameworks.join(" + ") : detected.language ?? "generic project";
82504
+ const desc = detected2.frameworks.length > 0 ? detected2.frameworks.join(" + ") : detected2.language ?? "generic project";
82499
82505
  console.log(`Detected ${desc}. Created .tmux-ide/workspace.yml.`);
82500
82506
  console.log("\nWhy this layout:");
82501
- for (const reason of detected.reasons) {
82507
+ for (const reason of detected2.reasons) {
82502
82508
  console.log(` - ${reason}`);
82503
82509
  }
82504
82510
  }
82505
82511
  return;
82506
82512
  }
82507
82513
  if (json2) {
82508
- console.log(JSON.stringify({ detected, suggestedConfig: suggested }, null, 2));
82514
+ console.log(JSON.stringify({ detected: detected2, suggestedConfig: suggested }, null, 2));
82509
82515
  return;
82510
82516
  }
82511
82517
  console.log("Detected stack:");
82512
- if (detected.packageManager) console.log(` Package manager: ${detected.packageManager}`);
82513
- if (detected.language) console.log(` Language: ${detected.language}`);
82514
- if (detected.frameworks.length) console.log(` Frameworks: ${detected.frameworks.join(", ")}`);
82515
- if (detected.devCommand) console.log(` Dev command: ${detected.devCommand}`);
82518
+ if (detected2.packageManager) console.log(` Package manager: ${detected2.packageManager}`);
82519
+ if (detected2.language) console.log(` Language: ${detected2.language}`);
82520
+ if (detected2.frameworks.length) console.log(` Frameworks: ${detected2.frameworks.join(", ")}`);
82521
+ if (detected2.devCommand) console.log(` Dev command: ${detected2.devCommand}`);
82516
82522
  console.log("\nReasoning:");
82517
- for (const reason of detected.reasons) {
82523
+ for (const reason of detected2.reasons) {
82518
82524
  console.log(` - ${reason}`);
82519
82525
  }
82520
82526
  console.log(
82521
82527
  "\nRun with --write to create .tmux-ide/workspace.yml, or --json to see the suggested config."
82522
82528
  );
82523
82529
  }
82524
- function pushFramework(detected, framework, reason) {
82525
- if (!detected.frameworks.includes(framework)) {
82526
- detected.frameworks.push(framework);
82530
+ function pushFramework(detected2, framework, reason) {
82531
+ if (!detected2.frameworks.includes(framework)) {
82532
+ detected2.frameworks.push(framework);
82527
82533
  }
82528
- detected.reasons.push(reason);
82534
+ detected2.reasons.push(reason);
82529
82535
  }
82530
82536
  var init_detect = __esm({
82531
82537
  "packages/daemon/src/detect.ts"() {
@@ -82554,7 +82560,7 @@ async function inspectProject(dir, io = {}) {
82554
82560
  }
82555
82561
  const probe = await probeProject(absoluteDir, io.probeIo);
82556
82562
  const stack = detectStack(absoluteDir);
82557
- const detected = {
82563
+ const detected2 = {
82558
82564
  packageManager: narrowPackageManager(stack.packageManager),
82559
82565
  frameworks: stack.frameworks,
82560
82566
  devCommand: stack.devCommand,
@@ -82570,7 +82576,7 @@ async function inspectProject(dir, io = {}) {
82570
82576
  ideConfigPath: probe.ideConfigPath,
82571
82577
  gitOrigin: probe.gitOrigin,
82572
82578
  gitBranch: probe.gitBranch,
82573
- detected
82579
+ detected: detected2
82574
82580
  };
82575
82581
  }
82576
82582
  var InspectDirNotFoundError, KNOWN_PACKAGE_MANAGERS;
@@ -89698,14 +89704,14 @@ async function init({
89698
89704
  }
89699
89705
  return;
89700
89706
  }
89701
- const detected = detectStack(dir);
89707
+ const detected2 = detectStack(dir);
89702
89708
  const name = basename19(dir);
89703
- if (detected.frameworks.length > 0) {
89704
- const config2 = suggestConfig(dir, detected);
89709
+ if (detected2.frameworks.length > 0) {
89710
+ const config2 = suggestConfig(dir, detected2);
89705
89711
  writeConfig(dir, config2);
89706
- const desc = detected.frameworks.join(" + ");
89712
+ const desc = detected2.frameworks.join(" + ");
89707
89713
  if (json2) {
89708
- console.log(JSON.stringify({ created: true, detected: detected.frameworks, name }));
89714
+ console.log(JSON.stringify({ created: true, detected: detected2.frameworks, name }));
89709
89715
  } else {
89710
89716
  console.log(`Detected ${desc}. Created .tmux-ide/workspace.yml for "${name}".`);
89711
89717
  printLayout(config2);
@@ -93714,6 +93720,252 @@ var init_wait_receipts = __esm({
93714
93720
  }
93715
93721
  });
93716
93722
 
93723
+ // packages/daemon/src/tui/integrations/claude-agent-teams.ts
93724
+ var claude_agent_teams_exports = {};
93725
+ __export(claude_agent_teams_exports, {
93726
+ AGENT_TEAMS_ENV: () => AGENT_TEAMS_ENV,
93727
+ DEFAULT_TEAMMATE_MODE: () => DEFAULT_TEAMMATE_MODE,
93728
+ InvalidClaudeSettingsError: () => InvalidClaudeSettingsError,
93729
+ agentTeamsPaths: () => agentTeamsPaths,
93730
+ agentTeamsSetting: () => agentTeamsSetting,
93731
+ claudeAgentTeamsStatus: () => claudeAgentTeamsStatus,
93732
+ claudeOnPath: () => claudeOnPath2,
93733
+ disableAgentTeams: () => disableAgentTeams,
93734
+ disableClaudeAgentTeams: () => disableClaudeAgentTeams,
93735
+ enableClaudeAgentTeams: () => enableClaudeAgentTeams,
93736
+ isOptOut: () => isOptOut,
93737
+ mergeAgentTeams: () => mergeAgentTeams
93738
+ });
93739
+ import {
93740
+ chmodSync as chmodSync8,
93741
+ existsSync as existsSync38,
93742
+ mkdirSync as mkdirSync32,
93743
+ readFileSync as readFileSync39,
93744
+ readdirSync as readdirSync11,
93745
+ renameSync as renameSync20,
93746
+ statSync as statSync22,
93747
+ copyFileSync as copyFileSync3,
93748
+ unlinkSync as unlinkSync10,
93749
+ writeFileSync as writeFileSync30,
93750
+ accessSync as accessSync12,
93751
+ constants as constants16
93752
+ } from "node:fs";
93753
+ import { basename as basename20, delimiter as delimiter4, dirname as dirname44, join as join52 } from "node:path";
93754
+ function isOptOut(value) {
93755
+ if (value === false || value === 0) return true;
93756
+ return typeof value === "string" && /^\s*(0|false|off|no)\s*$/iu.test(value);
93757
+ }
93758
+ function envOf(settings) {
93759
+ const env = settings.env;
93760
+ if (env === void 0) return void 0;
93761
+ if (!env || typeof env !== "object" || Array.isArray(env))
93762
+ throw new Error("settings env must be an object");
93763
+ return env;
93764
+ }
93765
+ function agentTeamsSetting(settings) {
93766
+ const value = envOf(settings)?.[AGENT_TEAMS_ENV];
93767
+ if (value === void 0) return "not-configured";
93768
+ return isOptOut(value) ? "disabled-by-user" : "enabled";
93769
+ }
93770
+ function mergeAgentTeams(settings, { overrideOptOut = false } = {}) {
93771
+ const setting = agentTeamsSetting(settings);
93772
+ if (setting === "disabled-by-user" && !overrideOptOut) return { settings, changes: [], setting };
93773
+ const changes = [];
93774
+ let next = settings;
93775
+ if (setting !== "enabled") {
93776
+ next = { ...next, env: { ...envOf(settings) ?? {}, [AGENT_TEAMS_ENV]: "1" } };
93777
+ changes.push(`env.${AGENT_TEAMS_ENV}=1`);
93778
+ }
93779
+ if (!("teammateMode" in settings)) {
93780
+ next = { ...next, teammateMode: DEFAULT_TEAMMATE_MODE };
93781
+ changes.push(`teammateMode=${DEFAULT_TEAMMATE_MODE}`);
93782
+ }
93783
+ return { settings: next, changes, setting: "enabled" };
93784
+ }
93785
+ function disableAgentTeams(settings) {
93786
+ if (agentTeamsSetting(settings) === "disabled-by-user")
93787
+ return { settings, changes: [], setting: "disabled-by-user" };
93788
+ return {
93789
+ settings: { ...settings, env: { ...envOf(settings) ?? {}, [AGENT_TEAMS_ENV]: "0" } },
93790
+ changes: [`env.${AGENT_TEAMS_ENV}=0`],
93791
+ setting: "disabled-by-user"
93792
+ };
93793
+ }
93794
+ function agentTeamsPaths() {
93795
+ const namespace = resolveRuntimeNamespace();
93796
+ return { settingsPath: namespace.claudeSettingsPath, claudeDir: namespace.claudeDir };
93797
+ }
93798
+ function claudeOnPath2(path2 = process.env.PATH ?? "") {
93799
+ return path2.split(delimiter4).filter(Boolean).some((dir) => {
93800
+ try {
93801
+ accessSync12(join52(dir, "claude"), constants16.X_OK);
93802
+ return statSync22(join52(dir, "claude")).isFile();
93803
+ } catch {
93804
+ return false;
93805
+ }
93806
+ });
93807
+ }
93808
+ function readSettings2(path2) {
93809
+ if (!existsSync38(path2)) return { settings: {}, exists: false };
93810
+ try {
93811
+ const parsed = JSON.parse(readFileSync39(path2, "utf8"));
93812
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
93813
+ throw new Error("not an object");
93814
+ envOf(parsed);
93815
+ return { settings: parsed, exists: true };
93816
+ } catch {
93817
+ throw new InvalidClaudeSettingsError(
93818
+ `${path2} is not valid settings JSON \u2014 fix or move it, then retry`
93819
+ );
93820
+ }
93821
+ }
93822
+ function existingBackup(settingsPath) {
93823
+ const dir = dirname44(settingsPath);
93824
+ const prefix = `${basename20(settingsPath)}${BACKUP_INFIX}`;
93825
+ try {
93826
+ const found = readdirSync11(dir).find((name) => name.startsWith(prefix));
93827
+ return found ? join52(dir, found) : null;
93828
+ } catch {
93829
+ return null;
93830
+ }
93831
+ }
93832
+ function writeSettings(path2, settings, exists) {
93833
+ mkdirSync32(dirname44(path2), { recursive: true });
93834
+ let backup = null;
93835
+ if (exists) {
93836
+ backup = existingBackup(path2);
93837
+ if (!backup) {
93838
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/gu, "").replace(/\.\d+Z$/u, "Z");
93839
+ backup = `${path2}${BACKUP_INFIX}${stamp}`;
93840
+ copyFileSync3(path2, backup);
93841
+ }
93842
+ }
93843
+ const temporary = join52(dirname44(path2), `.${basename20(path2)}.tmux-ide-${process.pid}.tmp`);
93844
+ try {
93845
+ writeFileSync30(temporary, `${JSON.stringify(settings, null, 2)}
93846
+ `, { mode: 384 });
93847
+ if (exists) chmodSync8(temporary, statSync22(path2).mode & 511);
93848
+ renameSync20(temporary, path2);
93849
+ } catch (error) {
93850
+ try {
93851
+ unlinkSync10(temporary);
93852
+ } catch {
93853
+ }
93854
+ throw error;
93855
+ }
93856
+ return backup;
93857
+ }
93858
+ function detected(paths, onPath) {
93859
+ return existsSync38(paths.claudeDir) || onPath();
93860
+ }
93861
+ function guarded(paths) {
93862
+ if (!paths && resolveRuntimeNamespace().development)
93863
+ throw new Error("Development agent-teams changes require explicit fixture paths");
93864
+ const resolved2 = paths ?? agentTeamsPaths();
93865
+ runtimeOwnedPath(resolved2.settingsPath);
93866
+ return resolved2;
93867
+ }
93868
+ function enableClaudeAgentTeams(paths, onPath = () => claudeOnPath2(), { overrideOptOut = false } = {}) {
93869
+ const resolved2 = guarded(paths);
93870
+ const { settingsPath } = resolved2;
93871
+ const base2 = { settingsPath, changes: [], backup: null };
93872
+ if (!detected(resolved2, onPath))
93873
+ return {
93874
+ ...base2,
93875
+ action: "skipped",
93876
+ claudeDetected: false,
93877
+ message: `Claude Code not found (no ${resolved2.claudeDir}, no claude on PATH); agent teams not configured.`
93878
+ };
93879
+ let read;
93880
+ try {
93881
+ read = readSettings2(settingsPath);
93882
+ } catch (error) {
93883
+ return { ...base2, action: "invalid", claudeDetected: true, message: error.message };
93884
+ }
93885
+ const merged = mergeAgentTeams(read.settings, { overrideOptOut });
93886
+ if (merged.setting === "disabled-by-user")
93887
+ return {
93888
+ ...base2,
93889
+ action: "disabled-by-user",
93890
+ claudeDetected: true,
93891
+ message: `Claude Code agent teams are disabled by user in ${settingsPath} (${AGENT_TEAMS_ENV}); left unchanged. Enable explicitly: tmux-ide integration agent-teams enable`
93892
+ };
93893
+ if (merged.changes.length === 0)
93894
+ return {
93895
+ ...base2,
93896
+ action: "unchanged",
93897
+ claudeDetected: true,
93898
+ message: `Claude Code agent teams already enabled in ${settingsPath}.`
93899
+ };
93900
+ const backup = writeSettings(settingsPath, merged.settings, read.exists);
93901
+ return {
93902
+ settingsPath,
93903
+ changes: merged.changes,
93904
+ backup,
93905
+ action: "enabled",
93906
+ claudeDetected: true,
93907
+ message: `Enabled Claude Code agent teams in ${settingsPath} (${merged.changes.join(", ")}${backup ? `; backup: ${backup}` : ""}). Disable: tmux-ide integration agent-teams disable`
93908
+ };
93909
+ }
93910
+ function disableClaudeAgentTeams(paths) {
93911
+ const resolved2 = guarded(paths);
93912
+ const { settingsPath } = resolved2;
93913
+ const base2 = { settingsPath, changes: [], backup: null, claudeDetected: true };
93914
+ let read;
93915
+ try {
93916
+ read = readSettings2(settingsPath);
93917
+ } catch (error) {
93918
+ return { ...base2, action: "invalid", message: error.message };
93919
+ }
93920
+ const next = disableAgentTeams(read.settings);
93921
+ if (next.changes.length === 0)
93922
+ return {
93923
+ ...base2,
93924
+ action: "unchanged",
93925
+ message: `Claude Code agent teams already disabled in ${settingsPath}.`
93926
+ };
93927
+ const backup = writeSettings(settingsPath, next.settings, read.exists);
93928
+ return {
93929
+ ...base2,
93930
+ changes: next.changes,
93931
+ backup,
93932
+ action: "disabled",
93933
+ message: `Disabled Claude Code agent teams in ${settingsPath} (${next.changes.join(", ")}${backup ? `; backup: ${backup}` : ""}). Re-enable: tmux-ide integration agent-teams enable`
93934
+ };
93935
+ }
93936
+ function claudeAgentTeamsStatus(paths = agentTeamsPaths(), onPath = () => claudeOnPath2()) {
93937
+ const claudeDetected = detected(paths, onPath);
93938
+ try {
93939
+ const { settings } = readSettings2(paths.settingsPath);
93940
+ const mode = settings.teammateMode;
93941
+ return {
93942
+ settingsPath: paths.settingsPath,
93943
+ claudeDetected,
93944
+ setting: agentTeamsSetting(settings),
93945
+ teammateMode: typeof mode === "string" ? mode : null
93946
+ };
93947
+ } catch {
93948
+ return {
93949
+ settingsPath: paths.settingsPath,
93950
+ claudeDetected,
93951
+ setting: "invalid-settings",
93952
+ teammateMode: null
93953
+ };
93954
+ }
93955
+ }
93956
+ var AGENT_TEAMS_ENV, DEFAULT_TEAMMATE_MODE, BACKUP_INFIX, InvalidClaudeSettingsError;
93957
+ var init_claude_agent_teams = __esm({
93958
+ "packages/daemon/src/tui/integrations/claude-agent-teams.ts"() {
93959
+ "use strict";
93960
+ init_runtime_namespace();
93961
+ AGENT_TEAMS_ENV = "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS";
93962
+ DEFAULT_TEAMMATE_MODE = "auto";
93963
+ BACKUP_INFIX = ".tmux-ide-backup-";
93964
+ InvalidClaudeSettingsError = class extends Error {
93965
+ };
93966
+ }
93967
+ });
93968
+
93717
93969
  // packages/daemon/src/lib/worktree.ts
93718
93970
  var worktree_exports = {};
93719
93971
  __export(worktree_exports, {
@@ -93729,7 +93981,7 @@ __export(worktree_exports, {
93729
93981
  worktreeSessionName: () => worktreeSessionName
93730
93982
  });
93731
93983
  import { execFileSync as execFileSync26 } from "node:child_process";
93732
- import { basename as basename20, dirname as dirname44, isAbsolute as isAbsolute26, join as join52, resolve as resolve39 } from "node:path";
93984
+ import { basename as basename21, dirname as dirname45, isAbsolute as isAbsolute26, join as join53, resolve as resolve39 } from "node:path";
93733
93985
  function sanitizeForTmux(part) {
93734
93986
  return part.replace(/[.:/\s]+/g, "-");
93735
93987
  }
@@ -93738,11 +93990,11 @@ function worktreeSessionName(project, branch) {
93738
93990
  }
93739
93991
  function defaultWorktreeBaseDir(repoDir) {
93740
93992
  const abs = resolve39(repoDir);
93741
- return join52(dirname44(abs), `${basename20(abs)}-worktrees`);
93993
+ return join53(dirname45(abs), `${basename21(abs)}-worktrees`);
93742
93994
  }
93743
93995
  function worktreePath(repoDir, branch, configuredDir) {
93744
93996
  const base2 = configuredDir && configuredDir.length > 0 ? isAbsolute26(configuredDir) ? configuredDir : resolve39(repoDir, configuredDir) : defaultWorktreeBaseDir(repoDir);
93745
- return join52(base2, branch);
93997
+ return join53(base2, branch);
93746
93998
  }
93747
93999
  function parseWorktreeList(porcelain) {
93748
94000
  const entries = [];
@@ -93876,8 +94128,8 @@ var init_worktree = __esm({
93876
94128
  });
93877
94129
 
93878
94130
  // packages/daemon/src/lib/managed-installer-update.ts
93879
- import { mkdtempSync, readFileSync as readFileSync39, realpathSync as realpathSync28, rmSync as rmSync7 } from "node:fs";
93880
- import { dirname as dirname45, join as join53 } from "node:path";
94131
+ import { mkdtempSync, readFileSync as readFileSync40, realpathSync as realpathSync28, rmSync as rmSync7 } from "node:fs";
94132
+ import { dirname as dirname46, join as join54 } from "node:path";
93881
94133
  import { tmpdir } from "node:os";
93882
94134
  import { execFileSync as execFileSync27 } from "node:child_process";
93883
94135
  function managedInstallerPrefix(cliPath) {
@@ -93886,16 +94138,16 @@ function managedInstallerPrefix(cliPath) {
93886
94138
  );
93887
94139
  if (!match) return null;
93888
94140
  const prefix = match[1] || "/";
93889
- const root = join53(prefix, "share/tmux-ide");
93890
- const release = join53(root, "releases", match[2]);
94141
+ const root = join54(prefix, "share/tmux-ide");
94142
+ const release = join54(root, "releases", match[2]);
93891
94143
  try {
93892
- if (realpathSync28(join53(root, "current")) !== release) return null;
94144
+ if (realpathSync28(join54(root, "current")) !== release) return null;
93893
94145
  if (realpathSync28(release) !== release) return null;
93894
- if (readFileSync39(join53(root, "installer-v1"), "utf8") !== "1\n") return null;
93895
- if (readFileSync39(join53(release, ".installer-release-v1"), "utf8") !== "1\n") return null;
93896
- if (!readFileSync39(join53(prefix, "bin/tmux-ide"), "utf8").split("\n").includes("# tmux-ide universal installer v1"))
94146
+ if (readFileSync40(join54(root, "installer-v1"), "utf8") !== "1\n") return null;
94147
+ if (readFileSync40(join54(release, ".installer-release-v1"), "utf8") !== "1\n") return null;
94148
+ if (!readFileSync40(join54(prefix, "bin/tmux-ide"), "utf8").split("\n").includes("# tmux-ide universal installer v1"))
93897
94149
  return null;
93898
- if (JSON.parse(readFileSync39(join53(dirname45(cliPath), "package.json"), "utf8")).name !== "tmux-ide")
94150
+ if (JSON.parse(readFileSync40(join54(dirname46(cliPath), "package.json"), "utf8")).name !== "tmux-ide")
93899
94151
  return null;
93900
94152
  return prefix;
93901
94153
  } catch {
@@ -93903,8 +94155,8 @@ function managedInstallerPrefix(cliPath) {
93903
94155
  }
93904
94156
  }
93905
94157
  function runManagedInstallerUpdate(prefix, channel, json2, execute2 = execFileSync27) {
93906
- const temporary = mkdtempSync(join53(tmpdir(), "tmux-ide-update-"));
93907
- const script = join53(temporary, "install.sh");
94158
+ const temporary = mkdtempSync(join54(tmpdir(), "tmux-ide-update-"));
94159
+ const script = join54(temporary, "install.sh");
93908
94160
  try {
93909
94161
  execute2(
93910
94162
  "curl",
@@ -93927,7 +94179,7 @@ function runManagedInstallerUpdate(prefix, channel, json2, execute2 = execFileSy
93927
94179
  ],
93928
94180
  { stdio: ["ignore", 2, 2] }
93929
94181
  );
93930
- if (!readFileSync39(script, "utf8").startsWith("#!/bin/sh\n"))
94182
+ if (!readFileSync40(script, "utf8").startsWith("#!/bin/sh\n"))
93931
94183
  throw new Error("Installer download was not a shell script; installation unchanged");
93932
94184
  execute2("/bin/sh", ["-n", script], { stdio: ["ignore", 2, 2] });
93933
94185
  execute2("/bin/sh", [script, "--prefix", prefix, "--version", channel], {
@@ -93946,8 +94198,8 @@ var init_managed_installer_update = __esm({
93946
94198
  });
93947
94199
 
93948
94200
  // packages/daemon/src/lib/install-origin.ts
93949
- import { existsSync as existsSync38, readFileSync as readFileSync40, realpathSync as realpathSync29 } from "node:fs";
93950
- import { dirname as dirname46, join as join54 } from "node:path";
94201
+ import { existsSync as existsSync39, readFileSync as readFileSync41, realpathSync as realpathSync29 } from "node:fs";
94202
+ import { dirname as dirname47, join as join55 } from "node:path";
93951
94203
  import { fileURLToPath as fileURLToPath13 } from "node:url";
93952
94204
  function detectPackageManager(path2) {
93953
94205
  if (/\/share\/tmux-ide\/releases\/install-[^/]+\/npm\/lib\/node_modules\/tmux-ide\/bin$/.test(path2))
@@ -93964,37 +94216,37 @@ function findGitCheckoutRoot(startDir) {
93964
94216
  let dir = startDir;
93965
94217
  for (; ; ) {
93966
94218
  if (dir.endsWith("/node_modules")) return null;
93967
- if (existsSync38(join54(dir, ".git"))) {
94219
+ if (existsSync39(join55(dir, ".git"))) {
93968
94220
  try {
93969
- if (JSON.parse(readFileSync40(join54(dir, "package.json"), "utf8")).name === "tmux-ide")
94221
+ if (JSON.parse(readFileSync41(join55(dir, "package.json"), "utf8")).name === "tmux-ide")
93970
94222
  return dir;
93971
94223
  } catch {
93972
94224
  }
93973
94225
  return null;
93974
94226
  }
93975
- const parent = dirname46(dir);
94227
+ const parent = dirname47(dir);
93976
94228
  if (parent === dir) return null;
93977
94229
  dir = parent;
93978
94230
  }
93979
94231
  }
93980
- function installOrigin(cliDir = dirname46(fileURLToPath13(import.meta.url))) {
94232
+ function installOrigin(cliDir = dirname47(fileURLToPath13(import.meta.url))) {
93981
94233
  let path2;
93982
94234
  try {
93983
94235
  path2 = realpathSync29(cliDir);
93984
94236
  } catch {
93985
94237
  return { origin: "unknown", path: cliDir, gitRoot: null };
93986
94238
  }
93987
- let detected = detectPackageManager(path2);
93988
- if (detected === "npm" || detected === "pnpm" || detected === "bun") {
94239
+ let detected2 = detectPackageManager(path2);
94240
+ if (detected2 === "npm" || detected2 === "pnpm" || detected2 === "bun") {
93989
94241
  try {
93990
- if (JSON.parse(readFileSync40(join54(path2, "../package.json"), "utf8")).name !== "tmux-ide")
93991
- detected = "unknown";
94242
+ if (JSON.parse(readFileSync41(join55(path2, "../package.json"), "utf8")).name !== "tmux-ide")
94243
+ detected2 = "unknown";
93992
94244
  } catch {
93993
- detected = "unknown";
94245
+ detected2 = "unknown";
93994
94246
  }
93995
94247
  }
93996
- const gitRoot = detected === "unknown" ? findGitCheckoutRoot(path2) : null;
93997
- return { origin: gitRoot ? "dev" : detected, path: path2, gitRoot };
94248
+ const gitRoot = detected2 === "unknown" ? findGitCheckoutRoot(path2) : null;
94249
+ return { origin: gitRoot ? "dev" : detected2, path: path2, gitRoot };
93998
94250
  }
93999
94251
  var init_install_origin = __esm({
94000
94252
  "packages/daemon/src/lib/install-origin.ts"() {
@@ -94013,7 +94265,7 @@ __export(update_exports, {
94013
94265
  runUpdate: () => runUpdate
94014
94266
  });
94015
94267
  import { realpathSync as realpathSync30 } from "node:fs";
94016
- import { dirname as dirname47, join as join55 } from "node:path";
94268
+ import { dirname as dirname48, join as join56 } from "node:path";
94017
94269
  import { execFileSync as execFileSync28 } from "node:child_process";
94018
94270
  function planUpdate(input) {
94019
94271
  const current = input.currentVersion ?? getCurrentVersion();
@@ -94103,7 +94355,7 @@ function runUpdate({ cliDir, dryRun, json: json2 = false }, dependencies = {}) {
94103
94355
  plan.executable === "bun" ? ["pm", "bin", "-g"] : ["root", "-g"]
94104
94356
  ).trim();
94105
94357
  if (!root.startsWith("/")) throw new Error("invalid manager path");
94106
- const target = plan.executable === "bun" ? dirname47(realpathSync30(join55(root, "tmux-ide"))) : realpathSync30(join55(root, "tmux-ide", "bin"));
94358
+ const target = plan.executable === "bun" ? dirname48(realpathSync30(join56(root, "tmux-ide"))) : realpathSync30(join56(root, "tmux-ide", "bin"));
94107
94359
  if (target !== source.path) throw new Error("different installation");
94108
94360
  } catch {
94109
94361
  plan = {
@@ -94165,7 +94417,7 @@ __export(pane_widget_exports, {
94165
94417
  paneWidgetId: () => paneWidgetId,
94166
94418
  paneWidgetIdForFile: () => paneWidgetIdForFile
94167
94419
  });
94168
- import { basename as basename21, extname } from "node:path";
94420
+ import { basename as basename22, extname } from "node:path";
94169
94421
  function imageMediaTypeFor(fileName) {
94170
94422
  return IMAGE_MEDIA_BY_EXTENSION.get(extname(fileName).toLowerCase()) ?? null;
94171
94423
  }
@@ -94183,7 +94435,7 @@ function buildMarkdownAnnouncement(text, title) {
94183
94435
  }
94184
94436
  }
94185
94437
  function buildImageAnnouncement(bytes, filePath) {
94186
- const name = basename21(filePath);
94438
+ const name = basename22(filePath);
94187
94439
  const media = imageMediaTypeFor(name);
94188
94440
  if (media === null) {
94189
94441
  throw new PaneWidgetRefusal(
@@ -94237,7 +94489,7 @@ function paneWidgetIdForFile(fileName) {
94237
94489
  if ([".md", ".markdown"].includes(extension)) return "markdown";
94238
94490
  if (IMAGE_MEDIA_BY_EXTENSION.has(extension)) return "image";
94239
94491
  if (extension === ".json") return "card";
94240
- const name = basename21(fileName) || fileName || "input";
94492
+ const name = basename22(fileName) || fileName || "input";
94241
94493
  throw new PaneWidgetRefusal(
94242
94494
  "unsupported-source",
94243
94495
  `tmux-ide cannot infer how to show "${name}". Supported: Markdown (.md, .markdown), raster images (${[...IMAGE_MEDIA_BY_EXTENSION.keys()].join(", ")}), and declarative cards (.json).`
@@ -94378,9 +94630,9 @@ var init_server3 = __esm({
94378
94630
 
94379
94631
  // bin/cli.ts
94380
94632
  import { parseArgs as parseArgs2 } from "node:util";
94381
- import { resolve as resolve40, dirname as dirname48, join as join56 } from "node:path";
94633
+ import { resolve as resolve40, dirname as dirname49, join as join57 } from "node:path";
94382
94634
  import { execFileSync as execFileSync29 } from "node:child_process";
94383
- import { appendFileSync as appendFileSync2, existsSync as existsSync39, mkdirSync as mkdirSync32, writeFileSync as writeFileSync30 } from "node:fs";
94635
+ import { appendFileSync as appendFileSync2, existsSync as existsSync40, mkdirSync as mkdirSync33, writeFileSync as writeFileSync31 } from "node:fs";
94384
94636
  import { fileURLToPath as fileURLToPath14 } from "node:url";
94385
94637
 
94386
94638
  // packages/daemon/src/tui/team/entry.ts
@@ -94398,7 +94650,7 @@ init_errors2();
94398
94650
  init_output();
94399
94651
  init_state_home();
94400
94652
  init_hosted();
94401
- var __dirname5 = dirname48(fileURLToPath14(import.meta.url));
94653
+ var __dirname5 = dirname49(fileURLToPath14(import.meta.url));
94402
94654
  var selfPath = fileURLToPath14(import.meta.url);
94403
94655
  var nodeCliPath = selfPath.endsWith(".js") ? selfPath : resolve40(__dirname5, "cli.js");
94404
94656
  var { positionals, values } = parseArgs2({
@@ -94588,7 +94840,7 @@ ${bold3("Usage:")}
94588
94840
  ${cyan2("tmux-ide restart")} ${dim3("Stop and relaunch the IDE session")}
94589
94841
  ${cyan2("tmux-ide restore")} [--dry-run] [--run-commands] [--resume-agents] [--json]
94590
94842
  ${dim3("Rebuild the fleet from the last snapshot after a tmux crash")}
94591
- ${dim3("(--resume-agents revives claude conversations via claude --resume)")}
94843
+ ${dim3("(--resume-agents resumes Claude Code, Codex, opencode, Cursor and Copilot sessions by their captured ids)")}
94592
94844
  ${cyan2("tmux-ide attach")} ${dim3("Reattach to a running session")}
94593
94845
  ${cyan2("tmux-ide team assign")} %PANE TEAM ${dim3("Group a pane; unassign removes membership")}
94594
94846
  ${cyan2("tmux-ide team")} [--json] ${dim3("TUI over all tmux sessions (--json prints fleet state)")}
@@ -94610,13 +94862,14 @@ ${bold3("Usage:")}
94610
94862
  ${cyan2("tmux-ide integration install opencode")} ${dim3("Capture opencode session ids for restore --resume-agents")}
94611
94863
  ${cyan2("tmux-ide integration uninstall")} <claude|opencode> ${dim3("Remove tmux-ide's integration entries")}
94612
94864
  ${cyan2("tmux-ide integration status")} [--json] ${dim3("Show discovered agents, integration state, and resume-id capture")}
94865
+ ${cyan2("tmux-ide integration agent-teams")} [enable|disable|status] [--json] ${dim3("Claude Code agent teams (installer enables; opt-out respected)")}
94613
94866
  ${cyan2("tmux-ide agent explain")} <pane> [--json] ${dim3("Debug how a pane's agent state is detected")}
94614
94867
  ${cyan2("tmux-ide cheatsheet")} ${dim3("Print the key cheat sheet (\u2325k / [ ? keys ] popup)")}
94615
94868
  ${cyan2("tmux-ide menu")} [--client N] ${dim3("Open the right-click actions menu (\u2325m / right-click any pane or the bar)")}
94616
94869
  ${cyan2("tmux-ide popup")} <widget> ${dim3("Open a widget as a floating panel (explorer/changes/config; \u2325e/\u2325g/\u2325,)")}
94617
94870
  ${cyan2("tmux-ide widget")} <markdown|image|card> [file] ${dim3("Render rich live content in the current pane")}
94618
94871
  ${cyan2("tmux-ide show")} <file> ${dim3("Show Markdown, images, GIFs, or cards by file type")}
94619
- ${cyan2("tmux-ide sidebar-toggle")} [--session S] ${dim3("Toggle the app nav column (\u2325b on adopted sessions)")}
94872
+ ${cyan2("tmux-ide sidebar-toggle")} [--session S] ${dim3("Toggle the tmux chrome sidebar column (prefix b / \u2325b in adopted sessions)")}
94620
94873
  ${cyan2("tmux-ide worktree create")} <branch> [--from <ref>] [--dir <path>] [--no-session]
94621
94874
  ${dim3("Add a git worktree (new branch) + open a session in it")}
94622
94875
  ${cyan2("tmux-ide worktree open")} <branch> ${dim3("Open (or switch to) the session for an existing worktree")}
@@ -94706,10 +94959,10 @@ Install bun (https://bun.sh) \u2014 the TUI surfaces run on it. Sources ship wit
94706
94959
  let automaticDiagnosticLog;
94707
94960
  if (surface === "app" && !process.env.TMUX_IDE_TUI_PERF_LOG && !process.env.TMUX_IDE_TUI_LOG) {
94708
94961
  try {
94709
- const logDirectory = join56(stateHome(), "logs");
94710
- mkdirSync32(logDirectory, { recursive: true, mode: 448 });
94711
- automaticDiagnosticLog = join56(logDirectory, "tui-latest.jsonl");
94712
- writeFileSync30(
94962
+ const logDirectory = join57(stateHome(), "logs");
94963
+ mkdirSync33(logDirectory, { recursive: true, mode: 448 });
94964
+ automaticDiagnosticLog = join57(logDirectory, "tui-latest.jsonl");
94965
+ writeFileSync31(
94713
94966
  automaticDiagnosticLog,
94714
94967
  `${JSON.stringify({
94715
94968
  phase: "launcher-start",
@@ -95033,7 +95286,7 @@ try {
95033
95286
  }
95034
95287
  }
95035
95288
  const targetDir = resolve40(startTargetDir || ".");
95036
- if (startTargetDir && !existsSync39(targetDir)) {
95289
+ if (startTargetDir && !existsSync40(targetDir)) {
95037
95290
  throw new IdeError(
95038
95291
  `No workspace config found in ${targetDir}. Run "tmux-ide init" or "tmux-ide detect --write" to create one.`,
95039
95292
  { code: "CONFIG_NOT_FOUND", exitCode: 1 }
@@ -95281,8 +95534,8 @@ try {
95281
95534
  const messageStart = values.to ? 1 : 2;
95282
95535
  let message = positionals.slice(messageStart).join(" ");
95283
95536
  if (!message && !process.stdin.isTTY) {
95284
- const { readFileSync: readFileSync41 } = await import("node:fs");
95285
- message = readFileSync41(0, "utf-8").trim();
95537
+ const { readFileSync: readFileSync42 } = await import("node:fs");
95538
+ message = readFileSync42(0, "utf-8").trim();
95286
95539
  }
95287
95540
  await (await Promise.resolve().then(() => (init_send(), send_exports))).send(null, { json, to: target, message, noEnter: values["no-enter"] });
95288
95541
  break;
@@ -95462,7 +95715,7 @@ try {
95462
95715
  break;
95463
95716
  }
95464
95717
  case "events": {
95465
- const { readFileSync: readFileSync41, existsSync: existsSync40, statSync: statSync22, openSync: openSync12, readSync: readSync4, closeSync: closeSync12 } = await import("node:fs");
95718
+ const { readFileSync: readFileSync42, existsSync: existsSync41, statSync: statSync23, openSync: openSync12, readSync: readSync4, closeSync: closeSync12 } = await import("node:fs");
95466
95719
  const { eventsPath: eventsPath2, formatEventLine: formatEventLine2 } = await Promise.resolve().then(() => (init_events(), events_exports));
95467
95720
  const path2 = eventsPath2();
95468
95721
  const paintStatus = (status2, text) => {
@@ -95487,8 +95740,8 @@ try {
95487
95740
  socketPath: typeof socketFlag === "string" ? socketFlag : void 0
95488
95741
  }).catch(() => null);
95489
95742
  if (client) {
95490
- if (existsSync40(path2)) {
95491
- const backlog = readFileSync41(path2, "utf8").split("\n").filter((l) => l.trim().length > 0);
95743
+ if (existsSync41(path2)) {
95744
+ const backlog = readFileSync42(path2, "utf8").split("\n").filter((l) => l.trim().length > 0);
95492
95745
  for (const line of backlog.slice(-50)) printLine(line);
95493
95746
  }
95494
95747
  await client.subscribe((frame) => {
@@ -95502,19 +95755,19 @@ try {
95502
95755
  break;
95503
95756
  }
95504
95757
  }
95505
- if (!existsSync40(path2)) {
95758
+ if (!existsSync41(path2)) {
95506
95759
  console.log("no events yet \u2014 is a session adopted? (the chrome updater writes events)");
95507
95760
  break;
95508
95761
  }
95509
- const allLines = readFileSync41(path2, "utf8").split("\n").filter((l) => l.trim().length > 0);
95762
+ const allLines = readFileSync42(path2, "utf8").split("\n").filter((l) => l.trim().length > 0);
95510
95763
  for (const line of allLines.slice(-50)) printLine(line);
95511
95764
  if (!values.follow) break;
95512
- let offset = statSync22(path2).size;
95765
+ let offset = statSync23(path2).size;
95513
95766
  let leftover = "";
95514
95767
  const timer = setInterval(() => {
95515
95768
  let size;
95516
95769
  try {
95517
- size = statSync22(path2).size;
95770
+ size = statSync23(path2).size;
95518
95771
  } catch {
95519
95772
  return;
95520
95773
  }
@@ -95614,10 +95867,41 @@ try {
95614
95867
  const installable = agent === "claude" || agent === "opencode";
95615
95868
  if (!sub || needsAgent && !installable) {
95616
95869
  console.error(
95617
- "Usage: tmux-ide integration <install|uninstall|status|offer> [claude|opencode]\n install claude: hook lifecycle events into tmux pane state\n opencode: plugin that records the session id for restore --resume-agents\n uninstall remove exactly the tmux-ide entries for that agent\n status list discovered agents + integration/capture state\n offer one-time first-adopt install prompt (used by the popup)"
95870
+ "Usage: tmux-ide integration <install|uninstall|status|offer|agent-teams> [claude|opencode]\n install claude: hook lifecycle events into tmux pane state\n opencode: plugin that records the session id for restore --resume-agents\n uninstall remove exactly the tmux-ide entries for that agent\n status list discovered agents + integration/capture state\n offer one-time first-adopt install prompt (used by the popup)\n agent-teams [enable|disable|status] Claude Code agent teams in ~/.claude/settings.json"
95618
95871
  );
95619
95872
  process.exit(1);
95620
95873
  }
95874
+ if (sub === "agent-teams") {
95875
+ const action = agent ?? "status";
95876
+ if (action !== "enable" && action !== "disable" && action !== "status") {
95877
+ console.error(
95878
+ "Usage: tmux-ide integration agent-teams [enable [--if-not-disabled]|disable|status] [--json]"
95879
+ );
95880
+ process.exit(1);
95881
+ }
95882
+ const teams = await Promise.resolve().then(() => (init_claude_agent_teams(), claude_agent_teams_exports));
95883
+ const { homedir: homedir9 } = await import("node:os");
95884
+ const tilde = (text) => text.replaceAll(`${homedir9()}/`, "~/");
95885
+ if (action === "status") {
95886
+ const status2 = teams.claudeAgentTeamsStatus();
95887
+ if (json) console.log(JSON.stringify(status2, null, 2));
95888
+ else {
95889
+ console.log(`settings: ${tilde(status2.settingsPath)}`);
95890
+ console.log(`claude: ${status2.claudeDetected ? "detected" : "not found"}`);
95891
+ console.log(`agent teams: ${status2.setting}`);
95892
+ console.log(`teammateMode: ${status2.teammateMode ?? "(unset)"}`);
95893
+ }
95894
+ if (status2.setting === "invalid-settings") process.exit(1);
95895
+ break;
95896
+ }
95897
+ const result2 = action === "enable" ? teams.enableClaudeAgentTeams(void 0, void 0, {
95898
+ overrideOptOut: values["if-not-disabled"] !== true
95899
+ }) : teams.disableClaudeAgentTeams();
95900
+ if (json) console.log(JSON.stringify(result2, null, 2));
95901
+ else console.log(tilde(result2.message));
95902
+ if (result2.action === "invalid") process.exit(1);
95903
+ break;
95904
+ }
95621
95905
  if (needsAgent && agent === "opencode") {
95622
95906
  const oc = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
95623
95907
  if (sub === "install") {
@@ -96213,8 +96497,8 @@ Known panels: ${POPUP_WIDGETS2.join(", ")}.`,
96213
96497
  paneWidgetIdForFile: paneWidgetIdForFile2
96214
96498
  } = await Promise.resolve().then(() => (init_pane_widget(), pane_widget_exports));
96215
96499
  const { publishWidgetAsset: publishWidgetAsset2, WidgetAssetStoreError: WidgetAssetStoreError2 } = await Promise.resolve().then(() => (init_widget_asset_store(), widget_asset_store_exports));
96216
- const { readFileSync: readFileSync41, watchFile, unwatchFile } = await import("node:fs");
96217
- const { basename: basename22 } = await import("node:path");
96500
+ const { readFileSync: readFileSync42, watchFile, unwatchFile } = await import("node:fs");
96501
+ const { basename: basename23 } = await import("node:path");
96218
96502
  const readStdin = async () => {
96219
96503
  const chunks = [];
96220
96504
  for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
@@ -96233,11 +96517,11 @@ Known panels: ${POPUP_WIDGETS2.join(", ")}.`,
96233
96517
  if (id2 === "markdown") {
96234
96518
  if (file) {
96235
96519
  const publish = () => {
96236
- const asset = publishWidgetAsset2(readFileSync41(file), {
96520
+ const asset = publishWidgetAsset2(readFileSync42(file), {
96237
96521
  media: "text/markdown",
96238
- name: basename22(file)
96522
+ name: basename23(file)
96239
96523
  });
96240
- return buildMarkdownAssetAnnouncement2(asset.assetId, basename22(file));
96524
+ return buildMarkdownAssetAnnouncement2(asset.assetId, basename23(file));
96241
96525
  };
96242
96526
  announcement = publish();
96243
96527
  watchedFile = file;
@@ -96252,20 +96536,20 @@ Known panels: ${POPUP_WIDGETS2.join(", ")}.`,
96252
96536
  if (!media) {
96253
96537
  throw new PaneWidgetRefusal2(
96254
96538
  "unsupported-media",
96255
- `"${basename22(file)}" is not a supported raster image.`
96539
+ `"${basename23(file)}" is not a supported raster image.`
96256
96540
  );
96257
96541
  }
96258
- const asset = publishWidgetAsset2(readFileSync41(file), {
96542
+ const asset = publishWidgetAsset2(readFileSync42(file), {
96259
96543
  media,
96260
- name: basename22(file)
96544
+ name: basename23(file)
96261
96545
  });
96262
- return buildImageAssetAnnouncement2(asset.assetId, { name: basename22(file) });
96546
+ return buildImageAssetAnnouncement2(asset.assetId, { name: basename23(file) });
96263
96547
  };
96264
96548
  announcement = publish();
96265
96549
  watchedFile = file;
96266
96550
  refreshAnnouncement = publish;
96267
96551
  } else {
96268
- const source = file ? readFileSync41(file, "utf8") : await readStdin();
96552
+ const source = file ? readFileSync42(file, "utf8") : await readStdin();
96269
96553
  announcement = buildCardAnnouncement2(JSON.parse(source));
96270
96554
  }
96271
96555
  } catch (error) {