@hivefloor/cli 0.1.5 → 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.
- package/LICENSE +6 -20
- package/README.md +29 -8
- package/dist/chunk-2ERPDCOT.js +38 -0
- package/dist/chunk-4G362W6G.js +19 -0
- package/dist/chunk-5OJUJCE3.js +817 -0
- package/dist/{chunk-U6RRUAC2.js → chunk-5XXYQQG6.js} +53 -8
- package/dist/chunk-AGIYVFDQ.js +10984 -0
- package/dist/{chunk-RYGL6XU4.js → chunk-BLLPDPTL.js} +4 -2
- package/dist/{chunk-3N5JYP5O.js → chunk-FPJNGKT5.js} +5 -3
- package/dist/chunk-HW3KRNCO.js +201 -0
- package/dist/{chunk-4DRHR7LR.js → chunk-HWBUESB4.js} +1158 -196
- package/dist/{chunk-C627OKTW.js → chunk-K2IRTZH5.js} +7 -6
- package/dist/chunk-KQMPCV57.js +122 -0
- package/dist/{chunk-J36OIJBM.js → chunk-L6EFW2SJ.js} +14 -10
- package/dist/{chunk-IJRHCDIG.js → chunk-LX5A25O6.js} +4 -2
- package/dist/{chunk-MZGGJ6ZS.js → chunk-MYJCU5JL.js} +4 -2
- package/dist/{chunk-H6NYMF2D.js → chunk-NMUH5NXN.js} +6 -4
- package/dist/{chunk-VX7SCIF2.js → chunk-NRJONTFT.js} +3 -1
- package/dist/chunk-QBBKGORP.js +327 -0
- package/dist/{chunk-SOXRITAW.js → chunk-QGULSOQ2.js} +3 -0
- package/dist/{chunk-6MDJB3BV.js → chunk-QLMLB7RB.js} +17 -9
- package/dist/{chunk-TKMIV7BG.js → chunk-QPAFN47B.js} +3 -1
- package/dist/chunk-SBOEAOHD.js +48 -0
- package/dist/{chunk-IWIDKNWC.js → chunk-TIR4CV3P.js} +21 -17
- package/dist/{chunk-6XVIEX75.js → chunk-X2KH6AR4.js} +25 -303
- package/dist/chunk-XAXKZ572.js +106 -0
- package/dist/{chunk-TPMFQUAW.js → chunk-XPGL7VYE.js} +12 -0
- package/dist/{cli-JCBZICR3.js → cli-BFOJWJNG.js} +56 -20
- package/dist/connect-ZJ4JXBAJ.js +27 -0
- package/dist/control-6GHTZQJV.js +25 -0
- package/dist/{disconnect-WQMDCUXT.js → disconnect-3T25NTKX.js} +24 -17
- package/dist/{hook-AYJNRGIY.js → hook-TPSHBCWU.js} +277 -17
- package/dist/index.js +9 -6
- package/dist/{link-ORT4LID6.js → link-EAS5F5PC.js} +14 -11
- package/dist/{machine-connect-N52CKQEW.js → machine-connect-KEI4BRWF.js} +23 -17
- package/dist/mcp-LVIYR3EN.js +1882 -0
- package/dist/orch-KVRL2YA2.js +137 -0
- package/dist/{run-ZAZ45MKQ.js → run-JL2OZWK3.js} +1920 -28
- package/dist/{status-GOCFNO7K.js → status-QXOOJGGN.js} +14 -11
- package/dist/{token-EMM4AJAU.js → token-BFWWQIDA.js} +10 -7
- package/dist/{voice-F5MIS3IZ.js → voice-QXHFXRWG.js} +5 -3
- package/dist/{where-XFXRTP7E.js → where-CMUORQIO.js} +11 -8
- package/package.json +5 -6
- package/dist/chunk-JCLWCMEM.js +0 -8
- package/dist/chunk-K3NQKI34.js +0 -10
- package/dist/chunk-X6B6R32A.js +0 -303
- package/dist/connect-2HLVPEOL.js +0 -23
- package/dist/mcp-2SF6Y73M.js +0 -118
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
4
|
+
import {
|
|
5
|
+
userBinDirs
|
|
6
|
+
} from "./chunk-XAXKZ572.js";
|
|
2
7
|
import {
|
|
3
8
|
atomicWrite,
|
|
4
9
|
atomicWriteUtf16,
|
|
@@ -8,15 +13,15 @@ import {
|
|
|
8
13
|
isRecord,
|
|
9
14
|
readText,
|
|
10
15
|
removeFile
|
|
11
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XPGL7VYE.js";
|
|
12
17
|
import {
|
|
13
18
|
normalizeHost,
|
|
14
19
|
runCmd,
|
|
15
20
|
sameOrigin
|
|
16
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-QGULSOQ2.js";
|
|
17
22
|
import {
|
|
18
23
|
cliNpxCommand
|
|
19
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-HWBUESB4.js";
|
|
20
25
|
|
|
21
26
|
// src/service/units.ts
|
|
22
27
|
import os from "os";
|
|
@@ -27,8 +32,11 @@ var SCHTASKS_TASK = "Hivefloor Machine";
|
|
|
27
32
|
var xml = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
28
33
|
var sdEscape = (s) => s.replace(/(["\\$])/g, "\\$1").replace(/%/g, "%%");
|
|
29
34
|
var sdQuote = (s) => /^[\w@+=:,./-]+$/.test(s) ? s : `"${sdEscape(s)}"`;
|
|
35
|
+
function unitPath(plan, system, homeDir = home()) {
|
|
36
|
+
if (/[\r\n\0]/.test(homeDir)) throw new Error("refusing to write a service unit: HOME contains a control character");
|
|
37
|
+
return [path.dirname(plan.node), ...userBinDirs(homeDir), ...system].filter((d, i, a) => a.indexOf(d) === i).join(":");
|
|
38
|
+
}
|
|
30
39
|
function launchdPlist(plan) {
|
|
31
|
-
const bin = path.dirname(plan.node);
|
|
32
40
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
33
41
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
34
42
|
<plist version="1.0">
|
|
@@ -54,7 +62,7 @@ function launchdPlist(plan) {
|
|
|
54
62
|
<key>EnvironmentVariables</key>
|
|
55
63
|
<dict>
|
|
56
64
|
<key>PATH</key>
|
|
57
|
-
<string>${xml(
|
|
65
|
+
<string>${xml(unitPath(plan, ["/usr/bin", "/bin", "/usr/sbin", "/sbin"]))}</string>
|
|
58
66
|
</dict>
|
|
59
67
|
<key>StandardOutPath</key>
|
|
60
68
|
<string>/dev/null</string>
|
|
@@ -66,14 +74,14 @@ function launchdPlist(plan) {
|
|
|
66
74
|
}
|
|
67
75
|
function systemdUnit(plan) {
|
|
68
76
|
return `[Unit]
|
|
69
|
-
Description=
|
|
77
|
+
Description=HiveFloor machine service
|
|
70
78
|
After=network-online.target
|
|
71
79
|
|
|
72
80
|
[Service]
|
|
73
81
|
ExecStart=${sdQuote(plan.node)} ${sdQuote(plan.script)} service run
|
|
74
82
|
Restart=on-failure
|
|
75
83
|
RestartSec=30
|
|
76
|
-
Environment="PATH=${sdEscape(
|
|
84
|
+
Environment="PATH=${sdEscape(unitPath(plan, ["/usr/bin", "/bin"]))}"
|
|
77
85
|
|
|
78
86
|
[Install]
|
|
79
87
|
WantedBy=default.target
|
|
@@ -95,7 +103,7 @@ function windowsTaskXml(plan, user) {
|
|
|
95
103
|
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
96
104
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
97
105
|
<RegistrationInfo>
|
|
98
|
-
<Description>
|
|
106
|
+
<Description>HiveFloor machine service</Description>
|
|
99
107
|
</RegistrationInfo>
|
|
100
108
|
<Triggers>
|
|
101
109
|
<LogonTrigger>
|
|
@@ -278,7 +286,7 @@ function writeCredentials(c) {
|
|
|
278
286
|
}
|
|
279
287
|
atomicWrite(file, JSON.stringify(c, null, 2) + "\n", 384);
|
|
280
288
|
}
|
|
281
|
-
var windowsAclError = () => new Error("could not restrict the
|
|
289
|
+
var windowsAclError = () => new Error("could not restrict the HiveFloor config to your Windows user with icacls; the token was not kept");
|
|
282
290
|
async function secureWindowsCredentials(run, username) {
|
|
283
291
|
if (!username) throw new Error("could not determine the Windows user; the token was not kept");
|
|
284
292
|
const dir = prepareConfigDir();
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
2
4
|
|
|
3
5
|
// src/args.ts
|
|
4
|
-
var BOOLEAN = /* @__PURE__ */ new Set(["no-open", "yes", "y", "reveal", "help", "h", "json", "no-cli", "agent", "no-service"]);
|
|
6
|
+
var BOOLEAN = /* @__PURE__ */ new Set(["no-open", "yes", "y", "reveal", "help", "h", "json", "no-cli", "agent", "no-service", "permission-prompt", "full", "no-full"]);
|
|
5
7
|
function parseArgs(argv) {
|
|
6
8
|
const positionals = [];
|
|
7
9
|
const flags = {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/service/control/private.ts
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
var uid = () => typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
8
|
+
function ensurePrivateDir(dir) {
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
10
|
+
if (process.platform !== "win32") fs.chmodSync(dir, 448);
|
|
11
|
+
}
|
|
12
|
+
function privateDirTrouble(dir) {
|
|
13
|
+
let st;
|
|
14
|
+
try {
|
|
15
|
+
st = fs.lstatSync(dir);
|
|
16
|
+
} catch {
|
|
17
|
+
return `${dir} does not exist`;
|
|
18
|
+
}
|
|
19
|
+
if (st.isSymbolicLink() || !st.isDirectory()) return `${dir} is not a plain folder`;
|
|
20
|
+
if (process.platform === "win32") return void 0;
|
|
21
|
+
if (uid() !== void 0 && st.uid !== uid()) return `${dir} is owned by another user`;
|
|
22
|
+
if ((st.mode & 63) !== 0) return `${dir} is open to group or others`;
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
function privateFileTrouble(file) {
|
|
26
|
+
let st;
|
|
27
|
+
try {
|
|
28
|
+
st = fs.lstatSync(file);
|
|
29
|
+
} catch {
|
|
30
|
+
return `${file} does not exist`;
|
|
31
|
+
}
|
|
32
|
+
if (st.isSymbolicLink() || !st.isFile()) return `${file} is not a regular file`;
|
|
33
|
+
if (process.platform === "win32") return void 0;
|
|
34
|
+
if (uid() !== void 0 && st.uid !== uid()) return `${file} is owned by another user`;
|
|
35
|
+
if ((st.mode & 63) !== 0) return `${file} is open to group or others`;
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
function safeName(id) {
|
|
39
|
+
const s = id.replace(/[^A-Za-z0-9_.-]/g, "_").replace(/^\.+/, "_").slice(0, 120);
|
|
40
|
+
return s === "" ? "_" : s;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
ensurePrivateDir,
|
|
45
|
+
privateDirTrouble,
|
|
46
|
+
privateFileTrouble,
|
|
47
|
+
safeName
|
|
48
|
+
};
|
|
@@ -1,44 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
2
4
|
import {
|
|
3
5
|
deviceLogin
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FPJNGKT5.js";
|
|
5
7
|
import {
|
|
6
8
|
RC_LINE,
|
|
7
9
|
addRcLine,
|
|
8
|
-
emptyReport,
|
|
9
|
-
envTokenSharedWith,
|
|
10
10
|
hasRcLine,
|
|
11
|
-
installClaude,
|
|
12
|
-
installCodex,
|
|
13
11
|
installCursor,
|
|
14
12
|
installGemini,
|
|
15
13
|
installGrok,
|
|
16
|
-
rcFileFor
|
|
14
|
+
rcFileFor
|
|
15
|
+
} from "./chunk-QBBKGORP.js";
|
|
16
|
+
import {
|
|
17
|
+
emptyReport,
|
|
18
|
+
envTokenSharedWith,
|
|
19
|
+
installClaude,
|
|
20
|
+
installCodex,
|
|
17
21
|
readManifest,
|
|
18
22
|
toolReadsEnvToken,
|
|
19
23
|
updateManifest
|
|
20
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-X2KH6AR4.js";
|
|
21
25
|
import {
|
|
22
26
|
detectRepo
|
|
23
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-BLLPDPTL.js";
|
|
24
28
|
import {
|
|
25
29
|
defaultHost,
|
|
26
30
|
loadToken,
|
|
27
31
|
saveToken
|
|
28
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-QLMLB7RB.js";
|
|
29
33
|
import {
|
|
30
34
|
checkUnknownFlags,
|
|
31
35
|
flagStr
|
|
32
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-QPAFN47B.js";
|
|
33
37
|
import {
|
|
34
38
|
VERSION
|
|
35
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-K2IRTZH5.js";
|
|
36
40
|
import {
|
|
37
41
|
readMachine
|
|
38
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-LX5A25O6.js";
|
|
39
43
|
import {
|
|
40
44
|
ApiError
|
|
41
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-NRJONTFT.js";
|
|
42
46
|
import {
|
|
43
47
|
ConfigError,
|
|
44
48
|
REAL_TOOLS,
|
|
@@ -47,19 +51,19 @@ import {
|
|
|
47
51
|
findBin,
|
|
48
52
|
isTool,
|
|
49
53
|
toolFromEnv
|
|
50
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-XPGL7VYE.js";
|
|
51
55
|
import {
|
|
52
56
|
hostFromEnv,
|
|
53
57
|
hostFromFlag,
|
|
54
58
|
machineName,
|
|
55
59
|
normalizeHost,
|
|
56
60
|
sameOrigin
|
|
57
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-QGULSOQ2.js";
|
|
58
62
|
import {
|
|
59
63
|
CLI_BIN_NAME,
|
|
60
64
|
CLI_INSTALL_COMMAND,
|
|
61
65
|
cliNpxCommand
|
|
62
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-HWBUESB4.js";
|
|
63
67
|
|
|
64
68
|
// src/connect.ts
|
|
65
69
|
var INSTALLERS = {
|
|
@@ -252,7 +256,7 @@ async function connect(ctx, p) {
|
|
|
252
256
|
return 2;
|
|
253
257
|
}
|
|
254
258
|
if (p.flags.agent || p.flags.tool !== void 0) return connectAgent(ctx, p);
|
|
255
|
-
return (await import("./machine-connect-
|
|
259
|
+
return (await import("./machine-connect-KEI4BRWF.js")).connectMachine(ctx, p);
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
export {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
2
4
|
import {
|
|
3
5
|
ApiError
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NRJONTFT.js";
|
|
5
7
|
import {
|
|
6
8
|
atomicWrite,
|
|
7
9
|
backupOnce,
|
|
@@ -14,14 +16,11 @@ import {
|
|
|
14
16
|
readText,
|
|
15
17
|
removeFile,
|
|
16
18
|
serializeJson
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XPGL7VYE.js";
|
|
18
20
|
import {
|
|
19
21
|
runCmd,
|
|
20
22
|
sameOrigin
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import {
|
|
23
|
-
cliNpxCommand
|
|
24
|
-
} from "./chunk-4DRHR7LR.js";
|
|
23
|
+
} from "./chunk-QGULSOQ2.js";
|
|
25
24
|
|
|
26
25
|
// src/manifest.ts
|
|
27
26
|
function readManifest() {
|
|
@@ -71,54 +70,8 @@ function envTokenSharedWith(host, tool, shellExportsToken) {
|
|
|
71
70
|
});
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
// src/shellrc.ts
|
|
75
|
-
import fs from "fs";
|
|
76
|
-
import path from "path";
|
|
77
|
-
var RC_MARK = "# hivefloor";
|
|
78
|
-
var RC_LINE = `export HIVEFLOOR_TOKEN="$(hivefloor token)" ${RC_MARK}`;
|
|
79
|
-
function rcFileFor(env) {
|
|
80
|
-
const shell = path.basename(env.SHELL ?? "");
|
|
81
|
-
if (shell === "zsh") return path.join(home(), ".zshrc");
|
|
82
|
-
if (shell === "bash") {
|
|
83
|
-
const profile = path.join(home(), ".bash_profile");
|
|
84
|
-
return process.platform === "darwin" && fs.existsSync(profile) ? profile : path.join(home(), ".bashrc");
|
|
85
|
-
}
|
|
86
|
-
return void 0;
|
|
87
|
-
}
|
|
88
|
-
function isRcLine(line) {
|
|
89
|
-
const t = line.trim();
|
|
90
|
-
return !t.startsWith("#") && t.includes("HIVEFLOOR_TOKEN") && t.includes("hivefloor token") && t.endsWith(RC_MARK);
|
|
91
|
-
}
|
|
92
|
-
function hasRcLine(file) {
|
|
93
|
-
return (readText(file) ?? "").split("\n").some(isRcLine);
|
|
94
|
-
}
|
|
95
|
-
function addRcLine(file) {
|
|
96
|
-
if (hasRcLine(file)) return false;
|
|
97
|
-
const cur = readText(file);
|
|
98
|
-
if (cur === void 0) addCreated(file);
|
|
99
|
-
const sep = cur && !cur.endsWith("\n") ? "\n" : "";
|
|
100
|
-
atomicWrite(file, `${cur ?? ""}${sep}${RC_LINE}
|
|
101
|
-
`);
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
function removeRcLine(file) {
|
|
105
|
-
const cur = readText(file);
|
|
106
|
-
if (cur === void 0) return false;
|
|
107
|
-
const lines = cur.split("\n");
|
|
108
|
-
const kept = lines.filter((l) => !isRcLine(l));
|
|
109
|
-
if (kept.length === lines.length) return false;
|
|
110
|
-
const next = kept.join("\n");
|
|
111
|
-
if (next.trim() === "" && wasCreated(file)) {
|
|
112
|
-
fs.rmSync(file, { force: true });
|
|
113
|
-
forgetCreated(file);
|
|
114
|
-
} else {
|
|
115
|
-
atomicWrite(file, next);
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
73
|
// src/writers/common.ts
|
|
121
|
-
import
|
|
74
|
+
import fs from "fs";
|
|
122
75
|
var emptyReport = () => ({ lines: [], warnings: [] });
|
|
123
76
|
var CLI_COPY_RE = /hivefloor[/\\]cli[/\\]index\.js$/;
|
|
124
77
|
var MACHINE_CMD_RE = /hivefloor[/\\]+cli[/\\]+index\.js"?\s+hook\s/;
|
|
@@ -197,7 +150,7 @@ function editJson(file, mutate, opts = {}) {
|
|
|
197
150
|
function secureFile(file) {
|
|
198
151
|
for (const f of [file, `${file}.hivefloor.bak`]) {
|
|
199
152
|
try {
|
|
200
|
-
|
|
153
|
+
fs.chmodSync(f, 384);
|
|
201
154
|
} catch {
|
|
202
155
|
}
|
|
203
156
|
}
|
|
@@ -214,10 +167,10 @@ function dropBackupWithEntry(file, name) {
|
|
|
214
167
|
}
|
|
215
168
|
|
|
216
169
|
// src/writers/claude.ts
|
|
217
|
-
import
|
|
170
|
+
import path from "path";
|
|
218
171
|
var CLAUDE_EVENTS = ["SessionStart", "SessionEnd", "UserPromptSubmit", "Stop", "Notification", "SubagentStart", "SubagentStop"];
|
|
219
|
-
var claudeJson = () =>
|
|
220
|
-
var claudeSettings = () =>
|
|
172
|
+
var claudeJson = () => path.join(home(), ".claude.json");
|
|
173
|
+
var claudeSettings = () => path.join(home(), ".claude", "settings.json");
|
|
221
174
|
var MCP_NAME = "hivefloor";
|
|
222
175
|
function claudeHookSpecs() {
|
|
223
176
|
return CLAUDE_EVENTS.map((event) => ({
|
|
@@ -295,7 +248,7 @@ async function removeClaude(ctx, viaCli, keepHooks = false, viaFile = false) {
|
|
|
295
248
|
}
|
|
296
249
|
|
|
297
250
|
// src/writers/codex.ts
|
|
298
|
-
import
|
|
251
|
+
import path2 from "path";
|
|
299
252
|
|
|
300
253
|
// src/writers/toml.ts
|
|
301
254
|
var BEGIN = (name, sep) => `# hivefloor:begin ${name} sep=${sep}`;
|
|
@@ -423,9 +376,9 @@ function restoreFeatureHooks(content) {
|
|
|
423
376
|
|
|
424
377
|
// src/writers/codex.ts
|
|
425
378
|
var CODEX_EVENTS = ["SessionStart", "SessionEnd", "UserPromptSubmit", "Stop", "SubagentStart", "SubagentStop"];
|
|
426
|
-
var codexDir = () =>
|
|
427
|
-
var codexConfig = () =>
|
|
428
|
-
var codexHooks = () =>
|
|
379
|
+
var codexDir = () => path2.join(process.env.CODEX_HOME || path2.join(home(), ".codex"));
|
|
380
|
+
var codexConfig = () => path2.join(codexDir(), "config.toml");
|
|
381
|
+
var codexHooks = () => path2.join(codexDir(), "hooks.json");
|
|
429
382
|
function codexHookSpecs() {
|
|
430
383
|
return CODEX_EVENTS.map((event) => ({ event, entry: { type: "command", command: `hivefloor hook codex ${event}` } }));
|
|
431
384
|
}
|
|
@@ -530,7 +483,7 @@ async function installCodex(i) {
|
|
|
530
483
|
report.lines.push(`Codex hooks: ${codexHooks()} (${CODEX_EVENTS.join(", ")})`);
|
|
531
484
|
editToml(enableFeatureHooks);
|
|
532
485
|
report.lines.push(`Codex: features.hooks = true in ${codexConfig()}`);
|
|
533
|
-
report.warnings.push("Codex asks you to trust new hooks: run codex, open /hooks and approve the
|
|
486
|
+
report.warnings.push("Codex asks you to trust new hooks: run codex, open /hooks and approve the HiveFloor hooks once.");
|
|
534
487
|
}
|
|
535
488
|
}
|
|
536
489
|
return { report, mcp };
|
|
@@ -552,234 +505,6 @@ async function removeCodex(ctx, viaCli, keepHooks = false) {
|
|
|
552
505
|
return report;
|
|
553
506
|
}
|
|
554
507
|
|
|
555
|
-
// src/writers/cursor.ts
|
|
556
|
-
import path4 from "path";
|
|
557
|
-
var CURSOR_EVENTS = ["sessionStart", "sessionEnd", "beforeSubmitPrompt", "stop", "subagentStart", "subagentStop"];
|
|
558
|
-
var cursorMcp = () => path4.join(home(), ".cursor", "mcp.json");
|
|
559
|
-
var cursorHooks = () => path4.join(home(), ".cursor", "hooks.json");
|
|
560
|
-
function cursorHookSpecs() {
|
|
561
|
-
return CURSOR_EVENTS.map((event) => ({ event, entry: { command: `hivefloor hook cursor ${event}` } }));
|
|
562
|
-
}
|
|
563
|
-
async function installCursor(i) {
|
|
564
|
-
const report = emptyReport();
|
|
565
|
-
const auth = i.useEnvToken ? "Bearer ${env:HIVEFLOOR_TOKEN}" : `Bearer ${i.token}`;
|
|
566
|
-
editJson(
|
|
567
|
-
cursorMcp(),
|
|
568
|
-
(d) => {
|
|
569
|
-
const servers = isRecord(d.mcpServers) ? d.mcpServers : d.mcpServers = {};
|
|
570
|
-
servers[MCP_NAME] = { url: i.mcpUrl, headers: { Authorization: auth } };
|
|
571
|
-
return true;
|
|
572
|
-
},
|
|
573
|
-
i.useEnvToken ? {} : { mode: 384 }
|
|
574
|
-
);
|
|
575
|
-
report.lines.push(`Cursor MCP: ${cursorMcp()} (mcpServers.${MCP_NAME})`);
|
|
576
|
-
i.onMcpRegistered?.("file");
|
|
577
|
-
if (!i.mcpOnly) {
|
|
578
|
-
editJson(cursorHooks(), (d) => {
|
|
579
|
-
if (d.version === void 0) d.version = 1;
|
|
580
|
-
addHooks(d, "flat", cursorHookSpecs());
|
|
581
|
-
return true;
|
|
582
|
-
});
|
|
583
|
-
report.lines.push(`Cursor hooks: ${cursorHooks()} (${CURSOR_EVENTS.join(", ")})`);
|
|
584
|
-
}
|
|
585
|
-
return { report, mcp: "file" };
|
|
586
|
-
}
|
|
587
|
-
async function removeCursor() {
|
|
588
|
-
const report = emptyReport();
|
|
589
|
-
const changed = editJson(
|
|
590
|
-
cursorMcp(),
|
|
591
|
-
(d) => {
|
|
592
|
-
if (!isRecord(d.mcpServers) || !(MCP_NAME in d.mcpServers)) return false;
|
|
593
|
-
delete d.mcpServers[MCP_NAME];
|
|
594
|
-
if (Object.keys(d.mcpServers).length === 0) delete d.mcpServers;
|
|
595
|
-
return true;
|
|
596
|
-
},
|
|
597
|
-
{ drop: true }
|
|
598
|
-
);
|
|
599
|
-
if (changed) report.lines.push(`Cursor MCP: removed from ${cursorMcp()}`);
|
|
600
|
-
if (editJson(cursorHooks(), (d) => removeHooks(d, "flat") > 0, { drop: true })) report.lines.push(`Cursor hooks: removed from ${cursorHooks()}`);
|
|
601
|
-
return report;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// src/writers/gemini.ts
|
|
605
|
-
import path5 from "path";
|
|
606
|
-
var GEMINI_EVENTS = ["SessionStart", "SessionEnd", "AfterAgent"];
|
|
607
|
-
var geminiSettings = () => path5.join(home(), ".gemini", "settings.json");
|
|
608
|
-
function geminiHookSpecs() {
|
|
609
|
-
return GEMINI_EVENTS.map((event) => ({
|
|
610
|
-
event,
|
|
611
|
-
// Gemini hook entries carry a name: ours is "hivefloor", which is also how disconnect finds them.
|
|
612
|
-
entry: { name: "hivefloor", type: "command", command: `hivefloor hook gemini ${event}` }
|
|
613
|
-
}));
|
|
614
|
-
}
|
|
615
|
-
async function installGemini(i) {
|
|
616
|
-
const report = emptyReport();
|
|
617
|
-
const auth = i.useEnvToken ? "Bearer $HIVEFLOOR_TOKEN" : `Bearer ${i.token}`;
|
|
618
|
-
let mcp = "file";
|
|
619
|
-
const priorCli = !i.useEnvToken && readManifest().tools.gemini?.mcp === "cli";
|
|
620
|
-
const bin = i.noCli ? void 0 : findBin("gemini", i.ctx.env);
|
|
621
|
-
if (bin && (i.useEnvToken || priorCli)) {
|
|
622
|
-
await runCmd(bin, ["mcp", "remove", MCP_NAME, "-s", "user"], { env: i.ctx.env });
|
|
623
|
-
if (i.useEnvToken) {
|
|
624
|
-
const r = await runCmd(bin, ["mcp", "add", MCP_NAME, i.mcpUrl, "-t", "http", "-s", "user", "-H", `Authorization: ${auth}`], { env: i.ctx.env });
|
|
625
|
-
if (r.code === 0) {
|
|
626
|
-
mcp = "cli";
|
|
627
|
-
report.lines.push(`Gemini MCP: gemini mcp add (user scope) -> ${i.mcpUrl}`);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (mcp === "file") {
|
|
632
|
-
editJson(
|
|
633
|
-
geminiSettings(),
|
|
634
|
-
(d) => {
|
|
635
|
-
const servers = isRecord(d.mcpServers) ? d.mcpServers : d.mcpServers = {};
|
|
636
|
-
servers[MCP_NAME] = { httpUrl: i.mcpUrl, headers: { Authorization: auth } };
|
|
637
|
-
return true;
|
|
638
|
-
},
|
|
639
|
-
i.useEnvToken ? {} : { mode: 384 }
|
|
640
|
-
);
|
|
641
|
-
if (!i.useEnvToken) secureFile(geminiSettings());
|
|
642
|
-
report.lines.push(`Gemini MCP: ${geminiSettings()} (mcpServers.${MCP_NAME})`);
|
|
643
|
-
}
|
|
644
|
-
i.onMcpRegistered?.(mcp);
|
|
645
|
-
if (!i.mcpOnly) {
|
|
646
|
-
editJson(geminiSettings(), (d) => (addHooks(d, "nested", geminiHookSpecs()), true), i.useEnvToken ? {} : { mode: 384 });
|
|
647
|
-
report.lines.push(`Gemini hooks: ${geminiSettings()} (${GEMINI_EVENTS.join(", ")})`);
|
|
648
|
-
}
|
|
649
|
-
return { report, mcp };
|
|
650
|
-
}
|
|
651
|
-
async function removeGemini(ctx, viaCli, viaFile = false) {
|
|
652
|
-
const report = emptyReport();
|
|
653
|
-
if (viaCli) {
|
|
654
|
-
const bin = findBin("gemini", ctx.env);
|
|
655
|
-
if (bin && (await runCmd(bin, ["mcp", "remove", MCP_NAME, "-s", "user"], { env: ctx.env })).code === 0) report.lines.push("Gemini MCP: gemini mcp remove");
|
|
656
|
-
}
|
|
657
|
-
const changed = editJson(
|
|
658
|
-
geminiSettings(),
|
|
659
|
-
(d) => {
|
|
660
|
-
let did = removeHooks(d, "nested") > 0;
|
|
661
|
-
if (viaFile && isRecord(d.mcpServers) && MCP_NAME in d.mcpServers) {
|
|
662
|
-
delete d.mcpServers[MCP_NAME];
|
|
663
|
-
if (Object.keys(d.mcpServers).length === 0) delete d.mcpServers;
|
|
664
|
-
did = true;
|
|
665
|
-
}
|
|
666
|
-
return did;
|
|
667
|
-
},
|
|
668
|
-
{ drop: true }
|
|
669
|
-
);
|
|
670
|
-
if (changed) report.lines.push(`Gemini: removed our entries from ${geminiSettings()}`);
|
|
671
|
-
dropBackupWithEntry(geminiSettings(), MCP_NAME);
|
|
672
|
-
return report;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// src/writers/grok.ts
|
|
676
|
-
import path6 from "path";
|
|
677
|
-
var grokConfig = () => path6.join(home(), ".grok", "config.toml");
|
|
678
|
-
var HOOKS_LINE = "Grok hooks: none needed (Grok reads the Claude Code hooks in ~/.claude/settings.json; connect Claude Code too for live sessions)";
|
|
679
|
-
function editGrokToml(fn, opts = {}) {
|
|
680
|
-
const file = grokConfig();
|
|
681
|
-
const before = readText(file);
|
|
682
|
-
const next = fn(before ?? "");
|
|
683
|
-
if (next === (before ?? "")) return false;
|
|
684
|
-
if (opts.drop && wasCreated(file) && next.trim() === "") {
|
|
685
|
-
removeFile(file);
|
|
686
|
-
forgetCreated(file);
|
|
687
|
-
return true;
|
|
688
|
-
}
|
|
689
|
-
if (before === void 0) addCreated(file);
|
|
690
|
-
else if (!wasCreated(file)) backupOnce(file);
|
|
691
|
-
atomicWrite(file, next, opts.mode);
|
|
692
|
-
if (opts.drop) dropBackupIfSame(file);
|
|
693
|
-
return true;
|
|
694
|
-
}
|
|
695
|
-
function grokMcpBlock(mcpUrl, auth) {
|
|
696
|
-
return `[mcp_servers.${MCP_NAME}]
|
|
697
|
-
url = ${tomlString(mcpUrl)}
|
|
698
|
-
enabled = true
|
|
699
|
-
|
|
700
|
-
[mcp_servers.${MCP_NAME}.headers]
|
|
701
|
-
Authorization = ${tomlString(auth)}`;
|
|
702
|
-
}
|
|
703
|
-
var GROK_TABLE = `mcp_servers.${MCP_NAME}`;
|
|
704
|
-
var ENV_AUTH = "Bearer ${HIVEFLOOR_TOKEN}";
|
|
705
|
-
function outsideHasRawAuthorization(content) {
|
|
706
|
-
const stripped = content.replace(/# hivefloor:begin[\s\S]*?# hivefloor:end [^\n]*(?:\n|$)/g, "");
|
|
707
|
-
let inTable = false;
|
|
708
|
-
for (const line of stripped.split("\n")) {
|
|
709
|
-
const bare = line.replace(/\r$/, "");
|
|
710
|
-
const header = /^\s*\[\s*([^\]]+?)\s*\]/.exec(bare);
|
|
711
|
-
if (header) {
|
|
712
|
-
const name = header[1].replace(/\s+/g, "");
|
|
713
|
-
inTable = name === GROK_TABLE || name.startsWith(`${GROK_TABLE}.`);
|
|
714
|
-
continue;
|
|
715
|
-
}
|
|
716
|
-
if (!inTable) continue;
|
|
717
|
-
const auth = /Authorization\s*=\s*["']([^"']*)["']/.exec(bare);
|
|
718
|
-
if (auth && auth[1] !== ENV_AUTH) return true;
|
|
719
|
-
}
|
|
720
|
-
return false;
|
|
721
|
-
}
|
|
722
|
-
async function dropOutsideServer(env, bin) {
|
|
723
|
-
const file = grokConfig();
|
|
724
|
-
const bak = `${file}.hivefloor.bak`;
|
|
725
|
-
const before = readText(file);
|
|
726
|
-
const beforeBak = readText(bak);
|
|
727
|
-
const staleLive = before !== void 0 && hasOutsideTable(before, GROK_TABLE);
|
|
728
|
-
const staleBak = beforeBak !== void 0 && hasOutsideTable(beforeBak, GROK_TABLE);
|
|
729
|
-
if (!staleLive && !staleBak) return false;
|
|
730
|
-
if (bin && staleLive) await runCmd(bin, ["mcp", "remove", MCP_NAME, "-s", "user"], { env });
|
|
731
|
-
for (const f of [file, bak]) {
|
|
732
|
-
const cur = readText(f);
|
|
733
|
-
if (cur === void 0 || !hasOutsideTable(cur, GROK_TABLE)) continue;
|
|
734
|
-
const next = removeOutsideTable(cur, GROK_TABLE);
|
|
735
|
-
if (next.trim() === "") removeFile(f);
|
|
736
|
-
else atomicWrite(f, next);
|
|
737
|
-
}
|
|
738
|
-
const left = readText(file);
|
|
739
|
-
if (left !== void 0 && left.trim() === "") removeFile(file);
|
|
740
|
-
return true;
|
|
741
|
-
}
|
|
742
|
-
async function installGrok(i) {
|
|
743
|
-
const report = emptyReport();
|
|
744
|
-
const auth = i.useEnvToken ? ENV_AUTH : `Bearer ${i.token}`;
|
|
745
|
-
const bin = i.noCli ? void 0 : findBin("grok", i.ctx.env);
|
|
746
|
-
const liveBefore = readText(grokConfig());
|
|
747
|
-
const bakBefore = readText(`${grokConfig()}.hivefloor.bak`);
|
|
748
|
-
const hadRaw = [liveBefore, bakBefore].some((t) => t !== void 0 && outsideHasRawAuthorization(t));
|
|
749
|
-
const removed = await dropOutsideServer(i.ctx.env, bin);
|
|
750
|
-
if (removed && hadRaw) report.warnings.push(`${grokConfig()} had [${GROK_TABLE}] outside our block; removed it so an older token does not stay on disk`);
|
|
751
|
-
if (bin && i.useEnvToken) {
|
|
752
|
-
await runCmd(bin, ["mcp", "remove", MCP_NAME, "-s", "user"], { env: i.ctx.env });
|
|
753
|
-
const r = await runCmd(bin, ["mcp", "add", "--transport", "http", MCP_NAME, i.mcpUrl, "-s", "user", "--header", `Authorization: ${auth}`], { env: i.ctx.env });
|
|
754
|
-
if (r.code === 0) {
|
|
755
|
-
report.lines.push(`Grok MCP: grok mcp add (user scope) -> ${i.mcpUrl}`);
|
|
756
|
-
if (!i.mcpOnly) report.lines.push(HOOKS_LINE);
|
|
757
|
-
i.onMcpRegistered?.("cli");
|
|
758
|
-
return { report, mcp: "cli" };
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
const file = grokConfig();
|
|
762
|
-
const changed = editGrokToml((c) => setBlock(c, "mcp", grokMcpBlock(i.mcpUrl, auth)), i.useEnvToken ? {} : { mode: 384 });
|
|
763
|
-
if (!i.useEnvToken && (changed || (readText(file) ?? "").includes(i.token))) secureFile(file);
|
|
764
|
-
if (changed || hasBlock(readText(file) ?? "", "mcp")) {
|
|
765
|
-
report.lines.push(`Grok MCP: ${file} ([${GROK_TABLE}])`);
|
|
766
|
-
if (!i.mcpOnly) report.lines.push(HOOKS_LINE);
|
|
767
|
-
i.onMcpRegistered?.("file");
|
|
768
|
-
return { report, mcp: "file" };
|
|
769
|
-
}
|
|
770
|
-
report.warnings.push(`Could not run the grok CLI. Add the server by hand: grok mcp add --transport http ${MCP_NAME} ${i.mcpUrl} -s user --header "Authorization: Bearer <token from ${cliNpxCommand("token --reveal")}>"`);
|
|
771
|
-
return { report, mcp: "manual" };
|
|
772
|
-
}
|
|
773
|
-
async function removeGrok(ctx, viaCli, viaFile = false) {
|
|
774
|
-
const report = emptyReport();
|
|
775
|
-
if (viaCli) {
|
|
776
|
-
const bin = findBin("grok", ctx.env);
|
|
777
|
-
if (bin && (await runCmd(bin, ["mcp", "remove", MCP_NAME, "-s", "user"], { env: ctx.env })).code === 0) report.lines.push("Grok MCP: grok mcp remove");
|
|
778
|
-
}
|
|
779
|
-
if (viaFile && editGrokToml((c) => removeBlock(c, "mcp"), { drop: true })) report.lines.push(`Grok MCP: removed from ${grokConfig()}`);
|
|
780
|
-
return report;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
508
|
export {
|
|
784
509
|
readManifest,
|
|
785
510
|
updateManifest,
|
|
@@ -788,29 +513,26 @@ export {
|
|
|
788
513
|
forgetCreated,
|
|
789
514
|
toolReadsEnvToken,
|
|
790
515
|
envTokenSharedWith,
|
|
791
|
-
RC_LINE,
|
|
792
|
-
rcFileFor,
|
|
793
|
-
hasRcLine,
|
|
794
|
-
addRcLine,
|
|
795
|
-
removeRcLine,
|
|
796
516
|
emptyReport,
|
|
797
517
|
addHooks,
|
|
798
518
|
removeHooks,
|
|
799
519
|
editJson,
|
|
520
|
+
secureFile,
|
|
521
|
+
dropBackupWithEntry,
|
|
800
522
|
CLAUDE_EVENTS,
|
|
801
523
|
claudeJson,
|
|
524
|
+
MCP_NAME,
|
|
802
525
|
installClaude,
|
|
803
526
|
removeClaude,
|
|
527
|
+
tomlString,
|
|
528
|
+
setBlock,
|
|
529
|
+
removeBlock,
|
|
530
|
+
hasBlock,
|
|
531
|
+
removeOutsideTable,
|
|
532
|
+
hasOutsideTable,
|
|
804
533
|
enableFeatureHooks,
|
|
805
534
|
restoreFeatureHooks,
|
|
806
535
|
CODEX_EVENTS,
|
|
807
536
|
installCodex,
|
|
808
|
-
removeCodex
|
|
809
|
-
installCursor,
|
|
810
|
-
removeCursor,
|
|
811
|
-
geminiSettings,
|
|
812
|
-
installGemini,
|
|
813
|
-
removeGemini,
|
|
814
|
-
installGrok,
|
|
815
|
-
removeGrok
|
|
537
|
+
removeCodex
|
|
816
538
|
};
|