@xerktech/claude-hud 0.1.0

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 (60) hide show
  1. package/README.md +50 -0
  2. package/dist/_broker/attached.js +78 -0
  3. package/dist/_broker/attached.js.map +1 -0
  4. package/dist/_broker/audio-codec.js +82 -0
  5. package/dist/_broker/audio-codec.js.map +1 -0
  6. package/dist/_broker/audio-session.js +81 -0
  7. package/dist/_broker/audio-session.js.map +1 -0
  8. package/dist/_broker/auth.js +32 -0
  9. package/dist/_broker/auth.js.map +1 -0
  10. package/dist/_broker/bus.js +76 -0
  11. package/dist/_broker/bus.js.map +1 -0
  12. package/dist/_broker/cert.js +72 -0
  13. package/dist/_broker/cert.js.map +1 -0
  14. package/dist/_broker/claude.js +160 -0
  15. package/dist/_broker/claude.js.map +1 -0
  16. package/dist/_broker/cli.js +134 -0
  17. package/dist/_broker/cli.js.map +1 -0
  18. package/dist/_broker/cors.js +48 -0
  19. package/dist/_broker/cors.js.map +1 -0
  20. package/dist/_broker/hooks.js +196 -0
  21. package/dist/_broker/hooks.js.map +1 -0
  22. package/dist/_broker/index.js +48 -0
  23. package/dist/_broker/index.js.map +1 -0
  24. package/dist/_broker/intent-dispatcher.js +86 -0
  25. package/dist/_broker/intent-dispatcher.js.map +1 -0
  26. package/dist/_broker/intent.js +127 -0
  27. package/dist/_broker/intent.js.map +1 -0
  28. package/dist/_broker/jsonl-tail.js +185 -0
  29. package/dist/_broker/jsonl-tail.js.map +1 -0
  30. package/dist/_broker/mdns.js +41 -0
  31. package/dist/_broker/mdns.js.map +1 -0
  32. package/dist/_broker/projects.js +161 -0
  33. package/dist/_broker/projects.js.map +1 -0
  34. package/dist/_broker/qr.js +11 -0
  35. package/dist/_broker/qr.js.map +1 -0
  36. package/dist/_broker/routes.js +379 -0
  37. package/dist/_broker/routes.js.map +1 -0
  38. package/dist/_broker/server.js +325 -0
  39. package/dist/_broker/server.js.map +1 -0
  40. package/dist/_broker/sessions-store.js +50 -0
  41. package/dist/_broker/sessions-store.js.map +1 -0
  42. package/dist/_broker/sessions.js +792 -0
  43. package/dist/_broker/sessions.js.map +1 -0
  44. package/dist/_broker/store.js +79 -0
  45. package/dist/_broker/store.js.map +1 -0
  46. package/dist/_broker/stt.js +93 -0
  47. package/dist/_broker/stt.js.map +1 -0
  48. package/dist/broker-bin.js +37 -0
  49. package/dist/broker-bin.js.map +1 -0
  50. package/dist/broker-lifecycle.js +186 -0
  51. package/dist/broker-lifecycle.js.map +1 -0
  52. package/dist/index.js +189 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/paths.js +17 -0
  55. package/dist/paths.js.map +1 -0
  56. package/dist/wrapper/index.js +263 -0
  57. package/dist/wrapper/index.js.map +1 -0
  58. package/dist/wrapper/slug.js +5 -0
  59. package/dist/wrapper/slug.js.map +1 -0
  60. package/package.json +70 -0
package/dist/index.js ADDED
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import process from 'node:process';
5
+ import qrcode from 'qrcode-terminal';
6
+ import { Store } from './_broker/store.js';
7
+ import { stateDir, pidFile, logFile } from "./paths.js";
8
+ import { ensureBrokerRunning, brokerStatus, stopBroker } from "./broker-lifecycle.js";
9
+ import { runWrapped } from "./wrapper/index.js";
10
+ const DEFAULT_IO = {
11
+ stdout: line => process.stdout.write(line + '\n'),
12
+ stderr: line => process.stderr.write(line + '\n'),
13
+ };
14
+ export async function runCli(argv, io = DEFAULT_IO) {
15
+ const [first, ...rest] = argv;
16
+ switch (first) {
17
+ case undefined:
18
+ return await runDefault([], io);
19
+ case 'pair':
20
+ return await cmdPair(io);
21
+ case 'broker':
22
+ return await cmdBroker(rest, io);
23
+ case '--help':
24
+ case '-h':
25
+ case 'help':
26
+ io.stdout(usage());
27
+ return 0;
28
+ default:
29
+ // Everything else is pass-through to `claude` — `claude-hud --resume X`
30
+ // is the same as `claude --resume X` plus broker attachment.
31
+ return await runDefault([first, ...rest], io);
32
+ }
33
+ }
34
+ function usage() {
35
+ return [
36
+ 'usage:',
37
+ ' claude-hud [<claude-args>...] run claude here and attach to the glasses',
38
+ ' claude-hud pair re-show the pairing QR for the broker',
39
+ ' claude-hud broker stop stop the detached broker',
40
+ ' claude-hud broker status report whether the broker is up',
41
+ ' claude-hud broker logs tail the detached broker log',
42
+ ].join('\n');
43
+ }
44
+ async function runDefault(passThroughArgv, io) {
45
+ // 1. Ensure the broker is up (spawn detached if not).
46
+ let lifecycle;
47
+ try {
48
+ lifecycle = await ensureBrokerRunning();
49
+ }
50
+ catch (err) {
51
+ io.stderr(`[claude-hud] broker did not start: ${err.message}`);
52
+ io.stderr(` log: ${logFile()}`);
53
+ return 1;
54
+ }
55
+ // 2. Register this cwd with the broker (idempotent).
56
+ const cwd = process.cwd();
57
+ const project = await ensureProject(lifecycle.url, lifecycle.token, cwd);
58
+ if (!project) {
59
+ io.stderr('[claude-hud] failed to register project with the broker');
60
+ return 1;
61
+ }
62
+ // 3. First-time pairing — print the QR until the user has scanned it once.
63
+ await maybePrintPairingQr(lifecycle.url, lifecycle.token, io);
64
+ if (lifecycle.spawned) {
65
+ io.stdout(`[claude-hud] broker started at ${lifecycle.url} (pid ${lifecycle.pid})`);
66
+ }
67
+ // 4. Run claude inside the wrapper.
68
+ const exitCode = await runWrapped({
69
+ argv: passThroughArgv,
70
+ brokerUrl: lifecycle.url,
71
+ token: lifecycle.token,
72
+ cwd,
73
+ projectId: project.id,
74
+ label: project.label,
75
+ });
76
+ return exitCode;
77
+ }
78
+ async function cmdPair(io) {
79
+ let lifecycle;
80
+ try {
81
+ lifecycle = await ensureBrokerRunning();
82
+ }
83
+ catch (err) {
84
+ io.stderr(`[claude-hud] broker did not start: ${err.message}`);
85
+ return 1;
86
+ }
87
+ const store = new Store(stateDir());
88
+ store.update(s => {
89
+ s.paired = false;
90
+ });
91
+ printPairingQr({ url: lifecycle.url, token: lifecycle.token }, io);
92
+ store.update(s => {
93
+ s.paired = true;
94
+ });
95
+ return 0;
96
+ }
97
+ async function cmdBroker(args, io) {
98
+ const [sub] = args;
99
+ switch (sub) {
100
+ case 'stop': {
101
+ const stopped = await stopBroker();
102
+ io.stdout(stopped ? '[claude-hud] broker stopped' : '[claude-hud] broker was not running');
103
+ return 0;
104
+ }
105
+ case 'status': {
106
+ const status = await brokerStatus();
107
+ if (status.running) {
108
+ io.stdout(`broker: running (pid ${status.pid}) at ${status.url}`);
109
+ return 0;
110
+ }
111
+ io.stdout(`broker: not running (${status.reason})`);
112
+ return 0;
113
+ }
114
+ case 'logs': {
115
+ const file = logFile();
116
+ if (!fs.existsSync(file)) {
117
+ io.stdout('(no broker log yet)');
118
+ return 0;
119
+ }
120
+ io.stdout(fs.readFileSync(file, 'utf8'));
121
+ return 0;
122
+ }
123
+ default:
124
+ io.stderr(`unknown broker subcommand: ${sub ?? '(missing)'}`);
125
+ io.stderr('usage: claude-hud broker stop|status|logs');
126
+ return 2;
127
+ }
128
+ }
129
+ async function ensureProject(brokerUrl, token, cwd) {
130
+ // Allow self-signed certs the broker generated locally.
131
+ const prev = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
132
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
133
+ try {
134
+ const res = await fetch(`${brokerUrl}/api/projects/ensure`, {
135
+ method: 'POST',
136
+ headers: {
137
+ Authorization: `Bearer ${token}`,
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ body: JSON.stringify({ cwd }),
141
+ });
142
+ if (!res.ok)
143
+ return null;
144
+ return (await res.json());
145
+ }
146
+ catch {
147
+ return null;
148
+ }
149
+ finally {
150
+ if (prev === undefined)
151
+ delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
152
+ else
153
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = prev;
154
+ }
155
+ }
156
+ async function maybePrintPairingQr(brokerUrl, token, io) {
157
+ const store = new Store(stateDir());
158
+ const state = store.load();
159
+ if (state.paired)
160
+ return;
161
+ printPairingQr({ url: brokerUrl, token }, io);
162
+ store.update(s => {
163
+ s.paired = true;
164
+ });
165
+ }
166
+ export function printPairingQr(p, io) {
167
+ io.stdout('[claude-hud] First run — scan this QR with the plugin onboarding screen:');
168
+ io.stdout(` url: ${p.url}`);
169
+ io.stdout(` token: ${p.token}`);
170
+ const payload = JSON.stringify({ url: p.url, token: p.token });
171
+ qrcode.generate(payload, { small: true }, (out) => {
172
+ io.stdout(out);
173
+ });
174
+ }
175
+ // Entry — only when invoked as a script.
176
+ const isEntrypoint = typeof process !== 'undefined' &&
177
+ typeof process.argv?.[1] === 'string' &&
178
+ (process.argv[1].endsWith('index.ts') ||
179
+ process.argv[1].endsWith('index.js') ||
180
+ path.basename(process.argv[1]) === 'claude-hud');
181
+ if (isEntrypoint) {
182
+ void (async () => {
183
+ const code = await runCli(process.argv.slice(2));
184
+ process.exit(code);
185
+ })();
186
+ }
187
+ // Re-exports used by tests / future bin scripts.
188
+ export { ensureBrokerRunning, brokerStatus, stopBroker, stateDir, pidFile, logFile, runWrapped };
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/paths.js ADDED
@@ -0,0 +1,17 @@
1
+ import path from 'node:path';
2
+ import os from 'node:os';
3
+ /**
4
+ * One place that knows where `~/.claude-hud/` lives. Both the broker and the
5
+ * CLI read from this dir; the env override matters for tests and for users on
6
+ * shared installs.
7
+ */
8
+ export function stateDir() {
9
+ return process.env.CLAUDE_HUD_DIR ?? path.join(os.homedir(), '.claude-hud');
10
+ }
11
+ export function pidFile() {
12
+ return path.join(stateDir(), 'broker.pid');
13
+ }
14
+ export function logFile() {
15
+ return path.join(stateDir(), 'broker.log');
16
+ }
17
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,SAAS,CAAA;AAExB;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,YAAY,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,YAAY,CAAC,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,263 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import * as pty from 'node-pty';
4
+ import chokidar from 'chokidar';
5
+ import { WebSocket } from 'ws';
6
+ import { claudeCodeProjectSlug, claudeProjectsRoot } from "./slug.js";
7
+ const DEFAULT_JSONL_TIMEOUT_MS = 3_000;
8
+ const DEFAULT_QUIET_WINDOW_MS = 200;
9
+ export async function runWrapped(opts) {
10
+ const io = opts.io ?? {
11
+ stdin: process.stdin,
12
+ stdout: process.stdout,
13
+ process,
14
+ };
15
+ const cwd = opts.cwd ?? io.process.cwd();
16
+ const claudeBin = opts.claudeBin ?? resolveClaudeBin();
17
+ const spawnPty = opts.spawnPty ?? pty.spawn;
18
+ const watch = opts.watch ?? chokidar.watch.bind(chokidar);
19
+ const Ws = opts.webSocketImpl ?? WebSocket;
20
+ const fetchImpl = opts.fetchImpl ?? fetch;
21
+ const jsonlTimeoutMs = opts.jsonlTimeoutMs ?? DEFAULT_JSONL_TIMEOUT_MS;
22
+ const quietWindowMs = opts.quietWindowMs ?? DEFAULT_QUIET_WINDOW_MS;
23
+ const cols = io.stdout.columns ?? 120;
24
+ const rows = io.stdout.rows ?? 30;
25
+ const child = spawnPty(claudeBin, opts.argv, {
26
+ name: 'xterm-color',
27
+ cols,
28
+ rows,
29
+ cwd,
30
+ env: process.env,
31
+ });
32
+ // Forward pty output verbatim so the TUI renders normally.
33
+ child.onData(d => {
34
+ try {
35
+ io.stdout.write(d);
36
+ }
37
+ catch {
38
+ // ignore — writer may have been closed during shutdown
39
+ }
40
+ });
41
+ let lastUserInputAt = 0;
42
+ const onUserData = (d) => {
43
+ lastUserInputAt = Date.now();
44
+ try {
45
+ child.write(typeof d === 'string' ? d : d.toString('utf8'));
46
+ }
47
+ catch {
48
+ // pty closed
49
+ }
50
+ };
51
+ if (!opts.noTty && io.stdin.isTTY && typeof io.stdin.setRawMode === 'function') {
52
+ io.stdin.setRawMode(true);
53
+ }
54
+ io.stdin.on('data', onUserData);
55
+ io.stdin.resume();
56
+ const onResize = () => {
57
+ try {
58
+ child.resize(io.stdout.columns ?? cols, io.stdout.rows ?? rows);
59
+ }
60
+ catch {
61
+ // ignore
62
+ }
63
+ };
64
+ io.stdout.on?.('resize', onResize);
65
+ io.process.on('SIGWINCH', onResize);
66
+ // Discover the jsonl Claude Code writes for this session. We don't know the
67
+ // session uuid yet, so we watch the per-cwd projects directory for `add`.
68
+ const projectsRoot = opts.projectsRoot ?? claudeProjectsRoot();
69
+ const slug = claudeCodeProjectSlug(path.resolve(cwd));
70
+ const projectDir = path.join(projectsRoot, slug);
71
+ fs.mkdirSync(projectDir, { recursive: true });
72
+ let watcher;
73
+ let sessionId;
74
+ let injectWs;
75
+ let registered = false;
76
+ const close = async (exitCode) => {
77
+ if (!opts.noTty && io.stdin.isTTY && typeof io.stdin.setRawMode === 'function') {
78
+ try {
79
+ io.stdin.setRawMode(false);
80
+ }
81
+ catch {
82
+ // ignore
83
+ }
84
+ }
85
+ io.stdin.off('data', onUserData);
86
+ io.stdin.pause();
87
+ io.stdout.off?.('resize', onResize);
88
+ io.process.off('SIGWINCH', onResize);
89
+ if (watcher) {
90
+ try {
91
+ await watcher.close();
92
+ }
93
+ catch {
94
+ // ignore
95
+ }
96
+ }
97
+ if (injectWs) {
98
+ try {
99
+ injectWs.close();
100
+ }
101
+ catch {
102
+ // ignore
103
+ }
104
+ }
105
+ if (registered && sessionId) {
106
+ try {
107
+ await fetchImpl(`${opts.brokerUrl}/api/sessions/${sessionId}/detached`, {
108
+ method: 'POST',
109
+ headers: {
110
+ Authorization: `Bearer ${opts.token}`,
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ body: JSON.stringify({ exitCode }),
114
+ });
115
+ }
116
+ catch {
117
+ // ignore — best-effort
118
+ }
119
+ }
120
+ };
121
+ const exitPromise = new Promise(resolve => {
122
+ child.onExit(({ exitCode }) => {
123
+ void close(exitCode ?? 0).then(() => resolve(exitCode ?? 0));
124
+ });
125
+ });
126
+ // chokidar's `add` for an empty file fires almost immediately; the actual
127
+ // `change` events come as Claude Code writes lines.
128
+ const onJsonlFound = async (filePath) => {
129
+ if (sessionId)
130
+ return;
131
+ const base = path.basename(filePath);
132
+ if (!base.endsWith('.jsonl'))
133
+ return;
134
+ const id = base.slice(0, -'.jsonl'.length);
135
+ if (!isUuid(id))
136
+ return;
137
+ sessionId = id;
138
+ try {
139
+ await registerAttached({
140
+ brokerUrl: opts.brokerUrl,
141
+ token: opts.token,
142
+ sessionId: id,
143
+ projectId: opts.projectId,
144
+ cwd,
145
+ label: opts.label,
146
+ jsonlPath: filePath,
147
+ wrapperPid: child.pid,
148
+ fetchImpl,
149
+ });
150
+ registered = true;
151
+ injectWs = openInjectWs({
152
+ brokerUrl: opts.brokerUrl,
153
+ token: opts.token,
154
+ sessionId: id,
155
+ webSocketImpl: Ws,
156
+ onText: text => {
157
+ // Honour the quiet window so we don't intercept a user mid-keystroke.
158
+ const sinceUser = Date.now() - lastUserInputAt;
159
+ const delay = sinceUser < quietWindowMs ? quietWindowMs - sinceUser : 0;
160
+ setTimeout(() => {
161
+ try {
162
+ child.write(text + '\r');
163
+ }
164
+ catch {
165
+ // ignore
166
+ }
167
+ }, delay);
168
+ },
169
+ });
170
+ }
171
+ catch (err) {
172
+ try {
173
+ io.stdout.write(`\r\n[claude-hud] failed to register session with broker: ${err.message}\r\n`);
174
+ }
175
+ catch {
176
+ // ignore
177
+ }
178
+ }
179
+ };
180
+ watcher = watch(projectDir, {
181
+ persistent: true,
182
+ ignoreInitial: false,
183
+ depth: 1,
184
+ awaitWriteFinish: false,
185
+ });
186
+ watcher.on('add', p => {
187
+ void onJsonlFound(p);
188
+ });
189
+ // Time out the wait — if the jsonl never appears, claude is still running
190
+ // and the user shouldn't notice; we just won't have a broker-side session.
191
+ const jsonlDeadline = setTimeout(() => {
192
+ if (!sessionId) {
193
+ try {
194
+ io.stdout.write(`\r\n[claude-hud] no session jsonl appeared within ${jsonlTimeoutMs}ms; broker won't see this session\r\n`);
195
+ }
196
+ catch {
197
+ // ignore
198
+ }
199
+ }
200
+ }, jsonlTimeoutMs);
201
+ void exitPromise.then(() => clearTimeout(jsonlDeadline));
202
+ // Bail-out paths — if the user hits Ctrl+C, the keystroke is forwarded to
203
+ // claude (which exits cleanly). We don't need to handle it specially here.
204
+ // The pty's onExit drives the resolve.
205
+ return await exitPromise;
206
+ }
207
+ function resolveClaudeBin() {
208
+ // We let node-pty / the OS resolve `claude` from PATH on POSIX. On Windows
209
+ // node-pty's `spawn` already understands `.exe` lookups so a bare 'claude'
210
+ // works there too as long as one of `claude.exe` / `claude.cmd` is on PATH.
211
+ return 'claude';
212
+ }
213
+ function isUuid(s) {
214
+ return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(s);
215
+ }
216
+ async function registerAttached(args) {
217
+ const res = await args.fetchImpl(`${args.brokerUrl}/api/sessions/attached`, {
218
+ method: 'POST',
219
+ headers: {
220
+ Authorization: `Bearer ${args.token}`,
221
+ 'Content-Type': 'application/json',
222
+ },
223
+ body: JSON.stringify({
224
+ id: args.sessionId,
225
+ projectId: args.projectId,
226
+ cwd: args.cwd,
227
+ label: args.label,
228
+ jsonlPath: args.jsonlPath,
229
+ wrapperPid: args.wrapperPid,
230
+ }),
231
+ });
232
+ if (!res.ok) {
233
+ throw new Error(`attached register failed: ${res.status}`);
234
+ }
235
+ }
236
+ function openInjectWs(args) {
237
+ const wsUrl = httpToWs(args.brokerUrl) +
238
+ `/api/sessions/${args.sessionId}/inject?token=${encodeURIComponent(args.token)}`;
239
+ const Ctor = args.webSocketImpl;
240
+ const ws = new Ctor(wsUrl, {
241
+ rejectUnauthorized: false,
242
+ });
243
+ ws.on('message', data => {
244
+ try {
245
+ const parsed = JSON.parse(data.toString());
246
+ if (parsed.type === 'inject' && typeof parsed.text === 'string') {
247
+ args.onText(parsed.text);
248
+ }
249
+ }
250
+ catch {
251
+ // ignore — protocol frame we don't recognise
252
+ }
253
+ });
254
+ return ws;
255
+ }
256
+ function httpToWs(url) {
257
+ if (url.startsWith('https://'))
258
+ return 'wss://' + url.slice('https://'.length);
259
+ if (url.startsWith('http://'))
260
+ return 'ws://' + url.slice('http://'.length);
261
+ return url;
262
+ }
263
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wrapper/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ // Re-export the broker's canonical slug helper so the CLI and the broker
2
+ // agree byte-for-byte on the on-disk Claude Code layout. Living next to the
3
+ // tailer (broker/src/jsonl-tail.ts) keeps both consumers honest.
4
+ export { claudeCodeProjectSlug, claudeProjectsRoot } from '../_broker/jsonl-tail.js';
5
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/wrapper/slug.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,iEAAiE;AACjE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@xerktech/claude-hud",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Drive Claude Code sessions from Even Realities G2 smart glasses. Spawns a local broker, registers the cwd, and runs `claude` inside a PTY so the glasses can attach.",
6
+ "keywords": [
7
+ "claude",
8
+ "claude-code",
9
+ "even-realities",
10
+ "g2",
11
+ "smart-glasses",
12
+ "cli"
13
+ ],
14
+ "homepage": "https://github.com/xerktech/claudehud#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/xerktech/claudehud/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/xerktech/claudehud.git",
21
+ "directory": "cli"
22
+ },
23
+ "license": "MIT",
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "main": "dist/index.js",
28
+ "bin": {
29
+ "claude-hud": "dist/index.js"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "registry": "https://registry.npmjs.org"
39
+ },
40
+ "scripts": {
41
+ "dev": "tsx src/index.ts",
42
+ "start": "tsx src/index.ts",
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "bundle": "node ../scripts/bundle-cli.mjs",
45
+ "prepack": "npm run build && npm run bundle",
46
+ "typecheck": "tsc --noEmit",
47
+ "test": "vitest run",
48
+ "test:coverage": "vitest run --coverage"
49
+ },
50
+ "dependencies": {
51
+ "bonjour-service": "^1.3.0",
52
+ "chokidar": "^4.0.3",
53
+ "express": "^4.21.2",
54
+ "fuse.js": "^7.3.0",
55
+ "node-pty": "^1.0.0",
56
+ "qrcode-terminal": "^0.12.0",
57
+ "selfsigned": "^2.4.1",
58
+ "ws": "^8.18.0"
59
+ },
60
+ "devDependencies": {
61
+ "@claude-hud/broker": "*",
62
+ "@types/node": "^22.10.5",
63
+ "@types/qrcode-terminal": "^0.12.2",
64
+ "@types/ws": "^8.5.13",
65
+ "@vitest/coverage-v8": "^2.1.9",
66
+ "tsx": "^4.19.2",
67
+ "typescript": "^5.7.2",
68
+ "vitest": "^2.1.8"
69
+ }
70
+ }