devwing 0.1.21 → 0.1.22
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 +305 -423
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2787,7 +2787,7 @@ function getVersion() {
|
|
|
2787
2787
|
continue;
|
|
2788
2788
|
}
|
|
2789
2789
|
}
|
|
2790
|
-
return "0.1.
|
|
2790
|
+
return "0.1.22";
|
|
2791
2791
|
}
|
|
2792
2792
|
var DEMO_USER2 = {
|
|
2793
2793
|
id: "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
@@ -2802,8 +2802,7 @@ var DEMO_USER2 = {
|
|
|
2802
2802
|
tokens_reset_at: "2026-04-10T00:00:00Z"
|
|
2803
2803
|
};
|
|
2804
2804
|
var DEMO_WORKSPACE2 = {
|
|
2805
|
-
name: "Kano State Government"
|
|
2806
|
-
plan: "enterprise"};
|
|
2805
|
+
name: "Kano State Government"};
|
|
2807
2806
|
var DEMO_PROJECT2 = {
|
|
2808
2807
|
name: "Tallon SaaS ERP"};
|
|
2809
2808
|
var DEMO_MODELS = [
|
|
@@ -2812,11 +2811,11 @@ var DEMO_MODELS = [
|
|
|
2812
2811
|
{ name: "devwing-backend-1", display_name: "DevWing Backend", domain: "backend", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 82, version: "1.0" },
|
|
2813
2812
|
{ name: "devwing-security-1", display_name: "DevWing Security", domain: "security", status: "active", min_plan: "pro", context_window: 32768, tokens_per_sec: 74, version: "1.0" },
|
|
2814
2813
|
{ name: "devwing-devops-1", display_name: "DevWing DevOps", domain: "devops", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 70, version: "0.9" },
|
|
2815
|
-
{ name: "devwing-mobile-1", display_name: "DevWing Mobile", domain: "
|
|
2816
|
-
{ name: "devwing-data-1", display_name: "DevWing Data", domain: "
|
|
2814
|
+
{ name: "devwing-mobile-1", display_name: "DevWing Mobile", domain: "mobile", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 72, version: "0.8" },
|
|
2815
|
+
{ name: "devwing-data-1", display_name: "DevWing Data", domain: "data", status: "beta", min_plan: "pro", context_window: 32768, tokens_per_sec: 68, version: "0.7" }
|
|
2817
2816
|
];
|
|
2818
2817
|
var DEMO_PLANS = [
|
|
2819
|
-
{ name: "Free", price: "$0", tokens_day: "50,000", models: "General only", projects: "1", seats: "1" },
|
|
2818
|
+
{ name: "Free", price: "$0/mo", tokens_day: "50,000", models: "General only", projects: "1", seats: "1" },
|
|
2820
2819
|
{ name: "Pro", price: "$19/mo", tokens_day: "500,000", models: "All models", projects: "10", seats: "1" },
|
|
2821
2820
|
{ name: "Team", price: "$99/mo", tokens_day: "2,000,000", models: "All + priority", projects: "Unlimited", seats: "5 included" },
|
|
2822
2821
|
{ name: "Enterprise", price: "Custom", tokens_day: "Unlimited", models: "Dedicated", projects: "Unlimited", seats: "Unlimited" }
|
|
@@ -2841,8 +2840,7 @@ var InteractiveSession = class {
|
|
|
2841
2840
|
sigintCount = 0;
|
|
2842
2841
|
sigintTimer = null;
|
|
2843
2842
|
version;
|
|
2844
|
-
|
|
2845
|
-
// prevent readline events during command execution
|
|
2843
|
+
isRunningCommand = false;
|
|
2846
2844
|
constructor(options) {
|
|
2847
2845
|
this.options = options;
|
|
2848
2846
|
this.isDemo = isDemoMode();
|
|
@@ -2861,63 +2859,76 @@ var InteractiveSession = class {
|
|
|
2861
2859
|
this.printSystemInfo();
|
|
2862
2860
|
this.createReadline();
|
|
2863
2861
|
console.log();
|
|
2864
|
-
this.
|
|
2862
|
+
this.prompt();
|
|
2865
2863
|
}
|
|
2866
2864
|
// ============================================================
|
|
2867
|
-
// READLINE
|
|
2865
|
+
// READLINE — created once, never destroyed
|
|
2868
2866
|
// ============================================================
|
|
2869
2867
|
createReadline() {
|
|
2870
|
-
this.isBusy = false;
|
|
2871
2868
|
this.rl = readline.createInterface({
|
|
2872
2869
|
input: process.stdin,
|
|
2873
2870
|
output: process.stdout,
|
|
2874
|
-
prompt:
|
|
2875
|
-
|
|
2871
|
+
prompt: "",
|
|
2872
|
+
terminal: true
|
|
2876
2873
|
});
|
|
2877
2874
|
this.rl.on("SIGINT", () => {
|
|
2875
|
+
if (this.isRunningCommand) {
|
|
2876
|
+
process.stdout.write("\n");
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2878
2879
|
this.sigintCount++;
|
|
2879
2880
|
if (this.sigintCount >= 2) {
|
|
2880
2881
|
this.exitSession();
|
|
2881
2882
|
return;
|
|
2882
2883
|
}
|
|
2883
|
-
|
|
2884
|
+
process.stdout.write(chalk7.dim("\n Press Ctrl+C again to exit, or type /exit\n"));
|
|
2884
2885
|
this.sigintTimer = setTimeout(() => {
|
|
2885
2886
|
this.sigintCount = 0;
|
|
2886
2887
|
}, 1500);
|
|
2887
|
-
this.
|
|
2888
|
+
this.prompt();
|
|
2888
2889
|
});
|
|
2889
|
-
const currentRl = this.rl;
|
|
2890
2890
|
this.rl.on("line", async (input) => {
|
|
2891
|
-
if (this.
|
|
2891
|
+
if (this.isRunningCommand) return;
|
|
2892
2892
|
const trimmed = input.trim();
|
|
2893
2893
|
if (!trimmed) {
|
|
2894
|
-
this.
|
|
2894
|
+
this.prompt();
|
|
2895
2895
|
return;
|
|
2896
2896
|
}
|
|
2897
|
-
this.
|
|
2897
|
+
this.isRunningCommand = true;
|
|
2898
|
+
this.rl.pause();
|
|
2898
2899
|
try {
|
|
2899
2900
|
if (trimmed.startsWith("/")) {
|
|
2900
2901
|
await this.handleSlashCommand(trimmed);
|
|
2901
|
-
return;
|
|
2902
2902
|
} else {
|
|
2903
2903
|
await this.handleAIPrompt(trimmed);
|
|
2904
2904
|
}
|
|
2905
2905
|
} catch (error) {
|
|
2906
2906
|
logger.error(error.message || "An error occurred");
|
|
2907
2907
|
}
|
|
2908
|
-
this.
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2908
|
+
this.restoreStdin();
|
|
2909
|
+
await sleep2(60);
|
|
2910
|
+
this.isRunningCommand = false;
|
|
2911
|
+
this.rl.resume();
|
|
2912
|
+
this.prompt();
|
|
2913
2913
|
});
|
|
2914
2914
|
this.rl.on("close", () => {
|
|
2915
|
-
if (!this.
|
|
2915
|
+
if (!this.isRunningCommand) {
|
|
2916
2916
|
this.exitSession();
|
|
2917
2917
|
}
|
|
2918
2918
|
});
|
|
2919
2919
|
}
|
|
2920
|
-
|
|
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();
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
restoreStdin() {
|
|
2921
2932
|
try {
|
|
2922
2933
|
if (typeof process.stdin.setRawMode === "function") {
|
|
2923
2934
|
try {
|
|
@@ -2927,18 +2938,17 @@ var InteractiveSession = class {
|
|
|
2927
2938
|
}
|
|
2928
2939
|
process.stdin.removeAllListeners("keypress");
|
|
2929
2940
|
process.stdin.removeAllListeners("data");
|
|
2930
|
-
if (process.stdin.isPaused())
|
|
2931
|
-
process.stdin.resume();
|
|
2932
|
-
}
|
|
2941
|
+
if (process.stdin.isPaused()) process.stdin.resume();
|
|
2933
2942
|
} catch {
|
|
2934
2943
|
}
|
|
2935
2944
|
}
|
|
2936
|
-
|
|
2937
|
-
this.
|
|
2938
|
-
|
|
2945
|
+
prompt() {
|
|
2946
|
+
const p = this.buildPrompt();
|
|
2947
|
+
process.stdout.write(p);
|
|
2948
|
+
this.rl.setPrompt(p);
|
|
2939
2949
|
}
|
|
2940
2950
|
// ============================================================
|
|
2941
|
-
// STARTUP UI
|
|
2951
|
+
// STARTUP UI — Claude Code style
|
|
2942
2952
|
// ============================================================
|
|
2943
2953
|
printStartupBanner() {
|
|
2944
2954
|
const banner = gradient.pastel.multiline([
|
|
@@ -2952,78 +2962,79 @@ var InteractiveSession = class {
|
|
|
2952
2962
|
""
|
|
2953
2963
|
].join("\n"));
|
|
2954
2964
|
console.log(banner);
|
|
2955
|
-
console.log(
|
|
2965
|
+
console.log(
|
|
2966
|
+
chalk7.dim(" Your AI Wingman in the Terminal") + chalk7.dim(" ".repeat(18)) + chalk7.dim(`v${this.version}`)
|
|
2967
|
+
);
|
|
2956
2968
|
console.log();
|
|
2957
2969
|
}
|
|
2958
2970
|
printSystemInfo() {
|
|
2959
|
-
const
|
|
2960
|
-
|
|
2971
|
+
const W = 64;
|
|
2972
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
2973
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
2974
|
+
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
2975
|
+
const row = (label, value) => {
|
|
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");
|
|
2980
|
+
};
|
|
2981
|
+
console.log(top);
|
|
2961
2982
|
if (this.isAuthenticated && this.userProfile) {
|
|
2962
2983
|
const name = this.userProfile.full_name || this.userProfile.email;
|
|
2963
2984
|
const plan = (this.userProfile.subscription_plan || "free").toUpperCase();
|
|
2964
|
-
const
|
|
2965
|
-
console.log(
|
|
2966
|
-
` ${chalk7.bold("Auth")} ${chalk7.green("\u25CF")} ${name} ${planColor(`(${plan})`)}`
|
|
2967
|
-
);
|
|
2968
|
-
} else if (this.isAuthenticated) {
|
|
2969
|
-
console.log(
|
|
2970
|
-
` ${chalk7.bold("Auth")} ${chalk7.green("\u25CF")} Authenticated ${chalk7.dim("(offline)")}`
|
|
2971
|
-
);
|
|
2985
|
+
const planBadge = plan === "PRO" ? chalk7.bgCyan.black(` ${plan} `) : plan === "ENTERPRISE" ? chalk7.bgMagenta.white(` ${plan} `) : plan === "TEAM" ? chalk7.bgYellow.black(` ${plan} `) : chalk7.bgGray.white(` ${plan} `);
|
|
2986
|
+
console.log(row("Logged in", chalk7.green("\u25CF ") + chalk7.white(name) + " " + planBadge));
|
|
2972
2987
|
} else {
|
|
2973
|
-
console.log(
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
const
|
|
2978
|
-
const
|
|
2979
|
-
|
|
2980
|
-
const
|
|
2988
|
+
console.log(row("Auth", chalk7.red("\u25CF ") + chalk7.dim("Not logged in \u2014 type ") + chalk7.cyan("/login")));
|
|
2989
|
+
}
|
|
2990
|
+
console.log(div);
|
|
2991
|
+
const modeVal = chalk7.yellow.bold(this.currentMode);
|
|
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"));
|
|
2999
|
+
console.log(div);
|
|
2981
3000
|
if (this.isDemo) {
|
|
2982
|
-
console.log(
|
|
3001
|
+
console.log(row("Project", chalk7.cyan(DEMO_PROJECT2.name)));
|
|
2983
3002
|
} else {
|
|
2984
|
-
const
|
|
2985
|
-
|
|
2986
|
-
console.log(` ${chalk7.bold("Project")} ${projectStr} ${chalk7.bold("CWD")} ${chalk7.dim(cwd)}`);
|
|
3003
|
+
const pid = configManager.getProjectId();
|
|
3004
|
+
console.log(row("Project", pid ? chalk7.cyan(pid) : chalk7.dim("none")));
|
|
2987
3005
|
}
|
|
2988
|
-
const
|
|
2989
|
-
console.log(
|
|
3006
|
+
const cwd = process.cwd().replace(process.env.HOME || "", "~");
|
|
3007
|
+
console.log(row("Directory", chalk7.dim(cwd)));
|
|
2990
3008
|
if (this.isDemo) {
|
|
2991
|
-
console.log(
|
|
3009
|
+
console.log(div);
|
|
3010
|
+
console.log(row("Demo", chalk7.yellow("\u25C6 ") + chalk7.yellow("Demo mode") + chalk7.dim(" \u2014 no backend required")));
|
|
2992
3011
|
}
|
|
2993
|
-
console.log(
|
|
3012
|
+
console.log(bottom);
|
|
2994
3013
|
console.log();
|
|
2995
|
-
console.log(
|
|
3014
|
+
console.log(
|
|
3015
|
+
chalk7.dim(" Chat freely, or use ") + chalk7.cyan("/help") + chalk7.dim(" to see all commands.")
|
|
3016
|
+
);
|
|
2996
3017
|
}
|
|
2997
3018
|
// ============================================================
|
|
2998
|
-
// PROMPT
|
|
3019
|
+
// PROMPT LINE — Claude Code style
|
|
2999
3020
|
// ============================================================
|
|
3000
3021
|
buildPrompt() {
|
|
3001
3022
|
const parts = [];
|
|
3002
|
-
|
|
3003
|
-
|
|
3023
|
+
const sep = chalk7.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
3024
|
+
let nameTag = "";
|
|
3004
3025
|
if (this.isAuthenticated && this.userProfile) {
|
|
3005
|
-
const
|
|
3006
|
-
|
|
3007
|
-
}
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
if (!line.startsWith("/")) return [[], line];
|
|
3018
|
-
const allNames = [];
|
|
3019
|
-
for (const cmd of this.commands.values()) {
|
|
3020
|
-
allNames.push("/" + cmd.name);
|
|
3021
|
-
for (const alias of cmd.aliases) {
|
|
3022
|
-
allNames.push("/" + alias);
|
|
3023
|
-
}
|
|
3024
|
-
}
|
|
3025
|
-
const hits = allNames.filter((n) => n.startsWith(line));
|
|
3026
|
-
return [hits.length ? hits : allNames, line];
|
|
3026
|
+
const first = (this.userProfile.full_name || this.userProfile.email).split(" ")[0].split("@")[0];
|
|
3027
|
+
nameTag = chalk7.dim("@") + chalk7.green(first.toLowerCase());
|
|
3028
|
+
}
|
|
3029
|
+
const modeTag = chalk7.dim("[") + chalk7.yellow(this.currentMode) + chalk7.dim("]");
|
|
3030
|
+
const demoTag = this.isDemo ? chalk7.dim.yellow(" demo") : "";
|
|
3031
|
+
const icon = chalk7.bold.cyan("\u2B21");
|
|
3032
|
+
const label = chalk7.bold.white("devwing");
|
|
3033
|
+
parts.push(`
|
|
3034
|
+
${sep}`);
|
|
3035
|
+
parts.push(` ${icon} ${label} ${modeTag}${nameTag ? " " + nameTag : ""}${demoTag}`);
|
|
3036
|
+
parts.push(" " + chalk7.bold.cyan("\u276F") + " ");
|
|
3037
|
+
return parts.join("\n");
|
|
3027
3038
|
}
|
|
3028
3039
|
// ============================================================
|
|
3029
3040
|
// AUTH CHECK
|
|
@@ -3070,23 +3081,17 @@ var InteractiveSession = class {
|
|
|
3070
3081
|
}
|
|
3071
3082
|
}
|
|
3072
3083
|
if (!command) {
|
|
3084
|
+
console.log();
|
|
3073
3085
|
logger.warn(`Unknown command: /${cmdName}. Type /help for available commands.`);
|
|
3074
3086
|
return;
|
|
3075
3087
|
}
|
|
3076
3088
|
if (command.requiresAuth && !this.isAuthenticated) {
|
|
3089
|
+
console.log();
|
|
3077
3090
|
logger.warn("You need to be logged in for this command. Type /login first.");
|
|
3078
3091
|
return;
|
|
3079
3092
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
try {
|
|
3083
|
-
await command.handler(args);
|
|
3084
|
-
} catch (error) {
|
|
3085
|
-
logger.error(error.message || "Command failed");
|
|
3086
|
-
}
|
|
3087
|
-
this.resetStdin();
|
|
3088
|
-
await sleep2(80);
|
|
3089
|
-
this.recreateReadline();
|
|
3093
|
+
console.log();
|
|
3094
|
+
await command.handler(args);
|
|
3090
3095
|
}
|
|
3091
3096
|
// ============================================================
|
|
3092
3097
|
// AI PROMPT HANDLER
|
|
@@ -3099,20 +3104,11 @@ var InteractiveSession = class {
|
|
|
3099
3104
|
}
|
|
3100
3105
|
console.log();
|
|
3101
3106
|
if (this.isDemo) {
|
|
3102
|
-
this.
|
|
3103
|
-
this.
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
{ role: "user", content: input, timestamp: /* @__PURE__ */ new Date() },
|
|
3108
|
-
{ role: "assistant", content: "[demo response]", timestamp: /* @__PURE__ */ new Date() }
|
|
3109
|
-
);
|
|
3110
|
-
} catch (error) {
|
|
3111
|
-
logger.error(error.message || "Command failed");
|
|
3112
|
-
}
|
|
3113
|
-
this.resetStdin();
|
|
3114
|
-
await sleep2(80);
|
|
3115
|
-
this.recreateReadline();
|
|
3107
|
+
await demoPromptCommand(input, { ...this.options, mode: this.currentMode });
|
|
3108
|
+
this.conversationHistory.push(
|
|
3109
|
+
{ role: "user", content: input, timestamp: /* @__PURE__ */ new Date() },
|
|
3110
|
+
{ role: "assistant", content: "[demo response]", timestamp: /* @__PURE__ */ new Date() }
|
|
3111
|
+
);
|
|
3116
3112
|
return;
|
|
3117
3113
|
}
|
|
3118
3114
|
if (!this.sessionContext) {
|
|
@@ -3173,9 +3169,7 @@ var InteractiveSession = class {
|
|
|
3173
3169
|
}
|
|
3174
3170
|
buildPromptWithHistory() {
|
|
3175
3171
|
const history = this.conversationHistory;
|
|
3176
|
-
if (history.length <= 1)
|
|
3177
|
-
return history[history.length - 1]?.content || "";
|
|
3178
|
-
}
|
|
3172
|
+
if (history.length <= 1) return history[history.length - 1]?.content || "";
|
|
3179
3173
|
const recent = history.slice(-10);
|
|
3180
3174
|
const context = recent.slice(0, -1).map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${m.content}`).join("\n\n");
|
|
3181
3175
|
return `Previous conversation:
|
|
@@ -3189,9 +3183,9 @@ ${recent[recent.length - 1].content}`;
|
|
|
3189
3183
|
// ============================================================
|
|
3190
3184
|
exitSession() {
|
|
3191
3185
|
if (this.sigintTimer) clearTimeout(this.sigintTimer);
|
|
3192
|
-
this.
|
|
3186
|
+
this.restoreStdin();
|
|
3193
3187
|
console.log();
|
|
3194
|
-
console.log(chalk7.dim(" Goodbye! Happy
|
|
3188
|
+
console.log(chalk7.dim(" Goodbye! Happy shipping. \u{1F680}"));
|
|
3195
3189
|
console.log();
|
|
3196
3190
|
process.exit(0);
|
|
3197
3191
|
}
|
|
@@ -3199,150 +3193,24 @@ ${recent[recent.length - 1].content}`;
|
|
|
3199
3193
|
// COMMAND REGISTRATION
|
|
3200
3194
|
// ============================================================
|
|
3201
3195
|
registerCommands() {
|
|
3202
|
-
this.addCommand({
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
});
|
|
3210
|
-
this.addCommand({
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
});
|
|
3218
|
-
this.addCommand({
|
|
3219
|
-
|
|
3220
|
-
aliases: ["cls"],
|
|
3221
|
-
description: "Clear screen and conversation",
|
|
3222
|
-
category: "session",
|
|
3223
|
-
requiresAuth: false,
|
|
3224
|
-
handler: async () => this.cmdClear()
|
|
3225
|
-
});
|
|
3226
|
-
this.addCommand({
|
|
3227
|
-
name: "login",
|
|
3228
|
-
aliases: ["signin"],
|
|
3229
|
-
description: "Authenticate with DevWing",
|
|
3230
|
-
category: "session",
|
|
3231
|
-
requiresAuth: false,
|
|
3232
|
-
handler: async () => this.cmdLogin()
|
|
3233
|
-
});
|
|
3234
|
-
this.addCommand({
|
|
3235
|
-
name: "logout",
|
|
3236
|
-
aliases: ["signout"],
|
|
3237
|
-
description: "Clear credentials and log out",
|
|
3238
|
-
category: "session",
|
|
3239
|
-
requiresAuth: true,
|
|
3240
|
-
handler: async () => this.cmdLogout()
|
|
3241
|
-
});
|
|
3242
|
-
this.addCommand({
|
|
3243
|
-
name: "status",
|
|
3244
|
-
aliases: ["whoami"],
|
|
3245
|
-
description: "Show auth status and profile",
|
|
3246
|
-
category: "session",
|
|
3247
|
-
requiresAuth: false,
|
|
3248
|
-
handler: async () => this.cmdStatus()
|
|
3249
|
-
});
|
|
3250
|
-
this.addCommand({
|
|
3251
|
-
name: "scan",
|
|
3252
|
-
aliases: [],
|
|
3253
|
-
description: "Run security vulnerability scan",
|
|
3254
|
-
category: "tools",
|
|
3255
|
-
requiresAuth: true,
|
|
3256
|
-
handler: async () => this.cmdScan()
|
|
3257
|
-
});
|
|
3258
|
-
this.addCommand({
|
|
3259
|
-
name: "review",
|
|
3260
|
-
aliases: [],
|
|
3261
|
-
description: "Perform code review on recent changes",
|
|
3262
|
-
category: "tools",
|
|
3263
|
-
requiresAuth: true,
|
|
3264
|
-
handler: async () => this.cmdReview()
|
|
3265
|
-
});
|
|
3266
|
-
this.addCommand({
|
|
3267
|
-
name: "explain",
|
|
3268
|
-
aliases: [],
|
|
3269
|
-
description: "Explain code, file, or concept",
|
|
3270
|
-
category: "tools",
|
|
3271
|
-
requiresAuth: true,
|
|
3272
|
-
handler: async (args) => this.cmdExplain(args)
|
|
3273
|
-
});
|
|
3274
|
-
this.addCommand({
|
|
3275
|
-
name: "memory",
|
|
3276
|
-
aliases: ["mem"],
|
|
3277
|
-
description: "Manage project memory (save/show/clear)",
|
|
3278
|
-
category: "tools",
|
|
3279
|
-
requiresAuth: true,
|
|
3280
|
-
handler: async (args) => this.cmdMemory(args)
|
|
3281
|
-
});
|
|
3282
|
-
this.addCommand({
|
|
3283
|
-
name: "mode",
|
|
3284
|
-
aliases: [],
|
|
3285
|
-
description: "Show or set AI mode",
|
|
3286
|
-
category: "config",
|
|
3287
|
-
requiresAuth: false,
|
|
3288
|
-
handler: async (args) => this.cmdMode(args)
|
|
3289
|
-
});
|
|
3290
|
-
this.addCommand({
|
|
3291
|
-
name: "model",
|
|
3292
|
-
aliases: [],
|
|
3293
|
-
description: "Show or set AI model",
|
|
3294
|
-
category: "config",
|
|
3295
|
-
requiresAuth: false,
|
|
3296
|
-
handler: async (args) => this.cmdModel(args)
|
|
3297
|
-
});
|
|
3298
|
-
this.addCommand({
|
|
3299
|
-
name: "models",
|
|
3300
|
-
aliases: [],
|
|
3301
|
-
description: "List all available AI models",
|
|
3302
|
-
category: "config",
|
|
3303
|
-
requiresAuth: false,
|
|
3304
|
-
handler: async () => this.cmdModels()
|
|
3305
|
-
});
|
|
3306
|
-
this.addCommand({
|
|
3307
|
-
name: "usage",
|
|
3308
|
-
aliases: ["stats"],
|
|
3309
|
-
description: "Show token usage statistics",
|
|
3310
|
-
category: "config",
|
|
3311
|
-
requiresAuth: true,
|
|
3312
|
-
handler: async () => this.cmdUsage()
|
|
3313
|
-
});
|
|
3314
|
-
this.addCommand({
|
|
3315
|
-
name: "plans",
|
|
3316
|
-
aliases: ["pricing"],
|
|
3317
|
-
description: "Show available plans and pricing",
|
|
3318
|
-
category: "config",
|
|
3319
|
-
requiresAuth: false,
|
|
3320
|
-
handler: async () => this.cmdPlans()
|
|
3321
|
-
});
|
|
3322
|
-
this.addCommand({
|
|
3323
|
-
name: "context",
|
|
3324
|
-
aliases: ["ctx"],
|
|
3325
|
-
description: "Show loaded codebase context",
|
|
3326
|
-
category: "config",
|
|
3327
|
-
requiresAuth: false,
|
|
3328
|
-
handler: async () => this.cmdContext()
|
|
3329
|
-
});
|
|
3330
|
-
this.addCommand({
|
|
3331
|
-
name: "history",
|
|
3332
|
-
aliases: [],
|
|
3333
|
-
description: "Show conversation history",
|
|
3334
|
-
category: "config",
|
|
3335
|
-
requiresAuth: false,
|
|
3336
|
-
handler: async () => this.cmdHistory()
|
|
3337
|
-
});
|
|
3338
|
-
this.addCommand({
|
|
3339
|
-
name: "config",
|
|
3340
|
-
aliases: ["settings"],
|
|
3341
|
-
description: "Show or set CLI configuration",
|
|
3342
|
-
category: "config",
|
|
3343
|
-
requiresAuth: false,
|
|
3344
|
-
handler: async (args) => this.cmdConfig(args)
|
|
3345
|
-
});
|
|
3196
|
+
this.addCommand({ name: "help", aliases: ["h", "?"], description: "Show all available commands", category: "session", requiresAuth: false, handler: async () => this.cmdHelp() });
|
|
3197
|
+
this.addCommand({ name: "exit", aliases: ["quit", "q"], description: "Exit DevWing", category: "session", requiresAuth: false, handler: async () => this.exitSession() });
|
|
3198
|
+
this.addCommand({ name: "clear", aliases: ["cls"], description: "Clear screen and conversation", category: "session", requiresAuth: false, handler: async () => this.cmdClear() });
|
|
3199
|
+
this.addCommand({ name: "login", aliases: ["signin"], description: "Authenticate with DevWing", category: "session", requiresAuth: false, handler: async () => this.cmdLogin() });
|
|
3200
|
+
this.addCommand({ name: "logout", aliases: ["signout"], description: "Clear credentials and log out", category: "session", requiresAuth: true, handler: async () => this.cmdLogout() });
|
|
3201
|
+
this.addCommand({ name: "status", aliases: ["whoami"], description: "Show auth status and profile", category: "session", requiresAuth: false, handler: async () => this.cmdStatus() });
|
|
3202
|
+
this.addCommand({ name: "scan", aliases: [], description: "Run security vulnerability scan", category: "tools", requiresAuth: true, handler: async () => this.cmdScan() });
|
|
3203
|
+
this.addCommand({ name: "review", aliases: [], description: "Perform code review on recent changes", category: "tools", requiresAuth: true, handler: async () => this.cmdReview() });
|
|
3204
|
+
this.addCommand({ name: "explain", aliases: [], description: "Explain code, file, or concept", category: "tools", requiresAuth: true, handler: async (a) => this.cmdExplain(a) });
|
|
3205
|
+
this.addCommand({ name: "memory", aliases: ["mem"], description: "Manage project memory (save/show/clear)", category: "tools", requiresAuth: true, handler: async (a) => this.cmdMemory(a) });
|
|
3206
|
+
this.addCommand({ name: "mode", aliases: [], description: "Show or set AI mode", category: "config", requiresAuth: false, handler: async (a) => this.cmdMode(a) });
|
|
3207
|
+
this.addCommand({ name: "model", aliases: [], description: "Show or set AI model", category: "config", requiresAuth: false, handler: async (a) => this.cmdModel(a) });
|
|
3208
|
+
this.addCommand({ name: "models", aliases: [], description: "List all available AI models", category: "config", requiresAuth: false, handler: async () => this.cmdModels() });
|
|
3209
|
+
this.addCommand({ name: "usage", aliases: ["stats"], description: "Show token usage statistics", category: "config", requiresAuth: true, handler: async () => this.cmdUsage() });
|
|
3210
|
+
this.addCommand({ name: "plans", aliases: ["pricing"], description: "Show available plans and pricing", category: "config", requiresAuth: false, handler: async () => this.cmdPlans() });
|
|
3211
|
+
this.addCommand({ name: "context", aliases: ["ctx"], description: "Show loaded codebase context", category: "config", requiresAuth: false, handler: async () => this.cmdContext() });
|
|
3212
|
+
this.addCommand({ name: "history", aliases: [], description: "Show conversation history", category: "config", requiresAuth: false, handler: async () => this.cmdHistory() });
|
|
3213
|
+
this.addCommand({ name: "config", aliases: ["settings"], description: "Show or set CLI configuration", category: "config", requiresAuth: false, handler: async (a) => this.cmdConfig(a) });
|
|
3346
3214
|
}
|
|
3347
3215
|
addCommand(cmd) {
|
|
3348
3216
|
this.commands.set(cmd.name, cmd);
|
|
@@ -3351,24 +3219,42 @@ ${recent[recent.length - 1].content}`;
|
|
|
3351
3219
|
// COMMAND IMPLEMENTATIONS
|
|
3352
3220
|
// ============================================================
|
|
3353
3221
|
async cmdHelp() {
|
|
3354
|
-
|
|
3222
|
+
const W = 64;
|
|
3223
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3224
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3225
|
+
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
3226
|
+
const hRow = (left, right) => {
|
|
3227
|
+
const rawLeft = left.replace(/\x1B\[[0-9;]*m/g, "");
|
|
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, "");
|
|
3234
|
+
const pad = W - 4 - raw.length;
|
|
3235
|
+
return chalk7.dim("\u2502 ") + label + " ".repeat(Math.max(0, pad)) + chalk7.dim(" \u2502");
|
|
3236
|
+
};
|
|
3355
3237
|
const categories = [
|
|
3356
3238
|
{ key: "session", label: "Session", color: chalk7.bold.green },
|
|
3357
3239
|
{ key: "tools", label: "AI Tools", color: chalk7.bold.magenta },
|
|
3358
3240
|
{ key: "config", label: "Configuration", color: chalk7.bold.yellow }
|
|
3359
3241
|
];
|
|
3360
|
-
|
|
3242
|
+
console.log(top);
|
|
3243
|
+
console.log(catRow(chalk7.bold.white(" Commands")));
|
|
3361
3244
|
for (const cat of categories) {
|
|
3362
|
-
|
|
3245
|
+
console.log(div);
|
|
3246
|
+
console.log(catRow(" " + cat.color(cat.label)));
|
|
3363
3247
|
for (const cmd of this.commands.values()) {
|
|
3364
3248
|
if (cmd.category !== cat.key) continue;
|
|
3365
|
-
const
|
|
3366
|
-
|
|
3249
|
+
const cmdStr = chalk7.cyan(("/" + cmd.name).padEnd(14));
|
|
3250
|
+
const descStr = chalk7.dim(cmd.description);
|
|
3251
|
+
const aliasStr = cmd.aliases.length > 0 ? chalk7.dim(` \xB7 ${cmd.aliases.map((a) => "/" + a).join(", ")}`) : "";
|
|
3252
|
+
console.log(hRow(" " + cmdStr + " " + descStr, aliasStr));
|
|
3367
3253
|
}
|
|
3368
|
-
lines.push("");
|
|
3369
3254
|
}
|
|
3370
|
-
|
|
3371
|
-
|
|
3255
|
+
console.log(div);
|
|
3256
|
+
console.log(catRow(chalk7.dim(" Just type a message to chat with DevWing AI")));
|
|
3257
|
+
console.log(bottom);
|
|
3372
3258
|
}
|
|
3373
3259
|
async cmdClear() {
|
|
3374
3260
|
this.conversationHistory = [];
|
|
@@ -3379,53 +3265,50 @@ ${recent[recent.length - 1].content}`;
|
|
|
3379
3265
|
this.printSystemInfo();
|
|
3380
3266
|
}
|
|
3381
3267
|
async cmdLogin() {
|
|
3382
|
-
console.log();
|
|
3383
3268
|
if (this.isDemo) {
|
|
3384
|
-
await demoLoginCommand({ fromSession: true });
|
|
3269
|
+
await this.withInquirer(() => demoLoginCommand({ fromSession: true }));
|
|
3385
3270
|
} else {
|
|
3386
|
-
await loginCommand();
|
|
3271
|
+
await this.withInquirer(() => loginCommand());
|
|
3387
3272
|
}
|
|
3388
3273
|
await this.checkAuthStatus();
|
|
3389
|
-
this.rl.setPrompt(this.buildPrompt());
|
|
3390
3274
|
}
|
|
3391
3275
|
async cmdLogout() {
|
|
3392
|
-
console.log();
|
|
3393
3276
|
if (this.isDemo) {
|
|
3394
|
-
await demoLogoutCommand();
|
|
3277
|
+
await this.withInquirer(() => demoLogoutCommand());
|
|
3395
3278
|
} else {
|
|
3396
|
-
await logoutCommand();
|
|
3279
|
+
await this.withInquirer(() => logoutCommand());
|
|
3397
3280
|
}
|
|
3398
3281
|
await this.checkAuthStatus();
|
|
3399
|
-
this.rl.setPrompt(this.buildPrompt());
|
|
3400
3282
|
}
|
|
3401
3283
|
async cmdStatus() {
|
|
3402
|
-
console.log();
|
|
3403
3284
|
if (!this.isAuthenticated) {
|
|
3404
3285
|
logger.info("Not logged in. Type /login to authenticate.");
|
|
3405
3286
|
return;
|
|
3406
3287
|
}
|
|
3407
3288
|
if (this.isDemo) {
|
|
3408
|
-
const
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
);
|
|
3422
|
-
console.log(
|
|
3289
|
+
const W = 54;
|
|
3290
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3291
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3292
|
+
const row = (k, v) => {
|
|
3293
|
+
const rawV = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3294
|
+
const pad = W - 4 - k.length - rawV.length;
|
|
3295
|
+
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3296
|
+
};
|
|
3297
|
+
console.log(top);
|
|
3298
|
+
console.log(row("Email", DEMO_USER2.email));
|
|
3299
|
+
console.log(row("Name", DEMO_USER2.full_name));
|
|
3300
|
+
console.log(row("Plan", chalk7.bgCyan.black(" PRO ")));
|
|
3301
|
+
console.log(row("Verified", chalk7.green("\u2713 Yes")));
|
|
3302
|
+
console.log(row("2FA", chalk7.dim("Disabled")));
|
|
3303
|
+
console.log(row("Workspace", DEMO_WORKSPACE2.name + chalk7.dim(" (enterprise)")));
|
|
3304
|
+
console.log(row("Project", DEMO_PROJECT2.name));
|
|
3305
|
+
console.log(row("Tokens today", `${(DEMO_USER2.tokens_used_today).toLocaleString()} / 500,000`));
|
|
3306
|
+
console.log(bottom);
|
|
3423
3307
|
} else {
|
|
3424
3308
|
await statusCommand();
|
|
3425
3309
|
}
|
|
3426
3310
|
}
|
|
3427
3311
|
async cmdScan() {
|
|
3428
|
-
console.log();
|
|
3429
3312
|
if (this.isDemo) {
|
|
3430
3313
|
await demoPromptCommand("scan auth service for OWASP vulnerabilities", { ...this.options, mode: "security" });
|
|
3431
3314
|
} else {
|
|
@@ -3433,7 +3316,6 @@ ${recent[recent.length - 1].content}`;
|
|
|
3433
3316
|
}
|
|
3434
3317
|
}
|
|
3435
3318
|
async cmdReview() {
|
|
3436
|
-
console.log();
|
|
3437
3319
|
if (this.isDemo) {
|
|
3438
3320
|
await demoReviewCommand();
|
|
3439
3321
|
} else {
|
|
@@ -3446,7 +3328,6 @@ ${recent[recent.length - 1].content}`;
|
|
|
3446
3328
|
logger.info("Example: /explain src/auth/middleware.ts");
|
|
3447
3329
|
return;
|
|
3448
3330
|
}
|
|
3449
|
-
console.log();
|
|
3450
3331
|
if (this.isDemo) {
|
|
3451
3332
|
await demoExplainCommand(args);
|
|
3452
3333
|
} else {
|
|
@@ -3463,10 +3344,11 @@ ${recent[recent.length - 1].content}`;
|
|
|
3463
3344
|
console.log(` ${chalk7.cyan("/memory clear")} \u2014 Clear all memories`);
|
|
3464
3345
|
return;
|
|
3465
3346
|
}
|
|
3466
|
-
console.log();
|
|
3467
3347
|
const content = parts.slice(1).join(" ").trim();
|
|
3468
3348
|
if (this.isDemo) {
|
|
3469
|
-
await
|
|
3349
|
+
await this.withInquirer(
|
|
3350
|
+
() => demoMemoryCommand(sub, content || void 0)
|
|
3351
|
+
);
|
|
3470
3352
|
} else {
|
|
3471
3353
|
await memoryCommand(sub, content || void 0, this.options);
|
|
3472
3354
|
}
|
|
@@ -3474,17 +3356,32 @@ ${recent[recent.length - 1].content}`;
|
|
|
3474
3356
|
async cmdMode(args) {
|
|
3475
3357
|
const validModes = ["general", "frontend", "backend", "security", "devops"];
|
|
3476
3358
|
if (!args) {
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
const
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3359
|
+
const W = 58;
|
|
3360
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3361
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3362
|
+
const row = (icon, name, desc) => {
|
|
3363
|
+
const left = ` ${icon} ${name.padEnd(12)} ${chalk7.dim(desc)}`;
|
|
3364
|
+
const rawLeft = left.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3365
|
+
const pad = W - 2 - rawLeft.length;
|
|
3366
|
+
return chalk7.dim("\u2502") + left + " ".repeat(Math.max(0, pad)) + chalk7.dim("\u2502");
|
|
3367
|
+
};
|
|
3368
|
+
console.log(top);
|
|
3369
|
+
console.log(chalk7.dim("\u2502 ") + chalk7.bold("AI Mode".padEnd(W - 4)) + chalk7.dim(" \u2502"));
|
|
3370
|
+
for (const m of validModes) {
|
|
3371
|
+
const active = m === this.currentMode;
|
|
3372
|
+
const icon = active ? chalk7.green("\u25CF") : chalk7.dim("\u25CB");
|
|
3373
|
+
const name = active ? chalk7.yellow.bold(m) : chalk7.white(m);
|
|
3374
|
+
const descs = {
|
|
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] || ""));
|
|
3485
3382
|
}
|
|
3486
|
-
console.log();
|
|
3487
|
-
console.log(chalk7.dim(
|
|
3383
|
+
console.log(bottom);
|
|
3384
|
+
console.log(chalk7.dim(" Usage: /mode <name>"));
|
|
3488
3385
|
return;
|
|
3489
3386
|
}
|
|
3490
3387
|
const mode = args.toLowerCase();
|
|
@@ -3494,124 +3391,111 @@ ${recent[recent.length - 1].content}`;
|
|
|
3494
3391
|
}
|
|
3495
3392
|
this.currentMode = mode;
|
|
3496
3393
|
this.options.mode = mode;
|
|
3497
|
-
|
|
3394
|
+
console.log();
|
|
3395
|
+
console.log(` ${chalk7.green("\u2713")} Mode \u2192 ${chalk7.yellow.bold(mode)}`);
|
|
3498
3396
|
}
|
|
3499
3397
|
async cmdModel(args) {
|
|
3500
3398
|
if (!args) {
|
|
3399
|
+
const current = this.currentModel || "auto";
|
|
3501
3400
|
console.log();
|
|
3502
|
-
|
|
3503
|
-
console.log(
|
|
3504
|
-
console.log(chalk7.dim(` Usage: /model <name> | /model auto | /models to list all`));
|
|
3401
|
+
console.log(` ${chalk7.bold("Current model:")} ${chalk7.cyan(current)}`);
|
|
3402
|
+
console.log(chalk7.dim(" /model <name> \xB7 /model auto \xB7 /models to list all"));
|
|
3505
3403
|
return;
|
|
3506
3404
|
}
|
|
3507
3405
|
if (args === "auto") {
|
|
3508
3406
|
this.currentModel = null;
|
|
3509
3407
|
this.options.model = void 0;
|
|
3510
|
-
logger.success("Model
|
|
3408
|
+
logger.success("Model \u2192 auto");
|
|
3511
3409
|
return;
|
|
3512
3410
|
}
|
|
3513
3411
|
this.currentModel = args;
|
|
3514
3412
|
this.options.model = args;
|
|
3515
|
-
|
|
3413
|
+
console.log();
|
|
3414
|
+
console.log(` ${chalk7.green("\u2713")} Model \u2192 ${chalk7.cyan.bold(args)}`);
|
|
3516
3415
|
}
|
|
3517
3416
|
async cmdModels() {
|
|
3518
|
-
console.log();
|
|
3519
3417
|
if (this.isDemo) {
|
|
3520
3418
|
const table = new Table3({
|
|
3521
3419
|
head: [
|
|
3522
3420
|
chalk7.bold("Model"),
|
|
3523
3421
|
chalk7.bold("Domain"),
|
|
3524
3422
|
chalk7.bold("Status"),
|
|
3525
|
-
chalk7.bold("
|
|
3423
|
+
chalk7.bold("Plan"),
|
|
3526
3424
|
chalk7.bold("Context"),
|
|
3527
3425
|
chalk7.bold("Speed")
|
|
3528
3426
|
],
|
|
3529
|
-
|
|
3427
|
+
style: { head: [], border: ["dim"] }
|
|
3530
3428
|
});
|
|
3531
3429
|
for (const m of DEMO_MODELS) {
|
|
3532
|
-
const
|
|
3533
|
-
const
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
statusColor(m.status),
|
|
3538
|
-
planColor(m.min_plan),
|
|
3539
|
-
`${(m.context_window / 1024).toFixed(0)}k`,
|
|
3540
|
-
`${m.tokens_per_sec} tok/s`
|
|
3541
|
-
]);
|
|
3430
|
+
const active = m.name === (this.currentModel || "");
|
|
3431
|
+
const nameStr = active ? chalk7.cyan.bold(m.display_name + " \u25CF") : m.display_name;
|
|
3432
|
+
const statusBadge = m.status === "active" ? chalk7.green("active") : chalk7.yellow("beta");
|
|
3433
|
+
const planBadge = m.min_plan === "free" ? chalk7.green("free") : chalk7.cyan("pro");
|
|
3434
|
+
table.push([nameStr, chalk7.yellow(m.domain), statusBadge, planBadge, `${(m.context_window / 1024).toFixed(0)}k`, `${m.tokens_per_sec} t/s`]);
|
|
3542
3435
|
}
|
|
3543
3436
|
console.log(table.toString());
|
|
3544
|
-
console.log();
|
|
3545
|
-
console.log(chalk7.dim(` Set a model: /model devwing-backend-1 | /model auto`));
|
|
3437
|
+
console.log(chalk7.dim(" /model <name> to select \xB7 /model auto for automatic"));
|
|
3546
3438
|
} else {
|
|
3547
3439
|
try {
|
|
3548
3440
|
const models = await apiClient.getModels();
|
|
3549
|
-
if (models.length
|
|
3441
|
+
if (!models.length) {
|
|
3550
3442
|
logger.info("No models available");
|
|
3551
3443
|
return;
|
|
3552
3444
|
}
|
|
3553
|
-
const table = new Table3({
|
|
3554
|
-
|
|
3555
|
-
});
|
|
3556
|
-
for (const m of models) {
|
|
3557
|
-
table.push([m.display_name || m.name, m.domain, m.status, m.min_plan]);
|
|
3558
|
-
}
|
|
3445
|
+
const table = new Table3({ head: [chalk7.bold("Name"), chalk7.bold("Domain"), chalk7.bold("Status"), chalk7.bold("Plan")] });
|
|
3446
|
+
for (const m of models) table.push([m.display_name || m.name, m.domain, m.status, m.min_plan]);
|
|
3559
3447
|
console.log(table.toString());
|
|
3560
|
-
} catch (
|
|
3561
|
-
logger.error("Failed to fetch models: " +
|
|
3448
|
+
} catch (e) {
|
|
3449
|
+
logger.error("Failed to fetch models: " + e.message);
|
|
3562
3450
|
}
|
|
3563
3451
|
}
|
|
3564
3452
|
}
|
|
3565
3453
|
async cmdUsage() {
|
|
3566
|
-
console.log();
|
|
3567
3454
|
if (this.isDemo) {
|
|
3568
|
-
console.log(chalk7.bold(" Token Usage"));
|
|
3569
|
-
console.log();
|
|
3570
3455
|
const table = new Table3({
|
|
3571
|
-
head: [chalk7.bold("Period"), chalk7.bold("Requests"), chalk7.bold("Tokens In"), chalk7.bold("Tokens Out"), chalk7.bold("Cost")]
|
|
3456
|
+
head: [chalk7.bold("Period"), chalk7.bold("Requests"), chalk7.bold("Tokens In"), chalk7.bold("Tokens Out"), chalk7.bold("Cost")],
|
|
3457
|
+
style: { head: [], border: ["dim"] }
|
|
3572
3458
|
});
|
|
3573
3459
|
table.push(
|
|
3574
|
-
["Today", DEMO_USAGE.today.requests
|
|
3575
|
-
["This Week", DEMO_USAGE.week.requests
|
|
3576
|
-
["This Month", DEMO_USAGE.month.requests
|
|
3460
|
+
["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
|
+
["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
|
+
["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)}`]
|
|
3577
3463
|
);
|
|
3578
3464
|
console.log(table.toString());
|
|
3579
|
-
console.log();
|
|
3580
3465
|
const used = DEMO_USER2.tokens_used_today;
|
|
3581
3466
|
const limit = 5e5;
|
|
3582
3467
|
const pct = Math.round(used / limit * 100);
|
|
3583
|
-
const
|
|
3584
|
-
const filled = Math.round(pct / 100 *
|
|
3585
|
-
const bar = chalk7.cyan("\u2588".repeat(filled)) + chalk7.dim("\u2591".repeat(
|
|
3586
|
-
console.log(` Daily Quota: ${bar} ${pct}% (${used.toLocaleString()} / ${limit.toLocaleString()})`);
|
|
3468
|
+
const barW = 32;
|
|
3469
|
+
const filled = Math.round(pct / 100 * barW);
|
|
3470
|
+
const bar = chalk7.cyan("\u2588".repeat(filled)) + chalk7.dim("\u2591".repeat(barW - filled));
|
|
3587
3471
|
console.log();
|
|
3588
|
-
console.log(chalk7.bold("
|
|
3472
|
+
console.log(` Daily Quota ${bar} ${chalk7.bold(pct + "%")} ${chalk7.dim(`${used.toLocaleString()} / ${limit.toLocaleString()} tokens`)}`);
|
|
3589
3473
|
console.log();
|
|
3590
|
-
|
|
3591
|
-
|
|
3474
|
+
console.log(chalk7.bold(" By Model"));
|
|
3475
|
+
const mt = new Table3({
|
|
3476
|
+
head: [chalk7.bold("Model"), chalk7.bold("Requests"), chalk7.bold("Tokens"), chalk7.bold("Cost")],
|
|
3477
|
+
style: { head: [], border: ["dim"] }
|
|
3592
3478
|
});
|
|
3593
|
-
|
|
3479
|
+
mt.push(
|
|
3594
3480
|
["devwing-backend-1", "312", "421,000", "$1.4721"],
|
|
3595
3481
|
["devwing-security-1", "145", "198,500", "$0.6948"],
|
|
3596
3482
|
["devwing-general-1", "98", "132,200", "$0.4627"],
|
|
3597
3483
|
["devwing-frontend-1", "42", "56,800", "$0.1988"],
|
|
3598
3484
|
["devwing-devops-1", "15", "15,600", "$0.1728"]
|
|
3599
3485
|
);
|
|
3600
|
-
console.log(
|
|
3486
|
+
console.log(mt.toString());
|
|
3601
3487
|
} else {
|
|
3602
3488
|
try {
|
|
3603
3489
|
const usage = await apiClient.getUsage();
|
|
3604
|
-
console.log(`
|
|
3605
|
-
console.log(` Tokens
|
|
3606
|
-
console.log(` Tokens Out: ${usage.total_tokens_out.toLocaleString()}`);
|
|
3490
|
+
console.log(` Requests: ${usage.total_requests}`);
|
|
3491
|
+
console.log(` Tokens: ${usage.total_tokens_in.toLocaleString()} in, ${usage.total_tokens_out.toLocaleString()} out`);
|
|
3607
3492
|
console.log(` Cost: $${usage.total_cost_usd.toFixed(4)}`);
|
|
3608
|
-
} catch (
|
|
3609
|
-
logger.error("Failed to fetch usage: " +
|
|
3493
|
+
} catch (e) {
|
|
3494
|
+
logger.error("Failed to fetch usage: " + e.message);
|
|
3610
3495
|
}
|
|
3611
3496
|
}
|
|
3612
3497
|
}
|
|
3613
3498
|
async cmdPlans() {
|
|
3614
|
-
console.log();
|
|
3615
3499
|
const table = new Table3({
|
|
3616
3500
|
head: [
|
|
3617
3501
|
chalk7.bold("Plan"),
|
|
@@ -3621,102 +3505,100 @@ ${recent[recent.length - 1].content}`;
|
|
|
3621
3505
|
chalk7.bold("Projects"),
|
|
3622
3506
|
chalk7.bold("Seats")
|
|
3623
3507
|
],
|
|
3624
|
-
|
|
3508
|
+
style: { head: [], border: ["dim"] }
|
|
3625
3509
|
});
|
|
3510
|
+
const currentPlan = this.userProfile?.subscription_plan?.toLowerCase() || "";
|
|
3626
3511
|
for (const plan of DEMO_PLANS) {
|
|
3627
|
-
const
|
|
3628
|
-
const nameStr =
|
|
3512
|
+
const isCurrent = this.isAuthenticated && currentPlan === plan.name.toLowerCase();
|
|
3513
|
+
const nameStr = isCurrent ? chalk7.cyan.bold(plan.name) + chalk7.dim(" \u2190") : plan.name;
|
|
3629
3514
|
table.push([nameStr, plan.price, plan.tokens_day, plan.models, plan.projects, plan.seats]);
|
|
3630
3515
|
}
|
|
3631
3516
|
console.log(table.toString());
|
|
3632
3517
|
console.log();
|
|
3633
3518
|
if (this.isAuthenticated) {
|
|
3634
|
-
|
|
3635
|
-
console.log(chalk7.dim(` Your plan: ${currentPlan.toUpperCase()}. Upgrade at https://devwing.ai/dashboard/billing`));
|
|
3519
|
+
console.log(chalk7.dim(` Your plan: ${currentPlan.toUpperCase()} \xB7 Upgrade at devwing.ai/dashboard/billing`));
|
|
3636
3520
|
} else {
|
|
3637
|
-
console.log(chalk7.dim(" Sign up at
|
|
3521
|
+
console.log(chalk7.dim(" Sign up at devwing.ai"));
|
|
3638
3522
|
}
|
|
3639
3523
|
}
|
|
3640
3524
|
async cmdContext() {
|
|
3641
|
-
console.log();
|
|
3642
3525
|
if (this.isDemo) {
|
|
3643
|
-
const
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
"
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
console.log(
|
|
3526
|
+
const W = 58;
|
|
3527
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3528
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3529
|
+
const div = chalk7.dim("\u251C" + "\u2500".repeat(W - 2) + "\u2524");
|
|
3530
|
+
const row = (k, v) => {
|
|
3531
|
+
const rawV = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3532
|
+
const pad = W - 4 - k.length - rawV.length;
|
|
3533
|
+
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3534
|
+
};
|
|
3535
|
+
const fileRow = (f) => {
|
|
3536
|
+
const pad = W - 4 - 2 - f.length;
|
|
3537
|
+
return chalk7.dim("\u2502 ") + chalk7.dim("\xB7") + " " + chalk7.cyan(f) + " ".repeat(Math.max(0, pad)) + chalk7.dim("\u2502");
|
|
3538
|
+
};
|
|
3539
|
+
const textRow = (t) => {
|
|
3540
|
+
const pad = W - 4 - t.length;
|
|
3541
|
+
return chalk7.dim("\u2502 ") + t + " ".repeat(Math.max(0, pad)) + chalk7.dim(" \u2502");
|
|
3542
|
+
};
|
|
3543
|
+
console.log(top);
|
|
3544
|
+
console.log(row("Directory", chalk7.cyan(process.cwd().replace(process.env.HOME || "", "~"))));
|
|
3545
|
+
console.log(row("Git Branch", "main"));
|
|
3546
|
+
console.log(row("Files Loaded", "34"));
|
|
3547
|
+
console.log(row("Framework", "FastAPI + TypeScript"));
|
|
3548
|
+
console.log(row("Shell", process.env.SHELL?.split("/").pop() || "unknown"));
|
|
3549
|
+
console.log(div);
|
|
3550
|
+
console.log(textRow(chalk7.bold("Top files in context")));
|
|
3551
|
+
const files = ["src/auth/auth_controller.ts", "src/middleware/jwt.middleware.ts", "src/services/user_service.ts", "src/auth/repositories/user.repository.ts", "package.json", "docker-compose.yml"];
|
|
3552
|
+
for (const f of files) console.log(fileRow(f));
|
|
3553
|
+
console.log(textRow(chalk7.dim("... and 28 more")));
|
|
3554
|
+
console.log(bottom);
|
|
3670
3555
|
} else if (this.sessionContext) {
|
|
3671
|
-
console.log(`
|
|
3672
|
-
console.log(`
|
|
3673
|
-
console.log(` Files: ${this.sessionContext.files.length}`);
|
|
3674
|
-
if (this.sessionContext.git_branch) {
|
|
3675
|
-
console.log(` Git Branch: ${this.sessionContext.git_branch}`);
|
|
3676
|
-
}
|
|
3556
|
+
console.log(` Dir: ${chalk7.cyan(this.sessionContext.cwd)} \xB7 Shell: ${this.sessionContext.shell} \xB7 Files: ${this.sessionContext.files.length}`);
|
|
3557
|
+
if (this.sessionContext.git_branch) console.log(` Branch: ${this.sessionContext.git_branch}`);
|
|
3677
3558
|
console.log();
|
|
3678
|
-
console.log(chalk7.bold(" Files in context:"));
|
|
3679
3559
|
for (const f of this.sessionContext.files.slice(0, 10)) {
|
|
3680
|
-
console.log(`
|
|
3560
|
+
console.log(` ${chalk7.dim("\xB7")} ${chalk7.cyan(f.path)}`);
|
|
3681
3561
|
}
|
|
3682
3562
|
if (this.sessionContext.files.length > 10) {
|
|
3683
|
-
console.log(chalk7.dim(`
|
|
3563
|
+
console.log(chalk7.dim(` ... and ${this.sessionContext.files.length - 10} more`));
|
|
3684
3564
|
}
|
|
3685
3565
|
} else {
|
|
3686
3566
|
logger.info("No context loaded yet. Send a message to load context.");
|
|
3687
3567
|
}
|
|
3688
3568
|
}
|
|
3689
3569
|
async cmdHistory() {
|
|
3690
|
-
|
|
3691
|
-
if (this.conversationHistory.length === 0) {
|
|
3570
|
+
if (!this.conversationHistory.length) {
|
|
3692
3571
|
logger.info("No conversation history yet.");
|
|
3693
3572
|
return;
|
|
3694
3573
|
}
|
|
3574
|
+
console.log();
|
|
3695
3575
|
for (const msg of this.conversationHistory.slice(-20)) {
|
|
3696
|
-
const label = msg.role === "user" ? chalk7.green.bold("You") : chalk7.cyan.bold("DevWing");
|
|
3576
|
+
const label = msg.role === "user" ? chalk7.green.bold("You ") : chalk7.cyan.bold("DevWing ");
|
|
3697
3577
|
const time = chalk7.dim(msg.timestamp.toLocaleTimeString());
|
|
3698
|
-
const preview = msg.content.length >
|
|
3699
|
-
console.log(` ${time}
|
|
3578
|
+
const preview = msg.content.length > 100 ? msg.content.substring(0, 100) + "\u2026" : msg.content;
|
|
3579
|
+
console.log(` ${time} ${label} ${preview}`);
|
|
3700
3580
|
}
|
|
3701
3581
|
}
|
|
3702
3582
|
async cmdConfig(args) {
|
|
3703
3583
|
if (!args) {
|
|
3704
|
-
console.log();
|
|
3705
3584
|
const config = configManager.getAll();
|
|
3706
|
-
const
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
);
|
|
3717
|
-
console.log(
|
|
3718
|
-
console.log();
|
|
3719
|
-
console.log(chalk7.dim(
|
|
3585
|
+
const W = 56;
|
|
3586
|
+
const top = chalk7.dim("\u256D" + "\u2500".repeat(W - 2) + "\u256E");
|
|
3587
|
+
const bottom = chalk7.dim("\u2570" + "\u2500".repeat(W - 2) + "\u256F");
|
|
3588
|
+
const row = (k, v) => {
|
|
3589
|
+
const rawV = v.replace(/\x1B\[[0-9;]*m/g, "");
|
|
3590
|
+
const pad = W - 4 - k.length - rawV.length;
|
|
3591
|
+
return chalk7.dim("\u2502 ") + chalk7.bold(k) + " ".repeat(Math.max(0, pad)) + v + chalk7.dim(" \u2502");
|
|
3592
|
+
};
|
|
3593
|
+
console.log(top);
|
|
3594
|
+
console.log(row("API URL", chalk7.dim(config.apiUrl || "default")));
|
|
3595
|
+
console.log(row("Workspace", chalk7.dim(config.workspaceId || "none")));
|
|
3596
|
+
console.log(row("Project", chalk7.dim(config.projectId || "none")));
|
|
3597
|
+
console.log(row("Model", chalk7.dim(config.model || "auto")));
|
|
3598
|
+
console.log(row("Mode", chalk7.dim(config.mode || "general")));
|
|
3599
|
+
console.log(row("Config", chalk7.dim(configManager.getPath())));
|
|
3600
|
+
console.log(bottom);
|
|
3601
|
+
console.log(chalk7.dim(" /config set <key> <value> \xB7 /config get <key>"));
|
|
3720
3602
|
return;
|
|
3721
3603
|
}
|
|
3722
3604
|
const parts = args.split(/\s+/);
|