@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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -0
  3. package/dist/commands/hq/attach.d.ts +10 -0
  4. package/dist/commands/hq/attach.d.ts.map +1 -0
  5. package/dist/commands/hq/attach.js +29 -0
  6. package/dist/commands/hq/attach.js.map +1 -0
  7. package/dist/commands/hq/config.d.ts +12 -0
  8. package/dist/commands/hq/config.d.ts.map +1 -0
  9. package/dist/commands/hq/config.js +56 -0
  10. package/dist/commands/hq/config.js.map +1 -0
  11. package/dist/commands/hq/list.d.ts +12 -0
  12. package/dist/commands/hq/list.d.ts.map +1 -0
  13. package/dist/commands/hq/list.js +54 -0
  14. package/dist/commands/hq/list.js.map +1 -0
  15. package/dist/commands/hq/spawn.d.ts +17 -0
  16. package/dist/commands/hq/spawn.d.ts.map +1 -0
  17. package/dist/commands/hq/spawn.js +100 -0
  18. package/dist/commands/hq/spawn.js.map +1 -0
  19. package/dist/commands/hq/start.d.ts +14 -0
  20. package/dist/commands/hq/start.d.ts.map +1 -0
  21. package/dist/commands/hq/start.js +178 -0
  22. package/dist/commands/hq/start.js.map +1 -0
  23. package/dist/commands/hq/status.d.ts +11 -0
  24. package/dist/commands/hq/status.d.ts.map +1 -0
  25. package/dist/commands/hq/status.js +34 -0
  26. package/dist/commands/hq/status.js.map +1 -0
  27. package/dist/commands/hq/stop-all.d.ts +7 -0
  28. package/dist/commands/hq/stop-all.d.ts.map +1 -0
  29. package/dist/commands/hq/stop-all.js +20 -0
  30. package/dist/commands/hq/stop-all.js.map +1 -0
  31. package/dist/commands/hq/stop.d.ts +10 -0
  32. package/dist/commands/hq/stop.d.ts.map +1 -0
  33. package/dist/commands/hq/stop.js +28 -0
  34. package/dist/commands/hq/stop.js.map +1 -0
  35. package/dist/config/index.d.ts +6 -0
  36. package/dist/config/index.d.ts.map +1 -0
  37. package/dist/config/index.js +59 -0
  38. package/dist/config/index.js.map +1 -0
  39. package/dist/config/schema.d.ts +25 -0
  40. package/dist/config/schema.d.ts.map +1 -0
  41. package/dist/config/schema.js +17 -0
  42. package/dist/config/schema.js.map +1 -0
  43. package/dist/config/setup.d.ts +3 -0
  44. package/dist/config/setup.d.ts.map +1 -0
  45. package/dist/config/setup.js +147 -0
  46. package/dist/config/setup.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +4 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/lib/base-command.d.ts +17 -0
  52. package/dist/lib/base-command.d.ts.map +1 -0
  53. package/dist/lib/base-command.js +17 -0
  54. package/dist/lib/base-command.js.map +1 -0
  55. package/dist/services/claude.d.ts +11 -0
  56. package/dist/services/claude.d.ts.map +1 -0
  57. package/dist/services/claude.js +37 -0
  58. package/dist/services/claude.js.map +1 -0
  59. package/dist/services/projects.d.ts +20 -0
  60. package/dist/services/projects.d.ts.map +1 -0
  61. package/dist/services/projects.js +147 -0
  62. package/dist/services/projects.js.map +1 -0
  63. package/dist/services/telegram.d.ts +8 -0
  64. package/dist/services/telegram.d.ts.map +1 -0
  65. package/dist/services/telegram.js +26 -0
  66. package/dist/services/telegram.js.map +1 -0
  67. package/dist/services/tmux.d.ts +25 -0
  68. package/dist/services/tmux.d.ts.map +1 -0
  69. package/dist/services/tmux.js +87 -0
  70. package/dist/services/tmux.js.map +1 -0
  71. package/dist/utils/banner.d.ts +7 -0
  72. package/dist/utils/banner.d.ts.map +1 -0
  73. package/dist/utils/banner.js +80 -0
  74. package/dist/utils/banner.js.map +1 -0
  75. package/dist/utils/log.d.ts +2 -0
  76. package/dist/utils/log.d.ts.map +1 -0
  77. package/dist/utils/log.js +5 -0
  78. package/dist/utils/log.js.map +1 -0
  79. package/dist/utils/paths.d.ts +4 -0
  80. package/dist/utils/paths.d.ts.map +1 -0
  81. package/dist/utils/paths.js +10 -0
  82. package/dist/utils/paths.js.map +1 -0
  83. package/dist/utils/trust.d.ts +13 -0
  84. package/dist/utils/trust.d.ts.map +1 -0
  85. package/dist/utils/trust.js +29 -0
  86. package/dist/utils/trust.js.map +1 -0
  87. package/help/hq/attach.md +32 -0
  88. package/help/hq/config.md +50 -0
  89. package/help/hq/list.md +42 -0
  90. package/help/hq/spawn.md +47 -0
  91. package/help/hq/start.md +39 -0
  92. package/help/hq/status.md +38 -0
  93. package/help/hq/stop-all.md +20 -0
  94. package/help/hq/stop.md +31 -0
  95. package/help/hq.md +48 -0
  96. package/oclif.manifest.json +395 -0
  97. 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,7 @@
1
+ import type { HqConfig } from "../config/schema.js";
2
+ export declare function renderBanner(opts: {
3
+ config: HqConfig;
4
+ sessionName: string;
5
+ logFile: string;
6
+ }): string;
7
+ //# sourceMappingURL=banner.d.ts.map
@@ -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,2 @@
1
+ export declare function log(message: string): void;
2
+ //# sourceMappingURL=log.d.ts.map
@@ -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,5 @@
1
+ export function log(message) {
2
+ const ts = new Date().toISOString().replace("T", " ").slice(0, 19);
3
+ console.log(`[${ts}] ${message}`);
4
+ }
5
+ //# sourceMappingURL=log.js.map
@@ -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,4 @@
1
+ export declare const HQ_DATA_DIR: string;
2
+ export declare const LOG_DIR: string;
3
+ export declare function expandHome(p: string): string;
4
+ //# sourceMappingURL=paths.d.ts.map
@@ -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.
@@ -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.