@hivefloor/cli 0.1.4 → 0.1.5

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 (38) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -1
  3. package/dist/{chunk-R5KDI4WI.js → chunk-3N5JYP5O.js} +7 -3
  4. package/dist/{chunk-ZC2DAKB5.js → chunk-4DRHR7LR.js} +349 -127
  5. package/dist/{chunk-PDXYOREI.js → chunk-6MDJB3BV.js} +97 -26
  6. package/dist/{chunk-QHYZBHXO.js → chunk-6XVIEX75.js} +293 -71
  7. package/dist/{chunk-DNG5CRT3.js → chunk-C627OKTW.js} +2 -2
  8. package/dist/chunk-H6NYMF2D.js +50 -0
  9. package/dist/{chunk-T7TG6WA4.js → chunk-IJRHCDIG.js} +1 -1
  10. package/dist/{chunk-SD65CIIY.js → chunk-IWIDKNWC.js} +109 -29
  11. package/dist/{chunk-UJ4BQFWV.js → chunk-J36OIJBM.js} +41 -23
  12. package/dist/{chunk-W7DROKC7.js → chunk-MZGGJ6ZS.js} +87 -13
  13. package/dist/{chunk-2BSA7LFD.js → chunk-RYGL6XU4.js} +5 -3
  14. package/dist/chunk-SOXRITAW.js +139 -0
  15. package/dist/{chunk-VNCQFFQO.js → chunk-TPMFQUAW.js} +102 -1
  16. package/dist/chunk-U6RRUAC2.js +229 -0
  17. package/dist/chunk-VX7SCIF2.js +65 -0
  18. package/dist/{chunk-O2TC3WSS.js → chunk-X6B6R32A.js} +1 -1
  19. package/dist/cli-JCBZICR3.js +243 -0
  20. package/dist/connect-2HLVPEOL.js +23 -0
  21. package/dist/{disconnect-MKRHK4CX.js → disconnect-WQMDCUXT.js} +41 -27
  22. package/dist/{hook-KR2HGVAR.js → hook-AYJNRGIY.js} +22 -8
  23. package/dist/index.js +2 -2
  24. package/dist/{link-HXBMMSG3.js → link-ORT4LID6.js} +29 -16
  25. package/dist/{machine-connect-BYHZRRRB.js → machine-connect-N52CKQEW.js} +21 -21
  26. package/dist/{mcp-N2TMD4GR.js → mcp-2SF6Y73M.js} +27 -30
  27. package/dist/{run-336BSU72.js → run-ZAZ45MKQ.js} +22 -10
  28. package/dist/{status-KBBSAADD.js → status-GOCFNO7K.js} +25 -13
  29. package/dist/{token-JDRLEV5D.js → token-EMM4AJAU.js} +15 -6
  30. package/dist/voice-F5MIS3IZ.js +262 -0
  31. package/dist/{where-KR7VWSEC.js → where-XFXRTP7E.js} +16 -7
  32. package/package.json +2 -2
  33. package/dist/chunk-2IMJECYD.js +0 -71
  34. package/dist/chunk-7KF7IQJN.js +0 -30
  35. package/dist/chunk-GT3HFFT4.js +0 -132
  36. package/dist/chunk-PY74LT2W.js +0 -41
  37. package/dist/cli-P3DYE5IR.js +0 -103
  38. package/dist/connect-ACNM5DQG.js +0 -23
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  removeCliCopy,
4
4
  removeMachineHooks
5
- } from "./chunk-GT3HFFT4.js";
5
+ } from "./chunk-U6RRUAC2.js";
6
6
  import {
7
7
  claudeJson,
8
8
  geminiSettings,
@@ -14,41 +14,42 @@ import {
14
14
  removeGrok,
15
15
  removeRcLine,
16
16
  updateManifest
17
- } from "./chunk-QHYZBHXO.js";
17
+ } from "./chunk-6XVIEX75.js";
18
18
  import {
19
- REAL_TOOLS,
20
- TOOL_LABEL,
21
- isTool
22
- } from "./chunk-2IMJECYD.js";
19
+ KEYCHAIN_SERVICE,
20
+ deleteCredentials,
21
+ readCredentials,
22
+ uninstallService
23
+ } from "./chunk-6MDJB3BV.js";
23
24
  import {
24
25
  checkUnknownFlags,
25
26
  flagStr
26
27
  } from "./chunk-TKMIV7BG.js";
27
- import {
28
- deleteCredentials,
29
- readCredentials,
30
- uninstallService
31
- } from "./chunk-PDXYOREI.js";
32
- import "./chunk-UJ4BQFWV.js";
28
+ import "./chunk-J36OIJBM.js";
33
29
  import {
34
30
  readMachine,
35
31
  removeMachineFile
36
- } from "./chunk-T7TG6WA4.js";
32
+ } from "./chunk-IJRHCDIG.js";
37
33
  import {
38
34
  apiRequest
39
- } from "./chunk-PY74LT2W.js";
35
+ } from "./chunk-VX7SCIF2.js";
40
36
  import {
41
37
  ConfigError,
38
+ REAL_TOOLS,
39
+ TOOL_LABEL,
40
+ isTool,
42
41
  machineSpoolFile,
43
42
  manifestFile,
44
43
  removeFile,
45
44
  serviceLogFile,
46
45
  serviceStateFile
47
- } from "./chunk-VNCQFFQO.js";
46
+ } from "./chunk-TPMFQUAW.js";
48
47
  import {
49
- normalizeHost,
50
- runCmd
51
- } from "./chunk-ZC2DAKB5.js";
48
+ hostFromFlag,
49
+ runCmd,
50
+ sameOrigin
51
+ } from "./chunk-SOXRITAW.js";
52
+ import "./chunk-4DRHR7LR.js";
52
53
  import "./chunk-K3NQKI34.js";
53
54
 
54
55
  // src/disconnect.ts
@@ -68,13 +69,13 @@ async function disconnect(ctx, p) {
68
69
  return 2;
69
70
  }
70
71
  const hostFlag = flagStr(p, "host");
71
- const host = hostFlag ? normalizeHost(hostFlag) : void 0;
72
+ const host = hostFlag ? hostFromFlag(ctx, hostFlag) : void 0;
72
73
  const tools = toolFlag ? [toolFlag] : REAL_TOOLS;
73
74
  const manifest = readManifest();
74
75
  const lines = [];
75
76
  const warnings = [];
76
77
  const machine = readMachine();
77
- if (machine && !toolFlag) {
78
+ if (machine && !toolFlag && (host === void 0 || sameOrigin(machine.host, host))) {
78
79
  if (!machine.revoked) {
79
80
  try {
80
81
  const r = await apiRequest(ctx, machine.host, "/api/v1/machine/disconnect", { method: "POST", token: machine.token, body: {}, timeoutMs: 8e3 });
@@ -95,14 +96,26 @@ async function disconnect(ctx, p) {
95
96
  lines.push("Machine token and state removed");
96
97
  }
97
98
  const keepHooks = machine !== void 0 && !machine.revoked && toolFlag !== void 0;
98
- for (const tool of tools) {
99
+ const credHosts = Object.keys(readCredentials().hosts);
100
+ const otherHosts = host === void 0 ? [] : credHosts.filter((h) => h !== host && !sameOrigin(h, host));
101
+ const disconnectsStoredHost = host !== void 0 && credHosts.some((h) => h === host || sameOrigin(h, host));
102
+ const lastHost = disconnectsStoredHost && otherHosts.length === 0;
103
+ const ownedHere = (owner) => host === void 0 || lastHost || typeof owner === "string" && owner.length > 0 && sameOrigin(owner, host);
104
+ const dropping = tools.filter((tool) => toolFlag !== void 0 || ownedHere(manifest.tools[tool]?.host));
105
+ const owners = Object.values(manifest.tools).map((e) => e?.host).filter((h) => typeof h === "string" && h.length > 0);
106
+ const rcOwnedHere = host === void 0 || lastHost || owners.length > 0 && owners.every((o) => sameOrigin(o, host));
107
+ const mixedOwners = owners.length > 1 && owners.some((o) => !sameOrigin(o, owners[0]));
108
+ if (host !== void 0 && !rcOwnedHere && mixedOwners && manifest.rc.length > 0) {
109
+ warnings.push(`shell export kept while tools point at more than one host; "hivefloor token" follows the last host, so it can still be a token for ${host} after this disconnect`);
110
+ }
111
+ for (const tool of dropping) {
99
112
  const entry = manifest.tools[tool];
100
113
  const viaCli = entry?.mcp === "cli";
101
114
  const legacyBak = tool === "claude" ? fs.existsSync(claudeJson() + ".hivefloor.bak") : tool === "gemini" ? fs.existsSync(geminiSettings() + ".hivefloor.bak") : false;
102
115
  const viaFile = entry ? entry.mcp === "file" : legacyBak;
103
116
  let r;
104
117
  try {
105
- r = tool === "claude" ? await removeClaude(ctx, viaCli, keepHooks, viaFile) : tool === "codex" ? await removeCodex(ctx, viaCli, keepHooks) : tool === "cursor" ? await removeCursor() : tool === "gemini" ? await removeGemini(ctx, viaCli, viaFile) : await removeGrok(ctx, viaCli);
118
+ r = tool === "claude" ? await removeClaude(ctx, viaCli, keepHooks, viaFile) : tool === "codex" ? await removeCodex(ctx, viaCli, keepHooks) : tool === "cursor" ? await removeCursor() : tool === "gemini" ? await removeGemini(ctx, viaCli, viaFile) : await removeGrok(ctx, viaCli, viaFile);
106
119
  } catch (e) {
107
120
  if (!(e instanceof ConfigError)) throw e;
108
121
  warnings.push(e.message);
@@ -112,21 +125,22 @@ async function disconnect(ctx, p) {
112
125
  warnings.push(...r.warnings);
113
126
  if (viaCli && r.lines.length === 0) warnings.push(`${TOOL_LABEL[tool]}: could not run its CLI to remove the "hivefloor" MCP server; remove it by hand`);
114
127
  }
115
- const n = await deleteCredentials(host, toolFlag);
128
+ const { removed: n, leftover } = await deleteCredentials(host, toolFlag);
116
129
  if (n > 0) lines.push(`Removed ${n} stored token${n === 1 ? "" : "s"}`);
130
+ for (const a of leftover) warnings.push(`keychain entry ${a} (service ${KEYCHAIN_SERVICE}) was not removed; delete it in your OS keychain app`);
117
131
  const left = Object.keys(readCredentials().hosts).length > 0;
118
- if (!toolFlag || !left) {
132
+ if ((!toolFlag || !left) && rcOwnedHere) {
119
133
  const files = readManifest().rc;
120
134
  for (const f of files) if (removeRcLine(f)) lines.push(`Shell: removed the token export from ${f}`);
121
135
  updateManifest((m2) => m2.rc = []);
122
136
  }
123
137
  updateManifest((m2) => {
124
- for (const t of tools) delete m2.tools[t];
138
+ for (const t of dropping) delete m2.tools[t];
125
139
  });
126
140
  const m = readManifest();
127
141
  if (Object.keys(m.tools).length === 0 && m.rc.length === 0) removeFile(manifestFile());
128
- if (lines.length === 0) ctx.out("Nothing to remove: no Hivefloor entries found.\n");
129
- else {
142
+ if (lines.length === 0 && warnings.length === 0) ctx.out("Nothing to remove: no Hivefloor entries found.\n");
143
+ else if (lines.length > 0) {
130
144
  ctx.out("Disconnected:\n");
131
145
  for (const l of lines) ctx.out(` ${l}
132
146
  `);
@@ -4,11 +4,15 @@ import {
4
4
  } from "./chunk-JCLWCMEM.js";
5
5
  import {
6
6
  detectRepo
7
- } from "./chunk-2BSA7LFD.js";
7
+ } from "./chunk-RYGL6XU4.js";
8
+ import {
9
+ envTokenForHost
10
+ } from "./chunk-H6NYMF2D.js";
8
11
  import {
9
12
  defaultHost,
10
13
  loadToken
11
- } from "./chunk-PDXYOREI.js";
14
+ } from "./chunk-6MDJB3BV.js";
15
+ import "./chunk-TKMIV7BG.js";
12
16
  import {
13
17
  appendToSpool,
14
18
  contextEventName,
@@ -18,23 +22,26 @@ import {
18
22
  stashNudges,
19
23
  takeSpool,
20
24
  takeStashed
21
- } from "./chunk-O2TC3WSS.js";
25
+ } from "./chunk-X6B6R32A.js";
22
26
  import {
23
27
  readMachine,
24
28
  serviceAlive
25
- } from "./chunk-T7TG6WA4.js";
29
+ } from "./chunk-IJRHCDIG.js";
26
30
  import {
27
31
  configDir,
28
32
  machineSpoolFile
29
- } from "./chunk-VNCQFFQO.js";
33
+ } from "./chunk-TPMFQUAW.js";
30
34
  import {
31
35
  DEFAULT_HOST,
36
+ assertTokenTransport,
37
+ hostFromEnv
38
+ } from "./chunk-SOXRITAW.js";
39
+ import {
32
40
  HOOK_BATCH_MAX,
33
41
  PROFILE_KEY_RE,
34
42
  SESSION_ACCOUNT_RE,
35
- hostFromEnv,
36
43
  redact
37
- } from "./chunk-ZC2DAKB5.js";
44
+ } from "./chunk-4DRHR7LR.js";
38
45
  import "./chunk-K3NQKI34.js";
39
46
 
40
47
  // src/hook.ts
@@ -152,11 +159,18 @@ function isDuplicate(key, nowMs) {
152
159
  return dup;
153
160
  }
154
161
  async function post(deps, host, token, events, timeoutMs, route = "/api/v1/hooks", nudges) {
162
+ try {
163
+ assertTokenTransport(host);
164
+ } catch {
165
+ return "drop";
166
+ }
155
167
  try {
156
168
  const res = await deps.fetch(`${host}${route}`, {
157
169
  method: "POST",
158
170
  headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
159
171
  body: JSON.stringify({ events }),
172
+ redirect: "error",
173
+ // a 3xx would send this bearer token to another URL
160
174
  signal: AbortSignal.timeout(timeoutMs)
161
175
  });
162
176
  const text = await res.text().catch(() => "");
@@ -199,7 +213,7 @@ async function runHookInner(args, deps, startedAt) {
199
213
  const host = machine ? machine.host : deps.env.HIVEFLOOR_URL ? hostFromEnv(deps.env) : defaultHost() ?? DEFAULT_HOST;
200
214
  const grokId = deps.env.GROK_SESSION_ID;
201
215
  const tool = grokId ? "grok" : toolArg;
202
- const envToken = deps.env.HIVEFLOOR_TOKEN;
216
+ const envToken = machine ? void 0 : envTokenForHost(deps.env, host);
203
217
  const stored = !machine && !envToken ? await loadToken(host, tool) : void 0;
204
218
  const token = machine ? machine.token : envToken || stored?.token;
205
219
  if (!token) return;
package/dist/index.js CHANGED
@@ -11,12 +11,12 @@ if (argv[0] === "hook") {
11
11
  process.on("unhandledRejection", () => process.exit(0));
12
12
  setTimeout(() => process.exit(0), HARD_EXIT_MS).unref();
13
13
  try {
14
- const { runHookCli } = await import("./hook-KR2HGVAR.js");
14
+ const { runHookCli } = await import("./hook-AYJNRGIY.js");
15
15
  await runHookCli(argv.slice(1));
16
16
  } catch {
17
17
  }
18
18
  process.exit(0);
19
19
  } else {
20
- const { run } = await import("./cli-P3DYE5IR.js");
20
+ const { run } = await import("./cli-JCBZICR3.js");
21
21
  process.exitCode = await run(argv);
22
22
  }
@@ -1,38 +1,53 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  deviceLogin
4
- } from "./chunk-R5KDI4WI.js";
4
+ } from "./chunk-3N5JYP5O.js";
5
5
  import {
6
6
  detectRepo
7
- } from "./chunk-2BSA7LFD.js";
7
+ } from "./chunk-RYGL6XU4.js";
8
8
  import {
9
9
  resolveSession
10
- } from "./chunk-7KF7IQJN.js";
10
+ } from "./chunk-H6NYMF2D.js";
11
11
  import {
12
- isTool
13
- } from "./chunk-2IMJECYD.js";
12
+ saveToken
13
+ } from "./chunk-6MDJB3BV.js";
14
14
  import {
15
+ checkUnknownFlags,
15
16
  flagStr
16
17
  } from "./chunk-TKMIV7BG.js";
17
- import {
18
- saveToken
19
- } from "./chunk-PDXYOREI.js";
20
18
  import {
21
19
  VERSION
22
- } from "./chunk-DNG5CRT3.js";
20
+ } from "./chunk-C627OKTW.js";
23
21
  import {
24
22
  apiRequest,
25
23
  errorOf
26
- } from "./chunk-PY74LT2W.js";
27
- import "./chunk-VNCQFFQO.js";
24
+ } from "./chunk-VX7SCIF2.js";
25
+ import {
26
+ isTool
27
+ } from "./chunk-TPMFQUAW.js";
28
28
  import {
29
- cliNpxCommand,
30
29
  machineName
31
- } from "./chunk-ZC2DAKB5.js";
30
+ } from "./chunk-SOXRITAW.js";
31
+ import {
32
+ cliNpxCommand
33
+ } from "./chunk-4DRHR7LR.js";
32
34
  import "./chunk-K3NQKI34.js";
33
35
 
34
36
  // src/link.ts
37
+ var LINK_FLAGS = /* @__PURE__ */ new Set(["project", "new", "path", "tool", "host", "no-open", "help", "h"]);
35
38
  async function link(ctx, p) {
39
+ const unknown = checkUnknownFlags(p, LINK_FLAGS);
40
+ if (unknown) {
41
+ ctx.err(`hivefloor: unknown flag "--${unknown}". Run "hivefloor help".
42
+ `);
43
+ return 2;
44
+ }
45
+ const project = flagStr(p, "project");
46
+ const newName = flagStr(p, "new");
47
+ if (project && newName) {
48
+ ctx.err("hivefloor: pass --project or --new, not both.\n");
49
+ return 2;
50
+ }
36
51
  const repo = await detectRepo(ctx.cwd);
37
52
  if (!repo) {
38
53
  ctx.err("hivefloor: this directory has no git remote to link.\n");
@@ -44,8 +59,6 @@ async function link(ctx, p) {
44
59
  `);
45
60
  return 1;
46
61
  }
47
- const project = flagStr(p, "project");
48
- const newName = flagStr(p, "new");
49
62
  const prefix = flagStr(p, "path") ?? repo.path;
50
63
  if (project || newName) {
51
64
  const body = { remote: repo.remote, ...prefix ? { path_prefix: prefix } : {}, ...project ? { project_id: project } : { new_project_name: newName } };
@@ -64,7 +77,7 @@ async function link(ctx, p) {
64
77
  const tool = toolFlag && isTool(toolFlag) ? toolFlag : isTool(s.tool) ? s.tool : "other";
65
78
  const request = {
66
79
  client: { tool, machine: machineName(), os: process.platform, cli_version: VERSION },
67
- repo: { remote: repo.remote, ...repo.branch ? { branch: repo.branch } : {}, ...repo.path ? { path: repo.path } : {} }
80
+ repo: { remote: repo.remote, ...repo.branch ? { branch: repo.branch } : {}, ...prefix ? { path: prefix } : {} }
68
81
  };
69
82
  const result = await deviceLogin(ctx, { host: s.host, request, openBrowser: !p.flags["no-open"] });
70
83
  await saveToken(s.host, tool, result.token, { agent: result.agent, project: result.project });
@@ -1,53 +1,53 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveHost
4
- } from "./chunk-SD65CIIY.js";
4
+ } from "./chunk-IWIDKNWC.js";
5
5
  import {
6
6
  deviceLogin
7
- } from "./chunk-R5KDI4WI.js";
7
+ } from "./chunk-3N5JYP5O.js";
8
8
  import {
9
9
  installCliCopy,
10
10
  installMachineHooks
11
- } from "./chunk-GT3HFFT4.js";
12
- import "./chunk-QHYZBHXO.js";
13
- import "./chunk-2BSA7LFD.js";
11
+ } from "./chunk-U6RRUAC2.js";
12
+ import "./chunk-6XVIEX75.js";
13
+ import "./chunk-RYGL6XU4.js";
14
14
  import {
15
- findBin
16
- } from "./chunk-2IMJECYD.js";
15
+ installService,
16
+ windowsUser
17
+ } from "./chunk-6MDJB3BV.js";
17
18
  import {
18
19
  flagStr
19
20
  } from "./chunk-TKMIV7BG.js";
20
- import {
21
- installService,
22
- windowsUser
23
- } from "./chunk-PDXYOREI.js";
24
21
  import {
25
22
  claudeDirsOfScan,
26
23
  cliVersionOs,
27
24
  scanProcesses
28
- } from "./chunk-W7DROKC7.js";
25
+ } from "./chunk-MZGGJ6ZS.js";
29
26
  import {
30
27
  VERSION
31
- } from "./chunk-DNG5CRT3.js";
28
+ } from "./chunk-C627OKTW.js";
32
29
  import {
33
30
  codexConfigDir
34
- } from "./chunk-UJ4BQFWV.js";
31
+ } from "./chunk-J36OIJBM.js";
35
32
  import {
36
33
  readMachine,
37
34
  secureWindowsMachine,
38
35
  writeMachine
39
- } from "./chunk-T7TG6WA4.js";
40
- import "./chunk-PY74LT2W.js";
36
+ } from "./chunk-IJRHCDIG.js";
37
+ import "./chunk-VX7SCIF2.js";
41
38
  import {
42
- cliEntry
43
- } from "./chunk-VNCQFFQO.js";
39
+ cliEntry,
40
+ findBin
41
+ } from "./chunk-TPMFQUAW.js";
44
42
  import {
45
- cliNpxCommand,
46
43
  machineName,
47
- machineTokenSuccessSchema,
48
44
  normalizeHost,
49
45
  runCmd
50
- } from "./chunk-ZC2DAKB5.js";
46
+ } from "./chunk-SOXRITAW.js";
47
+ import {
48
+ cliNpxCommand,
49
+ machineTokenSuccessSchema
50
+ } from "./chunk-4DRHR7LR.js";
51
51
  import "./chunk-K3NQKI34.js";
52
52
 
53
53
  // src/machine-connect.ts
@@ -1,25 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectRepo
4
- } from "./chunk-2BSA7LFD.js";
4
+ } from "./chunk-RYGL6XU4.js";
5
5
  import {
6
6
  resolveSession
7
- } from "./chunk-7KF7IQJN.js";
8
- import {
9
- toolFromEnv
10
- } from "./chunk-2IMJECYD.js";
7
+ } from "./chunk-H6NYMF2D.js";
8
+ import "./chunk-6MDJB3BV.js";
11
9
  import {
10
+ checkUnknownFlags,
12
11
  flagStr
13
12
  } from "./chunk-TKMIV7BG.js";
14
13
  import {
15
- loadToken
16
- } from "./chunk-PDXYOREI.js";
17
- import "./chunk-VNCQFFQO.js";
14
+ toolFromEnv
15
+ } from "./chunk-TPMFQUAW.js";
16
+ import {
17
+ assertTokenTransport,
18
+ sameOrigin
19
+ } from "./chunk-SOXRITAW.js";
18
20
  import {
19
- cliNpxCommand,
20
- isSecureUrl,
21
- normalizeHost
22
- } from "./chunk-ZC2DAKB5.js";
21
+ cliNpxCommand
22
+ } from "./chunk-4DRHR7LR.js";
23
23
  import "./chunk-K3NQKI34.js";
24
24
 
25
25
  // src/mcp.ts
@@ -42,17 +42,21 @@ async function contextHeaders(ctx, token, toolName) {
42
42
  }
43
43
  var isRequest = (m) => "method" in m && "id" in m;
44
44
  function mcpTargetUrl(flagUrl, host) {
45
- if (!flagUrl) return new URL(`${host}/mcp`);
46
- let u;
47
45
  try {
48
- u = new URL(flagUrl);
49
- } catch {
50
- throw new Error("--url is not a URL");
46
+ return assertTokenTransport(flagUrl ?? `${host}/mcp`);
47
+ } catch (e) {
48
+ if (flagUrl && e.message === "not a URL") throw new Error("--url is not a URL");
49
+ throw e;
51
50
  }
52
- if (!isSecureUrl(u)) throw new Error(`--url must be https (http is only allowed on localhost): ${u.origin}`);
53
- return u;
54
51
  }
52
+ var MCP_FLAGS = /* @__PURE__ */ new Set(["url", "host", "tool", "help", "h"]);
55
53
  async function runMcpProxy(ctx, p, io = { stdin: process.stdin, stdout: process.stdout }) {
54
+ const unknown = checkUnknownFlags(p, MCP_FLAGS);
55
+ if (unknown) {
56
+ ctx.err(`hivefloor: unknown flag "--${unknown}". Run "hivefloor help".
57
+ `);
58
+ return 2;
59
+ }
56
60
  const s = await resolveSession(ctx, p);
57
61
  if (!s) {
58
62
  ctx.err(`hivefloor: not connected. Run: ${cliNpxCommand("connect")}
@@ -67,19 +71,12 @@ async function runMcpProxy(ctx, p, io = { stdin: process.stdin, stdout: process.
67
71
  `);
68
72
  return 1;
69
73
  }
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
74
+ if (!sameOrigin(url.origin, s.host)) {
75
+ ctx.err(`hivefloor mcp: refusing to send the token of ${s.host} to ${url.origin}; --url must be the same host
76
76
  `);
77
- return 1;
78
- }
79
- token = other.token;
80
- tool = other.tool;
77
+ return 1;
81
78
  }
82
- const headers = await contextHeaders(ctx, token, tool);
79
+ const headers = await contextHeaders(ctx, s.token, s.tool);
83
80
  const upstream = new StreamableHTTPClientTransport(url, { requestInit: { headers } });
84
81
  const downstream = new StdioServerTransport(io.stdin, io.stdout);
85
82
  return await new Promise((resolve) => {
@@ -4,30 +4,30 @@ import {
4
4
  releaseSpool,
5
5
  stashNudges,
6
6
  takeSpool
7
- } from "./chunk-O2TC3WSS.js";
7
+ } from "./chunk-X6B6R32A.js";
8
8
  import {
9
9
  buildProfiles,
10
10
  cliVersionOs,
11
11
  makeEnvReader,
12
12
  scanProcesses
13
- } from "./chunk-W7DROKC7.js";
13
+ } from "./chunk-MZGGJ6ZS.js";
14
14
  import {
15
15
  VERSION
16
- } from "./chunk-DNG5CRT3.js";
16
+ } from "./chunk-C627OKTW.js";
17
17
  import {
18
18
  claudeDirsFromRc,
19
19
  profileKeyOf,
20
20
  profileKeys,
21
21
  uniqueProfileKey
22
- } from "./chunk-UJ4BQFWV.js";
22
+ } from "./chunk-J36OIJBM.js";
23
23
  import {
24
24
  readMachine,
25
25
  writeMachine,
26
26
  writeServiceState
27
- } from "./chunk-T7TG6WA4.js";
27
+ } from "./chunk-IJRHCDIG.js";
28
28
  import {
29
29
  apiRequest
30
- } from "./chunk-PY74LT2W.js";
30
+ } from "./chunk-VX7SCIF2.js";
31
31
  import {
32
32
  configDir,
33
33
  home,
@@ -35,16 +35,19 @@ import {
35
35
  isRecord,
36
36
  machineSpoolFile,
37
37
  serviceLogFile
38
- } from "./chunk-VNCQFFQO.js";
38
+ } from "./chunk-TPMFQUAW.js";
39
+ import {
40
+ runCmd
41
+ } from "./chunk-SOXRITAW.js";
39
42
  import {
40
43
  HOOK_BATCH_MAX,
41
44
  MACHINE_HEARTBEAT_SECONDS,
42
45
  MACHINE_MIN_INTERVAL_SECONDS,
46
+ estimateClaudeCostUsd,
43
47
  machineHeartbeatResponseSchema,
44
48
  parseUsageKey,
45
- runCmd,
46
49
  usageReadingSchema
47
- } from "./chunk-ZC2DAKB5.js";
50
+ } from "./chunk-4DRHR7LR.js";
48
51
  import "./chunk-K3NQKI34.js";
49
52
 
50
53
  // src/service/run.ts
@@ -285,7 +288,16 @@ function parseClaudeLine(state, line) {
285
288
  state.tokensIn += (input ?? 0) + (cacheCreate ?? 0) + (cacheRead ?? 0);
286
289
  state.tokensOut += output ?? 0;
287
290
  state.hasUsage = true;
288
- const cost = asPositiveCost(raw.costUSD ?? raw.cost_usd ?? msg.costUSD ?? msg.cost_usd ?? usage.cost_usd ?? usage.costUSD);
291
+ let cost = asPositiveCost(raw.costUSD ?? raw.cost_usd ?? msg.costUSD ?? msg.cost_usd ?? usage.cost_usd ?? usage.costUSD);
292
+ if (cost === void 0) {
293
+ const est = estimateClaudeCostUsd(typeof msg.model === "string" ? msg.model : void 0, {
294
+ input: input ?? 0,
295
+ output: output ?? 0,
296
+ cacheRead: cacheRead ?? 0,
297
+ cacheWrite: cacheCreate ?? 0
298
+ });
299
+ if (est !== null && est > 0) cost = est;
300
+ }
289
301
  if (cost !== void 0) {
290
302
  state.costUsd += cost;
291
303
  state.hasCost = true;
@@ -1,41 +1,52 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectRepo
4
- } from "./chunk-2BSA7LFD.js";
4
+ } from "./chunk-RYGL6XU4.js";
5
5
  import {
6
6
  resolveSession
7
- } from "./chunk-7KF7IQJN.js";
8
- import "./chunk-2IMJECYD.js";
9
- import "./chunk-TKMIV7BG.js";
7
+ } from "./chunk-H6NYMF2D.js";
10
8
  import {
11
9
  SCHTASKS_TASK,
10
+ hostKey,
12
11
  readCredentials,
13
12
  windowsServiceStatus
14
- } from "./chunk-PDXYOREI.js";
13
+ } from "./chunk-6MDJB3BV.js";
14
+ import {
15
+ checkUnknownFlags
16
+ } from "./chunk-TKMIV7BG.js";
15
17
  import {
16
18
  profileKeys
17
- } from "./chunk-UJ4BQFWV.js";
19
+ } from "./chunk-J36OIJBM.js";
18
20
  import {
19
21
  SERVICE_ALIVE_MS,
20
22
  readMachine,
21
23
  readServiceState
22
- } from "./chunk-T7TG6WA4.js";
24
+ } from "./chunk-IJRHCDIG.js";
23
25
  import {
24
26
  apiRequest,
25
27
  errorOf
26
- } from "./chunk-PY74LT2W.js";
27
- import "./chunk-VNCQFFQO.js";
28
+ } from "./chunk-VX7SCIF2.js";
29
+ import "./chunk-TPMFQUAW.js";
28
30
  import {
29
- cliNpxCommand,
30
31
  machineName,
31
32
  runCmd
32
- } from "./chunk-ZC2DAKB5.js";
33
+ } from "./chunk-SOXRITAW.js";
34
+ import {
35
+ cliNpxCommand
36
+ } from "./chunk-4DRHR7LR.js";
33
37
  import "./chunk-K3NQKI34.js";
34
38
 
35
39
  // src/status.ts
36
40
  var str = (v) => typeof v === "string" ? v : void 0;
37
41
  var rec = (v) => typeof v === "object" && v !== null ? v : {};
42
+ var STATUS_FLAGS = /* @__PURE__ */ new Set(["host", "tool", "help", "h"]);
38
43
  async function status(ctx, p) {
44
+ const unknown = checkUnknownFlags(p, STATUS_FLAGS);
45
+ if (unknown) {
46
+ ctx.err(`hivefloor: unknown flag "--${unknown}". Run "hivefloor help".
47
+ `);
48
+ return 2;
49
+ }
39
50
  const machine = readMachine();
40
51
  if (machine) await machineStatus(ctx, machine);
41
52
  const s = await resolveSession(ctx, p);
@@ -50,7 +61,8 @@ async function status(ctx, p) {
50
61
  ctx.out(`Host: ${s.host}
51
62
  Machine: ${machineName()}
52
63
  `);
53
- const connected = Object.keys(readCredentials().hosts[s.host]?.tools ?? {});
64
+ const creds = readCredentials();
65
+ const connected = Object.keys(creds.hosts[hostKey(creds, s.host) ?? ""]?.tools ?? {});
54
66
  if (connected.length > 0) ctx.out(`Connected tools: ${connected.join(", ")}
55
67
  `);
56
68
  if (repo) ctx.out(`Repo here: ${repo.remote}${repo.branch ? ` (${repo.branch})` : ""}
@@ -59,7 +71,7 @@ Machine: ${machineName()}
59
71
  try {
60
72
  res = await apiRequest(ctx, s.host, "/api/v1/agent/whoami", { token: s.token, headers: repo ? { "x-hf-repo": repo.remote } : {}, timeoutMs: 8e3 });
61
73
  } catch (e) {
62
- ctx.err(`hivefloor: could not reach ${s.host}: ${e.message}
74
+ ctx.err(`hivefloor: ${e.message}
63
75
  `);
64
76
  return 1;
65
77
  }
@@ -1,18 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
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";
4
+ } from "./chunk-H6NYMF2D.js";
5
+ import "./chunk-6MDJB3BV.js";
6
+ import {
7
+ checkUnknownFlags
8
+ } from "./chunk-TKMIV7BG.js";
9
+ import "./chunk-TPMFQUAW.js";
10
+ import "./chunk-SOXRITAW.js";
9
11
  import {
10
12
  cliNpxCommand
11
- } from "./chunk-ZC2DAKB5.js";
13
+ } from "./chunk-4DRHR7LR.js";
12
14
  import "./chunk-K3NQKI34.js";
13
15
 
14
16
  // src/token.ts
17
+ var TOKEN_FLAGS = /* @__PURE__ */ new Set(["reveal", "host", "tool", "help", "h"]);
15
18
  async function token(ctx, p) {
19
+ const unknown = checkUnknownFlags(p, TOKEN_FLAGS);
20
+ if (unknown) {
21
+ ctx.err(`hivefloor: unknown flag "--${unknown}". Run "hivefloor help".
22
+ `);
23
+ return 2;
24
+ }
16
25
  const s = await resolveSession(ctx, p);
17
26
  if (!s) {
18
27
  ctx.err(`hivefloor: no token stored. Run: ${cliNpxCommand("connect")}