mintree 0.5.5 → 0.5.8
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/README.md +1 -0
- package/dist/lib/claude.js +14 -1
- package/dist/lib/terminal.d.ts +13 -0
- package/dist/lib/terminal.js +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -292,6 +292,7 @@ Linear authentication lives in `~/.mintree/credentials.json` (user-scoped, not p
|
|
|
292
292
|
- **Sessions persist by issue**: each issue gets a UUID stored in `metadata.json`. Subsequent `worktree work` calls pass `--resume <uuid>` so Claude reopens the same conversation.
|
|
293
293
|
- **Live state** (optional): the four hooks installed by `mintree helpers session-signal install` write the current Claude state to `.mintree/session-states/<issue>.json` on every prompt / stop / notification / session-end. The dashboard reads those files to colour each row in real time.
|
|
294
294
|
- **Remote Control** (optional): `mintree doctor` checks `~/.claude.json` for `remoteControlAtStartup: true`. Enabling it lets you continue a local session from a different device.
|
|
295
|
+
- **iTerm2 session badge** (automatic): when you launch on [iTerm2](https://iterm2.com), mintree sets the terminal **badge** — the large translucent label drawn over the session — to the session name (the worktree issue id like `VAL-68`, or the orchestrator's name) so each tab stays identifiable at a glance. It uses the badge rather than the tab title because Claude Code overwrites the title while it runs; the badge is independent of it and persists for the whole session, then clears on exit. No-op on other terminals (detected via `TERM_PROGRAM` / `LC_TERMINAL`).
|
|
295
296
|
|
|
296
297
|
---
|
|
297
298
|
|
package/dist/lib/claude.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync, spawn } from "child_process";
|
|
|
2
2
|
import { existsSync, writeFileSync } from "fs";
|
|
3
3
|
import { homedir, tmpdir } from "os";
|
|
4
4
|
import { join } from "path";
|
|
5
|
+
import { setITermBadge, clearITermBadge } from "./terminal.js";
|
|
5
6
|
export const PERMISSION_MODES = ["default", "auto"];
|
|
6
7
|
/**
|
|
7
8
|
* Resolves the absolute path of the Claude Code CLI binary, or null if not on
|
|
@@ -74,5 +75,17 @@ export function launchClaude(options) {
|
|
|
74
75
|
if (options.prompt && options.prompt.length > 0) {
|
|
75
76
|
args.push("--", promptArg(options.prompt));
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
+
// Label the session with an iTerm2 badge before handing over the TTY. The
|
|
79
|
+
// badge survives Claude overwriting the terminal title, so the tab stays
|
|
80
|
+
// identifiable (worktree issue id, or orchestrator name) while it runs.
|
|
81
|
+
// No-op outside iTerm2.
|
|
82
|
+
const badge = options.remoteControlName;
|
|
83
|
+
if (badge)
|
|
84
|
+
setITermBadge(badge);
|
|
85
|
+
const child = spawn(bin, args, { stdio: "inherit", cwd: options.cwd });
|
|
86
|
+
// Clear the badge once Claude exits so the badge doesn't linger on the
|
|
87
|
+
// shell that regains the TTY.
|
|
88
|
+
if (badge)
|
|
89
|
+
child.on("exit", () => clearITermBadge());
|
|
90
|
+
return child;
|
|
78
91
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** True when the active terminal is iTerm2 (also detected through tmux). */
|
|
2
|
+
export declare function isITerm(): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Builds the raw iTerm2 SetBadgeFormat escape sequence for `text`. Pure (no I/O)
|
|
5
|
+
* so it can be unit-tested; an empty string clears the badge. The badge format
|
|
6
|
+
* supports `\(...)` interpolation in iTerm2, but plain ids/labels carry no
|
|
7
|
+
* parens so the base64-encoded literal renders verbatim.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildBadgeSequence(text: string): string;
|
|
10
|
+
/** Sets the iTerm2 badge to `text`. No-op outside iTerm2 or with empty text. */
|
|
11
|
+
export declare function setITermBadge(text: string): void;
|
|
12
|
+
/** Clears the iTerm2 badge. No-op outside iTerm2. */
|
|
13
|
+
export declare function clearITermBadge(): void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// iTerm2 badge integration.
|
|
2
|
+
//
|
|
3
|
+
// Claude Code overwrites the terminal title (OSC 0/2) while it runs and exposes
|
|
4
|
+
// no way to disable that or pin a custom title, so a tab title we set before
|
|
5
|
+
// launching wouldn't survive. The iTerm2 *badge* — a large translucent label
|
|
6
|
+
// drawn over the session — is independent of the title and Claude never touches
|
|
7
|
+
// it, so it's the one reliable way to identify a mintree session at a glance
|
|
8
|
+
// (e.g. the worktree issue id `VAL-68`, or `orchestrator-VAL-12_BE-16`).
|
|
9
|
+
//
|
|
10
|
+
// Everything here is a no-op outside iTerm2, so callers can invoke it
|
|
11
|
+
// unconditionally.
|
|
12
|
+
const BEL = String.fromCharCode(7); // \a (BEL)
|
|
13
|
+
const ESC = String.fromCharCode(27); // \e (ESC)
|
|
14
|
+
/** True when the active terminal is iTerm2 (also detected through tmux). */
|
|
15
|
+
export function isITerm() {
|
|
16
|
+
return process.env["TERM_PROGRAM"] === "iTerm.app" || process.env["LC_TERMINAL"] === "iTerm2";
|
|
17
|
+
}
|
|
18
|
+
// tmux swallows unknown escape sequences unless they're wrapped in its DCS
|
|
19
|
+
// passthrough (with every inner ESC doubled). Harmless when not in tmux, but we
|
|
20
|
+
// only wrap when $TMUX is set to keep the common case clean.
|
|
21
|
+
function wrapForTmux(seq) {
|
|
22
|
+
if (!process.env["TMUX"])
|
|
23
|
+
return seq;
|
|
24
|
+
const doubled = seq.split(ESC).join(ESC + ESC);
|
|
25
|
+
return `${ESC}Ptmux;${doubled}${ESC}\\`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Builds the raw iTerm2 SetBadgeFormat escape sequence for `text`. Pure (no I/O)
|
|
29
|
+
* so it can be unit-tested; an empty string clears the badge. The badge format
|
|
30
|
+
* supports `\(...)` interpolation in iTerm2, but plain ids/labels carry no
|
|
31
|
+
* parens so the base64-encoded literal renders verbatim.
|
|
32
|
+
*/
|
|
33
|
+
export function buildBadgeSequence(text) {
|
|
34
|
+
const b64 = Buffer.from(text, "utf8").toString("base64");
|
|
35
|
+
return wrapForTmux(`${ESC}]1337;SetBadgeFormat=${b64}${BEL}`);
|
|
36
|
+
}
|
|
37
|
+
function writeToTty(seq) {
|
|
38
|
+
// We only call this right before spawning Claude / right after it exits,
|
|
39
|
+
// moments when the parent process owns the TTY. Skip when stdout isn't a TTY
|
|
40
|
+
// (piped/CI) — there's no terminal to talk to.
|
|
41
|
+
if (process.stdout.isTTY)
|
|
42
|
+
process.stdout.write(seq);
|
|
43
|
+
}
|
|
44
|
+
/** Sets the iTerm2 badge to `text`. No-op outside iTerm2 or with empty text. */
|
|
45
|
+
export function setITermBadge(text) {
|
|
46
|
+
if (!isITerm() || !text)
|
|
47
|
+
return;
|
|
48
|
+
writeToTty(buildBadgeSequence(text));
|
|
49
|
+
}
|
|
50
|
+
/** Clears the iTerm2 badge. No-op outside iTerm2. */
|
|
51
|
+
export function clearITermBadge() {
|
|
52
|
+
if (!isITerm())
|
|
53
|
+
return;
|
|
54
|
+
writeToTty(buildBadgeSequence(""));
|
|
55
|
+
}
|
package/package.json
CHANGED