kubeagent 0.1.6 → 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/dist/auth.d.ts +1 -0
- package/dist/auth.js +55 -0
- package/dist/cli.js +6 -3
- package/dist/notify/setup.js +3 -2
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare function loadAuth(): AuthState | null;
|
|
|
10
10
|
export declare function saveAuth(auth: AuthState): void;
|
|
11
11
|
export declare function clearAuth(): void;
|
|
12
12
|
export declare function loginBrowser(serverUrl: string, appUrl: string): Promise<AuthState>;
|
|
13
|
+
export declare function loginDevice(serverUrl: string, appUrl: string): Promise<AuthState>;
|
|
13
14
|
export declare function createApiKey(auth: AuthState, name: string): Promise<{
|
|
14
15
|
key: string;
|
|
15
16
|
prefix: string;
|
package/dist/auth.js
CHANGED
|
@@ -126,6 +126,61 @@ export async function loginBrowser(serverUrl, appUrl) {
|
|
|
126
126
|
saveAuth(auth);
|
|
127
127
|
return auth;
|
|
128
128
|
}
|
|
129
|
+
// Device code flow — for headless/remote machines (RFC 8628 style):
|
|
130
|
+
// 1. POST /auth/device → get device_code + user_code
|
|
131
|
+
// 2. Print user_code and verification URL
|
|
132
|
+
// 3. Poll POST /auth/device/token until approved, expired, or timed out
|
|
133
|
+
export async function loginDevice(serverUrl, appUrl) {
|
|
134
|
+
// Step 1: request a device code
|
|
135
|
+
let initRes;
|
|
136
|
+
try {
|
|
137
|
+
initRes = await fetch(`${serverUrl}/auth/device`, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: { "Content-Type": "application/json", Origin: appUrl },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
throw new Error(`Could not reach server at ${serverUrl} — is it running?\n (${err.message})`);
|
|
144
|
+
}
|
|
145
|
+
if (!initRes.ok) {
|
|
146
|
+
throw new Error(`Failed to start device login (${initRes.status})`);
|
|
147
|
+
}
|
|
148
|
+
const { device_code, user_code, verification_uri, interval } = await initRes.json();
|
|
149
|
+
// Step 2: show the code
|
|
150
|
+
console.log(`\n Visit: ${verification_uri}`);
|
|
151
|
+
console.log(` Code: ${user_code}\n`);
|
|
152
|
+
console.log("Waiting for authorization...");
|
|
153
|
+
// Step 3: poll
|
|
154
|
+
const pollInterval = (interval ?? 5) * 1000;
|
|
155
|
+
const deadline = Date.now() + 15 * 60 * 1000;
|
|
156
|
+
while (Date.now() < deadline) {
|
|
157
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
158
|
+
let pollRes;
|
|
159
|
+
try {
|
|
160
|
+
pollRes = await fetch(`${serverUrl}/auth/device/token`, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: { "Content-Type": "application/json" },
|
|
163
|
+
body: JSON.stringify({ device_code }),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
continue; // network blip — keep polling
|
|
168
|
+
}
|
|
169
|
+
if (pollRes.status === 202)
|
|
170
|
+
continue; // still pending
|
|
171
|
+
if (!pollRes.ok) {
|
|
172
|
+
const body = await pollRes.json().catch(() => ({}));
|
|
173
|
+
if (body.error === "expired_token")
|
|
174
|
+
throw new Error("Device code expired. Run `kubeagent login` again.");
|
|
175
|
+
throw new Error(body.error ?? `Unexpected response (${pollRes.status})`);
|
|
176
|
+
}
|
|
177
|
+
const { token, email, name } = await pollRes.json();
|
|
178
|
+
const auth = { serverUrl, appUrl, token, email, name };
|
|
179
|
+
saveAuth(auth);
|
|
180
|
+
return auth;
|
|
181
|
+
}
|
|
182
|
+
throw new Error("Login timed out (15 minutes).");
|
|
183
|
+
}
|
|
129
184
|
export async function createApiKey(auth, name) {
|
|
130
185
|
const url = `${auth.serverUrl}/keys`;
|
|
131
186
|
let res;
|
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ import { sendResolve } from "./notify/index.js";
|
|
|
18
18
|
import { diagnose } from "./diagnoser/index.js";
|
|
19
19
|
import { buildSystemPrompt } from "./kb/loader.js";
|
|
20
20
|
import { join } from "node:path";
|
|
21
|
-
import { loadAuth, loginBrowser, createApiKey, showAccount, clearAuth } from "./auth.js";
|
|
21
|
+
import { loadAuth, loginBrowser, loginDevice, createApiKey, showAccount, clearAuth } from "./auth.js";
|
|
22
22
|
import { fetchSlackWebhook } from "./proxy-client.js";
|
|
23
23
|
import { createInterface } from "node:readline";
|
|
24
24
|
import { scanProjectDirectory, matchProjectsToWorkloads, bestMatches } from "./onboard/project-matcher.js";
|
|
@@ -383,12 +383,15 @@ const DEFAULT_SERVER = "https://api.kubeagent.net";
|
|
|
383
383
|
const DEFAULT_APP_URL = "https://app.kubeagent.net";
|
|
384
384
|
program
|
|
385
385
|
.command("login")
|
|
386
|
-
.description("Log in to KubeAgent (opens browser)")
|
|
386
|
+
.description("Log in to KubeAgent (opens browser, or use --device for headless machines)")
|
|
387
387
|
.option("-s, --server <url>", "API server URL", DEFAULT_SERVER)
|
|
388
388
|
.option("--app-url <url>", "Dashboard URL (for browser login)", DEFAULT_APP_URL)
|
|
389
|
+
.option("--device", "Use device code flow (for remote/headless machines — no browser required)")
|
|
389
390
|
.action(async (opts) => {
|
|
390
391
|
try {
|
|
391
|
-
const auth =
|
|
392
|
+
const auth = opts.device
|
|
393
|
+
? await loginDevice(opts.server, opts.appUrl)
|
|
394
|
+
: await loginBrowser(opts.server, opts.appUrl);
|
|
392
395
|
console.log(chalk.green(`Logged in as ${auth.email ?? auth.name ?? "unknown"}`));
|
|
393
396
|
const { prefix } = await createApiKey(auth, "cli-default");
|
|
394
397
|
console.log(chalk.dim(`API key created: ${prefix}...`));
|
package/dist/notify/setup.js
CHANGED
|
@@ -130,8 +130,9 @@ export async function setupWebhook() {
|
|
|
130
130
|
}
|
|
131
131
|
export async function setupPagerDuty() {
|
|
132
132
|
console.log(chalk.bold("\n PagerDuty Setup"));
|
|
133
|
-
console.log(chalk.dim("
|
|
134
|
-
|
|
133
|
+
console.log(chalk.dim(" Search for \"Events API v2\" (KubeAgent is a custom integration):"));
|
|
134
|
+
console.log(chalk.dim(" Services → Service Directory → [Service] → Integrations → Add another integration → Events API v2\n"));
|
|
135
|
+
const routing_key = await ask("Integration Key");
|
|
135
136
|
if (!routing_key)
|
|
136
137
|
return null;
|
|
137
138
|
const label = await ask("Label (optional)", "e.g. prod-cluster");
|