@hyperline/cli 0.1.0-build.1.9301c8c → 0.1.0-build.1.bf6bdf2

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.
@@ -71,6 +71,87 @@ async function clearCredentials() {
71
71
  } catch {
72
72
  }
73
73
  }
74
+ async function resolveCompanyId({ flagCompanyId }) {
75
+ if (flagCompanyId)
76
+ return flagCompanyId;
77
+ const envCompanyId = process.env.HYPERLINE_COMPANY_ID;
78
+ if (envCompanyId)
79
+ return envCompanyId;
80
+ const configFile = await readJsonFile(CONFIG_FILE);
81
+ return configFile?.companyId;
82
+ }
83
+ async function saveCompanyId({ companyId }) {
84
+ const existing = await readJsonFile(CONFIG_FILE) ?? {};
85
+ existing.companyId = companyId;
86
+ await writeJsonFile(CONFIG_FILE, existing);
87
+ }
88
+
89
+ // build/prompt.js
90
+ import * as readline from "node:readline";
91
+ function selectPrompt({ message, items }) {
92
+ if (items.length === 0)
93
+ return Promise.resolve(void 0);
94
+ if (items.length === 1)
95
+ return Promise.resolve(items[0].value);
96
+ return new Promise((resolve) => {
97
+ const input = process.stdin;
98
+ const output = process.stderr;
99
+ let selectedIndex = 0;
100
+ const wasRaw = input.isRaw;
101
+ if (!input.isTTY) {
102
+ resolve(items[0].value);
103
+ return;
104
+ }
105
+ input.setRawMode(true);
106
+ readline.emitKeypressEvents(input);
107
+ function render() {
108
+ output.write(`\x1B[?25l`);
109
+ output.write(`\x1B[${items.length}A`);
110
+ for (const [index, item] of items.entries()) {
111
+ const isSelected = index === selectedIndex;
112
+ const pointer = isSelected ? "\x1B[36m>\x1B[0m" : " ";
113
+ const label = isSelected ? `\x1B[36m${item.label}\x1B[0m` : item.label;
114
+ const hint = item.hint ? `\x1B[2m ${item.hint}\x1B[0m` : "";
115
+ output.write(`\x1B[2K${pointer} ${label}${hint}
116
+ `);
117
+ }
118
+ }
119
+ output.write(`${message}
120
+ `);
121
+ for (const [index, item] of items.entries()) {
122
+ const isSelected = index === selectedIndex;
123
+ const pointer = isSelected ? "\x1B[36m>\x1B[0m" : " ";
124
+ const label = isSelected ? `\x1B[36m${item.label}\x1B[0m` : item.label;
125
+ const hint = item.hint ? `\x1B[2m ${item.hint}\x1B[0m` : "";
126
+ output.write(`${pointer} ${label}${hint}
127
+ `);
128
+ }
129
+ function cleanup() {
130
+ input.setRawMode(wasRaw ?? false);
131
+ input.removeListener("keypress", onKeypress);
132
+ input.pause();
133
+ output.write("\x1B[?25h");
134
+ }
135
+ function onKeypress(_str, key) {
136
+ if (!key)
137
+ return;
138
+ if (key.name === "up" || key.name === "k" && !key.ctrl) {
139
+ selectedIndex = selectedIndex <= 0 ? items.length - 1 : selectedIndex - 1;
140
+ render();
141
+ } else if (key.name === "down" || key.name === "j" && !key.ctrl) {
142
+ selectedIndex = selectedIndex >= items.length - 1 ? 0 : selectedIndex + 1;
143
+ render();
144
+ } else if (key.name === "return") {
145
+ cleanup();
146
+ resolve(items[selectedIndex]?.value);
147
+ } else if (key.name === "escape" || key.name === "c" && key.ctrl) {
148
+ cleanup();
149
+ resolve(void 0);
150
+ }
151
+ }
152
+ input.on("keypress", onKeypress);
153
+ });
154
+ }
74
155
 
75
156
  // build/auth.js
76
157
  var CLI_CLIENT_NAME = "Hyperline CLI";
@@ -88,7 +169,10 @@ function generateState() {
88
169
  async function registerDynamicClient({ baseUrl, redirectUri }) {
89
170
  const response = await fetch(`${baseUrl}/oauth/register`, {
90
171
  method: "POST",
91
- headers: { "Content-Type": "application/json" },
172
+ headers: {
173
+ "Content-Type": "application/json",
174
+ "Hyperline-Source": "cli"
175
+ },
92
176
  body: JSON.stringify({
93
177
  client_name: CLI_CLIENT_NAME,
94
178
  redirect_uris: [redirectUri],
@@ -106,7 +190,10 @@ async function registerDynamicClient({ baseUrl, redirectUri }) {
106
190
  async function exchangeCodeForTokens({ baseUrl, code, clientId, codeVerifier, redirectUri }) {
107
191
  const response = await fetch(`${baseUrl}/oauth/tokens`, {
108
192
  method: "POST",
109
- headers: { "Content-Type": "application/json" },
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ "Hyperline-Source": "cli"
196
+ },
110
197
  body: JSON.stringify({
111
198
  grant_type: "authorization_code",
112
199
  code,
@@ -238,11 +325,59 @@ Please open this URL in your browser:
238
325
  expiresIn: tokens.expires_in
239
326
  });
240
327
  process.stdout.write("Login successful!\n");
328
+ await promptCompanySelection({
329
+ baseUrl,
330
+ accessToken: tokens.access_token
331
+ });
241
332
  } catch (error) {
242
333
  server.close();
243
334
  throw error;
244
335
  }
245
336
  }
337
+ async function fetchCompanies({ baseUrl, accessToken }) {
338
+ const response = await fetch(`${baseUrl}/v1/companies`, {
339
+ headers: {
340
+ Authorization: `Bearer ${accessToken}`,
341
+ "Hyperline-Source": "cli"
342
+ }
343
+ });
344
+ if (!response.ok) {
345
+ throw new Error(`Failed to fetch companies: ${response.status}`);
346
+ }
347
+ const body = await response.json();
348
+ return body.data;
349
+ }
350
+ async function promptCompanySelection({ baseUrl, accessToken }) {
351
+ process.stdout.write("\nFetching your companies...\n");
352
+ const companies = await fetchCompanies({ baseUrl, accessToken });
353
+ if (companies.length === 0) {
354
+ process.stdout.write("No companies found for this account.\n");
355
+ return;
356
+ }
357
+ if (companies.length === 1) {
358
+ const onlyCompany = companies[0];
359
+ await saveCompanyId({ companyId: onlyCompany.id });
360
+ process.stdout.write(`Company set to ${onlyCompany.name}
361
+ `);
362
+ return;
363
+ }
364
+ const selectedCompanyId = await selectPrompt({
365
+ message: "Select a company:",
366
+ items: companies.map((company) => ({
367
+ label: company.name,
368
+ value: company.id,
369
+ hint: company.id
370
+ }))
371
+ });
372
+ if (!selectedCompanyId) {
373
+ process.stdout.write("No company selected. You can set one later with: hyperline company select\n");
374
+ return;
375
+ }
376
+ await saveCompanyId({ companyId: selectedCompanyId });
377
+ const selectedCompany = companies.find((company) => company.id === selectedCompanyId);
378
+ process.stdout.write(`Company set to ${selectedCompany?.name ?? selectedCompanyId}
379
+ `);
380
+ }
246
381
 
247
382
  // build/commands/generated/analytics.js
248
383
  function registerAnalyticsCommands(parent) {
@@ -355,9 +490,9 @@ Examples:
355
490
  }
356
491
 
357
492
  // build/commands/confirm.js
358
- import * as readline from "node:readline";
493
+ import * as readline2 from "node:readline";
359
494
  function confirmPrompt(message) {
360
- const rl = readline.createInterface({
495
+ const rl = readline2.createInterface({
361
496
  input: process.stdin,
362
497
  output: process.stderr
363
498
  });
@@ -8805,7 +8940,7 @@ ${formatText(value, indent + 2)}`;
8805
8940
  }
8806
8941
 
8807
8942
  // build/http.js
8808
- function createCLIContext({ apiKey, baseUrl, outputFormat, source }) {
8943
+ function createCLIContext({ apiKey, baseUrl, outputFormat, source, companyId }) {
8809
8944
  const noop = () => {
8810
8945
  };
8811
8946
  const httpClient = buildHttpClient({
@@ -8831,7 +8966,8 @@ function createCLIContext({ apiKey, baseUrl, outputFormat, source }) {
8831
8966
  params,
8832
8967
  data: hasData ? requestData : void 0,
8833
8968
  headers: {
8834
- "Hyperline-Source": source
8969
+ "Hyperline-Source": source,
8970
+ ...companyId ? { "Hyperline-CompanyId": companyId } : {}
8835
8971
  }
8836
8972
  });
8837
8973
  process.stdout.write(formatOutput({ data: response.data, format: outputFormat }));
@@ -8877,7 +9013,7 @@ function isAxiosError2(error) {
8877
9013
 
8878
9014
  // build/bin/hyperline.js
8879
9015
  var program = new Command();
8880
- program.name("hyperline").description("Agent-first CLI for the Hyperline API").version("0.1.0").option("--api-key <key>", "Hyperline API key (overrides HYPERLINE_API_KEY)").option("--base-url <url>", "API base URL (overrides HYPERLINE_API_URL)").option("--output <format>", "Output format: json or text", "text");
9016
+ program.name("hyperline").description("Agent-first CLI for the Hyperline API").version("0.1.0").option("--api-key <key>", "Hyperline API key (overrides HYPERLINE_API_KEY)").option("--base-url <url>", "API base URL (overrides HYPERLINE_API_URL)").option("--output <format>", "Output format: json or text", "text").option("--company-id <id>", "Company ID (overrides HYPERLINE_COMPANY_ID and stored selection)");
8881
9017
  program.command("login").description("Authenticate with Hyperline via browser").action(async () => {
8882
9018
  const options = program.opts();
8883
9019
  const baseUrl = await resolveBaseUrl({
@@ -8889,10 +9025,63 @@ program.command("logout").description("Clear stored credentials").action(async (
8889
9025
  await clearCredentials();
8890
9026
  process.stdout.write("Logged out.\n");
8891
9027
  });
9028
+ var companyCommand = program.command("company").description("Manage active company");
9029
+ companyCommand.command("select").description("Interactively select the active company").action(async () => {
9030
+ const options = program.opts();
9031
+ const baseUrl = await resolveBaseUrl({
9032
+ flagBaseUrl: options.baseUrl
9033
+ });
9034
+ const apiKey = resolveApiKey({
9035
+ flagApiKey: options.apiKey
9036
+ });
9037
+ const accessToken = apiKey ?? await resolveAccessToken();
9038
+ if (!accessToken) {
9039
+ process.stderr.write("Error: No authentication found. Run: hyperline login\n");
9040
+ process.exit(1);
9041
+ }
9042
+ await promptCompanySelection({ baseUrl, accessToken });
9043
+ });
9044
+ companyCommand.command("set <companyId>").description("Set the active company by ID (for scripts and agents)").action(async (companyId) => {
9045
+ await saveCompanyId({ companyId });
9046
+ process.stdout.write(`Company set to ${companyId}
9047
+ `);
9048
+ });
9049
+ companyCommand.command("list").description("List all accessible companies").action(async () => {
9050
+ const options = program.opts();
9051
+ const baseUrl = await resolveBaseUrl({
9052
+ flagBaseUrl: options.baseUrl
9053
+ });
9054
+ const apiKey = resolveApiKey({
9055
+ flagApiKey: options.apiKey
9056
+ });
9057
+ const accessToken = apiKey ?? await resolveAccessToken();
9058
+ if (!accessToken) {
9059
+ process.stderr.write("Error: No authentication found. Run: hyperline login\n");
9060
+ process.exit(1);
9061
+ }
9062
+ const companies = await fetchCompanies({ baseUrl, accessToken });
9063
+ const currentCompanyId = await resolveCompanyId({});
9064
+ for (const company of companies) {
9065
+ const marker = company.id === currentCompanyId ? " (active)" : "";
9066
+ process.stdout.write(`${company.name} ${company.id}${marker}
9067
+ `);
9068
+ }
9069
+ });
9070
+ companyCommand.command("current").description("Show the currently active company").action(async () => {
9071
+ const companyId = await resolveCompanyId({});
9072
+ if (companyId) {
9073
+ process.stdout.write(`${companyId}
9074
+ `);
9075
+ } else {
9076
+ process.stdout.write("No company selected. Run: hyperline company select\n");
9077
+ }
9078
+ });
8892
9079
  registerAllCommands(program);
9080
+ var selfAuthCommands = /* @__PURE__ */ new Set(["login", "logout", "company"]);
8893
9081
  program.hook("preAction", async (thisCommand, actionCommand) => {
8894
9082
  const commandName = actionCommand.name();
8895
- if (commandName === "login" || commandName === "logout")
9083
+ const parentName = actionCommand.parent?.name();
9084
+ if (selfAuthCommands.has(commandName) || selfAuthCommands.has(parentName ?? ""))
8896
9085
  return;
8897
9086
  const options = program.opts();
8898
9087
  const outputFormat = options.output ?? "text";
@@ -8907,11 +9096,15 @@ program.hook("preAction", async (thisCommand, actionCommand) => {
8907
9096
  const baseUrl = await resolveBaseUrl({
8908
9097
  flagBaseUrl: options.baseUrl
8909
9098
  });
9099
+ const companyId = await resolveCompanyId({
9100
+ flagCompanyId: options.companyId
9101
+ });
8910
9102
  const ctx = createCLIContext({
8911
9103
  apiKey: token,
8912
9104
  baseUrl,
8913
9105
  outputFormat,
8914
- source: apiKey ? "cli" : "cli-oauth"
9106
+ source: apiKey ? "cli" : "cli-oauth",
9107
+ companyId
8915
9108
  });
8916
9109
  thisCommand.setOptionValue("_ctx", ctx);
8917
9110
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperline/cli",
3
- "version": "0.1.0-build.1.9301c8c",
3
+ "version": "0.1.0-build.1.bf6bdf2",
4
4
  "description": "Agent-first CLI for Hyperline API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",