@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.
- package/dist/bin/hyperline-main.js +202 -9
- package/package.json +1 -1
|
@@ -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: {
|
|
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: {
|
|
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
|
|
493
|
+
import * as readline2 from "node:readline";
|
|
359
494
|
function confirmPrompt(message) {
|
|
360
|
-
const rl =
|
|
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
|
-
|
|
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
|
});
|