@hypercli/hq 0.1.1
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/LICENSE +21 -0
- package/README.md +24 -0
- package/dist/commands/hq/attach.d.ts +10 -0
- package/dist/commands/hq/attach.d.ts.map +1 -0
- package/dist/commands/hq/attach.js +29 -0
- package/dist/commands/hq/attach.js.map +1 -0
- package/dist/commands/hq/config.d.ts +12 -0
- package/dist/commands/hq/config.d.ts.map +1 -0
- package/dist/commands/hq/config.js +56 -0
- package/dist/commands/hq/config.js.map +1 -0
- package/dist/commands/hq/list.d.ts +12 -0
- package/dist/commands/hq/list.d.ts.map +1 -0
- package/dist/commands/hq/list.js +54 -0
- package/dist/commands/hq/list.js.map +1 -0
- package/dist/commands/hq/spawn.d.ts +17 -0
- package/dist/commands/hq/spawn.d.ts.map +1 -0
- package/dist/commands/hq/spawn.js +100 -0
- package/dist/commands/hq/spawn.js.map +1 -0
- package/dist/commands/hq/start.d.ts +14 -0
- package/dist/commands/hq/start.d.ts.map +1 -0
- package/dist/commands/hq/start.js +178 -0
- package/dist/commands/hq/start.js.map +1 -0
- package/dist/commands/hq/status.d.ts +11 -0
- package/dist/commands/hq/status.d.ts.map +1 -0
- package/dist/commands/hq/status.js +34 -0
- package/dist/commands/hq/status.js.map +1 -0
- package/dist/commands/hq/stop-all.d.ts +7 -0
- package/dist/commands/hq/stop-all.d.ts.map +1 -0
- package/dist/commands/hq/stop-all.js +20 -0
- package/dist/commands/hq/stop-all.js.map +1 -0
- package/dist/commands/hq/stop.d.ts +10 -0
- package/dist/commands/hq/stop.d.ts.map +1 -0
- package/dist/commands/hq/stop.js +28 -0
- package/dist/commands/hq/stop.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +59 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +25 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +17 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/setup.d.ts +3 -0
- package/dist/config/setup.d.ts.map +1 -0
- package/dist/config/setup.js +147 -0
- package/dist/config/setup.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/base-command.d.ts +17 -0
- package/dist/lib/base-command.d.ts.map +1 -0
- package/dist/lib/base-command.js +17 -0
- package/dist/lib/base-command.js.map +1 -0
- package/dist/services/claude.d.ts +11 -0
- package/dist/services/claude.d.ts.map +1 -0
- package/dist/services/claude.js +37 -0
- package/dist/services/claude.js.map +1 -0
- package/dist/services/projects.d.ts +20 -0
- package/dist/services/projects.d.ts.map +1 -0
- package/dist/services/projects.js +147 -0
- package/dist/services/projects.js.map +1 -0
- package/dist/services/telegram.d.ts +8 -0
- package/dist/services/telegram.d.ts.map +1 -0
- package/dist/services/telegram.js +26 -0
- package/dist/services/telegram.js.map +1 -0
- package/dist/services/tmux.d.ts +25 -0
- package/dist/services/tmux.d.ts.map +1 -0
- package/dist/services/tmux.js +87 -0
- package/dist/services/tmux.js.map +1 -0
- package/dist/utils/banner.d.ts +7 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +80 -0
- package/dist/utils/banner.js.map +1 -0
- package/dist/utils/log.d.ts +2 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/dist/utils/log.js +5 -0
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/paths.d.ts +4 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +10 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/trust.d.ts +13 -0
- package/dist/utils/trust.d.ts.map +1 -0
- package/dist/utils/trust.js +29 -0
- package/dist/utils/trust.js.map +1 -0
- package/help/hq/attach.md +32 -0
- package/help/hq/config.md +50 -0
- package/help/hq/list.md +42 -0
- package/help/hq/spawn.md +47 -0
- package/help/hq/start.md +39 -0
- package/help/hq/status.md +38 -0
- package/help/hq/stop-all.md +20 -0
- package/help/hq/stop.md +31 -0
- package/help/hq.md +48 -0
- package/oclif.manifest.json +395 -0
- package/package.json +87 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { basename, resolve } from "node:path";
|
|
4
|
+
function isGitRepo(dir) {
|
|
5
|
+
// .git can be a directory (regular repo) or a file (worktree checkout)
|
|
6
|
+
return existsSync(resolve(dir, ".git"));
|
|
7
|
+
}
|
|
8
|
+
function parseWorktreeListPorcelain(output) {
|
|
9
|
+
const worktrees = [];
|
|
10
|
+
let current = {};
|
|
11
|
+
for (const line of output.split("\n")) {
|
|
12
|
+
if (line.startsWith("worktree ")) {
|
|
13
|
+
if (current.path)
|
|
14
|
+
worktrees.push(current);
|
|
15
|
+
current = { path: line.slice(9), isMain: false, isCurrent: false };
|
|
16
|
+
}
|
|
17
|
+
else if (line.startsWith("branch ")) {
|
|
18
|
+
const ref = line.slice(7); // refs/heads/main -> main
|
|
19
|
+
current.branch = ref.replace("refs/heads/", "");
|
|
20
|
+
}
|
|
21
|
+
else if (line === "bare") {
|
|
22
|
+
current.branch = "(bare)";
|
|
23
|
+
}
|
|
24
|
+
else if (line === "detached") {
|
|
25
|
+
current.branch = current.branch ?? "(detached)";
|
|
26
|
+
}
|
|
27
|
+
else if (line === "") {
|
|
28
|
+
// blank line = end of entry
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (current.path)
|
|
32
|
+
worktrees.push(current);
|
|
33
|
+
// Mark first as main
|
|
34
|
+
if (worktrees.length > 0) {
|
|
35
|
+
worktrees[0].isMain = true;
|
|
36
|
+
}
|
|
37
|
+
return worktrees;
|
|
38
|
+
}
|
|
39
|
+
function getWorktrees(projectDir) {
|
|
40
|
+
// Try wt list --format=json first (richer data)
|
|
41
|
+
const wtResult = spawnSync("wt", ["list", "--format=json"], {
|
|
42
|
+
cwd: projectDir,
|
|
43
|
+
encoding: "utf-8",
|
|
44
|
+
timeout: 5000,
|
|
45
|
+
});
|
|
46
|
+
if (wtResult.status === 0 && wtResult.stdout) {
|
|
47
|
+
try {
|
|
48
|
+
const data = JSON.parse(wtResult.stdout);
|
|
49
|
+
return data.map((w) => ({
|
|
50
|
+
path: w.path,
|
|
51
|
+
branch: w.branch,
|
|
52
|
+
isMain: w.is_main,
|
|
53
|
+
isCurrent: w.is_current,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Fall through to git worktree list
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Fallback to git worktree list
|
|
61
|
+
const gitResult = spawnSync("git", ["worktree", "list", "--porcelain"], {
|
|
62
|
+
cwd: projectDir,
|
|
63
|
+
encoding: "utf-8",
|
|
64
|
+
timeout: 5000,
|
|
65
|
+
});
|
|
66
|
+
if (gitResult.status === 0 && gitResult.stdout) {
|
|
67
|
+
return parseWorktreeListPorcelain(gitResult.stdout);
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
function discoverDir(dir, namePrefix, config) {
|
|
72
|
+
const projects = [];
|
|
73
|
+
let entries;
|
|
74
|
+
try {
|
|
75
|
+
entries = readdirSync(dir).filter((e) => {
|
|
76
|
+
const full = resolve(dir, e);
|
|
77
|
+
return statSync(full).isDirectory() && !e.startsWith(".");
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return projects;
|
|
82
|
+
}
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
const fullPath = resolve(dir, entry);
|
|
85
|
+
const projectName = namePrefix ? `${namePrefix}/${entry}` : entry;
|
|
86
|
+
const override = config.projects[entry];
|
|
87
|
+
// If configured as a group, recurse
|
|
88
|
+
if (override?.type === "group") {
|
|
89
|
+
projects.push(...discoverDir(fullPath, projectName, config));
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const git = isGitRepo(fullPath);
|
|
93
|
+
let worktrees = [];
|
|
94
|
+
let hasWorktrees = false;
|
|
95
|
+
if (git) {
|
|
96
|
+
worktrees = getWorktrees(fullPath);
|
|
97
|
+
hasWorktrees = worktrees.length > 1;
|
|
98
|
+
}
|
|
99
|
+
projects.push({
|
|
100
|
+
name: projectName,
|
|
101
|
+
path: fullPath,
|
|
102
|
+
isGit: git,
|
|
103
|
+
hasWorktrees,
|
|
104
|
+
worktrees,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return projects.sort((a, b) => a.name.localeCompare(b.name));
|
|
108
|
+
}
|
|
109
|
+
export function listProjects(config) {
|
|
110
|
+
return discoverDir(config.projects_root, "", config);
|
|
111
|
+
}
|
|
112
|
+
export function findProject(name, config) {
|
|
113
|
+
const projects = listProjects(config);
|
|
114
|
+
return projects.find((p) => p.name === name);
|
|
115
|
+
}
|
|
116
|
+
export function resolveProjectDir(project, config) {
|
|
117
|
+
if (project.startsWith("/"))
|
|
118
|
+
return project;
|
|
119
|
+
return resolve(config.projects_root, project);
|
|
120
|
+
}
|
|
121
|
+
export function createWorktree(projectDir, branch) {
|
|
122
|
+
const result = spawnSync("wt", ["switch", "-c", branch], {
|
|
123
|
+
cwd: projectDir,
|
|
124
|
+
encoding: "utf-8",
|
|
125
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
126
|
+
timeout: 30_000,
|
|
127
|
+
});
|
|
128
|
+
if (result.status !== 0) {
|
|
129
|
+
throw new Error(`Failed to create worktree '${branch}': ${result.stderr}`);
|
|
130
|
+
}
|
|
131
|
+
// wt switch changes directory — get the new worktree path
|
|
132
|
+
// Parse it from wt list
|
|
133
|
+
const worktrees = getWorktrees(projectDir);
|
|
134
|
+
const wt = worktrees.find((w) => w.branch === branch);
|
|
135
|
+
if (wt)
|
|
136
|
+
return wt.path;
|
|
137
|
+
// Fallback: construct path from worktrunk convention (sibling dir)
|
|
138
|
+
const repoName = basename(projectDir);
|
|
139
|
+
const sanitizedBranch = branch.replace(/\//g, "-");
|
|
140
|
+
return resolve(projectDir, "..", `${repoName}.${sanitizedBranch}`);
|
|
141
|
+
}
|
|
142
|
+
export function findWorktreePath(projectDir, branchOrName) {
|
|
143
|
+
const worktrees = getWorktrees(projectDir);
|
|
144
|
+
const match = worktrees.find((w) => w.branch === branchOrName || basename(w.path) === branchOrName);
|
|
145
|
+
return match?.path;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/services/projects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HqConfig } from "../config/schema.js";
|
|
2
|
+
export interface TelegramEnv {
|
|
3
|
+
TELEGRAM_BOT_TOKEN: string;
|
|
4
|
+
TELEGRAM_STATE_DIR: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getHqTelegramEnv(config: HqConfig): TelegramEnv | null;
|
|
7
|
+
export declare function getProjectTelegramEnv(projectName: string, config: HqConfig): TelegramEnv | null;
|
|
8
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/services/telegram.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AAID,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAQrE;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAU/F"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
const TELEGRAM_STATE_ROOT = resolve(homedir(), ".config/hyper/hq-telegram-state");
|
|
5
|
+
export function getHqTelegramEnv(config) {
|
|
6
|
+
if (!config.telegram.hq_bot_token)
|
|
7
|
+
return null;
|
|
8
|
+
const stateDir = resolve(TELEGRAM_STATE_ROOT, "hq");
|
|
9
|
+
mkdirSync(stateDir, { recursive: true });
|
|
10
|
+
return {
|
|
11
|
+
TELEGRAM_BOT_TOKEN: config.telegram.hq_bot_token,
|
|
12
|
+
TELEGRAM_STATE_DIR: stateDir,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function getProjectTelegramEnv(projectName, config) {
|
|
16
|
+
const token = config.telegram.project_bots[projectName];
|
|
17
|
+
if (!token)
|
|
18
|
+
return null;
|
|
19
|
+
const stateDir = resolve(TELEGRAM_STATE_ROOT, projectName);
|
|
20
|
+
mkdirSync(stateDir, { recursive: true });
|
|
21
|
+
return {
|
|
22
|
+
TELEGRAM_BOT_TOKEN: token,
|
|
23
|
+
TELEGRAM_STATE_DIR: stateDir,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/services/telegram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,MAAM,mBAAmB,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,iCAAiC,CAAC,CAAC;AAElF,MAAM,UAAU,gBAAgB,CAAC,MAAgB;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;IACpD,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,OAAO;QACN,kBAAkB,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY;QAChD,kBAAkB,EAAE,QAAQ;KAC5B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,WAAmB,EAAE,MAAgB;IAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,QAAQ,GAAG,OAAO,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IAC3D,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,OAAO;QACN,kBAAkB,EAAE,KAAK;QACzB,kBAAkB,EAAE,QAAQ;KAC5B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface TmuxSession {
|
|
2
|
+
name: string;
|
|
3
|
+
created: string;
|
|
4
|
+
windows: number;
|
|
5
|
+
attached: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Sanitize a string for use as a tmux session name (no dots or colons) */
|
|
8
|
+
export declare function sanitizeSessionName(name: string): string;
|
|
9
|
+
export declare function sessionExists(name: string): boolean;
|
|
10
|
+
export declare function createSession(opts: {
|
|
11
|
+
name: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
command: string;
|
|
14
|
+
}): void;
|
|
15
|
+
/**
|
|
16
|
+
* Wait and verify a session's command is still running.
|
|
17
|
+
* Polls for up to `timeoutMs`, checking every 500ms.
|
|
18
|
+
* Returns `'running'` if alive, `'dead'` if the pane's command exited.
|
|
19
|
+
*/
|
|
20
|
+
export declare function waitAndVerify(name: string, timeoutMs?: number): "running" | "dead";
|
|
21
|
+
export declare function killSession(name: string): boolean;
|
|
22
|
+
export declare function listSessions(prefix?: string): TmuxSession[];
|
|
23
|
+
export declare function disableRemainOnExit(name: string): void;
|
|
24
|
+
export declare function attachSession(name: string): never;
|
|
25
|
+
//# sourceMappingURL=tmux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../../src/services/tmux.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAWD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmBxF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,SAAS,GAAG,MAAM,CAkBhF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,YAAY,CAAC,MAAM,SAAU,GAAG,WAAW,EAAE,CAkB5D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAGjD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
+
/** Sanitize a string for use as a tmux session name (no dots or colons) */
|
|
3
|
+
export function sanitizeSessionName(name) {
|
|
4
|
+
return name.replace(/[.:]/g, "-");
|
|
5
|
+
}
|
|
6
|
+
function run(args) {
|
|
7
|
+
const result = spawnSync("tmux", args, { encoding: "utf-8" });
|
|
8
|
+
return {
|
|
9
|
+
ok: result.status === 0,
|
|
10
|
+
stdout: (result.stdout ?? "").trim(),
|
|
11
|
+
stderr: (result.stderr ?? "").trim(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function sessionExists(name) {
|
|
15
|
+
return run(["has-session", "-t", name]).ok;
|
|
16
|
+
}
|
|
17
|
+
export function createSession(opts) {
|
|
18
|
+
// Use remain-on-exit so the pane stays around if the command fails,
|
|
19
|
+
// allowing us to read the exit status and show a useful error.
|
|
20
|
+
const result = run([
|
|
21
|
+
"new-session",
|
|
22
|
+
"-d",
|
|
23
|
+
"-s",
|
|
24
|
+
opts.name,
|
|
25
|
+
"-c",
|
|
26
|
+
opts.cwd,
|
|
27
|
+
"-e",
|
|
28
|
+
"CLINT_SESSION=1",
|
|
29
|
+
opts.command,
|
|
30
|
+
]);
|
|
31
|
+
if (!result.ok) {
|
|
32
|
+
throw new Error(`Failed to create tmux session '${opts.name}': ${result.stderr}`);
|
|
33
|
+
}
|
|
34
|
+
// Keep the pane alive after the command exits so we can detect failures
|
|
35
|
+
run(["set-option", "-t", opts.name, "remain-on-exit", "on"]);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Wait and verify a session's command is still running.
|
|
39
|
+
* Polls for up to `timeoutMs`, checking every 500ms.
|
|
40
|
+
* Returns `'running'` if alive, `'dead'` if the pane's command exited.
|
|
41
|
+
*/
|
|
42
|
+
export function waitAndVerify(name, timeoutMs = 5000) {
|
|
43
|
+
const start = Date.now();
|
|
44
|
+
while (Date.now() - start < timeoutMs) {
|
|
45
|
+
spawnSync("sleep", ["0.5"]);
|
|
46
|
+
// Check if session still exists at all
|
|
47
|
+
if (!sessionExists(name))
|
|
48
|
+
return "dead";
|
|
49
|
+
// Check if the pane process is still running
|
|
50
|
+
const paneResult = run(["list-panes", "-t", name, "-F", "#{pane_dead}"]);
|
|
51
|
+
if (paneResult.ok && paneResult.stdout.trim() === "1") {
|
|
52
|
+
// Pane is dead — command exited. Clean up the session.
|
|
53
|
+
killSession(name);
|
|
54
|
+
return "dead";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return "running";
|
|
58
|
+
}
|
|
59
|
+
export function killSession(name) {
|
|
60
|
+
return run(["kill-session", "-t", name]).ok;
|
|
61
|
+
}
|
|
62
|
+
export function listSessions(prefix = "clint") {
|
|
63
|
+
const format = "#{session_name}\t#{session_created_string}\t#{session_windows}\t#{?session_attached,1,0}";
|
|
64
|
+
const result = run(["list-sessions", "-F", format]);
|
|
65
|
+
if (!result.ok)
|
|
66
|
+
return [];
|
|
67
|
+
return result.stdout
|
|
68
|
+
.split("\n")
|
|
69
|
+
.filter((line) => line.startsWith(prefix))
|
|
70
|
+
.map((line) => {
|
|
71
|
+
const [name, created, windows, attached] = line.split("\t");
|
|
72
|
+
return {
|
|
73
|
+
name: name,
|
|
74
|
+
created: created,
|
|
75
|
+
windows: Number.parseInt(windows, 10),
|
|
76
|
+
attached: attached === "1",
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export function disableRemainOnExit(name) {
|
|
81
|
+
run(["set-option", "-t", name, "remain-on-exit", "off"]);
|
|
82
|
+
}
|
|
83
|
+
export function attachSession(name) {
|
|
84
|
+
execFileSync("tmux", ["attach", "-t", name], { stdio: "inherit" });
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=tmux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/services/tmux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../src/utils/banner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAwBpD,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA4DT"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { CONFIG_PATH } from "../config/index.js";
|
|
4
|
+
import { listProjects } from "../services/projects.js";
|
|
5
|
+
function shorten(path) {
|
|
6
|
+
const home = homedir();
|
|
7
|
+
if (path.startsWith(home))
|
|
8
|
+
return `~${path.slice(home.length)}`;
|
|
9
|
+
return path;
|
|
10
|
+
}
|
|
11
|
+
function extractBridgeUrl(logFile) {
|
|
12
|
+
try {
|
|
13
|
+
const content = readFileSync(logFile, "utf-8");
|
|
14
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: need to strip ANSI escape codes from tmux log
|
|
15
|
+
const matches = content.match(/https:\/\/claude\.ai\/code\?bridge=[^\s\x1b]*/g);
|
|
16
|
+
if (matches && matches.length > 0)
|
|
17
|
+
return matches[matches.length - 1];
|
|
18
|
+
}
|
|
19
|
+
catch { }
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function pad(label, value, width) {
|
|
23
|
+
const content = ` ${label}${value}`;
|
|
24
|
+
return `║${content.padEnd(width)}║`;
|
|
25
|
+
}
|
|
26
|
+
export function renderBanner(opts) {
|
|
27
|
+
const { config, sessionName, logFile } = opts;
|
|
28
|
+
let projectCount;
|
|
29
|
+
try {
|
|
30
|
+
projectCount = listProjects(config).length;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
projectCount = 0;
|
|
34
|
+
}
|
|
35
|
+
const telegramStatus = config.telegram.hq_bot_token ? "enabled" : "disabled";
|
|
36
|
+
const bridgeUrl = extractBridgeUrl(logFile);
|
|
37
|
+
const connectValue = bridgeUrl ?? `claude.ai/code → ${sessionName}`;
|
|
38
|
+
// Build content rows to determine width
|
|
39
|
+
const rows = [
|
|
40
|
+
["Config: ", shorten(CONFIG_PATH)],
|
|
41
|
+
["Projects: ", `${shorten(config.projects_root)} (${projectCount} found)`],
|
|
42
|
+
["Telegram: ", telegramStatus],
|
|
43
|
+
null,
|
|
44
|
+
["Session: ", sessionName],
|
|
45
|
+
["Connect: ", connectValue],
|
|
46
|
+
null,
|
|
47
|
+
["Commands:", ""],
|
|
48
|
+
[" hyper hq list", " List projects"],
|
|
49
|
+
[" hyper hq spawn <name>", " Start project session"],
|
|
50
|
+
[" hyper hq status", " Show running sessions"],
|
|
51
|
+
[" hyper hq attach", " Attach to HQ terminal"],
|
|
52
|
+
[" hyper hq config", " Show configuration"],
|
|
53
|
+
[" hyper hq stop-all", " Stop everything"],
|
|
54
|
+
];
|
|
55
|
+
const title = " Hyper HQ — Claude Code Command Center";
|
|
56
|
+
// Calculate width: widest content + 2 for padding
|
|
57
|
+
let maxContent = title.length;
|
|
58
|
+
for (const row of rows) {
|
|
59
|
+
if (row) {
|
|
60
|
+
const len = ` ${row[0]}${row[1]}`.length;
|
|
61
|
+
if (len > maxContent)
|
|
62
|
+
maxContent = len;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const w = maxContent + 2; // inner width with padding
|
|
66
|
+
const bar = "═".repeat(w);
|
|
67
|
+
const empty = `║${" ".repeat(w)}║`;
|
|
68
|
+
const lines = ["", `╔${bar}╗`, `║${title.padEnd(w)}║`, `╠${bar}╣`, empty];
|
|
69
|
+
for (const row of rows) {
|
|
70
|
+
if (row === null) {
|
|
71
|
+
lines.push(empty);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
lines.push(pad(row[0], row[1], w));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
lines.push(empty, `╚${bar}╝`, "");
|
|
78
|
+
return lines.join("\n");
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/utils/banner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGzC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,CAAC,OAAe;IAClC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,QAAsC,CAAC;AAC/D,eAAO,MAAM,OAAO,QAA+B,CAAC;AAEpD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
export const HQ_DATA_DIR = resolve(homedir(), ".config/hyper");
|
|
4
|
+
export const LOG_DIR = resolve(HQ_DATA_DIR, "logs");
|
|
5
|
+
export function expandHome(p) {
|
|
6
|
+
if (p.startsWith("~/"))
|
|
7
|
+
return resolve(homedir(), p.slice(2));
|
|
8
|
+
return p;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAEpD,MAAM,UAAU,UAAU,CAAC,CAAS;IACnC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a directory (or any ancestor) is trusted by Claude Code.
|
|
3
|
+
* Workspace trust is stored as project dirs under ~/.claude/projects/
|
|
4
|
+
* with path encoded using dashes (e.g. /Users/foo/work → -Users-foo-work).
|
|
5
|
+
* Subdirectories of trusted workspaces are also trusted.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isWorkspaceTrusted(dir: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Trust a directory for Claude Code by creating its project entry.
|
|
10
|
+
* This is equivalent to running `claude` in the directory and accepting the trust dialog.
|
|
11
|
+
*/
|
|
12
|
+
export declare function trustWorkspace(dir: string): void;
|
|
13
|
+
//# sourceMappingURL=trust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../src/utils/trust.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGhD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
const CLAUDE_PROJECTS_DIR = resolve(homedir(), ".claude/projects");
|
|
5
|
+
/**
|
|
6
|
+
* Check if a directory (or any ancestor) is trusted by Claude Code.
|
|
7
|
+
* Workspace trust is stored as project dirs under ~/.claude/projects/
|
|
8
|
+
* with path encoded using dashes (e.g. /Users/foo/work → -Users-foo-work).
|
|
9
|
+
* Subdirectories of trusted workspaces are also trusted.
|
|
10
|
+
*/
|
|
11
|
+
export function isWorkspaceTrusted(dir) {
|
|
12
|
+
let current = dir;
|
|
13
|
+
while (current !== "/") {
|
|
14
|
+
const encoded = current.replace(/\//g, "-");
|
|
15
|
+
if (existsSync(resolve(CLAUDE_PROJECTS_DIR, encoded)))
|
|
16
|
+
return true;
|
|
17
|
+
current = dirname(current);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Trust a directory for Claude Code by creating its project entry.
|
|
23
|
+
* This is equivalent to running `claude` in the directory and accepting the trust dialog.
|
|
24
|
+
*/
|
|
25
|
+
export function trustWorkspace(dir) {
|
|
26
|
+
const encoded = dir.replace(/\//g, "-");
|
|
27
|
+
mkdirSync(resolve(CLAUDE_PROJECTS_DIR, encoded), { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=trust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.js","sourceRoot":"","sources":["../../src/utils/trust.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,mBAAmB,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC7C,IAAI,OAAO,GAAG,GAAG,CAAC;IAClB,OAAO,OAAO,KAAK,GAAG,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,OAAO,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACnE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,CAAC,mBAAmB,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# hyper hq attach
|
|
2
|
+
|
|
3
|
+
Attach to an HQ tmux session in your current terminal.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
`hyper hq attach [session]`
|
|
8
|
+
|
|
9
|
+
## Arguments
|
|
10
|
+
|
|
11
|
+
| Argument | Description |
|
|
12
|
+
|----------|-------------|
|
|
13
|
+
| `session` | Session name or project name (default: `hyper-hq`) |
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
# Attach to the main HQ session
|
|
19
|
+
hyper hq attach
|
|
20
|
+
|
|
21
|
+
# Attach to a project session by project name
|
|
22
|
+
hyper hq attach my-project
|
|
23
|
+
|
|
24
|
+
# Attach using the full session name
|
|
25
|
+
hyper hq attach hq-my-project
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Notes
|
|
29
|
+
|
|
30
|
+
- If the argument does not start with `hq`, the prefix `hq-` is added automatically — so `hyper hq attach my-project` targets the session named `hq-my-project`.
|
|
31
|
+
- Requires tmux to be installed and the session to already be running. Use `hyper hq status` to list active sessions.
|
|
32
|
+
- Detach from the session with `Ctrl-b d` (standard tmux detach).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# hyper hq config
|
|
2
|
+
|
|
3
|
+
Show HQ configuration.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
`hyper hq config [flags]`
|
|
8
|
+
|
|
9
|
+
## Flags
|
|
10
|
+
|
|
11
|
+
| Flag | Description |
|
|
12
|
+
|------|-------------|
|
|
13
|
+
| `--json` | Output as JSON |
|
|
14
|
+
| `--path` | Print the config file path only |
|
|
15
|
+
|
|
16
|
+
## Examples
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
# Show configuration summary
|
|
20
|
+
hyper hq config
|
|
21
|
+
|
|
22
|
+
# Print raw JSON
|
|
23
|
+
hyper hq config --json
|
|
24
|
+
|
|
25
|
+
# Print the config file path (useful for editors)
|
|
26
|
+
hyper hq config --path
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Output
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Config file: /home/user/.config/hyper/hq.toml
|
|
33
|
+
|
|
34
|
+
projects_root /home/user/projects
|
|
35
|
+
hq.name hyper-hq
|
|
36
|
+
hq.dir /home/user/.config/hyper/hq
|
|
37
|
+
hq.spawn_mode same-dir
|
|
38
|
+
hq.capacity 8
|
|
39
|
+
claude.mode default
|
|
40
|
+
telegram enabled (HQ bot configured)
|
|
41
|
+
project bots 3 project bot(s)
|
|
42
|
+
project groups none
|
|
43
|
+
|
|
44
|
+
Edit: /home/user/.config/hyper/hq.toml
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Notes
|
|
48
|
+
|
|
49
|
+
- If no config file exists yet, the command tells you to run `hyper hq start` to create one via the setup wizard.
|
|
50
|
+
- To edit settings directly, open the config file path shown in the output.
|
package/help/hq/list.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# hyper hq list
|
|
2
|
+
|
|
3
|
+
List available projects and their worktrees.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
`hyper hq list [flags]`
|
|
8
|
+
|
|
9
|
+
## Flags
|
|
10
|
+
|
|
11
|
+
| Flag | Description |
|
|
12
|
+
|------|-------------|
|
|
13
|
+
| `--root <dir>` | Override the projects root directory |
|
|
14
|
+
| `--json` | Output as JSON |
|
|
15
|
+
|
|
16
|
+
## Examples
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
# List all projects
|
|
20
|
+
hyper hq list
|
|
21
|
+
|
|
22
|
+
# Output as JSON (useful for scripting or HQ's internal use)
|
|
23
|
+
hyper hq list --json
|
|
24
|
+
|
|
25
|
+
# List projects from a different root
|
|
26
|
+
hyper hq list --root /path/to/projects
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Output
|
|
30
|
+
|
|
31
|
+
The default view shows each project with git and worktree metadata:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Projects (/home/user/projects)
|
|
35
|
+
──────────────────────────────────────────────────
|
|
36
|
+
my-app (git, 2 worktrees)
|
|
37
|
+
├─ main * /home/user/projects/my-app
|
|
38
|
+
└─ feat-auth /home/user/.worktrees/my-app/feat-auth
|
|
39
|
+
another-project (git)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
A `*` marks the main worktree.
|