@vibedrift/cli 0.3.0 → 0.3.2
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/LICENSE +1 -1
- package/README.md +2 -2
- package/dist/index.js +350 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -149,11 +149,11 @@ In short:
|
|
|
149
149
|
- No use to build competing products
|
|
150
150
|
- All rights reserved
|
|
151
151
|
|
|
152
|
-
For commercial licensing, partnerships, or enterprise terms: **sami@
|
|
152
|
+
For commercial licensing, partnerships, or enterprise terms: **sami.ahmadkhan12@gmail.com**
|
|
153
153
|
|
|
154
154
|
---
|
|
155
155
|
|
|
156
156
|
## Links
|
|
157
157
|
|
|
158
158
|
- **Website:** https://vibedrift.ai
|
|
159
|
-
- **Issues / Support:** sami@
|
|
159
|
+
- **Issues / Support:** sami.ahmadkhan12@gmail.com
|
package/dist/index.js
CHANGED
|
@@ -7889,6 +7889,119 @@ function previewToken(token) {
|
|
|
7889
7889
|
return token.slice(0, 12) + "\u2026";
|
|
7890
7890
|
}
|
|
7891
7891
|
|
|
7892
|
+
// src/auth/api.ts
|
|
7893
|
+
init_esm_shims();
|
|
7894
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
7895
|
+
var VibeDriftApiError = class extends Error {
|
|
7896
|
+
constructor(status, message) {
|
|
7897
|
+
super(message);
|
|
7898
|
+
this.status = status;
|
|
7899
|
+
this.name = "VibeDriftApiError";
|
|
7900
|
+
}
|
|
7901
|
+
status;
|
|
7902
|
+
};
|
|
7903
|
+
async function jsonFetch(url, init = {}) {
|
|
7904
|
+
const controller = new AbortController();
|
|
7905
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
7906
|
+
try {
|
|
7907
|
+
const res = await fetch(url, {
|
|
7908
|
+
...init,
|
|
7909
|
+
signal: controller.signal,
|
|
7910
|
+
headers: {
|
|
7911
|
+
Accept: "application/json",
|
|
7912
|
+
...init.body ? { "Content-Type": "application/json" } : {},
|
|
7913
|
+
...init.headers ?? {}
|
|
7914
|
+
}
|
|
7915
|
+
});
|
|
7916
|
+
if (!res.ok) {
|
|
7917
|
+
let detail = "";
|
|
7918
|
+
try {
|
|
7919
|
+
const body = await res.json();
|
|
7920
|
+
detail = body.detail ?? body.message ?? "";
|
|
7921
|
+
} catch {
|
|
7922
|
+
try {
|
|
7923
|
+
detail = await res.text();
|
|
7924
|
+
} catch {
|
|
7925
|
+
}
|
|
7926
|
+
}
|
|
7927
|
+
throw new VibeDriftApiError(res.status, detail || `HTTP ${res.status}`);
|
|
7928
|
+
}
|
|
7929
|
+
return await res.json();
|
|
7930
|
+
} catch (err) {
|
|
7931
|
+
if (err?.name === "AbortError") {
|
|
7932
|
+
throw new VibeDriftApiError(0, `Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`);
|
|
7933
|
+
}
|
|
7934
|
+
if (err instanceof VibeDriftApiError) throw err;
|
|
7935
|
+
throw new VibeDriftApiError(0, err?.message ?? String(err));
|
|
7936
|
+
} finally {
|
|
7937
|
+
clearTimeout(timer);
|
|
7938
|
+
}
|
|
7939
|
+
}
|
|
7940
|
+
async function startDeviceAuth(opts) {
|
|
7941
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7942
|
+
return jsonFetch(`${base}/auth/device`, {
|
|
7943
|
+
method: "POST",
|
|
7944
|
+
body: JSON.stringify({ client_id: "vibedrift-cli" })
|
|
7945
|
+
});
|
|
7946
|
+
}
|
|
7947
|
+
async function pollDeviceAuth(deviceCode, opts) {
|
|
7948
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7949
|
+
return jsonFetch(`${base}/auth/poll`, {
|
|
7950
|
+
method: "POST",
|
|
7951
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
7952
|
+
});
|
|
7953
|
+
}
|
|
7954
|
+
async function validateToken(token, opts) {
|
|
7955
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7956
|
+
return jsonFetch(`${base}/auth/validate`, {
|
|
7957
|
+
method: "GET",
|
|
7958
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
7959
|
+
});
|
|
7960
|
+
}
|
|
7961
|
+
async function revokeToken(token, opts) {
|
|
7962
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7963
|
+
await jsonFetch(`${base}/auth/revoke`, {
|
|
7964
|
+
method: "POST",
|
|
7965
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
7966
|
+
});
|
|
7967
|
+
}
|
|
7968
|
+
async function fetchUsage(token, opts) {
|
|
7969
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7970
|
+
return jsonFetch(`${base}/account/usage`, {
|
|
7971
|
+
method: "GET",
|
|
7972
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
7973
|
+
});
|
|
7974
|
+
}
|
|
7975
|
+
async function sendFeedback(args) {
|
|
7976
|
+
const base = await resolveApiUrl(args.apiUrl);
|
|
7977
|
+
const headers = {};
|
|
7978
|
+
if (args.token) headers.Authorization = `Bearer ${args.token}`;
|
|
7979
|
+
return jsonFetch(`${base}/v1/feedback/general`, {
|
|
7980
|
+
method: "POST",
|
|
7981
|
+
headers,
|
|
7982
|
+
body: JSON.stringify({
|
|
7983
|
+
source: args.source,
|
|
7984
|
+
message: args.message,
|
|
7985
|
+
email: args.email,
|
|
7986
|
+
metadata: args.metadata
|
|
7987
|
+
})
|
|
7988
|
+
});
|
|
7989
|
+
}
|
|
7990
|
+
async function fetchCredits(token, opts) {
|
|
7991
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7992
|
+
return jsonFetch(`${base}/account/credits`, {
|
|
7993
|
+
method: "GET",
|
|
7994
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
7995
|
+
});
|
|
7996
|
+
}
|
|
7997
|
+
async function createPortalSession(token, opts) {
|
|
7998
|
+
const base = await resolveApiUrl(opts?.apiUrl);
|
|
7999
|
+
return jsonFetch(`${base}/account/portal`, {
|
|
8000
|
+
method: "POST",
|
|
8001
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
8002
|
+
});
|
|
8003
|
+
}
|
|
8004
|
+
|
|
7892
8005
|
// src/cli/commands/scan.ts
|
|
7893
8006
|
async function runScan(targetPath, options) {
|
|
7894
8007
|
const rootDir = resolve(targetPath);
|
|
@@ -7910,7 +8023,9 @@ async function runScan(targetPath, options) {
|
|
|
7910
8023
|
console.error("");
|
|
7911
8024
|
console.error(chalk2.red(" \u2717 Deep scans require a VibeDrift account."));
|
|
7912
8025
|
console.error("");
|
|
7913
|
-
console.error(
|
|
8026
|
+
console.error(chalk2.bgYellow.black.bold(" \u{1F381} But your first deep scan is FREE. "));
|
|
8027
|
+
console.error("");
|
|
8028
|
+
console.error(" Run " + chalk2.bold("vibedrift login") + " to sign in and claim it.");
|
|
7914
8029
|
console.error(" Or set " + chalk2.bold("VIBEDRIFT_TOKEN") + " in your environment for CI.");
|
|
7915
8030
|
console.error("");
|
|
7916
8031
|
process.exit(1);
|
|
@@ -7927,6 +8042,25 @@ async function runScan(targetPath, options) {
|
|
|
7927
8042
|
} catch {
|
|
7928
8043
|
}
|
|
7929
8044
|
}
|
|
8045
|
+
if (!options.json && options.format !== "json" && !options.deep) {
|
|
8046
|
+
if (bearerToken) {
|
|
8047
|
+
try {
|
|
8048
|
+
const credits = await fetchCredits(bearerToken, { apiUrl });
|
|
8049
|
+
if (credits.has_free_deep_scan && !credits.unlimited) {
|
|
8050
|
+
console.log("");
|
|
8051
|
+
console.log(chalk2.bgYellow.black.bold(" \u{1F381} 1 FREE DEEP SCAN AVAILABLE "));
|
|
8052
|
+
console.log(chalk2.yellow(" Run with ") + chalk2.bold.cyan("--deep") + chalk2.yellow(" to use Claude-powered analysis (no card required)."));
|
|
8053
|
+
console.log("");
|
|
8054
|
+
}
|
|
8055
|
+
} catch {
|
|
8056
|
+
}
|
|
8057
|
+
} else {
|
|
8058
|
+
console.log("");
|
|
8059
|
+
console.log(chalk2.dim(" Tip: ") + chalk2.yellow("sign up free to get 1 deep scan included"));
|
|
8060
|
+
console.log(chalk2.dim(" Run ") + chalk2.bold("vibedrift login") + chalk2.dim(" to claim it (no card required)."));
|
|
8061
|
+
console.log("");
|
|
8062
|
+
}
|
|
8063
|
+
}
|
|
7930
8064
|
const startTime = Date.now();
|
|
7931
8065
|
const timings = {};
|
|
7932
8066
|
const isTerminal = options.format === "terminal" && !options.json;
|
|
@@ -8281,97 +8415,6 @@ Update failed: ${message}`));
|
|
|
8281
8415
|
init_esm_shims();
|
|
8282
8416
|
import chalk4 from "chalk";
|
|
8283
8417
|
|
|
8284
|
-
// src/auth/api.ts
|
|
8285
|
-
init_esm_shims();
|
|
8286
|
-
var REQUEST_TIMEOUT_MS = 3e4;
|
|
8287
|
-
var VibeDriftApiError = class extends Error {
|
|
8288
|
-
constructor(status, message) {
|
|
8289
|
-
super(message);
|
|
8290
|
-
this.status = status;
|
|
8291
|
-
this.name = "VibeDriftApiError";
|
|
8292
|
-
}
|
|
8293
|
-
status;
|
|
8294
|
-
};
|
|
8295
|
-
async function jsonFetch(url, init = {}) {
|
|
8296
|
-
const controller = new AbortController();
|
|
8297
|
-
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
8298
|
-
try {
|
|
8299
|
-
const res = await fetch(url, {
|
|
8300
|
-
...init,
|
|
8301
|
-
signal: controller.signal,
|
|
8302
|
-
headers: {
|
|
8303
|
-
Accept: "application/json",
|
|
8304
|
-
...init.body ? { "Content-Type": "application/json" } : {},
|
|
8305
|
-
...init.headers ?? {}
|
|
8306
|
-
}
|
|
8307
|
-
});
|
|
8308
|
-
if (!res.ok) {
|
|
8309
|
-
let detail = "";
|
|
8310
|
-
try {
|
|
8311
|
-
const body = await res.json();
|
|
8312
|
-
detail = body.detail ?? body.message ?? "";
|
|
8313
|
-
} catch {
|
|
8314
|
-
try {
|
|
8315
|
-
detail = await res.text();
|
|
8316
|
-
} catch {
|
|
8317
|
-
}
|
|
8318
|
-
}
|
|
8319
|
-
throw new VibeDriftApiError(res.status, detail || `HTTP ${res.status}`);
|
|
8320
|
-
}
|
|
8321
|
-
return await res.json();
|
|
8322
|
-
} catch (err) {
|
|
8323
|
-
if (err?.name === "AbortError") {
|
|
8324
|
-
throw new VibeDriftApiError(0, `Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`);
|
|
8325
|
-
}
|
|
8326
|
-
if (err instanceof VibeDriftApiError) throw err;
|
|
8327
|
-
throw new VibeDriftApiError(0, err?.message ?? String(err));
|
|
8328
|
-
} finally {
|
|
8329
|
-
clearTimeout(timer);
|
|
8330
|
-
}
|
|
8331
|
-
}
|
|
8332
|
-
async function startDeviceAuth(opts) {
|
|
8333
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8334
|
-
return jsonFetch(`${base}/auth/device`, {
|
|
8335
|
-
method: "POST",
|
|
8336
|
-
body: JSON.stringify({ client_id: "vibedrift-cli" })
|
|
8337
|
-
});
|
|
8338
|
-
}
|
|
8339
|
-
async function pollDeviceAuth(deviceCode, opts) {
|
|
8340
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8341
|
-
return jsonFetch(`${base}/auth/poll`, {
|
|
8342
|
-
method: "POST",
|
|
8343
|
-
body: JSON.stringify({ device_code: deviceCode })
|
|
8344
|
-
});
|
|
8345
|
-
}
|
|
8346
|
-
async function validateToken(token, opts) {
|
|
8347
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8348
|
-
return jsonFetch(`${base}/auth/validate`, {
|
|
8349
|
-
method: "GET",
|
|
8350
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
8351
|
-
});
|
|
8352
|
-
}
|
|
8353
|
-
async function revokeToken(token, opts) {
|
|
8354
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8355
|
-
await jsonFetch(`${base}/auth/revoke`, {
|
|
8356
|
-
method: "POST",
|
|
8357
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
8358
|
-
});
|
|
8359
|
-
}
|
|
8360
|
-
async function fetchUsage(token, opts) {
|
|
8361
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8362
|
-
return jsonFetch(`${base}/account/usage`, {
|
|
8363
|
-
method: "GET",
|
|
8364
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
8365
|
-
});
|
|
8366
|
-
}
|
|
8367
|
-
async function createPortalSession(token, opts) {
|
|
8368
|
-
const base = await resolveApiUrl(opts?.apiUrl);
|
|
8369
|
-
return jsonFetch(`${base}/account/portal`, {
|
|
8370
|
-
method: "POST",
|
|
8371
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
8372
|
-
});
|
|
8373
|
-
}
|
|
8374
|
-
|
|
8375
8418
|
// src/auth/browser.ts
|
|
8376
8419
|
init_esm_shims();
|
|
8377
8420
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -8478,11 +8521,43 @@ async function runLogin(options = {}) {
|
|
|
8478
8521
|
console.log(` Account: ${chalk4.bold(result.email)}`);
|
|
8479
8522
|
console.log(` Plan: ${chalk4.bold(result.plan)}`);
|
|
8480
8523
|
console.log("");
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8524
|
+
try {
|
|
8525
|
+
const credits = await fetchCredits(result.access_token, {
|
|
8526
|
+
apiUrl: options.apiUrl
|
|
8527
|
+
});
|
|
8528
|
+
if (credits.has_free_deep_scan && !credits.unlimited) {
|
|
8529
|
+
console.log(
|
|
8530
|
+
chalk4.bgYellow.black.bold(" \u{1F381} 1 FREE deep scan included with your account ")
|
|
8531
|
+
);
|
|
8532
|
+
console.log("");
|
|
8533
|
+
console.log(
|
|
8534
|
+
chalk4.yellow(" Try the full pipeline (Claude analysis, security review,")
|
|
8535
|
+
);
|
|
8536
|
+
console.log(
|
|
8537
|
+
chalk4.yellow(" AI-powered drift detection) on any project \u2014 no card needed.")
|
|
8538
|
+
);
|
|
8539
|
+
console.log("");
|
|
8540
|
+
console.log(` ${chalk4.cyan("vibedrift . --deep")}`);
|
|
8541
|
+
console.log("");
|
|
8542
|
+
} else if (credits.unlimited) {
|
|
8543
|
+
console.log(chalk4.dim(" Run `vibedrift . --deep` to use AI-powered analysis."));
|
|
8544
|
+
console.log("");
|
|
8545
|
+
} else if (credits.available_total > 0) {
|
|
8546
|
+
console.log(
|
|
8547
|
+
chalk4.dim(` You have ${credits.available_total} deep scan credit${credits.available_total === 1 ? "" : "s"} available.`)
|
|
8548
|
+
);
|
|
8549
|
+
console.log(chalk4.dim(" Run `vibedrift . --deep` to use one."));
|
|
8550
|
+
console.log("");
|
|
8551
|
+
} else {
|
|
8552
|
+
console.log(chalk4.dim(" Run `vibedrift upgrade` to enable deep AI scans."));
|
|
8553
|
+
console.log("");
|
|
8554
|
+
}
|
|
8555
|
+
} catch {
|
|
8556
|
+
if (result.plan === "free") {
|
|
8557
|
+
console.log(chalk4.dim(" Run `vibedrift upgrade` to enable deep AI scans."));
|
|
8558
|
+
} else {
|
|
8559
|
+
console.log(chalk4.dim(" Run `vibedrift . --deep` to use AI-powered analysis."));
|
|
8560
|
+
}
|
|
8486
8561
|
console.log("");
|
|
8487
8562
|
}
|
|
8488
8563
|
return;
|
|
@@ -8594,6 +8669,21 @@ async function runStatus() {
|
|
|
8594
8669
|
console.log(chalk6.dim(` ${err.message}`));
|
|
8595
8670
|
}
|
|
8596
8671
|
}
|
|
8672
|
+
try {
|
|
8673
|
+
const credits = await fetchCredits(resolved.token, { apiUrl: config.apiUrl });
|
|
8674
|
+
console.log("");
|
|
8675
|
+
if (credits.unlimited) {
|
|
8676
|
+
console.log(` Deep scans: ${chalk6.bold.green("unlimited")} (${credits.plan})`);
|
|
8677
|
+
} else if (credits.has_free_deep_scan) {
|
|
8678
|
+
console.log(` Deep scans: ${chalk6.bold.yellow("1 free")} + ${credits.available_purchased} purchased`);
|
|
8679
|
+
console.log(chalk6.dim(" Run `vibedrift . --deep` to use your free credit."));
|
|
8680
|
+
} else if (credits.available_total > 0) {
|
|
8681
|
+
console.log(` Deep scans: ${chalk6.bold(credits.available_total)} credit${credits.available_total === 1 ? "" : "s"} available`);
|
|
8682
|
+
} else {
|
|
8683
|
+
console.log(` Deep scans: ${chalk6.dim("0 credits")} \u2014 run \`vibedrift upgrade\` for more`);
|
|
8684
|
+
}
|
|
8685
|
+
} catch {
|
|
8686
|
+
}
|
|
8597
8687
|
console.log("");
|
|
8598
8688
|
}
|
|
8599
8689
|
function describeSource(source) {
|
|
@@ -8885,6 +8975,145 @@ function describeSource2(source) {
|
|
|
8885
8975
|
}
|
|
8886
8976
|
}
|
|
8887
8977
|
|
|
8978
|
+
// src/cli/commands/feedback.ts
|
|
8979
|
+
init_esm_shims();
|
|
8980
|
+
import os from "os";
|
|
8981
|
+
import readline from "readline";
|
|
8982
|
+
import chalk11 from "chalk";
|
|
8983
|
+
init_version();
|
|
8984
|
+
var MAX_MESSAGE_BYTES = 4096;
|
|
8985
|
+
async function runFeedback(opts = {}) {
|
|
8986
|
+
console.log("");
|
|
8987
|
+
console.log(chalk11.bold(" VibeDrift feedback"));
|
|
8988
|
+
console.log(
|
|
8989
|
+
chalk11.dim(" Tell us what's broken, what's confusing, or what you wish existed.")
|
|
8990
|
+
);
|
|
8991
|
+
console.log(
|
|
8992
|
+
chalk11.dim(" Goes straight to the maintainer \u2014 anonymous unless you're logged in.")
|
|
8993
|
+
);
|
|
8994
|
+
console.log("");
|
|
8995
|
+
let message = (opts.message ?? "").trim();
|
|
8996
|
+
if (!message) {
|
|
8997
|
+
message = await promptForMultilineMessage();
|
|
8998
|
+
}
|
|
8999
|
+
if (!message) {
|
|
9000
|
+
console.error(chalk11.red(" \u2717 No feedback provided. Aborting."));
|
|
9001
|
+
process.exit(1);
|
|
9002
|
+
}
|
|
9003
|
+
if (Buffer.byteLength(message, "utf8") > MAX_MESSAGE_BYTES) {
|
|
9004
|
+
console.error(
|
|
9005
|
+
chalk11.red(
|
|
9006
|
+
` \u2717 Message too long (max ${MAX_MESSAGE_BYTES} bytes). Please trim it or open an issue on GitHub for longer reports.`
|
|
9007
|
+
)
|
|
9008
|
+
);
|
|
9009
|
+
process.exit(1);
|
|
9010
|
+
}
|
|
9011
|
+
let token = null;
|
|
9012
|
+
try {
|
|
9013
|
+
const resolved = await resolveToken();
|
|
9014
|
+
if (resolved) token = resolved.token;
|
|
9015
|
+
} catch {
|
|
9016
|
+
}
|
|
9017
|
+
const metadata = {
|
|
9018
|
+
cli_version: getVersion(),
|
|
9019
|
+
node_version: process.version,
|
|
9020
|
+
platform: process.platform,
|
|
9021
|
+
arch: process.arch,
|
|
9022
|
+
os_release: os.release(),
|
|
9023
|
+
locale: process.env.LANG ?? null,
|
|
9024
|
+
tty: process.stdin.isTTY === true
|
|
9025
|
+
};
|
|
9026
|
+
process.stdout.write(chalk11.dim(" Sending... "));
|
|
9027
|
+
try {
|
|
9028
|
+
const result = await sendFeedback({
|
|
9029
|
+
source: "cli",
|
|
9030
|
+
message,
|
|
9031
|
+
token: token ?? void 0,
|
|
9032
|
+
metadata,
|
|
9033
|
+
apiUrl: await resolveApiUrl(opts.apiUrl)
|
|
9034
|
+
});
|
|
9035
|
+
console.log(chalk11.green("ok"));
|
|
9036
|
+
console.log("");
|
|
9037
|
+
console.log(` ${chalk11.dim("Reference:")} ${chalk11.dim(result.id)}`);
|
|
9038
|
+
if (token) {
|
|
9039
|
+
console.log(
|
|
9040
|
+
chalk11.dim(
|
|
9041
|
+
" Submitted under your account \u2014 we'll reply to your email if needed."
|
|
9042
|
+
)
|
|
9043
|
+
);
|
|
9044
|
+
} else {
|
|
9045
|
+
console.log(
|
|
9046
|
+
chalk11.dim(
|
|
9047
|
+
" Submitted anonymously. If you'd like a reply, run `vibedrift login` first."
|
|
9048
|
+
)
|
|
9049
|
+
);
|
|
9050
|
+
}
|
|
9051
|
+
console.log("");
|
|
9052
|
+
console.log(chalk11.green(" \u2713 Thanks for helping us improve VibeDrift."));
|
|
9053
|
+
console.log("");
|
|
9054
|
+
} catch (err) {
|
|
9055
|
+
console.log(chalk11.red("failed"));
|
|
9056
|
+
console.log("");
|
|
9057
|
+
if (err instanceof VibeDriftApiError) {
|
|
9058
|
+
console.error(chalk11.red(` \u2717 ${err.message}`));
|
|
9059
|
+
} else {
|
|
9060
|
+
console.error(
|
|
9061
|
+
chalk11.red(` \u2717 ${err instanceof Error ? err.message : String(err)}`)
|
|
9062
|
+
);
|
|
9063
|
+
}
|
|
9064
|
+
console.error(
|
|
9065
|
+
chalk11.dim(
|
|
9066
|
+
" You can also email sami.ahmadkhan12@gmail.com directly."
|
|
9067
|
+
)
|
|
9068
|
+
);
|
|
9069
|
+
console.log("");
|
|
9070
|
+
process.exit(1);
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
function promptForMultilineMessage() {
|
|
9074
|
+
return new Promise((resolve2) => {
|
|
9075
|
+
if (!process.stdin.isTTY) {
|
|
9076
|
+
let buf = "";
|
|
9077
|
+
process.stdin.setEncoding("utf8");
|
|
9078
|
+
process.stdin.on("data", (chunk) => {
|
|
9079
|
+
buf += chunk;
|
|
9080
|
+
});
|
|
9081
|
+
process.stdin.on("end", () => resolve2(buf.trim()));
|
|
9082
|
+
return;
|
|
9083
|
+
}
|
|
9084
|
+
console.log(
|
|
9085
|
+
chalk11.dim(
|
|
9086
|
+
" Type your feedback below. Submit with a single line containing 'EOF',"
|
|
9087
|
+
)
|
|
9088
|
+
);
|
|
9089
|
+
console.log(chalk11.dim(" or press Ctrl-D when done. Press Ctrl-C to abort."));
|
|
9090
|
+
console.log("");
|
|
9091
|
+
const rl = readline.createInterface({
|
|
9092
|
+
input: process.stdin,
|
|
9093
|
+
output: process.stdout,
|
|
9094
|
+
prompt: chalk11.yellow(" > ")
|
|
9095
|
+
});
|
|
9096
|
+
const lines = [];
|
|
9097
|
+
rl.prompt();
|
|
9098
|
+
rl.on("line", (line) => {
|
|
9099
|
+
if (line.trim() === "EOF") {
|
|
9100
|
+
rl.close();
|
|
9101
|
+
return;
|
|
9102
|
+
}
|
|
9103
|
+
lines.push(line);
|
|
9104
|
+
rl.prompt();
|
|
9105
|
+
});
|
|
9106
|
+
rl.on("close", () => {
|
|
9107
|
+
console.log("");
|
|
9108
|
+
resolve2(lines.join("\n").trim());
|
|
9109
|
+
});
|
|
9110
|
+
rl.on("SIGINT", () => {
|
|
9111
|
+
console.log(chalk11.red("\n \u2717 Aborted."));
|
|
9112
|
+
process.exit(1);
|
|
9113
|
+
});
|
|
9114
|
+
});
|
|
9115
|
+
}
|
|
9116
|
+
|
|
8888
9117
|
// src/cli/index.ts
|
|
8889
9118
|
init_version();
|
|
8890
9119
|
var VERSION = getVersion();
|
|
@@ -8932,6 +9161,9 @@ program.command("scan", { isDefault: true }).description("Scan a project for vib
|
|
|
8932
9161
|
).option(
|
|
8933
9162
|
"--update",
|
|
8934
9163
|
"update the VibeDrift CLI to the latest version (alias for `vibedrift update`)"
|
|
9164
|
+
).option(
|
|
9165
|
+
"--feedback [message...]",
|
|
9166
|
+
"send feedback to the maintainer (alias for `vibedrift feedback`)"
|
|
8935
9167
|
).option("--verbose", "show timing breakdown and analyzer details").addOption(
|
|
8936
9168
|
new Option("--api-url <url>", "override the VibeDrift API base URL").hideHelp()
|
|
8937
9169
|
).action(async (path2, options) => {
|
|
@@ -8939,6 +9171,14 @@ program.command("scan", { isDefault: true }).description("Scan a project for vib
|
|
|
8939
9171
|
await runUpdate(VERSION);
|
|
8940
9172
|
return;
|
|
8941
9173
|
}
|
|
9174
|
+
if (options.feedback) {
|
|
9175
|
+
const inline = Array.isArray(options.feedback) ? options.feedback.join(" ").trim() : "";
|
|
9176
|
+
await runFeedback({
|
|
9177
|
+
message: inline || void 0,
|
|
9178
|
+
apiUrl: options.apiUrl
|
|
9179
|
+
});
|
|
9180
|
+
return;
|
|
9181
|
+
}
|
|
8942
9182
|
await runScan(path2, {
|
|
8943
9183
|
json: options.json,
|
|
8944
9184
|
format: options.json ? "json" : options.format,
|
|
@@ -8982,6 +9222,15 @@ program.command("doctor").description("Diagnose CLI installation, auth, and API
|
|
|
8982
9222
|
program.command("update").description("Update the VibeDrift CLI to the latest version").action(async () => {
|
|
8983
9223
|
await runUpdate(VERSION);
|
|
8984
9224
|
});
|
|
9225
|
+
program.command("feedback").description("Send feedback, bug reports, or feature requests directly to the maintainer").argument(
|
|
9226
|
+
"[message...]",
|
|
9227
|
+
"feedback text (omit to be prompted interactively)"
|
|
9228
|
+
).addOption(
|
|
9229
|
+
new Option("--api-url <url>", "override the API base URL").hideHelp()
|
|
9230
|
+
).action(async (messageWords, options) => {
|
|
9231
|
+
const message = (messageWords ?? []).join(" ").trim() || void 0;
|
|
9232
|
+
await runFeedback({ message, apiUrl: options.apiUrl });
|
|
9233
|
+
});
|
|
8985
9234
|
program.addHelpText(
|
|
8986
9235
|
"after",
|
|
8987
9236
|
`
|
|
@@ -9000,6 +9249,10 @@ Examples:
|
|
|
9000
9249
|
$ vibedrift upgrade open the pricing page
|
|
9001
9250
|
$ vibedrift billing manage your Stripe subscription
|
|
9002
9251
|
$ vibedrift update update to the latest CLI version
|
|
9252
|
+
$ vibedrift feedback open an interactive feedback prompt
|
|
9253
|
+
$ vibedrift feedback "the install is broken on Windows"
|
|
9254
|
+
send inline feedback in one shot
|
|
9255
|
+
$ vibedrift --feedback "..." same as above, top-level shortcut
|
|
9003
9256
|
|
|
9004
9257
|
Environment:
|
|
9005
9258
|
VIBEDRIFT_TOKEN bearer token (overrides ~/.vibedrift/config.json)
|