@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.
- package/dist/index.js +49 -20
- 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.
|
|
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
|
-
|
|
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
|
-
|
|
772
|
+
target: {
|
|
761
773
|
type: "positional",
|
|
762
|
-
description: "
|
|
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("
|
|
786
|
+
consola.error("Tab name or block ID is required");
|
|
775
787
|
process.exit(1);
|
|
776
788
|
}
|
|
777
789
|
const adapter = requireWaveAdapter();
|
|
778
|
-
const
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
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(
|
|
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) {
|