@hwip/cli 0.1.9 → 0.1.10
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/wrapper.d.ts +4 -0
- package/dist/wrapper.js +44 -9
- package/package.json +1 -1
package/dist/wrapper.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export declare const herdrSessionArgs: (session: string, env?: NodeJS.ProcessEnv
|
|
|
32
32
|
* an older tmux gets none, as before.
|
|
33
33
|
*/
|
|
34
34
|
export declare const herdrEnvArgs: (agentKind: string | undefined, env: NodeJS.ProcessEnv, tmuxVersion: string) => string[];
|
|
35
|
+
export declare const agentLaunchEnv: (agentKind: string | undefined, env: NodeJS.ProcessEnv) => Record<string, string>;
|
|
36
|
+
export declare const agentLaunchArgs: (agentKind: string | undefined, extra: string[]) => string[];
|
|
35
37
|
/** `tmux -V`, read once per process; empty when tmux does not answer. */
|
|
36
38
|
export declare const installedTmuxVersion: () => string;
|
|
37
39
|
/**
|
|
@@ -91,6 +93,8 @@ export interface SpawnTarget {
|
|
|
91
93
|
args: string[];
|
|
92
94
|
/** The tmux session name for the two tmux kinds — carried, not re-read off argv. */
|
|
93
95
|
session?: string;
|
|
96
|
+
/** Variables the agent runs with on top of this process's env (`direct`); the tmux kinds carry them as `-e`. */
|
|
97
|
+
env?: Record<string, string>;
|
|
94
98
|
}
|
|
95
99
|
/**
|
|
96
100
|
* `hwip <agent> --detach --label <x> --wt <name> …` — the wrapper-owned flags. They
|
package/dist/wrapper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleShellSession = exports.shellTargets = exports.readShellSessionState = exports.planShellSession = exports.handleAgentSession = exports.tmuxMissingMessage = exports.inPaneNote = exports.handOffExec = exports.ensureListenerRunning = exports.takeListenerLaunchMarker = exports.listenerVersionDrifted = exports.targetForAgent = exports.splitAgentOptions = exports.sanitizeLabel = exports.findAvailableSession = exports.familyNames = exports.firstFreeSession = exports.tmuxSessionName = exports.installedTmuxVersion = exports.herdrEnvArgs = exports.herdrSessionArgs = exports.sessionSidecarArgs = exports.detectProjectName = exports.detectProjectDir = exports.safeBasename = void 0;
|
|
3
|
+
exports.handleShellSession = exports.shellTargets = exports.readShellSessionState = exports.planShellSession = exports.handleAgentSession = exports.tmuxMissingMessage = exports.inPaneNote = exports.handOffExec = exports.ensureListenerRunning = exports.takeListenerLaunchMarker = exports.listenerVersionDrifted = exports.targetForAgent = exports.splitAgentOptions = exports.sanitizeLabel = exports.findAvailableSession = exports.familyNames = exports.firstFreeSession = exports.tmuxSessionName = exports.installedTmuxVersion = exports.agentLaunchArgs = exports.agentLaunchEnv = exports.herdrEnvArgs = exports.herdrSessionArgs = exports.sessionSidecarArgs = exports.detectProjectName = exports.detectProjectDir = exports.safeBasename = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* `hwip cc` / `hwip codex` / `hwip gemini` — spawn an agent inside a named
|
|
6
6
|
* tmux session so the resident listener (`hwip listener`) can address it
|
|
@@ -106,6 +106,36 @@ const herdrEnvArgs = (agentKind, env, tmuxVersion) => {
|
|
|
106
106
|
return config_js_1.HERDR_ENV_VARS.flatMap((name) => ['-e', `${name}=${native ? env[name] ?? '' : ''}`]);
|
|
107
107
|
};
|
|
108
108
|
exports.herdrEnvArgs = herdrEnvArgs;
|
|
109
|
+
/**
|
|
110
|
+
* Env that keeps an agent's transcript in tmux scrollback, by kind. A
|
|
111
|
+
* full-screen renderer draws on the alternate screen, where tmux keeps no
|
|
112
|
+
* history, so the phone cannot page back. Claude Code's fullscreen renderer
|
|
113
|
+
* is a user setting (`/tui fullscreen`); this forces the classic one. A value
|
|
114
|
+
* the launching shell already sets wins.
|
|
115
|
+
*/
|
|
116
|
+
const AGENT_LAUNCH_ENV = {
|
|
117
|
+
claude: { CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN: '1' },
|
|
118
|
+
};
|
|
119
|
+
const agentLaunchEnv = (agentKind, env) => Object.fromEntries(Object.entries(AGENT_LAUNCH_ENV[agentKind ?? ''] ?? {}).map(([name, value]) => [name, env[name] ?? value]));
|
|
120
|
+
exports.agentLaunchEnv = agentLaunchEnv;
|
|
121
|
+
/**
|
|
122
|
+
* Leading flags with the same aim, by kind, for an agent whose renderer is a
|
|
123
|
+
* flag: pi defaults to `--tui-mode fullscreen`. Left off when the caller
|
|
124
|
+
* passes the flag itself.
|
|
125
|
+
*/
|
|
126
|
+
const AGENT_LAUNCH_ARGS = {
|
|
127
|
+
pi: ['--tui-mode', 'regular'],
|
|
128
|
+
};
|
|
129
|
+
const agentLaunchArgs = (agentKind, extra) => {
|
|
130
|
+
const lead = AGENT_LAUNCH_ARGS[agentKind ?? ''] ?? [];
|
|
131
|
+
const flag = lead[0];
|
|
132
|
+
if (flag === undefined || extra.some((a) => a === flag || a.startsWith(`${flag}=`)))
|
|
133
|
+
return extra;
|
|
134
|
+
return [...lead, ...extra];
|
|
135
|
+
};
|
|
136
|
+
exports.agentLaunchArgs = agentLaunchArgs;
|
|
137
|
+
/** `new-session -e` flags for `agentLaunchEnv`; none before tmux 3.2, as for herdr. */
|
|
138
|
+
const launchEnvArgs = (launchEnv, tmuxVersion) => sessionEnvSupported(tmuxVersion) ? Object.entries(launchEnv).flatMap(([name, value]) => ['-e', `${name}=${value}`]) : [];
|
|
109
139
|
/** `tmux -V` says 3.2 or later (`new-session -e`); a development build (`next-3.7`, `master`) is newer. */
|
|
110
140
|
const sessionEnvSupported = (version) => {
|
|
111
141
|
if (/\b(master|next-)/.test(version))
|
|
@@ -310,8 +340,10 @@ const targetForAgent = (agent, extra, agentKind, opts = {}) => {
|
|
|
310
340
|
// is exactly where it runs from.
|
|
311
341
|
// A label asks for a tmux session by name; running in the current pane
|
|
312
342
|
// would drop that silently, so a label is the other exception.
|
|
343
|
+
const launchEnv = (0, exports.agentLaunchEnv)(agentKind, process.env);
|
|
344
|
+
extra = (0, exports.agentLaunchArgs)(agentKind, extra);
|
|
313
345
|
if (process.env.TMUX && !opts.detach && !opts.label) {
|
|
314
|
-
return { kind: 'direct', cmd: agent, args: extra };
|
|
346
|
+
return { kind: 'direct', cmd: agent, args: extra, ...(Object.keys(launchEnv).length ? { env: launchEnv } : {}) };
|
|
315
347
|
}
|
|
316
348
|
const projectDir = opts.projectDir ?? (0, exports.detectProjectDir)();
|
|
317
349
|
const base = (0, exports.tmuxSessionName)((0, exports.safeBasename)(projectDir));
|
|
@@ -342,11 +374,13 @@ const targetForAgent = (agent, extra, agentKind, opts = {}) => {
|
|
|
342
374
|
if (opts.detach) {
|
|
343
375
|
// Attached to no herdr pane: blank, whatever pane this command was typed in.
|
|
344
376
|
const herdrEnv = (0, exports.herdrEnvArgs)(agentKind, {}, (0, exports.installedTmuxVersion)());
|
|
345
|
-
|
|
377
|
+
const agentEnv = launchEnvArgs(launchEnv, (0, exports.installedTmuxVersion)());
|
|
378
|
+
return { kind: 'tmux-detached', cmd: 'tmux', args: ['new', '-d', '-s', session, '-c', projectDir, ...herdrEnv, ...agentEnv, shellCmd, ...sidecar], session };
|
|
346
379
|
}
|
|
347
380
|
// `tmux new -A`: attach if the named session exists, else create it. `-e` applies only when it creates.
|
|
348
381
|
const herdrEnv = (0, exports.herdrEnvArgs)(agentKind, process.env, (0, exports.installedTmuxVersion)());
|
|
349
|
-
|
|
382
|
+
const agentEnv = launchEnvArgs(launchEnv, (0, exports.installedTmuxVersion)());
|
|
383
|
+
return { kind: 'tmux-new', cmd: 'tmux', args: ['new', '-A', '-s', session, ...herdrEnv, ...agentEnv, shellCmd, ...sidecar, ...(0, exports.herdrSessionArgs)(session)], session };
|
|
350
384
|
};
|
|
351
385
|
exports.targetForAgent = targetForAgent;
|
|
352
386
|
// ── Background listener auto-start ────────────────────────────────────
|
|
@@ -561,7 +595,7 @@ const handleAgentSession = async (agent, extra = [], opts = {}, deps = {}) => {
|
|
|
561
595
|
// spawned from here would inherit the worktree as its cwd, and it is the one that later removes the directory.
|
|
562
596
|
if (opts.worktree && opts.projectDir)
|
|
563
597
|
process.chdir(opts.projectDir);
|
|
564
|
-
const { kind, cmd, args, session } = (0, exports.targetForAgent)(agent.binary, extra, agent.kind, opts);
|
|
598
|
+
const { kind, cmd, args, session, env } = (0, exports.targetForAgent)(agent.binary, extra, agent.kind, opts);
|
|
565
599
|
const note = kind === 'direct' ? (0, exports.inPaneNote)(agent.subcommands[0], currentTmuxSession()) : undefined;
|
|
566
600
|
if (note)
|
|
567
601
|
console.error(note);
|
|
@@ -575,7 +609,7 @@ const handleAgentSession = async (agent, extra = [], opts = {}, deps = {}) => {
|
|
|
575
609
|
return 1;
|
|
576
610
|
}
|
|
577
611
|
}
|
|
578
|
-
return (deps.launch ?? launchTarget)({ kind, cmd, args, session }, agent.binary);
|
|
612
|
+
return (deps.launch ?? launchTarget)({ kind, cmd, args, session, env }, agent.binary);
|
|
579
613
|
};
|
|
580
614
|
exports.handleAgentSession = handleAgentSession;
|
|
581
615
|
/**
|
|
@@ -583,7 +617,8 @@ exports.handleAgentSession = handleAgentSession;
|
|
|
583
617
|
* hands the terminal over (execve where it can, a waited child where not) and
|
|
584
618
|
* forwards the exit code. `what` names the program in the detached message.
|
|
585
619
|
*/
|
|
586
|
-
const launchTarget = async ({ kind, cmd, args, session }, what) => {
|
|
620
|
+
const launchTarget = async ({ kind, cmd, args, session, env: agentEnv }, what) => {
|
|
621
|
+
const env = agentEnv ? { ...process.env, ...agentEnv } : process.env;
|
|
587
622
|
if (kind === 'tmux-detached' && session) {
|
|
588
623
|
const r = (0, child_process_1.spawnSync)(cmd, args, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
589
624
|
if (r.error || r.status !== 0) {
|
|
@@ -601,7 +636,7 @@ const launchTarget = async ({ kind, cmd, args, session }, what) => {
|
|
|
601
636
|
// exit code that execve gives us for free by being the same process.
|
|
602
637
|
const handOff = (0, exports.handOffExec)({
|
|
603
638
|
execve: process.execve,
|
|
604
|
-
env
|
|
639
|
+
env,
|
|
605
640
|
kind,
|
|
606
641
|
stdinTTY: process.stdin.isTTY,
|
|
607
642
|
stdoutTTY: process.stdout.isTTY,
|
|
@@ -621,7 +656,7 @@ const launchTarget = async ({ kind, cmd, args, session }, what) => {
|
|
|
621
656
|
}
|
|
622
657
|
return new Promise((resolve) => {
|
|
623
658
|
const start = Date.now();
|
|
624
|
-
const child = (0, child_process_1.spawn)(cmd, args, { stdio: 'inherit' });
|
|
659
|
+
const child = (0, child_process_1.spawn)(cmd, args, { stdio: 'inherit', env });
|
|
625
660
|
child.on('exit', (code) => {
|
|
626
661
|
const dur = Date.now() - start;
|
|
627
662
|
// Short-lived non-zero exits are the symptom of "ran from a
|