devwing 0.1.22 → 0.1.23
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/index.js +332 -416
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,6 @@ import util from 'util';
|
|
|
22
22
|
import Table3 from 'cli-table3';
|
|
23
23
|
import { fileURLToPath } from 'url';
|
|
24
24
|
import semver from 'semver';
|
|
25
|
-
import readline from 'readline';
|
|
26
25
|
|
|
27
26
|
var SERVICE_NAME = "DevWing CLI";
|
|
28
27
|
var API_KEY_ACCOUNT = "api-key";
|
|
@@ -2772,7 +2771,7 @@ function isDemoMode() {
|
|
|
2772
2771
|
}
|
|
2773
2772
|
var __sessionFile = fileURLToPath(import.meta.url);
|
|
2774
2773
|
var __sessionDir = dirname(__sessionFile);
|
|
2775
|
-
var sleep2 = (ms) => new Promise((
|
|
2774
|
+
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
2776
2775
|
function getVersion() {
|
|
2777
2776
|
const paths = [
|
|
2778
2777
|
join(__sessionDir, "../package.json"),
|
|
@@ -2787,10 +2786,10 @@ function getVersion() {
|
|
|
2787
2786
|
continue;
|
|
2788
2787
|
}
|
|
2789
2788
|
}
|
|
2790
|
-
return "0.1.
|
|
2789
|
+
return "0.1.23";
|
|
2791
2790
|
}
|
|
2792
2791
|
var DEMO_USER2 = {
|
|
2793
|
-
id: "usr_a1b2c3d4
|
|
2792
|
+
id: "usr_a1b2c3d4",
|
|
2794
2793
|
email: "aliyu@devwing.ai",
|
|
2795
2794
|
full_name: "Aliyu Mohammed",
|
|
2796
2795
|
subscription_plan: "pro",
|
|
@@ -2801,18 +2800,16 @@ var DEMO_USER2 = {
|
|
|
2801
2800
|
tokens_used_today: 47832,
|
|
2802
2801
|
tokens_reset_at: "2026-04-10T00:00:00Z"
|
|
2803
2802
|
};
|
|
2804
|
-
var DEMO_WORKSPACE2 = {
|
|
2805
|
-
|
|
2806
|
-
var DEMO_PROJECT2 = {
|
|
2807
|
-
name: "Tallon SaaS ERP"};
|
|
2803
|
+
var DEMO_WORKSPACE2 = { name: "Kano State Government"};
|
|
2804
|
+
var DEMO_PROJECT2 = { name: "Tallon SaaS ERP"};
|
|
2808
2805
|
var DEMO_MODELS = [
|
|
2809
|
-
{ name: "devwing-general-1", display_name: "DevWing General", domain: "general", status: "active", min_plan: "free", context_window: 32768, tokens_per_sec: 85
|
|
2810
|
-
{ name: "devwing-frontend-1", display_name: "DevWing Frontend", domain: "frontend", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 78
|
|
2811
|
-
{ name: "devwing-backend-1", display_name: "DevWing Backend", domain: "backend", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 82
|
|
2812
|
-
{ name: "devwing-security-1", display_name: "DevWing Security", domain: "security", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 74
|
|
2813
|
-
{ name: "devwing-devops-1", display_name: "DevWing DevOps", domain: "devops", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 70
|
|
2814
|
-
{ name: "devwing-mobile-1", display_name: "DevWing Mobile", domain: "mobile", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 72
|
|
2815
|
-
{ name: "devwing-data-1", display_name: "DevWing Data", domain: "data", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 68
|
|
2806
|
+
{ name: "devwing-general-1", display_name: "DevWing General", domain: "general", status: "active", min_plan: "free", context_window: 32768, tokens_per_sec: 85 },
|
|
2807
|
+
{ name: "devwing-frontend-1", display_name: "DevWing Frontend", domain: "frontend", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 78 },
|
|
2808
|
+
{ name: "devwing-backend-1", display_name: "DevWing Backend", domain: "backend", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 82 },
|
|
2809
|
+
{ name: "devwing-security-1", display_name: "DevWing Security", domain: "security", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 74 },
|
|
2810
|
+
{ name: "devwing-devops-1", display_name: "DevWing DevOps", domain: "devops", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 70 },
|
|
2811
|
+
{ name: "devwing-mobile-1", display_name: "DevWing Mobile", domain: "mobile", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 72 },
|
|
2812
|
+
{ name: "devwing-data-1", display_name: "DevWing Data", domain: "data", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 68 }
|
|
2816
2813
|
];
|
|
2817
2814
|
var DEMO_PLANS = [
|
|
2818
2815
|
{ name: "Free", price: "$0/mo", tokens_day: "50,000", models: "General only", projects: "1", seats: "1" },
|
|
@@ -2825,6 +2822,65 @@ var DEMO_USAGE = {
|
|
|
2825
2822
|
week: { requests: 147, tokens_in: 198340, tokens_out: 102890, cost: 0.7213 },
|
|
2826
2823
|
month: { requests: 612, tokens_in: 824100, tokens_out: 428750, cost: 3.0012 }
|
|
2827
2824
|
};
|
|
2825
|
+
function readLine() {
|
|
2826
|
+
return new Promise((resolve) => {
|
|
2827
|
+
try {
|
|
2828
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
2829
|
+
process.stdin.setRawMode(false);
|
|
2830
|
+
}
|
|
2831
|
+
} catch {
|
|
2832
|
+
}
|
|
2833
|
+
process.stdin.resume();
|
|
2834
|
+
process.stdin.setEncoding("utf8");
|
|
2835
|
+
let buf = "";
|
|
2836
|
+
const onData = (chunk) => {
|
|
2837
|
+
for (const ch of chunk) {
|
|
2838
|
+
if (ch === "\n" || ch === "\r") {
|
|
2839
|
+
cleanup();
|
|
2840
|
+
resolve(buf);
|
|
2841
|
+
return;
|
|
2842
|
+
} else if (ch === "") {
|
|
2843
|
+
cleanup();
|
|
2844
|
+
resolve("");
|
|
2845
|
+
return;
|
|
2846
|
+
} else if (ch === "\x7F" || ch === "\b") {
|
|
2847
|
+
if (buf.length > 0) {
|
|
2848
|
+
buf = buf.slice(0, -1);
|
|
2849
|
+
process.stdout.write("\b \b");
|
|
2850
|
+
}
|
|
2851
|
+
} else if (ch >= " ") {
|
|
2852
|
+
buf += ch;
|
|
2853
|
+
process.stdout.write(ch);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
const onEnd = () => {
|
|
2858
|
+
cleanup();
|
|
2859
|
+
resolve("");
|
|
2860
|
+
};
|
|
2861
|
+
const cleanup = () => {
|
|
2862
|
+
process.stdin.removeListener("data", onData);
|
|
2863
|
+
process.stdin.removeListener("end", onEnd);
|
|
2864
|
+
process.stdin.pause();
|
|
2865
|
+
};
|
|
2866
|
+
process.stdin.on("data", onData);
|
|
2867
|
+
process.stdin.once("end", onEnd);
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
function restoreStdin() {
|
|
2871
|
+
try {
|
|
2872
|
+
if (typeof process.stdin.setRawMode === "function") {
|
|
2873
|
+
try {
|
|
2874
|
+
process.stdin.setRawMode(false);
|
|
2875
|
+
} catch {
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
process.stdin.removeAllListeners("keypress");
|
|
2879
|
+
process.stdin.removeAllListeners("data");
|
|
2880
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
2881
|
+
} catch {
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2828
2884
|
var InteractiveSession = class {
|
|
2829
2885
|
isAuthenticated = false;
|
|
2830
2886
|
userProfile = null;
|
|
@@ -2835,12 +2891,10 @@ var InteractiveSession = class {
|
|
|
2835
2891
|
sessionId = null;
|
|
2836
2892
|
isDemo;
|
|
2837
2893
|
options;
|
|
2838
|
-
rl;
|
|
2839
2894
|
commands = /* @__PURE__ */ new Map();
|
|
2840
|
-
sigintCount = 0;
|
|
2841
|
-
sigintTimer = null;
|
|
2842
2895
|
version;
|
|
2843
|
-
|
|
2896
|
+
running = true;
|
|
2897
|
+
ctrlCCount = 0;
|
|
2844
2898
|
constructor(options) {
|
|
2845
2899
|
this.options = options;
|
|
2846
2900
|
this.isDemo = isDemoMode();
|
|
@@ -2849,109 +2903,48 @@ var InteractiveSession = class {
|
|
|
2849
2903
|
if (options.model) this.currentModel = options.model;
|
|
2850
2904
|
this.registerCommands();
|
|
2851
2905
|
}
|
|
2852
|
-
//
|
|
2853
|
-
// START
|
|
2854
|
-
// ============================================================
|
|
2906
|
+
// ─── START ───────────────────────────────────────────────
|
|
2855
2907
|
async start() {
|
|
2856
2908
|
console.clear();
|
|
2857
|
-
this.
|
|
2858
|
-
await this.
|
|
2909
|
+
this.printBanner();
|
|
2910
|
+
await this.checkAuth();
|
|
2859
2911
|
this.printSystemInfo();
|
|
2860
|
-
this.createReadline();
|
|
2861
2912
|
console.log();
|
|
2862
|
-
this.
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
return;
|
|
2878
|
-
}
|
|
2879
|
-
this.sigintCount++;
|
|
2880
|
-
if (this.sigintCount >= 2) {
|
|
2881
|
-
this.exitSession();
|
|
2882
|
-
return;
|
|
2913
|
+
while (this.running) {
|
|
2914
|
+
this.printPrompt();
|
|
2915
|
+
const input = await readLine();
|
|
2916
|
+
process.stdout.write("\n");
|
|
2917
|
+
if (input === "") {
|
|
2918
|
+
this.ctrlCCount++;
|
|
2919
|
+
if (this.ctrlCCount >= 2) {
|
|
2920
|
+
this.exit();
|
|
2921
|
+
return;
|
|
2922
|
+
}
|
|
2923
|
+
console.log(chalk7.dim(" Press Ctrl+C again to exit, or type /exit"));
|
|
2924
|
+
setTimeout(() => {
|
|
2925
|
+
this.ctrlCCount = 0;
|
|
2926
|
+
}, 1500);
|
|
2927
|
+
continue;
|
|
2883
2928
|
}
|
|
2884
|
-
|
|
2885
|
-
this.sigintTimer = setTimeout(() => {
|
|
2886
|
-
this.sigintCount = 0;
|
|
2887
|
-
}, 1500);
|
|
2888
|
-
this.prompt();
|
|
2889
|
-
});
|
|
2890
|
-
this.rl.on("line", async (input) => {
|
|
2891
|
-
if (this.isRunningCommand) return;
|
|
2929
|
+
this.ctrlCCount = 0;
|
|
2892
2930
|
const trimmed = input.trim();
|
|
2893
|
-
if (!trimmed)
|
|
2894
|
-
this.prompt();
|
|
2895
|
-
return;
|
|
2896
|
-
}
|
|
2897
|
-
this.isRunningCommand = true;
|
|
2898
|
-
this.rl.pause();
|
|
2931
|
+
if (!trimmed) continue;
|
|
2899
2932
|
try {
|
|
2900
2933
|
if (trimmed.startsWith("/")) {
|
|
2901
|
-
await this.
|
|
2934
|
+
await this.handleSlash(trimmed);
|
|
2902
2935
|
} else {
|
|
2903
|
-
await this.
|
|
2936
|
+
await this.handlePrompt(trimmed);
|
|
2904
2937
|
}
|
|
2905
|
-
} catch (
|
|
2906
|
-
logger.error(
|
|
2938
|
+
} catch (err) {
|
|
2939
|
+
logger.error(err.message || "An error occurred");
|
|
2907
2940
|
}
|
|
2908
|
-
|
|
2909
|
-
await sleep2(
|
|
2910
|
-
this.isRunningCommand = false;
|
|
2911
|
-
this.rl.resume();
|
|
2912
|
-
this.prompt();
|
|
2913
|
-
});
|
|
2914
|
-
this.rl.on("close", () => {
|
|
2915
|
-
if (!this.isRunningCommand) {
|
|
2916
|
-
this.exitSession();
|
|
2917
|
-
}
|
|
2918
|
-
});
|
|
2919
|
-
}
|
|
2920
|
-
// Pause readline, run fn (which may use inquirer), restore
|
|
2921
|
-
async withInquirer(fn) {
|
|
2922
|
-
this.rl.pause();
|
|
2923
|
-
try {
|
|
2924
|
-
return await fn();
|
|
2925
|
-
} finally {
|
|
2926
|
-
this.restoreStdin();
|
|
2927
|
-
await sleep2(80);
|
|
2928
|
-
this.rl.resume();
|
|
2941
|
+
restoreStdin();
|
|
2942
|
+
await sleep2(50);
|
|
2929
2943
|
}
|
|
2930
2944
|
}
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
try {
|
|
2935
|
-
process.stdin.setRawMode(false);
|
|
2936
|
-
} catch {
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
process.stdin.removeAllListeners("keypress");
|
|
2940
|
-
process.stdin.removeAllListeners("data");
|
|
2941
|
-
if (process.stdin.isPaused()) process.stdin.resume();
|
|
2942
|
-
} catch {
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
prompt() {
|
|
2946
|
-
const p = this.buildPrompt();
|
|
2947
|
-
process.stdout.write(p);
|
|
2948
|
-
this.rl.setPrompt(p);
|
|
2949
|
-
}
|
|
2950
|
-
// ============================================================
|
|
2951
|
-
// STARTUP UI — Claude Code style
|
|
2952
|
-
// ============================================================
|
|
2953
|
-
printStartupBanner() {
|
|
2954
|
-
const banner = gradient.pastel.multiline([
|
|
2945
|
+
// ─── BANNER ──────────────────────────────────────────────
|
|
2946
|
+
printBanner() {
|
|
2947
|
+
const art = gradient.pastel.multiline([
|
|
2955
2948
|
"",
|
|
2956
2949
|
" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
|
|
2957
2950
|
" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ",
|
|
@@ -2961,102 +2954,81 @@ var InteractiveSession = class {
|
|
|
2961
2954
|
" \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D ",
|
|
2962
2955
|
""
|
|
2963
2956
|
].join("\n"));
|
|
2964
|
-
console.log(
|
|
2957
|
+
console.log(art);
|
|
2965
2958
|
console.log(
|
|
2966
|
-
chalk7.dim(" Your AI Wingman in the Terminal") +
|
|
2959
|
+
chalk7.dim(" Your AI Wingman in the Terminal") + " " + chalk7.dim(`v${this.version}`)
|
|
2967
2960
|
);
|
|
2968
2961
|
console.log();
|
|
2969
2962
|
}
|
|
2963
|
+
// ─── SYSTEM INFO PANEL ───────────────────────────────────
|
|
2970
2964
|
printSystemInfo() {
|
|
2971
|
-
const W =
|
|
2972
|
-
const
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
const labelPart2 = chalk7.dim("\u2502 ") + chalk7.bold(label.padEnd(11)) + chalk7.dim(" \u2502 ");
|
|
2977
|
-
const rawValue = value.replace(/\x1B\[[0-9;]*m/g, "");
|
|
2978
|
-
const padLen2 = W - 4 - 11 - 3 - rawValue.length;
|
|
2979
|
-
return labelPart2 + value + " ".repeat(Math.max(0, padLen2)) + chalk7.dim(" \u2502");
|
|
2965
|
+
const W = 62;
|
|
2966
|
+
const ln = (s = "") => {
|
|
2967
|
+
const raw = s.replace(/\x1B\[[0-9;]*m/g, "");
|
|
2968
|
+
const pad = W - 4 - raw.length;
|
|
2969
|
+
return chalk7.dim("\u2502 ") + s + " ".repeat(Math.max(0, pad)) + chalk7.dim(" \u2502");
|
|
2980
2970
|
};
|
|
2971
|
+
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
2972
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
2973
|
+
const bot = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
2974
|
+
const kv = (k, v) => ln(chalk7.bold(k.padEnd(12)) + v);
|
|
2981
2975
|
console.log(top);
|
|
2982
2976
|
if (this.isAuthenticated && this.userProfile) {
|
|
2983
2977
|
const name = this.userProfile.full_name || this.userProfile.email;
|
|
2984
2978
|
const plan = (this.userProfile.subscription_plan || "free").toUpperCase();
|
|
2985
|
-
const
|
|
2986
|
-
console.log(
|
|
2979
|
+
const badge = plan === "PRO" ? chalk7.bgCyan.black(` ${plan} `) : plan === "ENTERPRISE" ? chalk7.bgMagenta.white(` ${plan} `) : plan === "TEAM" ? chalk7.bgYellow.black(` ${plan} `) : chalk7.bgGray.white(` ${plan} `);
|
|
2980
|
+
console.log(ln(chalk7.bold("Auth".padEnd(12)) + chalk7.green("\u25CF ") + chalk7.white(name) + " " + badge));
|
|
2987
2981
|
} else {
|
|
2988
|
-
console.log(
|
|
2982
|
+
console.log(ln(chalk7.bold("Auth".padEnd(12)) + chalk7.red("\u25CF ") + chalk7.dim("Not logged in") + " " + chalk7.cyan("/login")));
|
|
2989
2983
|
}
|
|
2990
2984
|
console.log(div);
|
|
2991
|
-
|
|
2992
|
-
const modelVal = this.currentModel ? chalk7.cyan(this.currentModel) : chalk7.dim("auto");
|
|
2993
|
-
const labelPart = chalk7.dim("\u2502 ") + chalk7.bold("Mode".padEnd(11)) + chalk7.dim(" \u2502 ");
|
|
2994
|
-
const raw1 = this.currentMode;
|
|
2995
|
-
const mid = " " + chalk7.bold("Model".padEnd(8)) + " " + modelVal;
|
|
2996
|
-
const raw2 = mid.replace(/\x1B\[[0-9;]*m/g, "");
|
|
2997
|
-
const padLen = W - 4 - 11 - 3 - raw1.length - raw2.length;
|
|
2998
|
-
console.log(labelPart + modeVal + mid + " ".repeat(Math.max(0, padLen)) + chalk7.dim(" \u2502"));
|
|
2985
|
+
console.log(kv("Mode", chalk7.yellow(this.currentMode) + " " + chalk7.bold("Model".padEnd(8)) + (this.currentModel ? chalk7.cyan(this.currentModel) : chalk7.dim("auto"))));
|
|
2999
2986
|
console.log(div);
|
|
3000
2987
|
if (this.isDemo) {
|
|
3001
|
-
console.log(
|
|
2988
|
+
console.log(kv("Project", chalk7.cyan(DEMO_PROJECT2.name)));
|
|
3002
2989
|
} else {
|
|
3003
2990
|
const pid = configManager.getProjectId();
|
|
3004
|
-
console.log(
|
|
2991
|
+
console.log(kv("Project", pid ? chalk7.cyan(pid) : chalk7.dim("none")));
|
|
3005
2992
|
}
|
|
3006
2993
|
const cwd = process.cwd().replace(process.env.HOME || "", "~");
|
|
3007
|
-
console.log(
|
|
2994
|
+
console.log(kv("Directory", chalk7.dim(cwd)));
|
|
3008
2995
|
if (this.isDemo) {
|
|
3009
2996
|
console.log(div);
|
|
3010
|
-
console.log(
|
|
2997
|
+
console.log(ln(chalk7.yellow("\u25C6 ") + chalk7.yellow("Demo mode") + chalk7.dim(" \u2014 no backend required")));
|
|
3011
2998
|
}
|
|
3012
|
-
console.log(
|
|
2999
|
+
console.log(bot);
|
|
3013
3000
|
console.log();
|
|
3014
|
-
console.log(
|
|
3015
|
-
chalk7.dim(" Chat freely, or use ") + chalk7.cyan("/help") + chalk7.dim(" to see all commands.")
|
|
3016
|
-
);
|
|
3001
|
+
console.log(chalk7.dim(" Type a message to chat, or ") + chalk7.cyan("/help") + chalk7.dim(" for commands."));
|
|
3017
3002
|
}
|
|
3018
|
-
//
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
const
|
|
3023
|
-
const
|
|
3024
|
-
let
|
|
3003
|
+
// ─── PROMPT LINE ─────────────────────────────────────────
|
|
3004
|
+
printPrompt() {
|
|
3005
|
+
const sep = chalk7.dim("\n " + "\u2500".repeat(50));
|
|
3006
|
+
const icon = chalk7.bold.cyan("\u2B21");
|
|
3007
|
+
const name = chalk7.bold.white("devwing");
|
|
3008
|
+
const mode = chalk7.dim("[") + chalk7.yellow(this.currentMode) + chalk7.dim("]");
|
|
3009
|
+
let user = "";
|
|
3025
3010
|
if (this.isAuthenticated && this.userProfile) {
|
|
3026
|
-
const first = (this.userProfile.full_name || this.userProfile.email).split(" ")[0].split("@")[0];
|
|
3027
|
-
|
|
3011
|
+
const first = (this.userProfile.full_name || this.userProfile.email).split(" ")[0].split("@")[0].toLowerCase();
|
|
3012
|
+
user = " " + chalk7.dim("@") + chalk7.green(first);
|
|
3028
3013
|
}
|
|
3029
|
-
const
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
parts.push(" " + chalk7.bold.cyan("\u276F") + " ");
|
|
3037
|
-
return parts.join("\n");
|
|
3038
|
-
}
|
|
3039
|
-
// ============================================================
|
|
3040
|
-
// AUTH CHECK
|
|
3041
|
-
// ============================================================
|
|
3042
|
-
async checkAuthStatus() {
|
|
3014
|
+
const demo = this.isDemo ? chalk7.dim.yellow(" demo") : "";
|
|
3015
|
+
process.stdout.write(`${sep}
|
|
3016
|
+
${icon} ${name} ${mode}${user}${demo}
|
|
3017
|
+
${chalk7.bold.cyan("\u276F")} `);
|
|
3018
|
+
}
|
|
3019
|
+
// ─── AUTH CHECK ──────────────────────────────────────────
|
|
3020
|
+
async checkAuth() {
|
|
3043
3021
|
try {
|
|
3044
|
-
const
|
|
3022
|
+
const key = await configManager.getApiKey();
|
|
3045
3023
|
if (this.isDemo) {
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
this.userProfile = { ...DEMO_USER2 };
|
|
3049
|
-
} else {
|
|
3050
|
-
this.isAuthenticated = false;
|
|
3051
|
-
this.userProfile = null;
|
|
3052
|
-
}
|
|
3024
|
+
this.isAuthenticated = !!key;
|
|
3025
|
+
this.userProfile = key ? { ...DEMO_USER2 } : null;
|
|
3053
3026
|
return;
|
|
3054
3027
|
}
|
|
3055
|
-
if (!
|
|
3028
|
+
if (!key) return;
|
|
3056
3029
|
try {
|
|
3057
|
-
|
|
3030
|
+
this.userProfile = await apiClient.getProfile();
|
|
3058
3031
|
this.isAuthenticated = true;
|
|
3059
|
-
this.userProfile = profile;
|
|
3060
3032
|
} catch {
|
|
3061
3033
|
this.isAuthenticated = true;
|
|
3062
3034
|
this.userProfile = null;
|
|
@@ -3066,10 +3038,8 @@ ${sep}`);
|
|
|
3066
3038
|
this.userProfile = null;
|
|
3067
3039
|
}
|
|
3068
3040
|
}
|
|
3069
|
-
//
|
|
3070
|
-
|
|
3071
|
-
// ============================================================
|
|
3072
|
-
async handleSlashCommand(input) {
|
|
3041
|
+
// ─── SLASH COMMAND DISPATCH ──────────────────────────────
|
|
3042
|
+
async handleSlash(input) {
|
|
3073
3043
|
const parts = input.split(/\s+/);
|
|
3074
3044
|
const cmdName = parts[0].substring(1).toLowerCase();
|
|
3075
3045
|
const args = parts.slice(1).join(" ").trim();
|
|
@@ -3087,19 +3057,17 @@ ${sep}`);
|
|
|
3087
3057
|
}
|
|
3088
3058
|
if (command.requiresAuth && !this.isAuthenticated) {
|
|
3089
3059
|
console.log();
|
|
3090
|
-
logger.warn("You need to be logged in
|
|
3060
|
+
logger.warn("You need to be logged in. Type /login first.");
|
|
3091
3061
|
return;
|
|
3092
3062
|
}
|
|
3093
3063
|
console.log();
|
|
3094
3064
|
await command.handler(args);
|
|
3095
3065
|
}
|
|
3096
|
-
//
|
|
3097
|
-
|
|
3098
|
-
// ============================================================
|
|
3099
|
-
async handleAIPrompt(input) {
|
|
3066
|
+
// ─── AI PROMPT ───────────────────────────────────────────
|
|
3067
|
+
async handlePrompt(input) {
|
|
3100
3068
|
if (!this.isAuthenticated) {
|
|
3101
3069
|
console.log();
|
|
3102
|
-
logger.warn("You need to log in
|
|
3070
|
+
logger.warn("You need to log in first. Type /login to authenticate.");
|
|
3103
3071
|
return;
|
|
3104
3072
|
}
|
|
3105
3073
|
console.log();
|
|
@@ -3114,12 +3082,12 @@ ${sep}`);
|
|
|
3114
3082
|
if (!this.sessionContext) {
|
|
3115
3083
|
logger.startSpinner("Loading codebase context...");
|
|
3116
3084
|
try {
|
|
3117
|
-
const
|
|
3118
|
-
this.sessionContext = await
|
|
3085
|
+
const col = new ContextCollector(process.cwd());
|
|
3086
|
+
this.sessionContext = await col.collect(input);
|
|
3119
3087
|
logger.succeedSpinner(`Context loaded \u2014 ${this.sessionContext.files.length} files`);
|
|
3120
|
-
} catch (
|
|
3088
|
+
} catch (err) {
|
|
3121
3089
|
logger.failSpinner("Failed to load context");
|
|
3122
|
-
logger.error(
|
|
3090
|
+
logger.error(err.message);
|
|
3123
3091
|
return;
|
|
3124
3092
|
}
|
|
3125
3093
|
}
|
|
@@ -3127,8 +3095,8 @@ ${sep}`);
|
|
|
3127
3095
|
logger.info(chalk7.dim("DevWing is thinking..."));
|
|
3128
3096
|
console.log();
|
|
3129
3097
|
try {
|
|
3130
|
-
const
|
|
3131
|
-
prompt: this.
|
|
3098
|
+
const req = {
|
|
3099
|
+
prompt: this.buildHistory(),
|
|
3132
3100
|
mode: this.currentMode,
|
|
3133
3101
|
model: this.currentModel || void 0,
|
|
3134
3102
|
project_id: this.options.project || configManager.getProjectId(),
|
|
@@ -3136,149 +3104,134 @@ ${sep}`);
|
|
|
3136
3104
|
stream: true,
|
|
3137
3105
|
max_tokens: 4096
|
|
3138
3106
|
};
|
|
3139
|
-
let
|
|
3107
|
+
let reply = "";
|
|
3140
3108
|
streamingRenderer.reset();
|
|
3141
3109
|
streamingRenderer.clearPendingTools();
|
|
3142
|
-
for await (const
|
|
3143
|
-
await streamingRenderer.processMessage(
|
|
3144
|
-
if (
|
|
3145
|
-
|
|
3146
|
-
}
|
|
3147
|
-
if (message.session_id) {
|
|
3148
|
-
this.sessionId = message.session_id;
|
|
3149
|
-
}
|
|
3110
|
+
for await (const msg of apiClient.streamCompletion(req)) {
|
|
3111
|
+
await streamingRenderer.processMessage(msg);
|
|
3112
|
+
if (msg.type === "token" && msg.content) reply += msg.content;
|
|
3113
|
+
if (msg.session_id) this.sessionId = msg.session_id;
|
|
3150
3114
|
}
|
|
3151
|
-
if (
|
|
3152
|
-
this.conversationHistory.push({ role: "assistant", content:
|
|
3115
|
+
if (reply) {
|
|
3116
|
+
this.conversationHistory.push({ role: "assistant", content: reply, timestamp: /* @__PURE__ */ new Date() });
|
|
3153
3117
|
}
|
|
3154
|
-
const
|
|
3155
|
-
if (
|
|
3118
|
+
const pending = streamingRenderer.getPendingToolCalls();
|
|
3119
|
+
if (pending.length > 0) {
|
|
3156
3120
|
logger.newline();
|
|
3157
|
-
|
|
3158
|
-
const toolResults = await streamingRenderer.executePendingTools();
|
|
3121
|
+
const results = await streamingRenderer.executePendingTools();
|
|
3159
3122
|
if (this.sessionId) {
|
|
3160
|
-
for await (const
|
|
3161
|
-
await streamingRenderer.processMessage(
|
|
3123
|
+
for await (const msg of apiClient.continueCompletion(this.sessionId, results)) {
|
|
3124
|
+
await streamingRenderer.processMessage(msg);
|
|
3162
3125
|
}
|
|
3163
3126
|
}
|
|
3164
3127
|
}
|
|
3165
3128
|
console.log();
|
|
3166
|
-
} catch (
|
|
3167
|
-
logger.error(
|
|
3129
|
+
} catch (err) {
|
|
3130
|
+
logger.error(err.message || "AI request failed");
|
|
3168
3131
|
}
|
|
3169
3132
|
}
|
|
3170
|
-
|
|
3171
|
-
const
|
|
3172
|
-
if (
|
|
3173
|
-
const recent =
|
|
3174
|
-
const
|
|
3133
|
+
buildHistory() {
|
|
3134
|
+
const h = this.conversationHistory;
|
|
3135
|
+
if (h.length <= 1) return h[h.length - 1]?.content || "";
|
|
3136
|
+
const recent = h.slice(-10);
|
|
3137
|
+
const ctx = recent.slice(0, -1).map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${m.content}`).join("\n\n");
|
|
3175
3138
|
return `Previous conversation:
|
|
3176
|
-
${
|
|
3139
|
+
${ctx}
|
|
3177
3140
|
|
|
3178
3141
|
Current question:
|
|
3179
3142
|
${recent[recent.length - 1].content}`;
|
|
3180
3143
|
}
|
|
3181
|
-
//
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
exitSession() {
|
|
3185
|
-
if (this.sigintTimer) clearTimeout(this.sigintTimer);
|
|
3186
|
-
this.restoreStdin();
|
|
3144
|
+
// ─── EXIT ────────────────────────────────────────────────
|
|
3145
|
+
exit() {
|
|
3146
|
+
restoreStdin();
|
|
3187
3147
|
console.log();
|
|
3188
|
-
console.log(chalk7.dim(" Goodbye! Happy shipping.
|
|
3148
|
+
console.log(chalk7.dim(" Goodbye! Happy shipping."));
|
|
3189
3149
|
console.log();
|
|
3190
3150
|
process.exit(0);
|
|
3191
3151
|
}
|
|
3192
|
-
//
|
|
3193
|
-
// COMMAND REGISTRATION
|
|
3194
|
-
// ============================================================
|
|
3152
|
+
// ─── COMMAND REGISTRATION ────────────────────────────────
|
|
3195
3153
|
registerCommands() {
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
}
|
|
3218
|
-
// ============================================================
|
|
3219
|
-
// COMMAND IMPLEMENTATIONS
|
|
3220
|
-
// ============================================================
|
|
3154
|
+
const add = (c) => this.commands.set(c.name, c);
|
|
3155
|
+
add({ name: "help", aliases: ["h", "?"], description: "Show all available commands", category: "session", requiresAuth: false, handler: async () => this.cmdHelp() });
|
|
3156
|
+
add({ name: "exit", aliases: ["quit", "q"], description: "Exit DevWing", category: "session", requiresAuth: false, handler: async () => this.exit() });
|
|
3157
|
+
add({ name: "clear", aliases: ["cls"], description: "Clear screen and reset conversation", category: "session", requiresAuth: false, handler: async () => this.cmdClear() });
|
|
3158
|
+
add({ name: "login", aliases: ["signin"], description: "Authenticate with DevWing", category: "session", requiresAuth: false, handler: async () => this.cmdLogin() });
|
|
3159
|
+
add({ name: "logout", aliases: ["signout"], description: "Clear credentials and log out", category: "session", requiresAuth: true, handler: async () => this.cmdLogout() });
|
|
3160
|
+
add({ name: "status", aliases: ["whoami"], description: "Show auth status and profile", category: "session", requiresAuth: false, handler: async () => this.cmdStatus() });
|
|
3161
|
+
add({ name: "scan", aliases: [], description: "Run security vulnerability scan", category: "tools", requiresAuth: true, handler: async () => this.cmdScan() });
|
|
3162
|
+
add({ name: "review", aliases: [], description: "Perform code review on recent changes", category: "tools", requiresAuth: true, handler: async () => this.cmdReview() });
|
|
3163
|
+
add({ name: "explain", aliases: [], description: "Explain code, file, or concept", category: "tools", requiresAuth: true, handler: async (a) => this.cmdExplain(a) });
|
|
3164
|
+
add({ name: "memory", aliases: ["mem"], description: "Project memory save / show / clear", category: "tools", requiresAuth: true, handler: async (a) => this.cmdMemory(a) });
|
|
3165
|
+
add({ name: "mode", aliases: [], description: "Show or set AI mode", category: "config", requiresAuth: false, handler: async (a) => this.cmdMode(a) });
|
|
3166
|
+
add({ name: "model", aliases: [], description: "Show or set AI model", category: "config", requiresAuth: false, handler: async (a) => this.cmdModel(a) });
|
|
3167
|
+
add({ name: "models", aliases: [], description: "List all available AI models", category: "config", requiresAuth: false, handler: async () => this.cmdModels() });
|
|
3168
|
+
add({ name: "usage", aliases: ["stats"], description: "Show token usage statistics", category: "config", requiresAuth: true, handler: async () => this.cmdUsage() });
|
|
3169
|
+
add({ name: "plans", aliases: ["pricing"], description: "Show available plans and pricing", category: "config", requiresAuth: false, handler: async () => this.cmdPlans() });
|
|
3170
|
+
add({ name: "context", aliases: ["ctx"], description: "Show loaded codebase context", category: "config", requiresAuth: false, handler: async () => this.cmdContext() });
|
|
3171
|
+
add({ name: "history", aliases: [], description: "Show conversation history", category: "config", requiresAuth: false, handler: async () => this.cmdHistory() });
|
|
3172
|
+
add({ name: "config", aliases: ["settings"], description: "Show or set CLI configuration", category: "config", requiresAuth: false, handler: async (a) => this.cmdConfig(a) });
|
|
3173
|
+
}
|
|
3174
|
+
// ─── COMMAND IMPLEMENTATIONS ─────────────────────────────
|
|
3221
3175
|
async cmdHelp() {
|
|
3222
|
-
const W =
|
|
3176
|
+
const W = 62;
|
|
3223
3177
|
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3224
|
-
const
|
|
3178
|
+
const bot = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3225
3179
|
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
3226
|
-
const
|
|
3227
|
-
const
|
|
3228
|
-
const rawRight = right.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3229
|
-
const pad = W - 2 - rawLeft.length - rawRight.length - 2;
|
|
3230
|
-
return chalk7.dim("\u2502 ") + left + " ".repeat(Math.max(0, pad)) + right + chalk7.dim(" \u2502");
|
|
3231
|
-
};
|
|
3232
|
-
const catRow = (label) => {
|
|
3233
|
-
const raw = label.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3180
|
+
const ln = (s = "") => {
|
|
3181
|
+
const raw = s.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3234
3182
|
const pad = W - 4 - raw.length;
|
|
3235
|
-
return chalk7.dim("\u2502 ") +
|
|
3183
|
+
return chalk7.dim("\u2502 ") + s + " ".repeat(Math.max(0, pad)) + chalk7.dim(" \u2502");
|
|
3236
3184
|
};
|
|
3237
|
-
|
|
3185
|
+
console.log(top);
|
|
3186
|
+
console.log(ln(chalk7.bold.white("Commands")));
|
|
3187
|
+
const cats = [
|
|
3238
3188
|
{ key: "session", label: "Session", color: chalk7.bold.green },
|
|
3239
3189
|
{ key: "tools", label: "AI Tools", color: chalk7.bold.magenta },
|
|
3240
3190
|
{ key: "config", label: "Configuration", color: chalk7.bold.yellow }
|
|
3241
3191
|
];
|
|
3242
|
-
|
|
3243
|
-
console.log(catRow(chalk7.bold.white(" Commands")));
|
|
3244
|
-
for (const cat of categories) {
|
|
3192
|
+
for (const cat of cats) {
|
|
3245
3193
|
console.log(div);
|
|
3246
|
-
console.log(
|
|
3194
|
+
console.log(ln(" " + cat.color(cat.label)));
|
|
3247
3195
|
for (const cmd of this.commands.values()) {
|
|
3248
3196
|
if (cmd.category !== cat.key) continue;
|
|
3249
|
-
const cmdStr = chalk7.cyan(("/" + cmd.name).padEnd(
|
|
3197
|
+
const cmdStr = chalk7.cyan(("/" + cmd.name).padEnd(13));
|
|
3250
3198
|
const descStr = chalk7.dim(cmd.description);
|
|
3251
|
-
const
|
|
3252
|
-
console.log(
|
|
3199
|
+
const alias = cmd.aliases.length ? chalk7.dim(" \xB7 " + cmd.aliases.map((a) => "/" + a).join(", ")) : "";
|
|
3200
|
+
console.log(ln(" " + cmdStr + " " + descStr + alias));
|
|
3253
3201
|
}
|
|
3254
3202
|
}
|
|
3255
3203
|
console.log(div);
|
|
3256
|
-
console.log(
|
|
3257
|
-
console.log(
|
|
3204
|
+
console.log(ln(chalk7.dim(" Type any message to chat with DevWing AI")));
|
|
3205
|
+
console.log(bot);
|
|
3258
3206
|
}
|
|
3259
3207
|
async cmdClear() {
|
|
3260
3208
|
this.conversationHistory = [];
|
|
3261
3209
|
this.sessionContext = null;
|
|
3262
3210
|
this.sessionId = null;
|
|
3263
3211
|
console.clear();
|
|
3264
|
-
this.
|
|
3212
|
+
this.printBanner();
|
|
3265
3213
|
this.printSystemInfo();
|
|
3214
|
+
console.log();
|
|
3266
3215
|
}
|
|
3267
3216
|
async cmdLogin() {
|
|
3268
3217
|
if (this.isDemo) {
|
|
3269
|
-
await
|
|
3218
|
+
await demoLoginCommand({ fromSession: true });
|
|
3270
3219
|
} else {
|
|
3271
|
-
await
|
|
3220
|
+
await loginCommand();
|
|
3272
3221
|
}
|
|
3273
|
-
|
|
3222
|
+
restoreStdin();
|
|
3223
|
+
await sleep2(80);
|
|
3224
|
+
await this.checkAuth();
|
|
3274
3225
|
}
|
|
3275
3226
|
async cmdLogout() {
|
|
3276
3227
|
if (this.isDemo) {
|
|
3277
|
-
await
|
|
3228
|
+
await demoLogoutCommand();
|
|
3278
3229
|
} else {
|
|
3279
|
-
await
|
|
3230
|
+
await logoutCommand();
|
|
3280
3231
|
}
|
|
3281
|
-
|
|
3232
|
+
restoreStdin();
|
|
3233
|
+
await sleep2(80);
|
|
3234
|
+
await this.checkAuth();
|
|
3282
3235
|
}
|
|
3283
3236
|
async cmdStatus() {
|
|
3284
3237
|
if (!this.isAuthenticated) {
|
|
@@ -3288,22 +3241,22 @@ ${recent[recent.length - 1].content}`;
|
|
|
3288
3241
|
if (this.isDemo) {
|
|
3289
3242
|
const W = 54;
|
|
3290
3243
|
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3291
|
-
const
|
|
3292
|
-
const
|
|
3244
|
+
const bot = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3245
|
+
const kv = (k, v) => {
|
|
3293
3246
|
const rawV = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3294
3247
|
const pad = W - 4 - k.length - rawV.length;
|
|
3295
3248
|
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3296
3249
|
};
|
|
3297
3250
|
console.log(top);
|
|
3298
|
-
console.log(
|
|
3299
|
-
console.log(
|
|
3300
|
-
console.log(
|
|
3301
|
-
console.log(
|
|
3302
|
-
console.log(
|
|
3303
|
-
console.log(
|
|
3304
|
-
console.log(
|
|
3305
|
-
console.log(
|
|
3306
|
-
console.log(
|
|
3251
|
+
console.log(kv("Email", DEMO_USER2.email));
|
|
3252
|
+
console.log(kv("Name", DEMO_USER2.full_name));
|
|
3253
|
+
console.log(kv("Plan", chalk7.bgCyan.black(" PRO ")));
|
|
3254
|
+
console.log(kv("Verified", chalk7.green("\u2713 Yes")));
|
|
3255
|
+
console.log(kv("2FA", chalk7.dim("Disabled")));
|
|
3256
|
+
console.log(kv("Workspace", DEMO_WORKSPACE2.name + chalk7.dim(" (enterprise)")));
|
|
3257
|
+
console.log(kv("Project", DEMO_PROJECT2.name));
|
|
3258
|
+
console.log(kv("Tokens today", `${(DEMO_USER2.tokens_used_today).toLocaleString()} / 500,000`));
|
|
3259
|
+
console.log(bot);
|
|
3307
3260
|
} else {
|
|
3308
3261
|
await statusCommand();
|
|
3309
3262
|
}
|
|
@@ -3324,8 +3277,7 @@ ${recent[recent.length - 1].content}`;
|
|
|
3324
3277
|
}
|
|
3325
3278
|
async cmdExplain(args) {
|
|
3326
3279
|
if (!args) {
|
|
3327
|
-
logger.error("Usage: /explain <file
|
|
3328
|
-
logger.info("Example: /explain src/auth/middleware.ts");
|
|
3280
|
+
logger.error("Usage: /explain <file or concept>");
|
|
3329
3281
|
return;
|
|
3330
3282
|
}
|
|
3331
3283
|
if (this.isDemo) {
|
|
@@ -3338,7 +3290,6 @@ ${recent[recent.length - 1].content}`;
|
|
|
3338
3290
|
const parts = args.split(/\s+/);
|
|
3339
3291
|
const sub = parts[0]?.toLowerCase();
|
|
3340
3292
|
if (!sub || !["save", "show", "clear"].includes(sub)) {
|
|
3341
|
-
console.log();
|
|
3342
3293
|
console.log(` ${chalk7.cyan("/memory show")} \u2014 Show all project memories`);
|
|
3343
3294
|
console.log(` ${chalk7.cyan("/memory save <text>")} \u2014 Save a memory`);
|
|
3344
3295
|
console.log(` ${chalk7.cyan("/memory clear")} \u2014 Clear all memories`);
|
|
@@ -3346,59 +3297,46 @@ ${recent[recent.length - 1].content}`;
|
|
|
3346
3297
|
}
|
|
3347
3298
|
const content = parts.slice(1).join(" ").trim();
|
|
3348
3299
|
if (this.isDemo) {
|
|
3349
|
-
await
|
|
3350
|
-
|
|
3351
|
-
);
|
|
3300
|
+
await demoMemoryCommand(sub, content || void 0);
|
|
3301
|
+
restoreStdin();
|
|
3302
|
+
await sleep2(80);
|
|
3352
3303
|
} else {
|
|
3353
3304
|
await memoryCommand(sub, content || void 0, this.options);
|
|
3354
3305
|
}
|
|
3355
3306
|
}
|
|
3356
3307
|
async cmdMode(args) {
|
|
3357
|
-
const
|
|
3308
|
+
const valid = ["general", "frontend", "backend", "security", "devops"];
|
|
3358
3309
|
if (!args) {
|
|
3359
|
-
const
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
const pad = W - 2 - rawLeft.length;
|
|
3366
|
-
return chalk7.dim("\u2502") + left + " ".repeat(Math.max(0, pad)) + chalk7.dim("\u2502");
|
|
3310
|
+
const descs = {
|
|
3311
|
+
general: "All-purpose coding assistant",
|
|
3312
|
+
frontend: "React, Vue, CSS, TypeScript",
|
|
3313
|
+
backend: "APIs, databases, microservices",
|
|
3314
|
+
security: "OWASP, CVE, penetration testing",
|
|
3315
|
+
devops: "Docker, Kubernetes, CI/CD"
|
|
3367
3316
|
};
|
|
3368
|
-
|
|
3369
|
-
console.log(chalk7.dim("\u2502 ") + chalk7.bold("AI Mode".padEnd(W - 4)) + chalk7.dim(" \u2502"));
|
|
3370
|
-
for (const m of validModes) {
|
|
3317
|
+
for (const m of valid) {
|
|
3371
3318
|
const active = m === this.currentMode;
|
|
3372
|
-
const
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3375
|
-
general: "All-purpose coding assistant",
|
|
3376
|
-
frontend: "React, Vue, CSS, TypeScript",
|
|
3377
|
-
backend: "APIs, databases, microservices",
|
|
3378
|
-
security: "OWASP, CVE, penetration testing",
|
|
3379
|
-
devops: "Docker, Kubernetes, CI/CD"
|
|
3380
|
-
};
|
|
3381
|
-
console.log(row(icon, name, descs[m] || ""));
|
|
3319
|
+
const dot = active ? chalk7.green("\u25CF") : chalk7.dim("\u25CB");
|
|
3320
|
+
const label = active ? chalk7.yellow.bold(m.padEnd(10)) : chalk7.white(m.padEnd(10));
|
|
3321
|
+
console.log(` ${dot} ${label} ${chalk7.dim(descs[m])}`);
|
|
3382
3322
|
}
|
|
3383
|
-
console.log(
|
|
3323
|
+
console.log();
|
|
3384
3324
|
console.log(chalk7.dim(" Usage: /mode <name>"));
|
|
3385
3325
|
return;
|
|
3386
3326
|
}
|
|
3387
3327
|
const mode = args.toLowerCase();
|
|
3388
|
-
if (!
|
|
3389
|
-
logger.error(`Invalid mode "${args}". Valid: ${
|
|
3328
|
+
if (!valid.includes(mode)) {
|
|
3329
|
+
logger.error(`Invalid mode "${args}". Valid: ${valid.join(", ")}`);
|
|
3390
3330
|
return;
|
|
3391
3331
|
}
|
|
3392
3332
|
this.currentMode = mode;
|
|
3393
3333
|
this.options.mode = mode;
|
|
3394
|
-
console.log();
|
|
3395
3334
|
console.log(` ${chalk7.green("\u2713")} Mode \u2192 ${chalk7.yellow.bold(mode)}`);
|
|
3396
3335
|
}
|
|
3397
3336
|
async cmdModel(args) {
|
|
3398
3337
|
if (!args) {
|
|
3399
|
-
const
|
|
3400
|
-
console.log();
|
|
3401
|
-
console.log(` ${chalk7.bold("Current model:")} ${chalk7.cyan(current)}`);
|
|
3338
|
+
const cur = this.currentModel || "auto";
|
|
3339
|
+
console.log(` Current model: ${chalk7.cyan.bold(cur)}`);
|
|
3402
3340
|
console.log(chalk7.dim(" /model <name> \xB7 /model auto \xB7 /models to list all"));
|
|
3403
3341
|
return;
|
|
3404
3342
|
}
|
|
@@ -3410,28 +3348,20 @@ ${recent[recent.length - 1].content}`;
|
|
|
3410
3348
|
}
|
|
3411
3349
|
this.currentModel = args;
|
|
3412
3350
|
this.options.model = args;
|
|
3413
|
-
console.log();
|
|
3414
3351
|
console.log(` ${chalk7.green("\u2713")} Model \u2192 ${chalk7.cyan.bold(args)}`);
|
|
3415
3352
|
}
|
|
3416
3353
|
async cmdModels() {
|
|
3417
3354
|
if (this.isDemo) {
|
|
3418
3355
|
const table = new Table3({
|
|
3419
|
-
head: [
|
|
3420
|
-
|
|
3421
|
-
chalk7.bold("Domain"),
|
|
3422
|
-
chalk7.bold("Status"),
|
|
3423
|
-
chalk7.bold("Plan"),
|
|
3424
|
-
chalk7.bold("Context"),
|
|
3425
|
-
chalk7.bold("Speed")
|
|
3426
|
-
],
|
|
3427
|
-
style: { head: [], border: ["dim"] }
|
|
3356
|
+
head: [chalk7.bold("Model"), chalk7.bold("Domain"), chalk7.bold("Status"), chalk7.bold("Plan"), chalk7.bold("Context"), chalk7.bold("Speed")],
|
|
3357
|
+
style: { border: ["dim"] }
|
|
3428
3358
|
});
|
|
3429
3359
|
for (const m of DEMO_MODELS) {
|
|
3430
|
-
const
|
|
3431
|
-
const
|
|
3432
|
-
const
|
|
3433
|
-
const
|
|
3434
|
-
table.push([
|
|
3360
|
+
const cur = m.name === (this.currentModel || "");
|
|
3361
|
+
const nm = cur ? chalk7.cyan.bold(m.display_name + " \u25CF") : m.display_name;
|
|
3362
|
+
const status = m.status === "active" ? chalk7.green("active") : chalk7.yellow("beta");
|
|
3363
|
+
const plan = m.min_plan === "free" ? chalk7.green("free") : chalk7.cyan("pro");
|
|
3364
|
+
table.push([nm, chalk7.yellow(m.domain), status, plan, `${(m.context_window / 1024).toFixed(0)}k`, `${m.tokens_per_sec} t/s`]);
|
|
3435
3365
|
}
|
|
3436
3366
|
console.log(table.toString());
|
|
3437
3367
|
console.log(chalk7.dim(" /model <name> to select \xB7 /model auto for automatic"));
|
|
@@ -3452,29 +3382,28 @@ ${recent[recent.length - 1].content}`;
|
|
|
3452
3382
|
}
|
|
3453
3383
|
async cmdUsage() {
|
|
3454
3384
|
if (this.isDemo) {
|
|
3455
|
-
const
|
|
3385
|
+
const t = new Table3({
|
|
3456
3386
|
head: [chalk7.bold("Period"), chalk7.bold("Requests"), chalk7.bold("Tokens In"), chalk7.bold("Tokens Out"), chalk7.bold("Cost")],
|
|
3457
|
-
style: {
|
|
3387
|
+
style: { border: ["dim"] }
|
|
3458
3388
|
});
|
|
3459
|
-
|
|
3389
|
+
t.push(
|
|
3460
3390
|
["Today", String(DEMO_USAGE.today.requests), DEMO_USAGE.today.tokens_in.toLocaleString(), DEMO_USAGE.today.tokens_out.toLocaleString(), `$${DEMO_USAGE.today.cost.toFixed(4)}`],
|
|
3461
3391
|
["This Week", String(DEMO_USAGE.week.requests), DEMO_USAGE.week.tokens_in.toLocaleString(), DEMO_USAGE.week.tokens_out.toLocaleString(), `$${DEMO_USAGE.week.cost.toFixed(4)}`],
|
|
3462
3392
|
["This Month", String(DEMO_USAGE.month.requests), DEMO_USAGE.month.tokens_in.toLocaleString(), DEMO_USAGE.month.tokens_out.toLocaleString(), `$${DEMO_USAGE.month.cost.toFixed(4)}`]
|
|
3463
3393
|
);
|
|
3464
|
-
console.log(
|
|
3394
|
+
console.log(t.toString());
|
|
3465
3395
|
const used = DEMO_USER2.tokens_used_today;
|
|
3466
3396
|
const limit = 5e5;
|
|
3467
3397
|
const pct = Math.round(used / limit * 100);
|
|
3468
|
-
const barW =
|
|
3469
|
-
const
|
|
3470
|
-
const bar = chalk7.cyan("\u2588".repeat(
|
|
3398
|
+
const barW = 30;
|
|
3399
|
+
const fill = Math.round(pct / 100 * barW);
|
|
3400
|
+
const bar = chalk7.cyan("\u2588".repeat(fill)) + chalk7.dim("\u2591".repeat(barW - fill));
|
|
3471
3401
|
console.log();
|
|
3472
|
-
console.log(` Daily Quota ${bar} ${chalk7.bold(pct + "%")} ${chalk7.dim(`${used.toLocaleString()} / ${limit.toLocaleString()}
|
|
3402
|
+
console.log(` Daily Quota ${bar} ${chalk7.bold(pct + "%")} ${chalk7.dim(`${used.toLocaleString()} / ${limit.toLocaleString()}`)}`);
|
|
3473
3403
|
console.log();
|
|
3474
|
-
console.log(chalk7.bold(" By Model"));
|
|
3475
3404
|
const mt = new Table3({
|
|
3476
3405
|
head: [chalk7.bold("Model"), chalk7.bold("Requests"), chalk7.bold("Tokens"), chalk7.bold("Cost")],
|
|
3477
|
-
style: {
|
|
3406
|
+
style: { border: ["dim"] }
|
|
3478
3407
|
});
|
|
3479
3408
|
mt.push(
|
|
3480
3409
|
["devwing-backend-1", "312", "421,000", "$1.4721"],
|
|
@@ -3486,10 +3415,10 @@ ${recent[recent.length - 1].content}`;
|
|
|
3486
3415
|
console.log(mt.toString());
|
|
3487
3416
|
} else {
|
|
3488
3417
|
try {
|
|
3489
|
-
const
|
|
3490
|
-
console.log(` Requests: ${
|
|
3491
|
-
console.log(` Tokens: ${
|
|
3492
|
-
console.log(` Cost: $${
|
|
3418
|
+
const u = await apiClient.getUsage();
|
|
3419
|
+
console.log(` Requests: ${u.total_requests}`);
|
|
3420
|
+
console.log(` Tokens: ${u.total_tokens_in.toLocaleString()} in, ${u.total_tokens_out.toLocaleString()} out`);
|
|
3421
|
+
console.log(` Cost: $${u.total_cost_usd.toFixed(4)}`);
|
|
3493
3422
|
} catch (e) {
|
|
3494
3423
|
logger.error("Failed to fetch usage: " + e.message);
|
|
3495
3424
|
}
|
|
@@ -3497,71 +3426,60 @@ ${recent[recent.length - 1].content}`;
|
|
|
3497
3426
|
}
|
|
3498
3427
|
async cmdPlans() {
|
|
3499
3428
|
const table = new Table3({
|
|
3500
|
-
head: [
|
|
3501
|
-
|
|
3502
|
-
chalk7.bold("Price"),
|
|
3503
|
-
chalk7.bold("Tokens/Day"),
|
|
3504
|
-
chalk7.bold("Models"),
|
|
3505
|
-
chalk7.bold("Projects"),
|
|
3506
|
-
chalk7.bold("Seats")
|
|
3507
|
-
],
|
|
3508
|
-
style: { head: [], border: ["dim"] }
|
|
3429
|
+
head: [chalk7.bold("Plan"), chalk7.bold("Price"), chalk7.bold("Tokens/Day"), chalk7.bold("Models"), chalk7.bold("Projects"), chalk7.bold("Seats")],
|
|
3430
|
+
style: { border: ["dim"] }
|
|
3509
3431
|
});
|
|
3510
|
-
const
|
|
3511
|
-
for (const
|
|
3512
|
-
const
|
|
3513
|
-
const
|
|
3514
|
-
table.push([
|
|
3432
|
+
const cur = this.userProfile?.subscription_plan?.toLowerCase() || "";
|
|
3433
|
+
for (const p of DEMO_PLANS) {
|
|
3434
|
+
const isCur = this.isAuthenticated && cur === p.name.toLowerCase();
|
|
3435
|
+
const nm = isCur ? chalk7.cyan.bold(p.name) + chalk7.dim(" \u2190") : p.name;
|
|
3436
|
+
table.push([nm, p.price, p.tokens_day, p.models, p.projects, p.seats]);
|
|
3515
3437
|
}
|
|
3516
3438
|
console.log(table.toString());
|
|
3517
3439
|
console.log();
|
|
3518
3440
|
if (this.isAuthenticated) {
|
|
3519
|
-
console.log(chalk7.dim(` Your plan: ${
|
|
3441
|
+
console.log(chalk7.dim(` Your plan: ${cur.toUpperCase()} \xB7 Upgrade at devwing.ai/dashboard/billing`));
|
|
3520
3442
|
} else {
|
|
3521
3443
|
console.log(chalk7.dim(" Sign up at devwing.ai"));
|
|
3522
3444
|
}
|
|
3523
3445
|
}
|
|
3524
3446
|
async cmdContext() {
|
|
3525
3447
|
if (this.isDemo) {
|
|
3526
|
-
const W =
|
|
3448
|
+
const W = 56;
|
|
3527
3449
|
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3528
|
-
const
|
|
3450
|
+
const bot = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3529
3451
|
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
3530
|
-
const
|
|
3531
|
-
const
|
|
3532
|
-
const pad = W - 4 - k.length -
|
|
3452
|
+
const kv = (k, v) => {
|
|
3453
|
+
const rv = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3454
|
+
const pad = W - 4 - k.length - rv.length;
|
|
3533
3455
|
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3534
3456
|
};
|
|
3535
|
-
const
|
|
3536
|
-
const pad = W -
|
|
3537
|
-
return chalk7.dim("\u2502
|
|
3457
|
+
const fl = (f) => {
|
|
3458
|
+
const pad = W - 6 - f.length;
|
|
3459
|
+
return chalk7.dim("\u2502 \xB7 ") + chalk7.cyan(f) + " ".repeat(Math.max(0, pad)) + chalk7.dim("\u2502");
|
|
3538
3460
|
};
|
|
3539
|
-
const
|
|
3540
|
-
const
|
|
3541
|
-
|
|
3461
|
+
const ln = (s) => {
|
|
3462
|
+
const raw = s.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3463
|
+
const pad = W - 4 - raw.length;
|
|
3464
|
+
return chalk7.dim("\u2502 ") + s + " ".repeat(Math.max(0, pad)) + chalk7.dim(" \u2502");
|
|
3542
3465
|
};
|
|
3543
3466
|
console.log(top);
|
|
3544
|
-
console.log(
|
|
3545
|
-
console.log(
|
|
3546
|
-
console.log(
|
|
3547
|
-
console.log(
|
|
3548
|
-
console.log(row("Shell", process.env.SHELL?.split("/").pop() || "unknown"));
|
|
3467
|
+
console.log(kv("Directory", chalk7.dim(process.cwd().replace(process.env.HOME || "", "~"))));
|
|
3468
|
+
console.log(kv("Git Branch", "main"));
|
|
3469
|
+
console.log(kv("Files", "34 files loaded"));
|
|
3470
|
+
console.log(kv("Framework", "FastAPI + TypeScript"));
|
|
3549
3471
|
console.log(div);
|
|
3550
|
-
console.log(
|
|
3551
|
-
const
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
console.log(
|
|
3472
|
+
console.log(ln(chalk7.bold("Top files")));
|
|
3473
|
+
for (const f of ["src/auth/auth_controller.ts", "src/middleware/jwt.middleware.ts", "src/services/user_service.ts", "package.json", "docker-compose.yml"]) {
|
|
3474
|
+
console.log(fl(f));
|
|
3475
|
+
}
|
|
3476
|
+
console.log(ln(chalk7.dim("... and 29 more")));
|
|
3477
|
+
console.log(bot);
|
|
3555
3478
|
} else if (this.sessionContext) {
|
|
3556
|
-
console.log(` Dir: ${
|
|
3557
|
-
if (this.sessionContext.git_branch) console.log(` Branch: ${this.sessionContext.git_branch}`);
|
|
3558
|
-
console.log();
|
|
3479
|
+
console.log(` Dir: ${this.sessionContext.cwd} \xB7 Files: ${this.sessionContext.files.length}`);
|
|
3559
3480
|
for (const f of this.sessionContext.files.slice(0, 10)) {
|
|
3560
3481
|
console.log(` ${chalk7.dim("\xB7")} ${chalk7.cyan(f.path)}`);
|
|
3561
3482
|
}
|
|
3562
|
-
if (this.sessionContext.files.length > 10) {
|
|
3563
|
-
console.log(chalk7.dim(` ... and ${this.sessionContext.files.length - 10} more`));
|
|
3564
|
-
}
|
|
3565
3483
|
} else {
|
|
3566
3484
|
logger.info("No context loaded yet. Send a message to load context.");
|
|
3567
3485
|
}
|
|
@@ -3571,43 +3489,41 @@ ${recent[recent.length - 1].content}`;
|
|
|
3571
3489
|
logger.info("No conversation history yet.");
|
|
3572
3490
|
return;
|
|
3573
3491
|
}
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
const
|
|
3577
|
-
const
|
|
3578
|
-
const preview = msg.content.length > 100 ? msg.content.substring(0, 100) + "\u2026" : msg.content;
|
|
3492
|
+
for (const m of this.conversationHistory.slice(-20)) {
|
|
3493
|
+
const label = m.role === "user" ? chalk7.green.bold("You ") : chalk7.cyan.bold("DevWing ");
|
|
3494
|
+
const time = chalk7.dim(m.timestamp.toLocaleTimeString());
|
|
3495
|
+
const preview = m.content.length > 100 ? m.content.slice(0, 100) + "\u2026" : m.content;
|
|
3579
3496
|
console.log(` ${time} ${label} ${preview}`);
|
|
3580
3497
|
}
|
|
3581
3498
|
}
|
|
3582
3499
|
async cmdConfig(args) {
|
|
3583
3500
|
if (!args) {
|
|
3584
|
-
const
|
|
3585
|
-
const W =
|
|
3501
|
+
const cfg = configManager.getAll();
|
|
3502
|
+
const W = 54;
|
|
3586
3503
|
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3587
|
-
const
|
|
3588
|
-
const
|
|
3589
|
-
const
|
|
3590
|
-
const pad = W - 4 - k.length -
|
|
3504
|
+
const bot = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3505
|
+
const kv = (k, v) => {
|
|
3506
|
+
const rv = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3507
|
+
const pad = W - 4 - k.length - rv.length;
|
|
3591
3508
|
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3592
3509
|
};
|
|
3593
3510
|
console.log(top);
|
|
3594
|
-
console.log(
|
|
3595
|
-
console.log(
|
|
3596
|
-
console.log(
|
|
3597
|
-
console.log(
|
|
3598
|
-
console.log(
|
|
3599
|
-
console.log(
|
|
3600
|
-
console.log(
|
|
3511
|
+
console.log(kv("API URL", chalk7.dim(cfg.apiUrl || "default")));
|
|
3512
|
+
console.log(kv("Workspace", chalk7.dim(cfg.workspaceId || "none")));
|
|
3513
|
+
console.log(kv("Project", chalk7.dim(cfg.projectId || "none")));
|
|
3514
|
+
console.log(kv("Model", chalk7.dim(cfg.model || "auto")));
|
|
3515
|
+
console.log(kv("Mode", chalk7.dim(cfg.mode || "general")));
|
|
3516
|
+
console.log(kv("Config", chalk7.dim(configManager.getPath())));
|
|
3517
|
+
console.log(bot);
|
|
3601
3518
|
console.log(chalk7.dim(" /config set <key> <value> \xB7 /config get <key>"));
|
|
3602
3519
|
return;
|
|
3603
3520
|
}
|
|
3604
3521
|
const parts = args.split(/\s+/);
|
|
3605
|
-
|
|
3606
|
-
if (sub === "list") {
|
|
3522
|
+
if (parts[0] === "list") {
|
|
3607
3523
|
await configCommand("list");
|
|
3608
|
-
} else if (
|
|
3524
|
+
} else if (parts[0] === "get" && parts[1]) {
|
|
3609
3525
|
await configCommand("get", parts[1]);
|
|
3610
|
-
} else if (
|
|
3526
|
+
} else if (parts[0] === "set" && parts[1] && parts[2]) {
|
|
3611
3527
|
await configCommand("set", parts[1], parts[2]);
|
|
3612
3528
|
if (parts[1] === "mode") this.currentMode = parts[2];
|
|
3613
3529
|
if (parts[1] === "model") this.currentModel = parts[2];
|