@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.
- package/LICENSE +6 -20
- package/README.md +31 -9
- package/dist/chunk-2ERPDCOT.js +38 -0
- package/dist/chunk-4G362W6G.js +19 -0
- package/dist/chunk-5OJUJCE3.js +817 -0
- package/dist/chunk-5XXYQQG6.js +274 -0
- package/dist/chunk-AGIYVFDQ.js +10984 -0
- package/dist/{chunk-2BSA7LFD.js → chunk-BLLPDPTL.js} +7 -3
- package/dist/{chunk-R5KDI4WI.js → chunk-FPJNGKT5.js} +9 -3
- package/dist/chunk-HW3KRNCO.js +201 -0
- package/dist/{chunk-ZC2DAKB5.js → chunk-HWBUESB4.js} +1500 -316
- package/dist/{chunk-DNG5CRT3.js → chunk-K2IRTZH5.js} +8 -7
- package/dist/chunk-KQMPCV57.js +122 -0
- package/dist/{chunk-UJ4BQFWV.js → chunk-L6EFW2SJ.js} +53 -31
- package/dist/{chunk-T7TG6WA4.js → chunk-LX5A25O6.js} +4 -2
- package/dist/{chunk-W7DROKC7.js → chunk-MYJCU5JL.js} +89 -13
- package/dist/chunk-NMUH5NXN.js +52 -0
- package/dist/chunk-NRJONTFT.js +67 -0
- package/dist/chunk-QBBKGORP.js +327 -0
- package/dist/chunk-QGULSOQ2.js +142 -0
- package/dist/{chunk-PDXYOREI.js → chunk-QLMLB7RB.js} +110 -31
- package/dist/{chunk-TKMIV7BG.js → chunk-QPAFN47B.js} +3 -1
- package/dist/chunk-SBOEAOHD.js +48 -0
- package/dist/{chunk-SD65CIIY.js → chunk-TIR4CV3P.js} +117 -33
- package/dist/{chunk-QHYZBHXO.js → chunk-X2KH6AR4.js} +195 -251
- package/dist/chunk-XAXKZ572.js +106 -0
- package/dist/{chunk-VNCQFFQO.js → chunk-XPGL7VYE.js} +114 -1
- package/dist/cli-BFOJWJNG.js +279 -0
- package/dist/connect-ZJ4JXBAJ.js +27 -0
- package/dist/control-6GHTZQJV.js +25 -0
- package/dist/{disconnect-MKRHK4CX.js → disconnect-3T25NTKX.js} +55 -34
- package/dist/hook-TPSHBCWU.js +575 -0
- package/dist/index.js +9 -6
- package/dist/{link-HXBMMSG3.js → link-EAS5F5PC.js} +34 -18
- package/dist/{machine-connect-BYHZRRRB.js → machine-connect-KEI4BRWF.js} +30 -24
- package/dist/mcp-LVIYR3EN.js +1882 -0
- package/dist/orch-KVRL2YA2.js +137 -0
- package/dist/{run-336BSU72.js → run-JL2OZWK3.js} +1933 -29
- package/dist/{status-KBBSAADD.js → status-QXOOJGGN.js} +29 -14
- package/dist/token-BFWWQIDA.js +44 -0
- package/dist/voice-QXHFXRWG.js +264 -0
- package/dist/{where-KR7VWSEC.js → where-CMUORQIO.js} +20 -8
- package/package.json +6 -7
- package/dist/chunk-2IMJECYD.js +0 -71
- package/dist/chunk-7KF7IQJN.js +0 -30
- package/dist/chunk-GT3HFFT4.js +0 -132
- package/dist/chunk-JCLWCMEM.js +0 -8
- package/dist/chunk-K3NQKI34.js +0 -10
- package/dist/chunk-O2TC3WSS.js +0 -303
- package/dist/chunk-PY74LT2W.js +0 -41
- package/dist/cli-P3DYE5IR.js +0 -103
- package/dist/connect-ACNM5DQG.js +0 -23
- package/dist/hook-KR2HGVAR.js +0 -301
- package/dist/mcp-N2TMD4GR.js +0 -121
- package/dist/token-JDRLEV5D.js +0 -32
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __hfCreateRequire } from 'node:module';
|
|
3
|
+
const require = __hfCreateRequire(import.meta.url);
|
|
4
|
+
import {
|
|
5
|
+
PERMISSION_TIMEOUT_SEC
|
|
6
|
+
} from "./chunk-4G362W6G.js";
|
|
7
|
+
import {
|
|
8
|
+
CLAUDE_EVENTS,
|
|
9
|
+
CODEX_EVENTS,
|
|
10
|
+
addCreated,
|
|
11
|
+
addHooks,
|
|
12
|
+
editJson,
|
|
13
|
+
enableFeatureHooks,
|
|
14
|
+
forgetCreated,
|
|
15
|
+
removeHooks,
|
|
16
|
+
restoreFeatureHooks,
|
|
17
|
+
wasCreated
|
|
18
|
+
} from "./chunk-X2KH6AR4.js";
|
|
19
|
+
import {
|
|
20
|
+
activeVerbs,
|
|
21
|
+
readControl
|
|
22
|
+
} from "./chunk-KQMPCV57.js";
|
|
23
|
+
import {
|
|
24
|
+
claudeConfigDirs,
|
|
25
|
+
codexConfigDir,
|
|
26
|
+
profileKeys
|
|
27
|
+
} from "./chunk-L6EFW2SJ.js";
|
|
28
|
+
import {
|
|
29
|
+
atomicWrite,
|
|
30
|
+
backupOnce,
|
|
31
|
+
cliDir,
|
|
32
|
+
cliEntry,
|
|
33
|
+
dropBackupIfSame,
|
|
34
|
+
home,
|
|
35
|
+
isDir,
|
|
36
|
+
readText,
|
|
37
|
+
removeFile
|
|
38
|
+
} from "./chunk-XPGL7VYE.js";
|
|
39
|
+
|
|
40
|
+
// src/machine-hooks.ts
|
|
41
|
+
import fs from "fs";
|
|
42
|
+
import path from "path";
|
|
43
|
+
function installCliCopy(srcDir) {
|
|
44
|
+
if (!fs.existsSync(path.join(srcDir, "index.js"))) throw new Error(`cannot find the CLI bundle in ${srcDir}`);
|
|
45
|
+
const dest = cliDir();
|
|
46
|
+
fs.mkdirSync(dest, { recursive: true, mode: 448 });
|
|
47
|
+
for (const f of fs.readdirSync(srcDir)) {
|
|
48
|
+
if (!/\.(?:js|mjs)$/.test(f)) continue;
|
|
49
|
+
const tmp = path.join(dest, `${f}.${process.pid}.tmp`);
|
|
50
|
+
fs.copyFileSync(path.join(srcDir, f), tmp);
|
|
51
|
+
fs.renameSync(tmp, path.join(dest, f));
|
|
52
|
+
}
|
|
53
|
+
fs.writeFileSync(path.join(dest, "package.json"), '{"type":"module"}\n');
|
|
54
|
+
}
|
|
55
|
+
var removeCliCopy = () => fs.rmSync(cliDir(), { recursive: true, force: true });
|
|
56
|
+
function claudeMachineSpecs(node, profile, verbs = {}) {
|
|
57
|
+
const entry = (event, extra) => ({ type: "command", command: node, args: [cliEntry(), "hook", "claude", event, "--profile", profile], ...extra });
|
|
58
|
+
const specs = CLAUDE_EVENTS.map((event) => ({
|
|
59
|
+
event,
|
|
60
|
+
...event === "Notification" ? { matcher: "permission_prompt|idle_prompt" } : {},
|
|
61
|
+
// Exec form: no shell, no quoting. async: the hook never slows the agent down.
|
|
62
|
+
entry: entry(event, { async: true })
|
|
63
|
+
}));
|
|
64
|
+
if (verbs.message) specs.push({ event: "PostToolUse", entry: entry("PostToolUse", { async: true }) });
|
|
65
|
+
if (verbs.approve || verbs.deny) specs.push({ event: "PermissionRequest", entry: entry("PermissionRequest", { timeout: PERMISSION_TIMEOUT_SEC }) });
|
|
66
|
+
return specs;
|
|
67
|
+
}
|
|
68
|
+
var currentControlVerbs = () => activeVerbs(readControl());
|
|
69
|
+
function applyControlHooks(node, dirs, verbs) {
|
|
70
|
+
const out = { lines: [], warnings: [] };
|
|
71
|
+
const existing = distinctSettingsDirs(dirs.filter(isDir));
|
|
72
|
+
const keys = profileKeys("claude", existing);
|
|
73
|
+
for (const dir of existing) {
|
|
74
|
+
const file = path.join(dir, "settings.json");
|
|
75
|
+
try {
|
|
76
|
+
editJson(file, (d) => (addHooks(d, "nested", claudeMachineSpecs(node, keys.get(dir), verbs), "machine"), true));
|
|
77
|
+
out.lines.push(`Claude Code hooks (${keys.get(dir)}): ${file}`);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
out.warnings.push(e.message);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
var q = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
85
|
+
var CODEX_HOOK_CMD = "codex-hook.cmd";
|
|
86
|
+
var CMD_META = /[&|<>^%!]/;
|
|
87
|
+
var PS_META = /[$`;,']/;
|
|
88
|
+
function isWinPath(s) {
|
|
89
|
+
return /^[A-Za-z]:[\\/]|^\\\\|\\/.test(s);
|
|
90
|
+
}
|
|
91
|
+
function windowsCmdRules(paths) {
|
|
92
|
+
return process.platform === "win32" || paths.some(isWinPath);
|
|
93
|
+
}
|
|
94
|
+
function pathMod(s) {
|
|
95
|
+
return isWinPath(s) ? path.win32 : path;
|
|
96
|
+
}
|
|
97
|
+
function normalizeCmdPath(s) {
|
|
98
|
+
return isWinPath(s) ? path.win32.normalize(s) : s;
|
|
99
|
+
}
|
|
100
|
+
var hasCmdMeta = (s) => CMD_META.test(s);
|
|
101
|
+
var hasPsMeta = (s) => PS_META.test(s);
|
|
102
|
+
var bareClean = (s) => !/\s/.test(s) && !hasCmdMeta(s) && !hasPsMeta(s);
|
|
103
|
+
var doubleQuotedClean = (s) => !hasCmdMeta(s) && !hasPsMeta(s);
|
|
104
|
+
var qWinBody = (s) => `"${normalizeCmdPath(s).replace(/%/g, "%%").replace(/"/g, '""')}"`;
|
|
105
|
+
function shimCandidates(cliDirectory, homeDir) {
|
|
106
|
+
const m = pathMod(cliDirectory);
|
|
107
|
+
const cli = normalizeCmdPath(cliDirectory);
|
|
108
|
+
return [m.join(cli, CODEX_HOOK_CMD), m.join(m.dirname(cli), "codex-hook", CODEX_HOOK_CMD), m.join(homeDir, ".hivefloor", CODEX_HOOK_CMD)].map(normalizeCmdPath);
|
|
109
|
+
}
|
|
110
|
+
function codexShimPath(cliDirectory, homeDir) {
|
|
111
|
+
const ranked = shimCandidates(cliDirectory, homeDir);
|
|
112
|
+
const bare = ranked.find(bareClean);
|
|
113
|
+
if (bare) return bare;
|
|
114
|
+
const doubleOk = ranked.find(doubleQuotedClean);
|
|
115
|
+
if (doubleOk) return doubleOk;
|
|
116
|
+
const singleOk = ranked.find((p) => !hasCmdMeta(p));
|
|
117
|
+
if (singleOk) return singleOk;
|
|
118
|
+
if (windowsCmdRules(ranked)) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`cannot write the Codex Windows hook shim: every candidate contains a cmd metacharacter (& | < > ^ % !): ${ranked.join(", ")}. The shim was not written`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const beside = ranked[0];
|
|
124
|
+
if (beside !== void 0) return beside;
|
|
125
|
+
throw new Error("no Codex shim candidate");
|
|
126
|
+
}
|
|
127
|
+
function shimBesideCli(shim, cliDirectory) {
|
|
128
|
+
const m = pathMod(cliDirectory);
|
|
129
|
+
return m.normalize(m.dirname(shim)) === m.normalize(normalizeCmdPath(cliDirectory));
|
|
130
|
+
}
|
|
131
|
+
function codexHookCmd(node, script) {
|
|
132
|
+
const target = script ? qWinBody(script) : '"%~dp0index.js"';
|
|
133
|
+
return `@echo off\r
|
|
134
|
+
${qWinBody(node)} ${target} %*\r
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
function codexHookBody(node, cliDirectory, homeDir) {
|
|
138
|
+
const shim = codexShimPath(cliDirectory, homeDir);
|
|
139
|
+
const m = pathMod(cliDirectory);
|
|
140
|
+
const script = shimBesideCli(shim, cliDirectory) ? void 0 : m.join(normalizeCmdPath(cliDirectory), "index.js");
|
|
141
|
+
return codexHookCmd(node, script);
|
|
142
|
+
}
|
|
143
|
+
function codexCommandWindows(shim, event, profile) {
|
|
144
|
+
const win = normalizeCmdPath(shim);
|
|
145
|
+
if (hasCmdMeta(win) && !windowsCmdRules([win])) return void 0;
|
|
146
|
+
const tail = `hook codex ${event} --profile ${profile}`;
|
|
147
|
+
if (bareClean(win)) return `${win} ${tail}`;
|
|
148
|
+
if (!hasPsMeta(win)) return `& "${win.replace(/"/g, '""')}" ${tail}`;
|
|
149
|
+
return `& '${win.replace(/'/g, "''")}' ${tail}`;
|
|
150
|
+
}
|
|
151
|
+
function codexMachineSpecs(node, profile, shim = codexShimPath(cliDir(), home())) {
|
|
152
|
+
const tail = (event) => `hook codex ${event} --profile ${profile}`;
|
|
153
|
+
return CODEX_EVENTS.map((event) => {
|
|
154
|
+
const commandWindows = codexCommandWindows(shim, event, profile);
|
|
155
|
+
return {
|
|
156
|
+
event,
|
|
157
|
+
entry: {
|
|
158
|
+
type: "command",
|
|
159
|
+
command: `${q(node)} ${q(cliEntry())} ${tail(event)}`,
|
|
160
|
+
...commandWindows ? { commandWindows } : {}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function distinctSettingsDirs(dirs) {
|
|
166
|
+
const seen = /* @__PURE__ */ new Set();
|
|
167
|
+
return dirs.filter((dir) => {
|
|
168
|
+
const file = path.join(dir, "settings.json");
|
|
169
|
+
let real = file;
|
|
170
|
+
try {
|
|
171
|
+
real = fs.realpathSync(file);
|
|
172
|
+
} catch {
|
|
173
|
+
}
|
|
174
|
+
if (seen.has(real)) return false;
|
|
175
|
+
seen.add(real);
|
|
176
|
+
return true;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function installMachineHooks(node, opts) {
|
|
180
|
+
const res = { claude_dirs: [], lines: [], warnings: [] };
|
|
181
|
+
const verbs = currentControlVerbs();
|
|
182
|
+
const dirs = distinctSettingsDirs(claudeConfigDirs(opts.processDirs).filter(isDir));
|
|
183
|
+
const keys = profileKeys("claude", dirs);
|
|
184
|
+
for (const dir of dirs) {
|
|
185
|
+
const file = path.join(dir, "settings.json");
|
|
186
|
+
try {
|
|
187
|
+
editJson(file, (d) => (addHooks(d, "nested", claudeMachineSpecs(node, keys.get(dir), verbs), "machine"), true));
|
|
188
|
+
res.claude_dirs.push(dir);
|
|
189
|
+
res.lines.push(`Claude Code hooks (${keys.get(dir)}): ${file}`);
|
|
190
|
+
} catch (e) {
|
|
191
|
+
res.warnings.push(e.message);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (opts.codex && isDir(codexConfigDir(opts.env))) {
|
|
195
|
+
const dir = codexConfigDir(opts.env);
|
|
196
|
+
const key = profileKeys("codex", [dir]).get(dir);
|
|
197
|
+
try {
|
|
198
|
+
const dirCli = cliDir();
|
|
199
|
+
const shim = codexShimPath(dirCli, home());
|
|
200
|
+
fs.mkdirSync(path.dirname(shim), { recursive: true, mode: 448 });
|
|
201
|
+
atomicWrite(shim, codexHookBody(node, dirCli, home()));
|
|
202
|
+
const specs = codexMachineSpecs(node, key, shim);
|
|
203
|
+
editJson(path.join(dir, "hooks.json"), (d) => (addHooks(d, "nested", specs, "machine"), true));
|
|
204
|
+
editToml(path.join(dir, "config.toml"), (c) => enableFeatureHooks(c));
|
|
205
|
+
res.codex_dir = dir;
|
|
206
|
+
res.lines.push(`Codex hooks (${key}): ${path.join(dir, "hooks.json")}`);
|
|
207
|
+
if (specs.some((s) => s.entry.commandWindows === void 0)) {
|
|
208
|
+
res.warnings.push("Codex commandWindows was omitted: every shim path contains a cmd metacharacter (& | < > ^ % !). The POSIX hook command was written");
|
|
209
|
+
}
|
|
210
|
+
} catch (e) {
|
|
211
|
+
res.warnings.push(e.message);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return res;
|
|
215
|
+
}
|
|
216
|
+
function editToml(file, fn) {
|
|
217
|
+
const before = readText(file);
|
|
218
|
+
const next = fn(before ?? "");
|
|
219
|
+
if (next === (before ?? "")) return;
|
|
220
|
+
if (before === void 0) addCreated(file);
|
|
221
|
+
else if (!wasCreated(file)) backupOnce(file);
|
|
222
|
+
atomicWrite(file, next);
|
|
223
|
+
}
|
|
224
|
+
function removeShimFile(file) {
|
|
225
|
+
removeFile(file);
|
|
226
|
+
const dir = path.dirname(file);
|
|
227
|
+
const base = path.basename(dir);
|
|
228
|
+
if (base !== ".hivefloor" && base !== "codex-hook") return;
|
|
229
|
+
try {
|
|
230
|
+
if (fs.readdirSync(dir).length === 0) fs.rmdirSync(dir);
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function removeMachineHooks(inst) {
|
|
235
|
+
const lines = [];
|
|
236
|
+
for (const dir of inst.claude_dirs) {
|
|
237
|
+
const file = path.join(dir, "settings.json");
|
|
238
|
+
try {
|
|
239
|
+
if (editJson(file, (d) => removeHooks(d, "nested", "machine") > 0, { drop: true })) lines.push(`Claude Code hooks: removed from ${file}`);
|
|
240
|
+
} catch {
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (inst.codex_dir) {
|
|
244
|
+
const file = path.join(inst.codex_dir, "hooks.json");
|
|
245
|
+
try {
|
|
246
|
+
if (editJson(file, (d) => removeHooks(d, "nested", "machine") > 0, { drop: true })) lines.push(`Codex hooks: removed from ${file}`);
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
for (const file2 of shimCandidates(cliDir(), home())) removeShimFile(file2);
|
|
250
|
+
const cfg = path.join(inst.codex_dir, "config.toml");
|
|
251
|
+
const before = readText(cfg);
|
|
252
|
+
if (before !== void 0) {
|
|
253
|
+
const next = restoreFeatureHooks(before);
|
|
254
|
+
if (next !== before) {
|
|
255
|
+
if (wasCreated(cfg) && next.trim() === "") {
|
|
256
|
+
removeFile(cfg);
|
|
257
|
+
forgetCreated(cfg);
|
|
258
|
+
} else {
|
|
259
|
+
atomicWrite(cfg, next);
|
|
260
|
+
dropBackupIfSame(cfg);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return lines;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export {
|
|
269
|
+
installCliCopy,
|
|
270
|
+
removeCliCopy,
|
|
271
|
+
applyControlHooks,
|
|
272
|
+
installMachineHooks,
|
|
273
|
+
removeMachineHooks
|
|
274
|
+
};
|