@generativereality/agentherder 0.1.1 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/index.js +49 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { consola } from "consola";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
11
11
  //#region package.json
12
12
  var name = "@generativereality/agentherder";
13
- var version = "0.1.1";
13
+ var version = "0.1.3";
14
14
  var description = "Agent session manager for AI coding tools. Terminal tabs as the UI, no tmux.";
15
15
  var package_default = {
16
16
  name,
@@ -500,6 +500,10 @@ function ensureConfigExists() {
500
500
  async function openSession(opts) {
501
501
  const { tabName, claudeCmd, workspaceQuery } = opts;
502
502
  const dir = resolve(opts.dir.replace(/^~/, homedir()));
503
+ if (!existsSync(dir)) {
504
+ consola.error(`Directory does not exist: ${dir}`);
505
+ process.exit(1);
506
+ }
503
507
  const config = loadConfig();
504
508
  const adapter = requireWaveAdapter();
505
509
  let focusWindowId;
@@ -530,6 +534,7 @@ async function openSession(opts) {
530
534
  const extraFlags = config.claude.flags.join(" ");
531
535
  const cmd = `cd ${JSON.stringify(dir)} && ${claudeCmd} --name ${JSON.stringify(tabName)}${extraFlags ? " " + extraFlags : ""}\n`;
532
536
  await adapter.sendInput(blockId, cmd);
537
+ await new Promise((r) => setTimeout(r, 2e3));
533
538
  adapter.closeSocket();
534
539
  return tabId;
535
540
  }
@@ -545,18 +550,24 @@ const newCommand = define({
545
550
  },
546
551
  dir: {
547
552
  type: "positional",
548
- description: "Working directory (default: cwd)"
553
+ description: "Working directory / repo root (default: cwd)"
549
554
  },
550
555
  workspace: {
551
556
  type: "string",
552
557
  short: "w",
553
558
  description: "Target workspace"
559
+ },
560
+ worktree: {
561
+ type: "boolean",
562
+ short: "W",
563
+ description: "Launch claude with --worktree <name> for isolated branch work"
554
564
  }
555
565
  },
556
566
  async run(ctx) {
557
567
  const name = ctx.positionals[1];
558
568
  const dir = ctx.positionals[2] ?? process.cwd();
559
569
  const workspace = ctx.values.workspace;
570
+ const useWorktree = ctx.values.worktree ?? false;
560
571
  if (!name) {
561
572
  consola.error("Tab name is required");
562
573
  process.exit(1);
@@ -564,10 +575,11 @@ const newCommand = define({
564
575
  const tabId = await openSession({
565
576
  tabName: name,
566
577
  dir,
567
- claudeCmd: "claude",
578
+ claudeCmd: useWorktree ? `claude --worktree ${JSON.stringify(name)}` : "claude",
568
579
  workspaceQuery: workspace
569
580
  });
570
- consola.success(`Tab "${name}" [${tabId.slice(0, 8)}] claude at ${dir}`);
581
+ const suffix = useWorktree ? ` (worktree: .claude/worktrees/${name})` : "";
582
+ consola.success(`Tab "${name}" [${tabId.slice(0, 8)}] → claude at ${dir}${suffix}`);
571
583
  }
572
584
  });
573
585
  //#endregion
@@ -696,7 +708,7 @@ const closeCommand = define({
696
708
  const { tabsById, tabNames } = await adapter.getAllData();
697
709
  const matches = adapter.resolveTab(query, tabsById, tabNames);
698
710
  if (!matches.length) {
699
- consola.error(`No tab matching '${query}'`);
711
+ consola.error(`No tab matching '${query}' (tabs in workspaces with no open window are not visible — open that workspace first)`);
700
712
  process.exit(1);
701
713
  }
702
714
  if (matches.length > 1) {
@@ -755,11 +767,11 @@ const renameCommand = define({
755
767
  //#region src/commands/scrollback.ts
756
768
  const scrollbackCommand = define({
757
769
  name: "scrollback",
758
- description: "Show terminal output for a block (default: last 50 lines)",
770
+ description: "Show terminal output for a tab or block (default: last 50 lines)",
759
771
  args: {
760
- block: {
772
+ target: {
761
773
  type: "positional",
762
- description: "Block ID prefix"
774
+ description: "Tab name, tab ID prefix, or block ID prefix"
763
775
  },
764
776
  lines: {
765
777
  type: "number",
@@ -771,22 +783,39 @@ const scrollbackCommand = define({
771
783
  const query = ctx.positionals[1];
772
784
  const lines = ctx.values.lines ?? 50;
773
785
  if (!query) {
774
- consola.error("Block ID is required");
786
+ consola.error("Tab name or block ID is required");
775
787
  process.exit(1);
776
788
  }
777
789
  const adapter = requireWaveAdapter();
778
- const blocks = adapter.blocksList();
779
- const matches = adapter.resolveBlock(query, blocks);
780
- if (!matches.length) {
781
- consola.error(`No block matching '${query}'`);
782
- process.exit(1);
783
- }
784
- if (matches.length > 1) {
785
- consola.error(`Multiple blocks match '${query}':`);
786
- for (const b of matches) consola.log(` ${b.blockid}`);
790
+ const { tabsById, tabNames } = await adapter.getAllData();
791
+ const tabMatches = adapter.resolveTab(query, tabsById, tabNames);
792
+ let blockId;
793
+ if (tabMatches.length === 1) {
794
+ const blocks = (tabsById.get(tabMatches[0]) ?? []).filter((b) => b.view === "term");
795
+ if (!blocks.length) {
796
+ consola.error(`Tab "${tabNames.get(tabMatches[0])}" has no terminal block`);
797
+ process.exit(1);
798
+ }
799
+ blockId = blocks[0].blockid;
800
+ } else if (tabMatches.length > 1) {
801
+ consola.error(`Multiple tabs match '${query}':`);
802
+ for (const tid of tabMatches) consola.log(` "${tabNames.get(tid)}" [${tid.slice(0, 8)}]`);
787
803
  process.exit(1);
804
+ } else {
805
+ const allBlocks = adapter.blocksList();
806
+ const blockMatches = adapter.resolveBlock(query, allBlocks);
807
+ if (!blockMatches.length) {
808
+ consola.error(`No tab or block matching '${query}' (tabs in workspaces with no open window are not visible — open that workspace first)`);
809
+ process.exit(1);
810
+ }
811
+ if (blockMatches.length > 1) {
812
+ consola.error(`Multiple blocks match '${query}':`);
813
+ for (const b of blockMatches) consola.log(` ${b.blockid}`);
814
+ process.exit(1);
815
+ }
816
+ blockId = blockMatches[0].blockid;
788
817
  }
789
- process.stdout.write(adapter.scrollback(matches[0].blockid, lines));
818
+ process.stdout.write(adapter.scrollback(blockId, lines));
790
819
  }
791
820
  });
792
821
  //#endregion
@@ -850,7 +879,7 @@ const sendCommand = define({
850
879
  const allBlocks = adapter.blocksList();
851
880
  const blockMatches = adapter.resolveBlock(query, allBlocks);
852
881
  if (!blockMatches.length) {
853
- consola.error(`No tab or block matching '${query}'`);
882
+ consola.error(`No tab or block matching '${query}' (tabs in workspaces with no open window are not visible — open that workspace first)`);
854
883
  process.exit(1);
855
884
  }
856
885
  if (blockMatches.length > 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generativereality/agentherder",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Agent session manager for AI coding tools. Terminal tabs as the UI, no tmux.",
5
5
  "type": "module",
6
6
  "bin": {