@hivefloor/cli 0.1.4 → 0.1.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.
Files changed (55) hide show
  1. package/LICENSE +6 -20
  2. package/README.md +31 -9
  3. package/dist/chunk-2ERPDCOT.js +38 -0
  4. package/dist/chunk-4G362W6G.js +19 -0
  5. package/dist/chunk-5OJUJCE3.js +817 -0
  6. package/dist/chunk-5XXYQQG6.js +274 -0
  7. package/dist/chunk-AGIYVFDQ.js +10984 -0
  8. package/dist/{chunk-2BSA7LFD.js → chunk-BLLPDPTL.js} +7 -3
  9. package/dist/{chunk-R5KDI4WI.js → chunk-FPJNGKT5.js} +9 -3
  10. package/dist/chunk-HW3KRNCO.js +201 -0
  11. package/dist/{chunk-ZC2DAKB5.js → chunk-HWBUESB4.js} +1500 -316
  12. package/dist/{chunk-DNG5CRT3.js → chunk-K2IRTZH5.js} +8 -7
  13. package/dist/chunk-KQMPCV57.js +122 -0
  14. package/dist/{chunk-UJ4BQFWV.js → chunk-L6EFW2SJ.js} +53 -31
  15. package/dist/{chunk-T7TG6WA4.js → chunk-LX5A25O6.js} +4 -2
  16. package/dist/{chunk-W7DROKC7.js → chunk-MYJCU5JL.js} +89 -13
  17. package/dist/chunk-NMUH5NXN.js +52 -0
  18. package/dist/chunk-NRJONTFT.js +67 -0
  19. package/dist/chunk-QBBKGORP.js +327 -0
  20. package/dist/chunk-QGULSOQ2.js +142 -0
  21. package/dist/{chunk-PDXYOREI.js → chunk-QLMLB7RB.js} +110 -31
  22. package/dist/{chunk-TKMIV7BG.js → chunk-QPAFN47B.js} +3 -1
  23. package/dist/chunk-SBOEAOHD.js +48 -0
  24. package/dist/{chunk-SD65CIIY.js → chunk-TIR4CV3P.js} +117 -33
  25. package/dist/{chunk-QHYZBHXO.js → chunk-X2KH6AR4.js} +195 -251
  26. package/dist/chunk-XAXKZ572.js +106 -0
  27. package/dist/{chunk-VNCQFFQO.js → chunk-XPGL7VYE.js} +114 -1
  28. package/dist/cli-BFOJWJNG.js +279 -0
  29. package/dist/connect-ZJ4JXBAJ.js +27 -0
  30. package/dist/control-6GHTZQJV.js +25 -0
  31. package/dist/{disconnect-MKRHK4CX.js → disconnect-3T25NTKX.js} +55 -34
  32. package/dist/hook-TPSHBCWU.js +575 -0
  33. package/dist/index.js +9 -6
  34. package/dist/{link-HXBMMSG3.js → link-EAS5F5PC.js} +34 -18
  35. package/dist/{machine-connect-BYHZRRRB.js → machine-connect-KEI4BRWF.js} +30 -24
  36. package/dist/mcp-LVIYR3EN.js +1882 -0
  37. package/dist/orch-KVRL2YA2.js +137 -0
  38. package/dist/{run-336BSU72.js → run-JL2OZWK3.js} +1933 -29
  39. package/dist/{status-KBBSAADD.js → status-QXOOJGGN.js} +29 -14
  40. package/dist/token-BFWWQIDA.js +44 -0
  41. package/dist/voice-QXHFXRWG.js +264 -0
  42. package/dist/{where-KR7VWSEC.js → where-CMUORQIO.js} +20 -8
  43. package/package.json +6 -7
  44. package/dist/chunk-2IMJECYD.js +0 -71
  45. package/dist/chunk-7KF7IQJN.js +0 -30
  46. package/dist/chunk-GT3HFFT4.js +0 -132
  47. package/dist/chunk-JCLWCMEM.js +0 -8
  48. package/dist/chunk-K3NQKI34.js +0 -10
  49. package/dist/chunk-O2TC3WSS.js +0 -303
  50. package/dist/chunk-PY74LT2W.js +0 -41
  51. package/dist/cli-P3DYE5IR.js +0 -103
  52. package/dist/connect-ACNM5DQG.js +0 -23
  53. package/dist/hook-KR2HGVAR.js +0 -301
  54. package/dist/mcp-N2TMD4GR.js +0 -121
  55. package/dist/token-JDRLEV5D.js +0 -32
@@ -1,301 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- HARD_EXIT_MS
4
- } from "./chunk-JCLWCMEM.js";
5
- import {
6
- detectRepo
7
- } from "./chunk-2BSA7LFD.js";
8
- import {
9
- defaultHost,
10
- loadToken
11
- } from "./chunk-PDXYOREI.js";
12
- import {
13
- appendToSpool,
14
- contextEventName,
15
- contextOutput,
16
- nudgesOf,
17
- releaseSpool,
18
- stashNudges,
19
- takeSpool,
20
- takeStashed
21
- } from "./chunk-O2TC3WSS.js";
22
- import {
23
- readMachine,
24
- serviceAlive
25
- } from "./chunk-T7TG6WA4.js";
26
- import {
27
- configDir,
28
- machineSpoolFile
29
- } from "./chunk-VNCQFFQO.js";
30
- import {
31
- DEFAULT_HOST,
32
- HOOK_BATCH_MAX,
33
- PROFILE_KEY_RE,
34
- SESSION_ACCOUNT_RE,
35
- hostFromEnv,
36
- redact
37
- } from "./chunk-ZC2DAKB5.js";
38
- import "./chunk-K3NQKI34.js";
39
-
40
- // src/hook.ts
41
- import fs from "fs";
42
-
43
- // src/hookmap.ts
44
- var NAMES = {
45
- sessionstart: "session_start",
46
- sessionend: "session_end",
47
- userpromptsubmit: "prompt",
48
- beforesubmitprompt: "prompt",
49
- stop: "stop",
50
- afteragent: "stop",
51
- notification: "waiting",
52
- subagentstart: "subagent_start",
53
- subagentstop: "subagent_stop",
54
- pretooluse: "tool_agent_pre",
55
- posttooluse: "tool_agent_post"
56
- };
57
- var WAITING_TYPES = /* @__PURE__ */ new Set(["permission_prompt", "idle_prompt"]);
58
- var LINE_MAX = 140;
59
- var str = (v) => typeof v === "string" && v.trim() !== "" ? v : void 0;
60
- var rec = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
61
- function statusLine(text) {
62
- const t = str(text);
63
- if (!t) return void 0;
64
- const first = t.split(/\r?\n/).map((l) => l.trim()).find((l) => l !== "");
65
- if (!first) return void 0;
66
- return redact(first).text.slice(0, LINE_MAX).trim() || void 0;
67
- }
68
- function oneLine(text) {
69
- const t = str(text);
70
- return t ? redact(t.replace(/\s+/g, " ").trim()).text.slice(0, LINE_MAX) : void 0;
71
- }
72
- function mapHookEvent(tool, native, input) {
73
- const event = NAMES[native.toLowerCase()];
74
- if (!event) return null;
75
- const session_id = str(input.conversation_id) ?? str(input.session_id);
76
- if (!session_id) return null;
77
- const out = { tool, event, session_id };
78
- const model = str(input.model) ?? str(input.subagent_model);
79
- if (model) out.model = model;
80
- switch (event) {
81
- case "waiting": {
82
- if (tool !== "claude" || !WAITING_TYPES.has(String(input.notification_type))) return null;
83
- break;
84
- }
85
- case "subagent_start":
86
- case "subagent_stop": {
87
- const id = str(input.subagent_id) ?? str(input.agent_id);
88
- if (!id) return null;
89
- out.subagent_id = id;
90
- const type = str(input.subagent_type) ?? str(input.agent_type);
91
- if (type) out.subagent_type = type;
92
- if (event === "subagent_start") {
93
- const d = oneLine(input.description) ?? oneLine(input.task);
94
- if (d) out.description = d;
95
- } else {
96
- const s = statusLine(input.last_assistant_message) ?? statusLine(input.summary);
97
- if (s) out.status_line = s;
98
- }
99
- break;
100
- }
101
- case "tool_agent_pre":
102
- case "tool_agent_post": {
103
- if (input.tool_name !== "Agent" && input.tool_name !== "Task") return null;
104
- const ti = rec(input.tool_input);
105
- const type = str(ti.subagent_type);
106
- if (type) out.subagent_type = type;
107
- const d = oneLine(ti.description);
108
- if (d) out.description = d;
109
- break;
110
- }
111
- case "stop": {
112
- const s = statusLine(input.last_assistant_message) ?? statusLine(input.prompt_response);
113
- if (s) out.status_line = s;
114
- break;
115
- }
116
- default:
117
- break;
118
- }
119
- return out;
120
- }
121
- function cwdOf(input) {
122
- const roots = Array.isArray(input.workspace_roots) ? input.workspace_roots : [];
123
- return str(input.cwd) ?? str(roots[0]);
124
- }
125
-
126
- // src/hook.ts
127
- import path from "path";
128
- var POST_TIMEOUT_MS = 2e3;
129
- var EXIT_MARGIN_MS = 400;
130
- var MIN_POST_MS = 250;
131
- var TOOLS = /* @__PURE__ */ new Set(["claude", "codex", "cursor", "gemini", "grok"]);
132
- var DEDUPE_WINDOW_MS = 2e3;
133
- function dedupeFile() {
134
- return path.join(configDir(), "dedupe.json");
135
- }
136
- function isDuplicate(key, nowMs) {
137
- let seen = {};
138
- try {
139
- seen = JSON.parse(fs.readFileSync(dedupeFile(), "utf8"));
140
- } catch {
141
- }
142
- const fresh = Object.fromEntries(Object.entries(seen).filter(([, t]) => nowMs - t < 1e4));
143
- const dup = key in fresh && nowMs - fresh[key] < DEDUPE_WINDOW_MS;
144
- if (!dup) {
145
- fresh[key] = nowMs;
146
- try {
147
- fs.mkdirSync(configDir(), { recursive: true, mode: 448 });
148
- fs.writeFileSync(dedupeFile(), JSON.stringify(fresh), { mode: 384 });
149
- } catch {
150
- }
151
- }
152
- return dup;
153
- }
154
- async function post(deps, host, token, events, timeoutMs, route = "/api/v1/hooks", nudges) {
155
- try {
156
- const res = await deps.fetch(`${host}${route}`, {
157
- method: "POST",
158
- headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
159
- body: JSON.stringify({ events }),
160
- signal: AbortSignal.timeout(timeoutMs)
161
- });
162
- const text = await res.text().catch(() => "");
163
- if (res.status >= 200 && res.status < 300) {
164
- if (nudges && text.includes('"nudges"')) {
165
- try {
166
- nudges.push(...nudgesOf(JSON.parse(text)));
167
- } catch {
168
- }
169
- }
170
- return "ok";
171
- }
172
- if (res.status === 429 || res.status >= 500) return "retry";
173
- return "drop";
174
- } catch {
175
- return "retry";
176
- }
177
- }
178
- async function runHook(args, deps) {
179
- try {
180
- await runHookInner(args, deps, deps.now());
181
- } catch {
182
- }
183
- }
184
- function machineCoversTool(tool) {
185
- const m = readMachine();
186
- if (!m || m.revoked) return false;
187
- if (tool === "claude") return m.installed.claude_dirs.length > 0;
188
- if (tool === "codex") return m.installed.codex_dir !== void 0;
189
- return false;
190
- }
191
- async function runHookInner(args, deps, startedAt) {
192
- const [toolArg, native] = args;
193
- if (!toolArg || !native || !TOOLS.has(toolArg)) return;
194
- const pi = args.indexOf("--profile");
195
- const profile = pi >= 0 ? args[pi + 1] : void 0;
196
- const machine = profile !== void 0 ? readMachine() : void 0;
197
- if (profile !== void 0 && (!machine || machine.revoked || !PROFILE_KEY_RE.test(profile))) return;
198
- if (profile === void 0 && machineCoversTool(toolArg)) return;
199
- const host = machine ? machine.host : deps.env.HIVEFLOOR_URL ? hostFromEnv(deps.env) : defaultHost() ?? DEFAULT_HOST;
200
- const grokId = deps.env.GROK_SESSION_ID;
201
- const tool = grokId ? "grok" : toolArg;
202
- const envToken = deps.env.HIVEFLOOR_TOKEN;
203
- const stored = !machine && !envToken ? await loadToken(host, tool) : void 0;
204
- const token = machine ? machine.token : envToken || stored?.token;
205
- if (!token) return;
206
- let input = {};
207
- try {
208
- const raw = await deps.readStdin();
209
- const parsed = raw.trim() ? JSON.parse(raw) : {};
210
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) input = parsed;
211
- } catch {
212
- return;
213
- }
214
- if (grokId && !input.session_id && !input.conversation_id) input = { ...input, session_id: grokId };
215
- const mapped = mapHookEvent(toolArg === "grok" ? "claude" : toolArg, native, input);
216
- if (!mapped) return;
217
- const nowMs = deps.now();
218
- const event = { ...mapped, tool, client_at: new Date(nowMs).toISOString() };
219
- const contextName = grokId ? null : contextEventName(toolArg, native);
220
- if (contextName) event.deliver = true;
221
- const nudges = [];
222
- const show = () => printNudges(deps, contextName, event.session_id, nudges, nowMs);
223
- if (grokId && isDuplicate(`${tool}|${event.session_id}|${event.event}|${event.subagent_id ?? ""}`, nowMs)) return;
224
- const repo = await detectRepo(cwdOf(input) ?? deps.cwd);
225
- if (repo) event.repo = { remote: repo.remote, ...repo.branch ? { branch: repo.branch } : {}, ...repo.path ? { path: repo.path } : {} };
226
- if (machine && profile !== void 0) {
227
- const account = deps.env.FLEET_PROFILE?.trim();
228
- const mevent = { ...event, profile, ...account && SESSION_ACCOUNT_RE.test(account) ? { account } : {} };
229
- if (serviceAlive(deps.now())) {
230
- appendToSpool(mevent, machineSpoolFile());
231
- if (contextName) nudges.push(...takeStashed(event.session_id, nowMs).map((text) => ({ session_id: event.session_id, text })));
232
- show();
233
- return;
234
- }
235
- const claim2 = takeSpool(machineSpoolFile());
236
- await sendBatches(deps, host, token, [...claim2?.events ?? [], mevent], startedAt, "/api/v1/machine/hooks", claim2, machineSpoolFile(), nudges);
237
- show();
238
- return;
239
- }
240
- const claim = takeSpool();
241
- await sendBatches(deps, host, token, [...claim?.events ?? [], event], startedAt, "/api/v1/hooks", claim, void 0, nudges);
242
- show();
243
- }
244
- function printNudges(deps, contextName, sessionId, nudges, nowMs) {
245
- if (nudges.length === 0) return;
246
- const mine = contextName ? nudges.filter((n) => n.session_id === sessionId) : [];
247
- const others = nudges.filter((n) => !mine.includes(n));
248
- if (others.length > 0) stashNudges(others, nowMs);
249
- if (!contextName || mine.length === 0) return;
250
- const out = contextOutput(contextName, mine.map((n) => n.text));
251
- try {
252
- (deps.write ?? ((t) => void process.stdout.write(`${t}
253
- `)))(out);
254
- } catch {
255
- }
256
- }
257
- async function sendBatches(deps, host, token, pending, startedAt, route, claim, spool, nudges) {
258
- const batches = [];
259
- for (let k = 0; k < pending.length; k += HOOK_BATCH_MAX) batches.push(pending.slice(k, k + HOOK_BATCH_MAX));
260
- const unsent = [];
261
- let down = false;
262
- for (const batch of batches) {
263
- const left = HARD_EXIT_MS - EXIT_MARGIN_MS - (deps.now() - startedAt);
264
- if (down || left < MIN_POST_MS) {
265
- unsent.push(...batch);
266
- down = true;
267
- continue;
268
- }
269
- const r = await post(deps, host, token, batch, Math.min(POST_TIMEOUT_MS, left), route, nudges);
270
- if (r === "retry") {
271
- unsent.push(...batch);
272
- down = true;
273
- }
274
- }
275
- releaseSpool(claim, unsent, spool);
276
- }
277
- async function readStdin(timeoutMs = 1e3) {
278
- if (process.stdin.isTTY) return "";
279
- return await new Promise((resolve) => {
280
- const chunks = [];
281
- const done = () => resolve(Buffer.concat(chunks).toString("utf8"));
282
- const timer = setTimeout(done, timeoutMs);
283
- process.stdin.on("data", (c) => chunks.push(c));
284
- process.stdin.on("end", () => {
285
- clearTimeout(timer);
286
- done();
287
- });
288
- process.stdin.on("error", () => {
289
- clearTimeout(timer);
290
- done();
291
- });
292
- });
293
- }
294
- function runHookCli(args) {
295
- return runHook(args, { env: process.env, cwd: process.cwd(), fetch: (...a) => fetch(...a), now: () => Date.now(), readStdin });
296
- }
297
- export {
298
- readStdin,
299
- runHook,
300
- runHookCli
301
- };
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- detectRepo
4
- } from "./chunk-2BSA7LFD.js";
5
- import {
6
- resolveSession
7
- } from "./chunk-7KF7IQJN.js";
8
- import {
9
- toolFromEnv
10
- } from "./chunk-2IMJECYD.js";
11
- import {
12
- flagStr
13
- } from "./chunk-TKMIV7BG.js";
14
- import {
15
- loadToken
16
- } from "./chunk-PDXYOREI.js";
17
- import "./chunk-VNCQFFQO.js";
18
- import {
19
- cliNpxCommand,
20
- isSecureUrl,
21
- normalizeHost
22
- } from "./chunk-ZC2DAKB5.js";
23
- import "./chunk-K3NQKI34.js";
24
-
25
- // src/mcp.ts
26
- import os from "os";
27
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
28
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
29
- async function contextHeaders(ctx, token, toolName) {
30
- const h = { Authorization: `Bearer ${token}`, "X-HF-Tool": ctx.env.HIVEFLOOR_TOOL || toolFromEnv(ctx.env) || toolName, "X-HF-Machine": os.hostname().split(".")[0] ?? "machine" };
31
- const session = ctx.env.HIVEFLOOR_SESSION || ctx.env.CLAUDE_SESSION_ID || ctx.env.GROK_SESSION_ID || ctx.env.CODEX_SESSION_ID;
32
- if (session) h["X-HF-Session"] = session;
33
- const model = ctx.env.HIVEFLOOR_MODEL || ctx.env.ANTHROPIC_MODEL;
34
- if (model) h["X-HF-Model"] = model;
35
- const repo = await detectRepo(ctx.cwd);
36
- if (repo) {
37
- h["X-HF-Repo"] = repo.remote;
38
- if (repo.branch) h["X-HF-Branch"] = repo.branch;
39
- if (repo.path) h["X-HF-Path"] = repo.path;
40
- }
41
- return h;
42
- }
43
- var isRequest = (m) => "method" in m && "id" in m;
44
- function mcpTargetUrl(flagUrl, host) {
45
- if (!flagUrl) return new URL(`${host}/mcp`);
46
- let u;
47
- try {
48
- u = new URL(flagUrl);
49
- } catch {
50
- throw new Error("--url is not a URL");
51
- }
52
- if (!isSecureUrl(u)) throw new Error(`--url must be https (http is only allowed on localhost): ${u.origin}`);
53
- return u;
54
- }
55
- async function runMcpProxy(ctx, p, io = { stdin: process.stdin, stdout: process.stdout }) {
56
- const s = await resolveSession(ctx, p);
57
- if (!s) {
58
- ctx.err(`hivefloor: not connected. Run: ${cliNpxCommand("connect")}
59
- `);
60
- return 1;
61
- }
62
- let url;
63
- try {
64
- url = mcpTargetUrl(flagStr(p, "url"), s.host);
65
- } catch (e) {
66
- ctx.err(`hivefloor mcp: ${e.message}
67
- `);
68
- return 1;
69
- }
70
- let token = s.token;
71
- let tool = s.tool;
72
- if (url.origin !== new URL(s.host).origin) {
73
- const other = await loadToken(normalizeHost(url.origin));
74
- if (!other) {
75
- ctx.err(`hivefloor mcp: refusing to send the token of ${s.host} to ${url.origin}; connect to that host first
76
- `);
77
- return 1;
78
- }
79
- token = other.token;
80
- tool = other.tool;
81
- }
82
- const headers = await contextHeaders(ctx, token, tool);
83
- const upstream = new StreamableHTTPClientTransport(url, { requestInit: { headers } });
84
- const downstream = new StdioServerTransport(io.stdin, io.stdout);
85
- return await new Promise((resolve) => {
86
- let closing = false;
87
- const finish = (code) => {
88
- if (closing) return;
89
- closing = true;
90
- void Promise.allSettled([upstream.close(), downstream.close()]).then(() => resolve(code));
91
- };
92
- downstream.onmessage = (msg) => {
93
- upstream.send(msg).catch((e) => {
94
- if (isRequest(msg)) void downstream.send({ jsonrpc: "2.0", id: msg.id, error: { code: -32e3, message: `Hivefloor is not reachable: ${e.message}` } });
95
- });
96
- };
97
- upstream.onmessage = (msg) => {
98
- const result = msg.result;
99
- if (result && typeof result.protocolVersion === "string") upstream.setProtocolVersion?.(result.protocolVersion);
100
- void downstream.send(msg);
101
- };
102
- upstream.onerror = (e) => ctx.err(`hivefloor mcp: ${e.message}
103
- `);
104
- downstream.onerror = (e) => ctx.err(`hivefloor mcp: ${e.message}
105
- `);
106
- downstream.onclose = () => finish(0);
107
- io.stdin.once("end", () => finish(0));
108
- io.stdin.once("close", () => finish(0));
109
- upstream.onclose = () => finish(0);
110
- upstream.start().then(() => downstream.start()).catch((e) => {
111
- ctx.err(`hivefloor mcp: ${e.message}
112
- `);
113
- finish(1);
114
- });
115
- });
116
- }
117
- export {
118
- contextHeaders,
119
- mcpTargetUrl,
120
- runMcpProxy
121
- };
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- resolveSession
4
- } from "./chunk-7KF7IQJN.js";
5
- import "./chunk-2IMJECYD.js";
6
- import "./chunk-TKMIV7BG.js";
7
- import "./chunk-PDXYOREI.js";
8
- import "./chunk-VNCQFFQO.js";
9
- import {
10
- cliNpxCommand
11
- } from "./chunk-ZC2DAKB5.js";
12
- import "./chunk-K3NQKI34.js";
13
-
14
- // src/token.ts
15
- async function token(ctx, p) {
16
- const s = await resolveSession(ctx, p);
17
- if (!s) {
18
- ctx.err(`hivefloor: no token stored. Run: ${cliNpxCommand("connect")}
19
- `);
20
- return 1;
21
- }
22
- if (ctx.stdoutIsTTY && !p.flags.reveal) {
23
- ctx.err("hivefloor: refusing to print the token to a terminal. Use it in a pipe or $(...), or pass --reveal.\n");
24
- return 1;
25
- }
26
- ctx.out(`${s.token}
27
- `);
28
- return 0;
29
- }
30
- export {
31
- token
32
- };