@hivefloor/cli 0.0.0-stage → 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.
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ RC_LINE,
4
+ addRcLine,
5
+ hasRcLine,
6
+ installClaude,
7
+ installCodex,
8
+ installCursor,
9
+ installGemini,
10
+ installGrok,
11
+ rcFileFor,
12
+ updateManifest
13
+ } from "./chunk-LHF4KCEA.js";
14
+ import {
15
+ readMachine
16
+ } from "./chunk-3IMV5EHP.js";
17
+ import {
18
+ deviceLogin
19
+ } from "./chunk-UPRHMVYJ.js";
20
+ import {
21
+ detectRepo
22
+ } from "./chunk-OQ6QVFSH.js";
23
+ import {
24
+ REAL_TOOLS,
25
+ TOOL_LABEL,
26
+ detectTools,
27
+ findBin,
28
+ isTool,
29
+ toolFromEnv
30
+ } from "./chunk-2IMJECYD.js";
31
+ import {
32
+ checkUnknownFlags,
33
+ flagStr
34
+ } from "./chunk-TKMIV7BG.js";
35
+ import {
36
+ saveToken
37
+ } from "./chunk-4A5WOW2D.js";
38
+ import {
39
+ VERSION
40
+ } from "./chunk-IEYWMDXA.js";
41
+ import {
42
+ ApiError
43
+ } from "./chunk-PY74LT2W.js";
44
+ import {
45
+ ConfigError
46
+ } from "./chunk-WNDUGQDX.js";
47
+ import {
48
+ CLI_BIN_NAME,
49
+ CLI_INSTALL_COMMAND,
50
+ cliNpxCommand,
51
+ hostFromEnv,
52
+ machineName,
53
+ normalizeHost
54
+ } from "./chunk-RE2EQZWL.js";
55
+
56
+ // src/connect.ts
57
+ var INSTALLERS = {
58
+ claude: installClaude,
59
+ codex: installCodex,
60
+ cursor: installCursor,
61
+ gemini: installGemini,
62
+ grok: installGrok
63
+ };
64
+ function resolveHost(p, ctx) {
65
+ const h = flagStr(p, "host");
66
+ return h ? normalizeHost(h) : hostFromEnv(ctx.env);
67
+ }
68
+ async function chooseTool(ctx, p) {
69
+ const detected = detectTools(ctx.env).map((d) => d.tool);
70
+ const flag = flagStr(p, "tool");
71
+ if (flag !== void 0) {
72
+ if (!isTool(flag)) throw new ApiError(0, "invalid", `Unknown tool "${flag}". Use one of: ${[...REAL_TOOLS, "other"].join(", ")}.`);
73
+ return { tool: flag, others: detected.filter((t) => t !== flag) };
74
+ }
75
+ const hint = toolFromEnv(ctx.env);
76
+ let tool = hint ?? detected[0] ?? "other";
77
+ if (!hint && detected.length > 1 && ctx.stdoutIsTTY && !p.flags.yes) {
78
+ const answer = (await ctx.ask(`Which tool should this agent be? (${detected.join(", ")}) [${tool}]: `)).trim().toLowerCase();
79
+ if (isTool(answer)) tool = answer;
80
+ }
81
+ return { tool, others: detected.filter((t) => t !== tool) };
82
+ }
83
+ async function connectAgent(ctx, p) {
84
+ const host = resolveHost(p, ctx);
85
+ const { tool, others } = await chooseTool(ctx, p);
86
+ const repo = await detectRepo(ctx.cwd);
87
+ ctx.out(`Connecting ${TOOL_LABEL[tool]} on ${machineName()} to ${host}
88
+ `);
89
+ if (repo) ctx.out(`Repo: ${repo.remote}${repo.branch ? ` (${repo.branch})` : ""}${repo.path ? ` in ${repo.path}` : ""}
90
+ `);
91
+ else ctx.out("No git remote here: the agent will use your default project.\n");
92
+ const request = {
93
+ client: { tool, machine: machineName(), os: process.platform, cli_version: VERSION },
94
+ ...repo ? { repo: { remote: repo.remote, ...repo.branch ? { branch: repo.branch } : {}, ...repo.path ? { path: repo.path } : {} } } : {}
95
+ };
96
+ const canOpen = !p.flags["no-open"] && (process.platform !== "linux" || Boolean(ctx.env.DISPLAY || ctx.env.WAYLAND_DISPLAY));
97
+ const result = await deviceLogin(ctx, { host, request, openBrowser: canOpen });
98
+ const storage = await saveToken(host, tool, result.token, { agent: result.agent, project: result.project });
99
+ const rc = rcFileFor(ctx.env);
100
+ let rcInstalled = rc !== void 0 && hasRcLine(rc);
101
+ let rcAdded;
102
+ if (rc && !rcInstalled && tool !== "other") {
103
+ let yes = Boolean(p.flags.yes);
104
+ if (!yes && ctx.stdoutIsTTY) yes = /^y(es)?$/i.test((await ctx.ask(`Add this line to ${rc} so your tools can read the token?
105
+ ${RC_LINE}
106
+ Add it? [y/N] `)).trim());
107
+ if (yes) {
108
+ addRcLine(rc);
109
+ rcInstalled = true;
110
+ rcAdded = rc;
111
+ updateManifest((m) => {
112
+ if (!m.rc.includes(rc)) m.rc.push(rc);
113
+ });
114
+ }
115
+ }
116
+ const machine = readMachine();
117
+ const ownsHooks = machine !== void 0 && !machine.revoked;
118
+ const lines = [];
119
+ const warnings = [];
120
+ const mcpUrl = `${host}/mcp`;
121
+ if (tool === "other") {
122
+ lines.push(`MCP server: ${mcpUrl} (streamable HTTP), header "Authorization: Bearer <token>" (run: ${cliNpxCommand("token --reveal")})`);
123
+ lines.push("The agent shows up the first time it calls a tool.");
124
+ } else {
125
+ try {
126
+ const r = await INSTALLERS[tool]({
127
+ ctx,
128
+ mcpUrl,
129
+ token: result.token,
130
+ useEnvToken: rcInstalled,
131
+ noCli: Boolean(p.flags["no-cli"]),
132
+ skipHooks: ownsHooks,
133
+ onMcpRegistered: (mcp) => {
134
+ updateManifest((m) => {
135
+ m.tools[tool] = { mcp, host };
136
+ });
137
+ }
138
+ });
139
+ lines.push(...r.report.lines);
140
+ warnings.push(...r.report.warnings);
141
+ updateManifest((m) => {
142
+ m.tools[tool] = { mcp: r.mcp, host };
143
+ });
144
+ } catch (e) {
145
+ if (!(e instanceof ConfigError)) throw e;
146
+ warnings.push(e.message);
147
+ }
148
+ }
149
+ if (rcAdded) lines.push(`Shell: added the token export to ${rcAdded}`);
150
+ if (!findBin(CLI_BIN_NAME, ctx.env) && tool !== "other") warnings.push(`"${CLI_BIN_NAME}" is not on your PATH, so the hooks cannot run it. Install it once: ${CLI_INSTALL_COMMAND}`);
151
+ ctx.out(`
152
+ Connected as ${result.agent.name} to project ${result.project.name} (${result.project.key}).
153
+ `);
154
+ ctx.out(`Token stored in ${storage === "keychain" ? "the OS keychain" : "~/.config/hivefloor/credentials.json (mode 0600)"}.
155
+ `);
156
+ for (const l of lines) ctx.out(` ${l}
157
+ `);
158
+ for (const w of warnings) ctx.out(` note: ${w}
159
+ `);
160
+ if (others.length > 0) ctx.out(`Also installed: ${others.join(", ")}. Connect each with: ${cliNpxCommand("connect --tool <name>")}
161
+ `);
162
+ ctx.out(`Undo everything with: ${cliNpxCommand("disconnect")}
163
+ `);
164
+ return 0;
165
+ }
166
+ var CONNECT_FLAGS = /* @__PURE__ */ new Set(["host", "name", "no-open", "no-service", "yes", "y", "agent", "tool", "no-cli", "help", "h"]);
167
+ async function connect(ctx, p) {
168
+ const unknown = checkUnknownFlags(p, CONNECT_FLAGS);
169
+ if (unknown) {
170
+ ctx.err(`hivefloor: unknown flag "--${unknown}". Run "hivefloor help".
171
+ `);
172
+ return 2;
173
+ }
174
+ if (p.flags.agent || p.flags.tool !== void 0) return connectAgent(ctx, p);
175
+ return (await import("./machine-connect-RWNZ77NO.js")).connectMachine(ctx, p);
176
+ }
177
+
178
+ export {
179
+ resolveHost,
180
+ connectAgent,
181
+ connect
182
+ };
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ claudeConfigDirs,
4
+ claudeLabel,
5
+ codexConfigDir,
6
+ codexLabel,
7
+ profileKeys
8
+ } from "./chunk-M3PLXINO.js";
9
+
10
+ // src/osinfo.ts
11
+ import os from "os";
12
+ var cliVersionOs = () => `${os.platform()} ${os.release()}`.slice(0, 100);
13
+
14
+ // src/service/discovery.ts
15
+ import fs from "fs";
16
+ import path from "path";
17
+ var BY_EXE = { claude: "claude", codex: "codex", "cursor-agent": "cursor", gemini: "gemini", grok: "grok" };
18
+ var BY_DIR = { "claude-code": "claude", codex: "codex", "cursor-agent": "cursor", "gemini-cli": "gemini", "grok-cli": "grok" };
19
+ var RUNNERS = /* @__PURE__ */ new Set(["node", "bun", "deno", "npx"]);
20
+ var HELPER_ARGS = /* @__PURE__ */ new Set(["mcp", "update", "doctor", "--version"]);
21
+ var exeName = (tok) => (tok.replace(/^"|"$/g, "").split(/[\\/]/).pop() ?? "").replace(/\.(?:js|mjs|cjs|exe|cmd)$/, "");
22
+ var dirTool = (script) => {
23
+ for (const part of script.split(/[\\/]/).reverse()) {
24
+ const tool = BY_DIR[part];
25
+ if (tool) return tool;
26
+ }
27
+ return void 0;
28
+ };
29
+ function splitCommandLine(line) {
30
+ const toks = [];
31
+ let cur = "";
32
+ let quoted = false;
33
+ let started = false;
34
+ for (const c of line) {
35
+ if (c === '"') {
36
+ quoted = !quoted;
37
+ started = true;
38
+ } else if (!quoted && /\s/.test(c)) {
39
+ if (started) toks.push(cur);
40
+ cur = "";
41
+ started = false;
42
+ } else {
43
+ cur += c;
44
+ started = true;
45
+ }
46
+ }
47
+ if (started) toks.push(cur);
48
+ return toks;
49
+ }
50
+ function fromTokens(pid, toks) {
51
+ const first = exeName(toks[0] ?? "");
52
+ let rest = toks.slice(1);
53
+ let tool;
54
+ if (RUNNERS.has(first) && toks[1] && !toks[1].startsWith("-")) {
55
+ tool = BY_EXE[exeName(toks[1])] ?? dirTool(toks[1]);
56
+ rest = toks.slice(2);
57
+ } else {
58
+ tool = BY_EXE[first];
59
+ }
60
+ if (!tool || pid === process.pid) return void 0;
61
+ if (HELPER_ARGS.has(rest[0] ?? "")) return void 0;
62
+ const mi = rest.findIndex((t) => t === "--model" || t === "-m");
63
+ const eq = rest.find((t) => t.startsWith("--model="));
64
+ const model = eq ? eq.slice(8) : mi >= 0 ? rest[mi + 1] : void 0;
65
+ return { pid, tool, ...model && /^[\w.:\-/[\]]{1,100}$/.test(model) ? { model } : {} };
66
+ }
67
+ function parsePs(text, uid) {
68
+ const out = [];
69
+ for (const line of text.split("\n")) {
70
+ const m = /^\s*(\d+)\s+(\d+)\s+\S+\s+(.+)$/.exec(line);
71
+ if (!m) continue;
72
+ const pid = Number(m[1]);
73
+ if (uid !== void 0 && Number(m[2]) !== uid) continue;
74
+ const p = fromTokens(pid, m[3].trim().split(/\s+/));
75
+ if (p) out.push(p);
76
+ }
77
+ return out;
78
+ }
79
+ function parseWindowsProcesses(text) {
80
+ const raw = text.replace(/^\uFEFF/, "").trim();
81
+ if (raw === "" || raw === "null") return [];
82
+ let data;
83
+ try {
84
+ data = JSON.parse(raw);
85
+ } catch {
86
+ return [];
87
+ }
88
+ const out = [];
89
+ for (const item of Array.isArray(data) ? data : [data]) {
90
+ if (typeof item !== "object" || item === null) continue;
91
+ const p = item;
92
+ const pid = typeof p.ProcessId === "number" ? p.ProcessId : typeof p.ProcessId === "string" ? Number(p.ProcessId) : NaN;
93
+ if (!Number.isInteger(pid) || pid <= 0 || typeof p.CommandLine !== "string" || p.CommandLine.trim() === "") continue;
94
+ const found = fromTokens(pid, splitCommandLine(p.CommandLine));
95
+ if (found) out.push(found);
96
+ }
97
+ return out;
98
+ }
99
+ function makeEnvReader(platform, run) {
100
+ if (platform === "win32") return async () => void 0;
101
+ return async (pid, name) => {
102
+ try {
103
+ if (platform === "linux") {
104
+ const raw = fs.readFileSync(`/proc/${pid}/environ`, "utf8");
105
+ for (const kv of raw.split("\0")) if (kv.startsWith(`${name}=`)) return kv.slice(name.length + 1) || void 0;
106
+ return void 0;
107
+ }
108
+ if (platform === "darwin") {
109
+ const r = await run("ps", ["-E", "-ww", "-p", String(pid), "-o", "command="], { timeoutMs: 5e3 });
110
+ const m = new RegExp(`(?:^|\\s)${name}=(\\S+)`).exec(r.stdout);
111
+ return m?.[1];
112
+ }
113
+ } catch {
114
+ }
115
+ return void 0;
116
+ };
117
+ }
118
+ var WINDOWS_PROCESS_QUERY = [
119
+ "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8",
120
+ "$me = [Security.Principal.WindowsIdentity]::GetCurrent().Name",
121
+ "$names = @('claude.exe', 'claude', 'codex.exe', 'codex', 'cursor-agent.exe', 'cursor-agent', 'gemini.exe', 'gemini', 'grok.exe', 'grok', 'node.exe', 'node', 'bun.exe', 'bun', 'deno.exe', 'deno', 'npx.cmd', 'npx')",
122
+ '$rows = @(Get-CimInstance Win32_Process | Where-Object { $names -contains $_.Name.ToLowerInvariant() } | ForEach-Object { $p = $_; $o = Invoke-CimMethod -InputObject $p -MethodName GetOwner; if ($o.ReturnValue -eq 0) { $owner = if ($o.Domain) { "$($o.Domain)\\$($o.User)" } else { $o.User }; if ($owner -ieq $me) { [pscustomobject]@{ ProcessId = $p.ProcessId; CommandLine = $p.CommandLine } } } })',
123
+ "ConvertTo-Json -InputObject $rows -Compress"
124
+ ].join("; ");
125
+ async function scanProcesses(d) {
126
+ if (d.platform === "win32") {
127
+ const r2 = await d.run("powershell", ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_PROCESS_QUERY], { timeoutMs: 1e4 });
128
+ if (r2.code !== 0) return { procs: [] };
129
+ return { procs: parseWindowsProcesses(r2.stdout) };
130
+ }
131
+ const r = await d.run("ps", ["-axo", "pid=,uid=,etime=,command="], { timeoutMs: 1e4 });
132
+ if (r.code !== 0) return { procs: [] };
133
+ const readEnv = d.readEnv ?? makeEnvReader(d.platform, d.run);
134
+ const procs = [];
135
+ const uid = d.uid ?? (typeof process.getuid === "function" ? process.getuid() : void 0);
136
+ for (const p of parsePs(r.stdout, uid)) {
137
+ const dir = p.tool === "claude" ? await readEnv(p.pid, "CLAUDE_CONFIG_DIR") : p.tool === "codex" ? await readEnv(p.pid, "CODEX_HOME") : void 0;
138
+ procs.push({ ...p, ...dir ? { dir } : {} });
139
+ }
140
+ return { procs };
141
+ }
142
+ var claudeDirsOfScan = (s) => s.procs.filter((p) => p.tool === "claude" && p.dir).map((p) => p.dir);
143
+ function buildProfiles(scan, env, homeDir) {
144
+ const claudeDirs = claudeConfigDirs(claudeDirsOfScan(scan), homeDir);
145
+ const ckeys = profileKeys("claude", claudeDirs);
146
+ const out = [];
147
+ const defaultDir = claudeDirs[0];
148
+ for (const dir of claudeDirs) {
149
+ const key = ckeys.get(dir);
150
+ const here = scan.procs.filter((p) => p.tool === "claude" && (p.dir ? path.resolve(p.dir) : defaultDir) === dir);
151
+ if (here.length === 0 && !fs.existsSync(dir)) continue;
152
+ const model = latestModel(here);
153
+ out.push({ tool: "claude", key, label: claudeLabel(dir, key), ...model ? { model } : {}, running: here.length });
154
+ }
155
+ const cdir = codexConfigDir(env);
156
+ const codexProcs = scan.procs.filter((p) => p.tool === "codex");
157
+ const codexKeys = profileKeys("codex", [cdir, ...codexProcs.flatMap((p) => p.dir ? [path.resolve(p.dir)] : [])]);
158
+ const seenCodex = /* @__PURE__ */ new Set();
159
+ for (const [dir, key] of codexKeys) {
160
+ if (seenCodex.has(dir)) continue;
161
+ seenCodex.add(dir);
162
+ const here = codexProcs.filter((p) => p.dir ? path.resolve(p.dir) === dir : dir === cdir);
163
+ if (here.length === 0 && !fs.existsSync(dir)) continue;
164
+ const model = latestModel(here);
165
+ out.push({ tool: "codex", key, label: codexLabel(dir), ...model ? { model } : {}, running: here.length });
166
+ }
167
+ for (const tool of ["cursor", "gemini", "grok"]) {
168
+ const here = scan.procs.filter((p) => p.tool === tool);
169
+ if (here.length === 0) continue;
170
+ const model = latestModel(here);
171
+ out.push({ tool, key: "default", label: { cursor: "Cursor", gemini: "Gemini CLI", grok: "Grok CLI" }[tool], ...model ? { model } : {}, running: here.length });
172
+ }
173
+ return out;
174
+ }
175
+ var latestModel = (ps) => ps.map((p) => p.model).filter((m) => Boolean(m)).pop();
176
+
177
+ export {
178
+ cliVersionOs,
179
+ scanProcesses,
180
+ claudeDirsOfScan,
181
+ buildProfiles
182
+ };
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ isTool
4
+ } from "./chunk-2IMJECYD.js";
5
+ import {
6
+ flagStr
7
+ } from "./chunk-TKMIV7BG.js";
8
+ import {
9
+ defaultHost,
10
+ loadToken
11
+ } from "./chunk-4A5WOW2D.js";
12
+ import {
13
+ hostFromEnv,
14
+ normalizeHost
15
+ } from "./chunk-RE2EQZWL.js";
16
+
17
+ // src/session.ts
18
+ async function resolveSession(ctx, p) {
19
+ const flagHost = flagStr(p, "host");
20
+ const host = flagHost ? normalizeHost(flagHost) : ctx.env.HIVEFLOOR_URL ? hostFromEnv(ctx.env) : defaultHost() ?? hostFromEnv(ctx.env);
21
+ const toolFlag = flagStr(p, "tool");
22
+ const t = await loadToken(host, toolFlag && isTool(toolFlag) ? toolFlag : void 0);
23
+ if (t) return { host, token: t.token, tool: t.tool };
24
+ if (ctx.env.HIVEFLOOR_TOKEN) return { host, token: ctx.env.HIVEFLOOR_TOKEN, tool: toolFlag ?? "other" };
25
+ return void 0;
26
+ }
27
+
28
+ export {
29
+ resolveSession
30
+ };
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CLAUDE_EVENTS,
4
+ CODEX_EVENTS,
5
+ addCreated,
6
+ addHooks,
7
+ editJson,
8
+ enableFeatureHooks,
9
+ forgetCreated,
10
+ removeHooks,
11
+ restoreFeatureHooks,
12
+ wasCreated
13
+ } from "./chunk-LHF4KCEA.js";
14
+ import {
15
+ claudeConfigDirs,
16
+ codexConfigDir,
17
+ profileKeys
18
+ } from "./chunk-M3PLXINO.js";
19
+ import {
20
+ atomicWrite,
21
+ backupOnce,
22
+ cliDir,
23
+ cliEntry,
24
+ dropBackupIfSame,
25
+ readText,
26
+ removeFile
27
+ } from "./chunk-WNDUGQDX.js";
28
+
29
+ // src/machine-hooks.ts
30
+ import fs from "fs";
31
+ import path from "path";
32
+ function installCliCopy(srcDir) {
33
+ if (!fs.existsSync(path.join(srcDir, "index.js"))) throw new Error(`cannot find the CLI bundle in ${srcDir}`);
34
+ const dest = cliDir();
35
+ fs.mkdirSync(dest, { recursive: true, mode: 448 });
36
+ for (const f of fs.readdirSync(srcDir)) {
37
+ if (!/\.(?:js|mjs)$/.test(f)) continue;
38
+ const tmp = path.join(dest, `${f}.${process.pid}.tmp`);
39
+ fs.copyFileSync(path.join(srcDir, f), tmp);
40
+ fs.renameSync(tmp, path.join(dest, f));
41
+ }
42
+ fs.writeFileSync(path.join(dest, "package.json"), '{"type":"module"}\n');
43
+ }
44
+ var removeCliCopy = () => fs.rmSync(cliDir(), { recursive: true, force: true });
45
+ function claudeMachineSpecs(node, profile) {
46
+ return CLAUDE_EVENTS.map((event) => ({
47
+ event,
48
+ ...event === "Notification" ? { matcher: "permission_prompt|idle_prompt" } : {},
49
+ // Exec form: no shell, no quoting. async: the hook never slows the agent down.
50
+ entry: { type: "command", command: node, args: [cliEntry(), "hook", "claude", event, "--profile", profile], async: true }
51
+ }));
52
+ }
53
+ var q = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
54
+ function codexMachineSpecs(node, profile) {
55
+ return CODEX_EVENTS.map((event) => ({ event, entry: { type: "command", command: `${q(node)} ${q(cliEntry())} hook codex ${event} --profile ${profile}` } }));
56
+ }
57
+ var isDir = (p) => {
58
+ try {
59
+ return fs.statSync(p).isDirectory();
60
+ } catch {
61
+ return false;
62
+ }
63
+ };
64
+ function installMachineHooks(node, opts) {
65
+ const res = { claude_dirs: [], lines: [], warnings: [] };
66
+ const dirs = claudeConfigDirs(opts.processDirs).filter(isDir);
67
+ const keys = profileKeys("claude", dirs);
68
+ for (const dir of dirs) {
69
+ const file = path.join(dir, "settings.json");
70
+ try {
71
+ editJson(file, (d) => (addHooks(d, "nested", claudeMachineSpecs(node, keys.get(dir)), "machine"), true));
72
+ res.claude_dirs.push(dir);
73
+ res.lines.push(`Claude Code hooks (${keys.get(dir)}): ${file}`);
74
+ } catch (e) {
75
+ res.warnings.push(e.message);
76
+ }
77
+ }
78
+ if (opts.codex && isDir(codexConfigDir(opts.env))) {
79
+ const dir = codexConfigDir(opts.env);
80
+ const key = profileKeys("codex", [dir]).get(dir);
81
+ try {
82
+ editJson(path.join(dir, "hooks.json"), (d) => (addHooks(d, "nested", codexMachineSpecs(node, key), "machine"), true));
83
+ editToml(path.join(dir, "config.toml"), (c) => enableFeatureHooks(c));
84
+ res.codex_dir = dir;
85
+ res.lines.push(`Codex hooks (${key}): ${path.join(dir, "hooks.json")}`);
86
+ } catch (e) {
87
+ res.warnings.push(e.message);
88
+ }
89
+ }
90
+ return res;
91
+ }
92
+ function editToml(file, fn) {
93
+ const before = readText(file);
94
+ const next = fn(before ?? "");
95
+ if (next === (before ?? "")) return;
96
+ if (before === void 0) addCreated(file);
97
+ else if (!wasCreated(file)) backupOnce(file);
98
+ atomicWrite(file, next);
99
+ }
100
+ function removeMachineHooks(inst) {
101
+ const lines = [];
102
+ for (const dir of inst.claude_dirs) {
103
+ const file = path.join(dir, "settings.json");
104
+ try {
105
+ if (editJson(file, (d) => removeHooks(d, "nested", "machine") > 0, { drop: true })) lines.push(`Claude Code hooks: removed from ${file}`);
106
+ } catch {
107
+ }
108
+ }
109
+ if (inst.codex_dir) {
110
+ const file = path.join(inst.codex_dir, "hooks.json");
111
+ try {
112
+ if (editJson(file, (d) => removeHooks(d, "nested", "machine") > 0, { drop: true })) lines.push(`Codex hooks: removed from ${file}`);
113
+ } catch {
114
+ }
115
+ const cfg = path.join(inst.codex_dir, "config.toml");
116
+ const before = readText(cfg);
117
+ if (before !== void 0) {
118
+ const next = restoreFeatureHooks(before);
119
+ if (next !== before) {
120
+ if (wasCreated(cfg) && next.trim() === "") {
121
+ removeFile(cfg);
122
+ forgetCreated(cfg);
123
+ } else {
124
+ atomicWrite(cfg, next);
125
+ dropBackupIfSame(cfg);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ return lines;
131
+ }
132
+
133
+ export {
134
+ installCliCopy,
135
+ removeCliCopy,
136
+ installMachineHooks,
137
+ removeMachineHooks
138
+ };
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ // package.json
4
+ var package_default = {
5
+ name: "@hivefloor/cli",
6
+ version: "0.1.0",
7
+ description: "Connect your coding agents (Claude Code, Codex, Cursor, Gemini, Grok) to Hivefloor: live presence, task coordination and usage on one floor.",
8
+ keywords: [
9
+ "hivefloor",
10
+ "ai-agents",
11
+ "coding-agents",
12
+ "claude-code",
13
+ "codex",
14
+ "mcp",
15
+ "hooks",
16
+ "cli"
17
+ ],
18
+ homepage: "https://hivefloor.worldofz.info",
19
+ bugs: {
20
+ url: "https://github.com/Validate-QA/hivefloor/issues"
21
+ },
22
+ repository: {
23
+ type: "git",
24
+ url: "git+https://github.com/Validate-QA/hivefloor.git",
25
+ directory: "packages/cli"
26
+ },
27
+ license: "MIT",
28
+ type: "module",
29
+ bin: {
30
+ hivefloor: "dist/index.js"
31
+ },
32
+ files: [
33
+ "dist"
34
+ ],
35
+ engines: {
36
+ node: ">=22"
37
+ },
38
+ publishConfig: {
39
+ access: "public"
40
+ },
41
+ scripts: {
42
+ build: "tsup",
43
+ typecheck: "tsc -p tsconfig.json",
44
+ "pack-test": "bash scripts/pack-test.sh",
45
+ prepack: "npm run build && node scripts/pack-manifest.mjs strip",
46
+ postpack: "node scripts/pack-manifest.mjs restore"
47
+ },
48
+ devDependencies: {
49
+ "@hivefloor/shared": "workspace:*",
50
+ "@types/node": "^22.20.5",
51
+ tsup: "^8.5.1",
52
+ typescript: "~5.9.3"
53
+ },
54
+ dependencies: {
55
+ "@modelcontextprotocol/sdk": "^1.32.2"
56
+ },
57
+ optionalDependencies: {
58
+ "@napi-rs/keyring": "^2.1.2"
59
+ }
60
+ };
61
+
62
+ // src/version.ts
63
+ var VERSION = package_default.version;
64
+
65
+ export {
66
+ VERSION
67
+ };
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/hookclock.ts
4
+ var HARD_EXIT_MS = 4e3;
5
+
6
+ export {
7
+ HARD_EXIT_MS
8
+ };
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ export {
9
+ __export
10
+ };