@hivefloor/cli 0.1.2 → 0.1.3
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/dist/{chunk-OOMBZN4M.js → chunk-3YOTXIFP.js} +2 -2
- package/dist/{chunk-LF2NWQ4B.js → chunk-KHHSRIMU.js} +1 -1
- package/dist/{cli-F3F7SQLV.js → cli-MAHYTCYV.js} +4 -4
- package/dist/{connect-TG2H5SMB.js → connect-QA3QIEGL.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{link-JX4YLF2Z.js → link-5WSZHKBE.js} +1 -1
- package/dist/{machine-connect-NOQ3VZOO.js → machine-connect-GQJ4SB3D.js} +2 -2
- package/dist/{run-CKNHDPNX.js → run-BEE2ATEM.js} +135 -29
- package/package.json +1 -1
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "./chunk-DQV6FAJU.js";
|
|
35
35
|
import {
|
|
36
36
|
VERSION
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-KHHSRIMU.js";
|
|
38
38
|
import {
|
|
39
39
|
readMachine
|
|
40
40
|
} from "./chunk-T7TG6WA4.js";
|
|
@@ -172,7 +172,7 @@ async function connect(ctx, p) {
|
|
|
172
172
|
return 2;
|
|
173
173
|
}
|
|
174
174
|
if (p.flags.agent || p.flags.tool !== void 0) return connectAgent(ctx, p);
|
|
175
|
-
return (await import("./machine-connect-
|
|
175
|
+
return (await import("./machine-connect-GQJ4SB3D.js")).connectMachine(ctx, p);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
export {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@hivefloor/cli",
|
|
6
|
-
version: "0.1.
|
|
6
|
+
version: "0.1.3",
|
|
7
7
|
description: "Connect your coding agents (Claude Code, Codex, Cursor, Gemini, Grok) to Hivefloor: live presence, task coordination and usage on one floor.",
|
|
8
8
|
author: {
|
|
9
9
|
name: "Errr0rr404",
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-TKMIV7BG.js";
|
|
5
5
|
import {
|
|
6
6
|
VERSION
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KHHSRIMU.js";
|
|
8
8
|
import {
|
|
9
9
|
ApiError
|
|
10
10
|
} from "./chunk-PY74LT2W.js";
|
|
@@ -59,7 +59,7 @@ async function run(argv, ctx = defaultCtx()) {
|
|
|
59
59
|
try {
|
|
60
60
|
switch (cmd) {
|
|
61
61
|
case "connect":
|
|
62
|
-
return await (await import("./connect-
|
|
62
|
+
return await (await import("./connect-QA3QIEGL.js")).connect(ctx, p);
|
|
63
63
|
case "disconnect":
|
|
64
64
|
return await (await import("./disconnect-FI76IEZJ.js")).disconnect(ctx, p);
|
|
65
65
|
case "status":
|
|
@@ -71,9 +71,9 @@ async function run(argv, ctx = defaultCtx()) {
|
|
|
71
71
|
ctx.err("hivefloor: usage: hivefloor service run\n");
|
|
72
72
|
return 2;
|
|
73
73
|
}
|
|
74
|
-
return await (await import("./run-
|
|
74
|
+
return await (await import("./run-BEE2ATEM.js")).runService({ ctx });
|
|
75
75
|
case "link":
|
|
76
|
-
return await (await import("./link-
|
|
76
|
+
return await (await import("./link-5WSZHKBE.js")).link(ctx, p);
|
|
77
77
|
case "token":
|
|
78
78
|
return await (await import("./token-AUEAWQDH.js")).token(ctx, p);
|
|
79
79
|
case "mcp":
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
connect,
|
|
4
4
|
connectAgent,
|
|
5
5
|
resolveHost
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3YOTXIFP.js";
|
|
7
7
|
import "./chunk-HT5KXWXM.js";
|
|
8
8
|
import "./chunk-NLZXB26Y.js";
|
|
9
9
|
import "./chunk-YRNMECUF.js";
|
|
10
10
|
import "./chunk-2IMJECYD.js";
|
|
11
11
|
import "./chunk-TKMIV7BG.js";
|
|
12
12
|
import "./chunk-DQV6FAJU.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-KHHSRIMU.js";
|
|
14
14
|
import "./chunk-T7TG6WA4.js";
|
|
15
15
|
import "./chunk-PY74LT2W.js";
|
|
16
16
|
import "./chunk-VNCQFFQO.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveHost
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3YOTXIFP.js";
|
|
5
5
|
import {
|
|
6
6
|
deviceLogin
|
|
7
7
|
} from "./chunk-HT5KXWXM.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from "./chunk-O6VSA2JT.js";
|
|
29
29
|
import {
|
|
30
30
|
VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-KHHSRIMU.js";
|
|
32
32
|
import {
|
|
33
33
|
codexConfigDir
|
|
34
34
|
} from "./chunk-E4V47VEV.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./chunk-O6VSA2JT.js";
|
|
14
14
|
import {
|
|
15
15
|
VERSION
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-KHHSRIMU.js";
|
|
17
17
|
import {
|
|
18
18
|
claudeDirsFromRc,
|
|
19
19
|
profileKeyOf,
|
|
@@ -859,6 +859,7 @@ var readClaude = async (deps) => {
|
|
|
859
859
|
const out = emptyOutput();
|
|
860
860
|
const seenTokens = /* @__PURE__ */ new Set();
|
|
861
861
|
const seenLabels = /* @__PURE__ */ new Set();
|
|
862
|
+
const readLabels = /* @__PURE__ */ new Set();
|
|
862
863
|
for (const dir of claudeConfigDirs(deps)) {
|
|
863
864
|
let raw = deps.readFile(joinPath(dir, ".credentials.json"));
|
|
864
865
|
if (raw === null && deps.platform === "darwin" && deps.exec) {
|
|
@@ -875,7 +876,7 @@ var readClaude = async (deps) => {
|
|
|
875
876
|
if (creds.kind === "none") continue;
|
|
876
877
|
seenLabels.add(label);
|
|
877
878
|
if (creds.kind === "expired") {
|
|
878
|
-
out.issues.push(issue("claude", label, "expired",
|
|
879
|
+
out.issues.push(issue("claude", label, "expired", "The saved login is out of date (no Claude session used it lately). It updates the next time Claude Code runs on this profile."));
|
|
879
880
|
continue;
|
|
880
881
|
}
|
|
881
882
|
if (creds.kind === "no_scope") {
|
|
@@ -884,50 +885,155 @@ var readClaude = async (deps) => {
|
|
|
884
885
|
}
|
|
885
886
|
if (seenTokens.has(creds.token)) continue;
|
|
886
887
|
seenTokens.add(creds.token);
|
|
887
|
-
const headers = {
|
|
888
|
-
Authorization: `Bearer ${creds.token}`,
|
|
889
|
-
"anthropic-beta": "oauth-2025-04-20",
|
|
890
|
-
"anthropic-version": "2023-06-01",
|
|
891
|
-
Accept: "application/json"
|
|
892
|
-
};
|
|
893
888
|
try {
|
|
894
|
-
const parsed =
|
|
895
|
-
parsed.plan
|
|
896
|
-
try {
|
|
897
|
-
const profile = asRecord(await requestJson(deps, PROFILE_URL, { headers }));
|
|
898
|
-
const account = asRecord(profile?.account) ?? profile;
|
|
899
|
-
parsed.accountId = asString(account?.uuid) ?? asString(account?.id);
|
|
900
|
-
const org = asRecord(profile?.organization);
|
|
901
|
-
parsed.plan ??= planName(asString(org?.organization_type) ?? asString(org?.rate_limit_tier));
|
|
902
|
-
} catch {
|
|
903
|
-
}
|
|
904
|
-
if (parsed.windows.length === 0) throw new ReaderError("bad_response", issueMessage("bad_response"));
|
|
889
|
+
const parsed = await readTokenUsage(deps, creds.token);
|
|
890
|
+
parsed.plan ??= creds.plan;
|
|
905
891
|
out.readings.push(...toReadings("claude", label, parsed, "local_login"));
|
|
892
|
+
readLabels.add(label);
|
|
906
893
|
} catch (e) {
|
|
907
894
|
out.issues.push(failure("claude", label, e));
|
|
908
895
|
}
|
|
909
896
|
}
|
|
897
|
+
await readNamedTokens(deps, seenTokens, readLabels, out);
|
|
910
898
|
await readEnvTokens(deps, seenTokens, out);
|
|
911
899
|
return out;
|
|
912
900
|
};
|
|
901
|
+
var CLAUDE_HEADERS = (token) => ({
|
|
902
|
+
Authorization: `Bearer ${token}`,
|
|
903
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
904
|
+
"anthropic-version": "2023-06-01",
|
|
905
|
+
Accept: "application/json"
|
|
906
|
+
});
|
|
907
|
+
async function readTokenUsage(deps, token) {
|
|
908
|
+
const headers = CLAUDE_HEADERS(token);
|
|
909
|
+
let parsed;
|
|
910
|
+
try {
|
|
911
|
+
parsed = parseClaudeUsage(await requestJson(deps, USAGE_URL, { headers }));
|
|
912
|
+
if (parsed.windows.length === 0) throw new ReaderError("bad_response", issueMessage("bad_response"));
|
|
913
|
+
} catch (e) {
|
|
914
|
+
if (!(e instanceof ReaderError) || e.code !== "rejected" && e.code !== "rate_limited") throw e;
|
|
915
|
+
return probeRateLimits(deps, token);
|
|
916
|
+
}
|
|
917
|
+
try {
|
|
918
|
+
const profile = asRecord(await requestJson(deps, PROFILE_URL, { headers }));
|
|
919
|
+
const account = asRecord(profile?.account) ?? profile;
|
|
920
|
+
parsed.accountId = asString(account?.uuid) ?? asString(account?.id);
|
|
921
|
+
const org = asRecord(profile?.organization);
|
|
922
|
+
parsed.plan ??= planName(asString(org?.organization_type) ?? asString(org?.rate_limit_tier));
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
return parsed;
|
|
926
|
+
}
|
|
927
|
+
var PROBE_URL = "https://api.anthropic.com/v1/messages";
|
|
928
|
+
var PROBE_MODEL = "claude-haiku-5-5";
|
|
929
|
+
var PROBE_TTL_MS = 15 * 6e4;
|
|
930
|
+
var probeCache = /* @__PURE__ */ new Map();
|
|
931
|
+
function parseClaudeRateHeaders(h) {
|
|
932
|
+
const windows = [];
|
|
933
|
+
const names = {
|
|
934
|
+
"5h": ["5h", "5 hours"],
|
|
935
|
+
"7d": ["weekly", "Weekly"],
|
|
936
|
+
"7d_opus": ["weekly:opus", "Opus weekly"],
|
|
937
|
+
"7d_sonnet": ["weekly:sonnet", "Sonnet weekly"]
|
|
938
|
+
};
|
|
939
|
+
for (const [key, value] of Object.entries(h)) {
|
|
940
|
+
const m = /^anthropic-ratelimit-unified-([a-z0-9_]+)-utilization$/.exec(key.toLowerCase());
|
|
941
|
+
if (!m) continue;
|
|
942
|
+
const id = m[1];
|
|
943
|
+
const util = asNumber(Number(value));
|
|
944
|
+
if (util === void 0) continue;
|
|
945
|
+
const [window, label] = names[id] ?? (/^7d_[a-z0-9]+$/.test(id) ? [`weekly:${slug(id.slice(3))}`, `${id.slice(3)} weekly`] : [`${slug(id)}`, id]);
|
|
946
|
+
if (!/^[a-z0-9]+(?::[a-z0-9._-]+)?$/.test(window)) continue;
|
|
947
|
+
addWin(windows, { window, label, percent: util * 100, resets: h[`anthropic-ratelimit-unified-${id}-reset`] });
|
|
948
|
+
}
|
|
949
|
+
windows.sort((a, b) => a.window === "5h" ? -1 : b.window === "5h" ? 1 : a.window.localeCompare(b.window));
|
|
950
|
+
return { windows };
|
|
951
|
+
}
|
|
952
|
+
async function probeRateLimits(deps, token) {
|
|
953
|
+
const key = tokenLabel(token);
|
|
954
|
+
const cached = probeCache.get(key);
|
|
955
|
+
if (cached && deps.now() - cached.at < PROBE_TTL_MS) return { ...cached.parsed, windows: [...cached.parsed.windows] };
|
|
956
|
+
const model = /^[a-z0-9.-]{3,60}$/.test(deps.env.HIVEFLOOR_CLAUDE_PROBE_MODEL ?? "") ? deps.env.HIVEFLOOR_CLAUDE_PROBE_MODEL : PROBE_MODEL;
|
|
957
|
+
let res;
|
|
958
|
+
try {
|
|
959
|
+
res = await deps.fetch(PROBE_URL, {
|
|
960
|
+
method: "POST",
|
|
961
|
+
headers: { ...CLAUDE_HEADERS(token), "content-type": "application/json" },
|
|
962
|
+
body: JSON.stringify({
|
|
963
|
+
model,
|
|
964
|
+
max_tokens: 1,
|
|
965
|
+
system: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
966
|
+
messages: [{ role: "user", content: "hi" }]
|
|
967
|
+
})
|
|
968
|
+
});
|
|
969
|
+
await res.text();
|
|
970
|
+
} catch {
|
|
971
|
+
throw new ReaderError("unreachable", issueMessage("unreachable"));
|
|
972
|
+
}
|
|
973
|
+
const parsed = parseClaudeRateHeaders(res.headers ?? {});
|
|
974
|
+
if (parsed.windows.length > 0) {
|
|
975
|
+
probeCache.set(key, { at: deps.now(), parsed });
|
|
976
|
+
return parsed;
|
|
977
|
+
}
|
|
978
|
+
if (res.status === 401 || res.status === 403) throw new ReaderError("rejected", issueMessage("rejected"));
|
|
979
|
+
if (res.status === 429) throw new ReaderError("rate_limited", issueMessage("rate_limited"));
|
|
980
|
+
if (res.status >= 500) throw new ReaderError("unreachable", issueMessage("unreachable"));
|
|
981
|
+
throw new ReaderError("bad_response", issueMessage("bad_response"));
|
|
982
|
+
}
|
|
913
983
|
var MAX_SESSION_TOKENS = 20;
|
|
984
|
+
var NAME_RE = /^[A-Za-z0-9._-]{1,40}$/;
|
|
914
985
|
var tokenLabel = (token) => `token-${createHash2("sha256").update(token).digest("hex").slice(0, 6)}`;
|
|
986
|
+
function claudeTokenProfiles(deps) {
|
|
987
|
+
const names = /* @__PURE__ */ new Set();
|
|
988
|
+
const add = (n) => {
|
|
989
|
+
if (NAME_RE.test(n) && n !== "api") names.add(n);
|
|
990
|
+
};
|
|
991
|
+
for (const f of deps.readDir(joinPath(deps.home, ".config/fleet-cc")).sort()) {
|
|
992
|
+
const m = /^(.+)\.token$/.exec(f);
|
|
993
|
+
if (m) add(m[1]);
|
|
994
|
+
}
|
|
995
|
+
for (const d of deps.readDir(deps.home).sort()) {
|
|
996
|
+
const m = /^\.claude-([A-Za-z0-9._-]+)$/.exec(d);
|
|
997
|
+
if (m) add(m[1]);
|
|
998
|
+
}
|
|
999
|
+
const cc = deps.readFile(joinPath(deps.home, ".claude/fleet/cc.sh"));
|
|
1000
|
+
const line = cc ? /^PROFILES="([^"\n]*)"/m.exec(cc) : null;
|
|
1001
|
+
for (const n of (line?.[1] ?? "").split(/\s+/)) if (n) add(n);
|
|
1002
|
+
for (const n of (deps.env.HIVEFLOOR_CLAUDE_PROFILES ?? "").split(/[\s,]+/)) if (n) add(n);
|
|
1003
|
+
return [...names];
|
|
1004
|
+
}
|
|
1005
|
+
function namedToken(deps, name) {
|
|
1006
|
+
let t = deps.readFile(joinPath(deps.home, `.config/fleet-cc/${name}.token`));
|
|
1007
|
+
if ((t === null || t.trim() === "") && deps.platform === "darwin" && deps.exec) {
|
|
1008
|
+
t = deps.exec("security", ["find-generic-password", "-s", `fleet-cc-${name}`, "-w"]);
|
|
1009
|
+
}
|
|
1010
|
+
const v = t?.trim() ?? "";
|
|
1011
|
+
return /^[\w.~+/=-]{20,400}$/.test(v) ? v : null;
|
|
1012
|
+
}
|
|
1013
|
+
async function readNamedTokens(deps, seenTokens, readLabels, out) {
|
|
1014
|
+
for (const name of claudeTokenProfiles(deps)) {
|
|
1015
|
+
if (readLabels.has(name)) continue;
|
|
1016
|
+
const token = namedToken(deps, name);
|
|
1017
|
+
if (!token || seenTokens.has(token)) continue;
|
|
1018
|
+
seenTokens.add(token);
|
|
1019
|
+
try {
|
|
1020
|
+
const parsed = await readTokenUsage(deps, token);
|
|
1021
|
+
out.readings.push(...toReadings("claude", name, parsed, "local_login"));
|
|
1022
|
+
readLabels.add(name);
|
|
1023
|
+
out.issues = out.issues.filter((i) => !(i.provider === "claude" && i.account_label === name));
|
|
1024
|
+
} catch (e) {
|
|
1025
|
+
if (!out.issues.some((i) => i.provider === "claude" && i.account_label === name)) out.issues.push(failure("claude", name, e));
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
915
1029
|
async function readEnvTokens(deps, seenTokens, out) {
|
|
916
1030
|
const tokens = [...new Set(deps.claudeTokens ?? [])].filter((t) => t.length >= 20 && !seenTokens.has(t)).slice(0, MAX_SESSION_TOKENS);
|
|
917
1031
|
let blind = 0;
|
|
918
1032
|
for (const token of tokens) {
|
|
919
1033
|
seenTokens.add(token);
|
|
920
1034
|
const label = tokenLabel(token);
|
|
921
|
-
const headers = { Authorization: `Bearer ${token}`, "anthropic-beta": "oauth-2025-04-20", "anthropic-version": "2023-06-01", Accept: "application/json" };
|
|
922
1035
|
try {
|
|
923
|
-
const parsed =
|
|
924
|
-
try {
|
|
925
|
-
const profile = asRecord(await requestJson(deps, PROFILE_URL, { headers }));
|
|
926
|
-
const account = asRecord(profile?.account) ?? profile;
|
|
927
|
-
parsed.accountId = asString(account?.uuid) ?? asString(account?.id);
|
|
928
|
-
} catch {
|
|
929
|
-
}
|
|
930
|
-
if (parsed.windows.length === 0) throw new ReaderError("bad_response", issueMessage("bad_response"));
|
|
1036
|
+
const parsed = await readTokenUsage(deps, token);
|
|
931
1037
|
out.readings.push(...toReadings("claude", label, parsed, "env_key"));
|
|
932
1038
|
} catch (e) {
|
|
933
1039
|
if (e instanceof ReaderError && e.code === "rejected") blind++;
|
|
@@ -1627,7 +1733,7 @@ function nodeDeps() {
|
|
|
1627
1733
|
return {
|
|
1628
1734
|
async fetch(url, init = {}) {
|
|
1629
1735
|
const res = await fetch(url, { method: init.method ?? "GET", headers: init.headers, body: init.body, redirect: "manual", signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
1630
|
-
return { status: res.status, text: () => res.text() };
|
|
1736
|
+
return { status: res.status, text: () => res.text(), headers: Object.fromEntries([...res.headers].map(([k, v]) => [k.toLowerCase(), v])) };
|
|
1631
1737
|
},
|
|
1632
1738
|
readFile,
|
|
1633
1739
|
readDir(path2) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hivefloor/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Connect your coding agents (Claude Code, Codex, Cursor, Gemini, Grok) to Hivefloor: live presence, task coordination and usage on one floor.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Errr0rr404",
|