devwing 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import chalk3 from 'chalk';
4
- import inquirer from 'inquirer';
3
+ import chalk7 from 'chalk';
4
+ import inquirer5 from 'inquirer';
5
5
  import axios2 from 'axios';
6
6
  import Conf from 'conf';
7
7
  import { AsyncEntry } from '@napi-rs/keyring';
@@ -401,37 +401,37 @@ var Logger = class {
401
401
  * Success message
402
402
  */
403
403
  success(message) {
404
- console.log(chalk3.green("\u2713"), message);
404
+ console.log(chalk7.green("\u2713"), message);
405
405
  }
406
406
  /**
407
407
  * Error message
408
408
  */
409
409
  error(message, error) {
410
- console.log(chalk3.red("\u2717"), message);
410
+ console.log(chalk7.red("\u2717"), message);
411
411
  if (error && process.env.DEBUG) {
412
- console.error(chalk3.gray(error.stack || error));
412
+ console.error(chalk7.gray(error.stack || error));
413
413
  }
414
414
  }
415
415
  /**
416
416
  * Warning message
417
417
  */
418
418
  warn(message) {
419
- console.log(chalk3.yellow("\u26A0"), message);
419
+ console.log(chalk7.yellow("\u26A0"), message);
420
420
  }
421
421
  /**
422
422
  * Info message
423
423
  */
424
424
  info(message) {
425
- console.log(chalk3.blue("\u2139"), message);
425
+ console.log(chalk7.blue("\u2139"), message);
426
426
  }
427
427
  /**
428
428
  * Debug message (only shown if DEBUG env var is set)
429
429
  */
430
430
  debug(message, data) {
431
431
  if (process.env.DEBUG) {
432
- console.log(chalk3.gray("\u2699"), chalk3.gray(message));
432
+ console.log(chalk7.gray("\u2699"), chalk7.gray(message));
433
433
  if (data) {
434
- console.log(chalk3.gray(JSON.stringify(data, null, 2)));
434
+ console.log(chalk7.gray(JSON.stringify(data, null, 2)));
435
435
  }
436
436
  }
437
437
  }
@@ -530,7 +530,7 @@ async function loginCommand() {
530
530
  try {
531
531
  const existingKey = await configManager.getApiKey();
532
532
  if (existingKey) {
533
- const { overwrite } = await inquirer.prompt([
533
+ const { overwrite } = await inquirer5.prompt([
534
534
  {
535
535
  type: "confirm",
536
536
  name: "overwrite",
@@ -545,7 +545,7 @@ async function loginCommand() {
545
545
  }
546
546
  logger.printBanner();
547
547
  logger.newline();
548
- const { method } = await inquirer.prompt([
548
+ const { method } = await inquirer5.prompt([
549
549
  {
550
550
  type: "list",
551
551
  name: "method",
@@ -573,7 +573,7 @@ async function loginCommand() {
573
573
  }
574
574
  }
575
575
  async function loginWithEmail() {
576
- const { email, password } = await inquirer.prompt([
576
+ const { email, password } = await inquirer5.prompt([
577
577
  {
578
578
  type: "input",
579
579
  name: "email",
@@ -604,7 +604,7 @@ async function loginWithEmail() {
604
604
  if (loginResult.requires_2fa) {
605
605
  logger.succeedSpinner("Credentials verified");
606
606
  logger.info("Two-factor authentication is enabled on your account");
607
- const { totpCode } = await inquirer.prompt([
607
+ const { totpCode } = await inquirer5.prompt([
608
608
  {
609
609
  type: "input",
610
610
  name: "totpCode",
@@ -657,10 +657,10 @@ async function loginWithBrowser() {
657
657
  logger.success("Browser opened! Please log in to authorize this device.");
658
658
  } catch {
659
659
  logger.warn("Could not open browser automatically.");
660
- logger.info(`Please visit: ${chalk3.cyan(verifyUrl)}`);
660
+ logger.info(`Please visit: ${chalk7.cyan(verifyUrl)}`);
661
661
  }
662
662
  logger.newline();
663
- logger.info(chalk3.dim(`Device code: ${initResponse.user_code.substring(0, 8)}...`));
663
+ logger.info(chalk7.dim(`Device code: ${initResponse.user_code.substring(0, 8)}...`));
664
664
  logger.startSpinner("Waiting for authorization...");
665
665
  const pollInterval = (initResponse.interval || 5) * 1e3;
666
666
  const maxAttempts = Math.floor((initResponse.expires_in || 900) / (initResponse.interval || 5));
@@ -719,7 +719,7 @@ async function loginWithApiKey() {
719
719
  );
720
720
  logger.info(`Get your API key from the ${dashboardUrl}`);
721
721
  logger.newline();
722
- const { apiKey } = await inquirer.prompt([
722
+ const { apiKey } = await inquirer5.prompt([
723
723
  {
724
724
  type: "password",
725
725
  name: "apiKey",
@@ -759,7 +759,7 @@ async function logoutCommand() {
759
759
  logger.info("You are not logged in");
760
760
  return;
761
761
  }
762
- const { confirm } = await inquirer.prompt([
762
+ const { confirm } = await inquirer5.prompt([
763
763
  {
764
764
  type: "confirm",
765
765
  name: "confirm",
@@ -796,15 +796,15 @@ async function statusCommand() {
796
796
  const plan = getUserPlan(user);
797
797
  logger.succeedSpinner("Authenticated");
798
798
  logger.newline();
799
- console.log(chalk3.bold("User Profile:"));
799
+ console.log(chalk7.bold("User Profile:"));
800
800
  console.log(` Email: ${user.email}`);
801
801
  console.log(` Name: ${getUserDisplayName(user)}`);
802
802
  console.log(` Plan: ${plan.toUpperCase()}`);
803
803
  if (user.is_verified !== void 0) {
804
- console.log(` Verified: ${user.is_verified ? chalk3.green("Yes") : chalk3.yellow("No")}`);
804
+ console.log(` Verified: ${user.is_verified ? chalk7.green("Yes") : chalk7.yellow("No")}`);
805
805
  }
806
806
  if (user.totp_enabled !== void 0) {
807
- console.log(` 2FA: ${user.totp_enabled ? chalk3.green("Enabled") : chalk3.dim("Disabled")}`);
807
+ console.log(` 2FA: ${user.totp_enabled ? chalk7.green("Enabled") : chalk7.dim("Disabled")}`);
808
808
  }
809
809
  const config = configManager.getAll();
810
810
  if (config.workspaceId) {
@@ -1399,22 +1399,22 @@ Summary: ${result.summary.changes} changes, ${result.summary.insertions} inserti
1399
1399
  // src/streaming/renderer.ts
1400
1400
  marked.setOptions({
1401
1401
  renderer: new TerminalRenderer({
1402
- code: chalk3.cyan,
1403
- blockquote: chalk3.gray.italic,
1404
- html: chalk3.gray,
1405
- heading: chalk3.bold.underline,
1406
- firstHeading: chalk3.bold.magenta,
1407
- hr: chalk3.reset,
1408
- listitem: chalk3.reset,
1409
- list: chalk3.reset,
1410
- table: chalk3.reset,
1411
- paragraph: chalk3.reset,
1412
- strong: chalk3.bold,
1413
- em: chalk3.italic,
1414
- codespan: chalk3.cyan,
1415
- del: chalk3.dim.strikethrough,
1416
- link: chalk3.blue.underline,
1417
- href: chalk3.blue.underline
1402
+ code: chalk7.cyan,
1403
+ blockquote: chalk7.gray.italic,
1404
+ html: chalk7.gray,
1405
+ heading: chalk7.bold.underline,
1406
+ firstHeading: chalk7.bold.magenta,
1407
+ hr: chalk7.reset,
1408
+ listitem: chalk7.reset,
1409
+ list: chalk7.reset,
1410
+ table: chalk7.reset,
1411
+ paragraph: chalk7.reset,
1412
+ strong: chalk7.bold,
1413
+ em: chalk7.italic,
1414
+ codespan: chalk7.cyan,
1415
+ del: chalk7.dim.strikethrough,
1416
+ link: chalk7.blue.underline,
1417
+ href: chalk7.blue.underline
1418
1418
  })
1419
1419
  });
1420
1420
  var StreamingRenderer = class {
@@ -1509,10 +1509,10 @@ var StreamingRenderer = class {
1509
1509
  logger.newline();
1510
1510
  const { tool, args } = message;
1511
1511
  if (!tool) return;
1512
- logger.info(chalk3.yellow(`AI requested tool: ${chalk3.bold(tool)}`));
1512
+ logger.info(chalk7.yellow(`AI requested tool: ${chalk7.bold(tool)}`));
1513
1513
  if (args && Object.keys(args).length > 0) {
1514
- console.log(chalk3.gray("Arguments:"));
1515
- console.log(chalk3.gray(JSON.stringify(args, null, 2)));
1514
+ console.log(chalk7.gray("Arguments:"));
1515
+ console.log(chalk7.gray(JSON.stringify(args, null, 2)));
1516
1516
  }
1517
1517
  logger.newline();
1518
1518
  }
@@ -1524,11 +1524,11 @@ var StreamingRenderer = class {
1524
1524
  const results = [];
1525
1525
  for (const { tool, args } of this.pendingToolCalls) {
1526
1526
  logger.newline();
1527
- logger.info(chalk3.yellow(`Executing ${chalk3.bold(tool)}...`));
1527
+ logger.info(chalk7.yellow(`Executing ${chalk7.bold(tool)}...`));
1528
1528
  const requiresConfirmation = this.requiresConfirmation(tool);
1529
1529
  let confirmed = true;
1530
1530
  if (requiresConfirmation) {
1531
- const answers = await inquirer.prompt([
1531
+ const answers = await inquirer5.prompt([
1532
1532
  {
1533
1533
  type: "confirm",
1534
1534
  name: "confirmed",
@@ -1557,9 +1557,9 @@ var StreamingRenderer = class {
1557
1557
  const content = result.output || "";
1558
1558
  const preview = content.substring(0, 500);
1559
1559
  if (preview.length < content.length) {
1560
- console.log(chalk3.gray(preview + "... (truncated)"));
1560
+ console.log(chalk7.gray(preview + "... (truncated)"));
1561
1561
  } else {
1562
- console.log(chalk3.gray(preview));
1562
+ console.log(chalk7.gray(preview));
1563
1563
  }
1564
1564
  results.push({
1565
1565
  tool,
@@ -1597,9 +1597,9 @@ var StreamingRenderer = class {
1597
1597
  if (message.content) {
1598
1598
  const preview = message.content.substring(0, 500);
1599
1599
  if (preview.length < message.content.length) {
1600
- console.log(chalk3.gray(preview + "... (truncated)"));
1600
+ console.log(chalk7.gray(preview + "... (truncated)"));
1601
1601
  } else {
1602
- console.log(chalk3.gray(preview));
1602
+ console.log(chalk7.gray(preview));
1603
1603
  }
1604
1604
  }
1605
1605
  logger.newline();
@@ -1613,7 +1613,7 @@ var StreamingRenderer = class {
1613
1613
  if (message.usage) {
1614
1614
  const { tokens_in, tokens_out, cost_usd } = message.usage;
1615
1615
  console.log(
1616
- chalk3.gray(
1616
+ chalk7.gray(
1617
1617
  `\u{1F4CA} Tokens: ${tokens_in.toLocaleString()} in, ${tokens_out.toLocaleString()} out | Cost: $${cost_usd.toFixed(4)}`
1618
1618
  )
1619
1619
  );
@@ -1791,7 +1791,7 @@ async function memorySave(projectId, content) {
1791
1791
  logger.error("Please provide content to save");
1792
1792
  return;
1793
1793
  }
1794
- const { type } = await inquirer.prompt([
1794
+ const { type } = await inquirer5.prompt([
1795
1795
  {
1796
1796
  type: "list",
1797
1797
  name: "type",
@@ -1832,7 +1832,7 @@ async function memoryShow(projectId) {
1832
1832
  for (const memory of memories) {
1833
1833
  const preview = memory.content.length > 100 ? memory.content.substring(0, 100) + "..." : memory.content;
1834
1834
  table.push([
1835
- chalk3.cyan(memory.type),
1835
+ chalk7.cyan(memory.type),
1836
1836
  preview,
1837
1837
  new Date(memory.created_at).toLocaleDateString()
1838
1838
  ]);
@@ -1844,7 +1844,7 @@ async function memoryShow(projectId) {
1844
1844
  }
1845
1845
  }
1846
1846
  async function memoryClear(projectId) {
1847
- const { confirm } = await inquirer.prompt([
1847
+ const { confirm } = await inquirer5.prompt([
1848
1848
  {
1849
1849
  type: "confirm",
1850
1850
  name: "confirm",
@@ -1873,7 +1873,7 @@ async function configCommand(action, key, value) {
1873
1873
  if (!action || action === "list") {
1874
1874
  const config = configManager.getAll();
1875
1875
  const apiKey = await configManager.getApiKey();
1876
- console.log(chalk3.bold("Current Configuration:"));
1876
+ console.log(chalk7.bold("Current Configuration:"));
1877
1877
  console.log(` API URL: ${config.apiUrl}`);
1878
1878
  console.log(` API Key: ${apiKey ? apiKey.substring(0, 12) + "..." : "Not set"}`);
1879
1879
  console.log(` Workspace: ${config.workspaceId || "Not set"}`);
@@ -1881,7 +1881,7 @@ async function configCommand(action, key, value) {
1881
1881
  console.log(` Model: ${config.model || "Auto"}`);
1882
1882
  console.log(` Mode: ${config.mode || "Auto"}`);
1883
1883
  console.log();
1884
- console.log(chalk3.gray(`Config file: ${configManager.getPath()}`));
1884
+ console.log(chalk7.gray(`Config file: ${configManager.getPath()}`));
1885
1885
  return;
1886
1886
  }
1887
1887
  if (action === "get") {
@@ -1972,26 +1972,26 @@ async function handleSpecialCommand(command, session, options) {
1972
1972
  const mainCmd = parts[0].toLowerCase();
1973
1973
  if (cmd === "/help") {
1974
1974
  logger.box([
1975
- chalk3.bold("DevWing Chat Commands:"),
1975
+ chalk7.bold("DevWing Chat Commands:"),
1976
1976
  "",
1977
- chalk3.bold.yellow("Navigation & Session:"),
1978
- chalk3.cyan("/help") + " - Show this help message",
1979
- chalk3.cyan("/exit, /quit") + " - Exit chat mode",
1980
- chalk3.cyan("/clear") + " - Clear conversation history",
1981
- chalk3.cyan("/context") + " - Show current context",
1982
- chalk3.cyan("/history") + " - Show conversation history",
1977
+ chalk7.bold.yellow("Navigation & Session:"),
1978
+ chalk7.cyan("/help") + " - Show this help message",
1979
+ chalk7.cyan("/exit, /quit") + " - Exit chat mode",
1980
+ chalk7.cyan("/clear") + " - Clear conversation history",
1981
+ chalk7.cyan("/context") + " - Show current context",
1982
+ chalk7.cyan("/history") + " - Show conversation history",
1983
1983
  "",
1984
- chalk3.bold.yellow("Specialized Commands:"),
1985
- chalk3.cyan("/scan") + " - Run security vulnerability scan",
1986
- chalk3.cyan("/review") + " - Perform code review",
1987
- chalk3.cyan("/explain <target>") + " - Explain code, file, or concept",
1984
+ chalk7.bold.yellow("Specialized Commands:"),
1985
+ chalk7.cyan("/scan") + " - Run security vulnerability scan",
1986
+ chalk7.cyan("/review") + " - Perform code review",
1987
+ chalk7.cyan("/explain <target>") + " - Explain code, file, or concept",
1988
1988
  "",
1989
- chalk3.bold.yellow("Project Memory:"),
1990
- chalk3.cyan("/memory save <content>") + " - Save note to project memory",
1991
- chalk3.cyan("/memory show") + " - Show all project memories",
1992
- chalk3.cyan("/memory clear") + " - Clear all project memories",
1989
+ chalk7.bold.yellow("Project Memory:"),
1990
+ chalk7.cyan("/memory save <content>") + " - Save note to project memory",
1991
+ chalk7.cyan("/memory show") + " - Show all project memories",
1992
+ chalk7.cyan("/memory clear") + " - Clear all project memories",
1993
1993
  "",
1994
- chalk3.dim("Just type your message to chat with DevWing!")
1994
+ chalk7.dim("Just type your message to chat with DevWing!")
1995
1995
  ].join("\n"), { title: "Chat Commands", color: "blue" });
1996
1996
  return true;
1997
1997
  }
@@ -2013,9 +2013,9 @@ async function handleSpecialCommand(command, session, options) {
2013
2013
  return true;
2014
2014
  }
2015
2015
  logger.box([
2016
- chalk3.bold("Current Context:"),
2016
+ chalk7.bold("Current Context:"),
2017
2017
  "",
2018
- `Working Directory: ${chalk3.cyan(context.cwd)}`,
2018
+ `Working Directory: ${chalk7.cyan(context.cwd)}`,
2019
2019
  `Shell: ${context.shell}`,
2020
2020
  `OS: ${context.os}`,
2021
2021
  `Files: ${context.files.length}`,
@@ -2034,7 +2034,7 @@ async function handleSpecialCommand(command, session, options) {
2034
2034
  return true;
2035
2035
  }
2036
2036
  logger.box([
2037
- chalk3.bold("Conversation History:"),
2037
+ chalk7.bold("Conversation History:"),
2038
2038
  "",
2039
2039
  session.getConversationSummary()
2040
2040
  ].join("\n"), { title: "History", color: "magenta" });
@@ -2090,11 +2090,11 @@ async function handleSpecialCommand(command, session, options) {
2090
2090
  }
2091
2091
  function printWelcomeBanner() {
2092
2092
  logger.box([
2093
- chalk3.bold.cyan("DevWing AI - Interactive Chat Mode"),
2093
+ chalk7.bold.cyan("DevWing AI - Interactive Chat Mode"),
2094
2094
  "",
2095
2095
  "Chat with AI about your codebase. Type your message and press Enter.",
2096
2096
  "",
2097
- chalk3.dim("Type /help for commands \u2022 /exit to quit")
2097
+ chalk7.dim("Type /help for commands \u2022 /exit to quit")
2098
2098
  ].join("\n"), { title: "\u{1F680} Welcome", color: "cyan" });
2099
2099
  }
2100
2100
  async function chatCommand(options) {
@@ -2111,7 +2111,7 @@ async function chatCommand(options) {
2111
2111
  const rl = readline.createInterface({
2112
2112
  input: process.stdin,
2113
2113
  output: process.stdout,
2114
- prompt: chalk3.bold.green("You: ")
2114
+ prompt: chalk7.bold.green("You: ")
2115
2115
  });
2116
2116
  rl.on("SIGINT", () => {
2117
2117
  logger.newline();
@@ -2144,7 +2144,7 @@ async function chatCommand(options) {
2144
2144
  }
2145
2145
  session.addMessage("user", userMessage);
2146
2146
  logger.newline();
2147
- logger.info(chalk3.dim("DevWing is thinking..."));
2147
+ logger.info(chalk7.dim("DevWing is thinking..."));
2148
2148
  logger.newline();
2149
2149
  try {
2150
2150
  const request = {
@@ -2310,14 +2310,14 @@ function installUpdate(packageName, packageManager, version) {
2310
2310
  }
2311
2311
  function displayUpdateInfo(currentVersion, latestVersion) {
2312
2312
  console.log();
2313
- console.log(chalk3.cyan("\u2501".repeat(60)));
2314
- console.log(chalk3.bold.cyan(" DevWing CLI Update Available"));
2315
- console.log(chalk3.cyan("\u2501".repeat(60)));
2313
+ console.log(chalk7.cyan("\u2501".repeat(60)));
2314
+ console.log(chalk7.bold.cyan(" DevWing CLI Update Available"));
2315
+ console.log(chalk7.cyan("\u2501".repeat(60)));
2316
2316
  console.log();
2317
- console.log(` ${chalk3.gray("Current version:")} ${chalk3.yellow(currentVersion)}`);
2318
- console.log(` ${chalk3.gray("Latest version:")} ${chalk3.green(latestVersion)}`);
2317
+ console.log(` ${chalk7.gray("Current version:")} ${chalk7.yellow(currentVersion)}`);
2318
+ console.log(` ${chalk7.gray("Latest version:")} ${chalk7.green(latestVersion)}`);
2319
2319
  console.log();
2320
- console.log(chalk3.gray(" Changelog: https://github.com/devwing/devwing/releases"));
2320
+ console.log(chalk7.gray(" Changelog: https://github.com/devwing/devwing/releases"));
2321
2321
  console.log();
2322
2322
  }
2323
2323
  async function updateCommand(options) {
@@ -2325,7 +2325,7 @@ async function updateCommand(options) {
2325
2325
  const currentVersion = getCurrentVersion();
2326
2326
  const packageName = getPackageName();
2327
2327
  console.log();
2328
- console.log(chalk3.cyan(`\u{1F4E6} DevWing CLI v${currentVersion}`));
2328
+ console.log(chalk7.cyan(`\u{1F4E6} DevWing CLI v${currentVersion}`));
2329
2329
  console.log();
2330
2330
  logger.startSpinner("Checking for updates...");
2331
2331
  const latestVersion = await getLatestVersion(packageName);
@@ -2349,9 +2349,9 @@ async function updateCommand(options) {
2349
2349
  logger.error("No package manager found. Please install npm, pnpm, or yarn.");
2350
2350
  return;
2351
2351
  }
2352
- logger.info(`Detected package manager: ${chalk3.cyan(packageManager)}`);
2352
+ logger.info(`Detected package manager: ${chalk7.cyan(packageManager)}`);
2353
2353
  if (!options?.force) {
2354
- const { confirm } = await inquirer.prompt([
2354
+ const { confirm } = await inquirer5.prompt([
2355
2355
  {
2356
2356
  type: "confirm",
2357
2357
  name: "confirm",
@@ -2370,13 +2370,13 @@ async function updateCommand(options) {
2370
2370
  console.log();
2371
2371
  logger.success(`Successfully updated to v${latestVersion}`);
2372
2372
  console.log();
2373
- console.log(chalk3.gray(' Run "devwing --version" to verify'));
2373
+ console.log(chalk7.gray(' Run "devwing --version" to verify'));
2374
2374
  console.log();
2375
2375
  } else {
2376
2376
  console.log();
2377
2377
  logger.error("Update failed. Please try manually:");
2378
2378
  console.log();
2379
- console.log(chalk3.gray(` ${packageManager} install -g ${packageName}@${latestVersion}`));
2379
+ console.log(chalk7.gray(` ${packageManager} install -g ${packageName}@${latestVersion}`));
2380
2380
  console.log();
2381
2381
  process.exit(1);
2382
2382
  }
@@ -2385,6 +2385,770 @@ async function updateCommand(options) {
2385
2385
  process.exit(1);
2386
2386
  }
2387
2387
  }
2388
+ var TYPING_SPEED = 16;
2389
+ var PAUSE_SHORT = 300;
2390
+ var PAUSE_MEDIUM = 800;
2391
+ var PAUSE_LONG = 1500;
2392
+ function sleep(ms) {
2393
+ return new Promise((resolve) => setTimeout(resolve, ms));
2394
+ }
2395
+ async function typeOut(text, speed = TYPING_SPEED) {
2396
+ for (const char of text) {
2397
+ process.stdout.write(char);
2398
+ await sleep(speed);
2399
+ }
2400
+ }
2401
+ async function typeLine(text, speed = TYPING_SPEED) {
2402
+ await typeOut(text, speed);
2403
+ process.stdout.write("\n");
2404
+ }
2405
+ var DEMO_USER = {
2406
+ email: "aliyu@devwing.ai",
2407
+ full_name: "Aliyu Mohammed",
2408
+ subscription_plan: "pro"};
2409
+ var DEMO_API_KEY = "dw_sk_demo_4xK9mQzR2pLvBnWcYjEtHuFi";
2410
+ var DEMO_PASSWORD = "DevWing2026!";
2411
+ var DEMO_WORKSPACE = {
2412
+ name: "Kano State Government",
2413
+ plan: "enterprise"};
2414
+ var DEMO_PROJECT = {
2415
+ name: "Kano Smart API"};
2416
+ var DEMO_MEMORIES = [
2417
+ { id: "mem_001", type: "rule", content: "All API responses must include Hausa language support", created_at: "2026-03-01T10:00:00Z" },
2418
+ { id: "mem_002", type: "context", content: "Auth uses JWT with RS256 signing, 1hr expiry, refresh tokens in Redis", created_at: "2026-03-05T14:00:00Z" },
2419
+ { id: "mem_003", type: "decision", content: "Chose PostgreSQL over MongoDB for ACID compliance \u2014 government data requires strict consistency", created_at: "2026-03-10T09:00:00Z" },
2420
+ { id: "mem_004", type: "summary", content: 'Kano Smart serves 16M residents via kanostate.gov.ng and smart.kano.gov.ng \u2014 all responses branded "Powered by devwing.ai"', created_at: "2026-03-15T11:00:00Z" }
2421
+ ];
2422
+ async function demoLoginCommand() {
2423
+ try {
2424
+ const existingKey = await configManager.getApiKey();
2425
+ if (existingKey) {
2426
+ const { overwrite } = await inquirer5.prompt([
2427
+ {
2428
+ type: "confirm",
2429
+ name: "overwrite",
2430
+ message: "You are already logged in. Do you want to log in with a different account?",
2431
+ default: false
2432
+ }
2433
+ ]);
2434
+ if (!overwrite) {
2435
+ logger.info("Login cancelled");
2436
+ return;
2437
+ }
2438
+ }
2439
+ logger.printBanner();
2440
+ logger.newline();
2441
+ const { method } = await inquirer5.prompt([
2442
+ {
2443
+ type: "list",
2444
+ name: "method",
2445
+ message: "How would you like to authenticate?",
2446
+ choices: [
2447
+ { name: "Via Browser (easiest)", value: "browser" },
2448
+ { name: "Email & Password", value: "email" },
2449
+ { name: "API Key (from dashboard)", value: "apikey" }
2450
+ ]
2451
+ }
2452
+ ]);
2453
+ if (method === "email") {
2454
+ await demoLoginEmail();
2455
+ } else if (method === "browser") {
2456
+ await demoLoginBrowser();
2457
+ } else {
2458
+ await demoLoginApiKey();
2459
+ }
2460
+ } catch (error) {
2461
+ logger.error("Login failed");
2462
+ if (error.message) logger.error(error.message);
2463
+ process.exit(1);
2464
+ }
2465
+ }
2466
+ async function demoLoginEmail() {
2467
+ const { email, password } = await inquirer5.prompt([
2468
+ {
2469
+ type: "input",
2470
+ name: "email",
2471
+ message: "Email:",
2472
+ validate: (input) => {
2473
+ if (!input.includes("@") || !input.includes(".")) return "Please enter a valid email address";
2474
+ return true;
2475
+ }
2476
+ },
2477
+ {
2478
+ type: "password",
2479
+ name: "password",
2480
+ message: "Password:",
2481
+ mask: "*"
2482
+ }
2483
+ ]);
2484
+ logger.startSpinner("Authenticating...");
2485
+ await sleep(1200);
2486
+ if (email !== DEMO_USER.email || password !== DEMO_PASSWORD) {
2487
+ logger.failSpinner("Authentication failed");
2488
+ logger.error("Incorrect email or password");
2489
+ return;
2490
+ }
2491
+ logger.updateSpinner("Creating API key...");
2492
+ await sleep(800);
2493
+ await configManager.setApiKey(DEMO_API_KEY);
2494
+ logger.succeedSpinner(`Welcome back, ${DEMO_USER.full_name}!`);
2495
+ logger.success(`Plan: ${DEMO_USER.subscription_plan.toUpperCase()}`);
2496
+ logger.newline();
2497
+ showQuickStart2();
2498
+ }
2499
+ async function demoLoginBrowser() {
2500
+ logger.startSpinner("Initiating browser authentication...");
2501
+ await sleep(1e3);
2502
+ logger.succeedSpinner("Device code created");
2503
+ logger.newline();
2504
+ logger.success("Browser opened! Please log in to authorize this device.");
2505
+ logger.newline();
2506
+ logger.info(chalk7.dim("Device code: fSibdCwR..."));
2507
+ logger.startSpinner("Waiting for authorization...");
2508
+ await sleep(3e3);
2509
+ logger.updateSpinner("Authorization received!");
2510
+ await sleep(500);
2511
+ await configManager.setApiKey(DEMO_API_KEY);
2512
+ logger.updateSpinner("Fetching profile...");
2513
+ await sleep(600);
2514
+ logger.succeedSpinner(`Welcome, ${DEMO_USER.full_name}!`);
2515
+ logger.success(`Plan: ${DEMO_USER.subscription_plan.toUpperCase()}`);
2516
+ logger.newline();
2517
+ showQuickStart2();
2518
+ }
2519
+ async function demoLoginApiKey() {
2520
+ logger.info(`Get your API key from the dashboard`);
2521
+ logger.newline();
2522
+ const { apiKey } = await inquirer5.prompt([
2523
+ {
2524
+ type: "password",
2525
+ name: "apiKey",
2526
+ message: "API Key:",
2527
+ mask: "*",
2528
+ validate: (input) => {
2529
+ if (!input.startsWith("dw_sk_")) return 'Invalid API key format. Should start with "dw_sk_"';
2530
+ if (input.length < 20) return "API key seems too short";
2531
+ return true;
2532
+ }
2533
+ }
2534
+ ]);
2535
+ logger.startSpinner("Verifying API key...");
2536
+ await sleep(1e3);
2537
+ if (apiKey !== DEMO_API_KEY) {
2538
+ logger.failSpinner("Invalid API key");
2539
+ logger.error("API key not recognized");
2540
+ return;
2541
+ }
2542
+ await configManager.setApiKey(apiKey);
2543
+ logger.succeedSpinner(`Authenticated as ${DEMO_USER.full_name}!`);
2544
+ logger.success(`Plan: ${DEMO_USER.subscription_plan.toUpperCase()}`);
2545
+ logger.newline();
2546
+ showQuickStart2();
2547
+ }
2548
+ function showQuickStart2() {
2549
+ logger.box(
2550
+ [
2551
+ "Quick Start:",
2552
+ "",
2553
+ ' devwing "fix the auth bug" Ask anything',
2554
+ " devwing chat Interactive chat mode",
2555
+ " devwing scan Security scan",
2556
+ " devwing review Code review",
2557
+ " devwing explain file.js Explain code",
2558
+ "",
2559
+ "For more commands, run: devwing --help"
2560
+ ].join("\n"),
2561
+ { title: "Ready to go!", color: "green" }
2562
+ );
2563
+ }
2564
+ async function demoStatusCommand() {
2565
+ const apiKey = await configManager.getApiKey();
2566
+ if (!apiKey) {
2567
+ logger.warn("Not authenticated");
2568
+ logger.info('Run "devwing login" to get started');
2569
+ return;
2570
+ }
2571
+ logger.startSpinner("Fetching profile...");
2572
+ await sleep(800);
2573
+ logger.succeedSpinner("Authenticated");
2574
+ logger.newline();
2575
+ console.log(chalk7.bold("User Profile:"));
2576
+ console.log(` Email: ${DEMO_USER.email}`);
2577
+ console.log(` Name: ${DEMO_USER.full_name}`);
2578
+ console.log(` Plan: ${DEMO_USER.subscription_plan.toUpperCase()}`);
2579
+ console.log(` Verified: ${chalk7.green("Yes")}`);
2580
+ console.log(` 2FA: ${chalk7.dim("Disabled")}`);
2581
+ console.log(` Workspace: ${DEMO_WORKSPACE.name} (${DEMO_WORKSPACE.plan})`);
2582
+ console.log(` Project: ${DEMO_PROJECT.name}`);
2583
+ logger.newline();
2584
+ }
2585
+ async function demoLogoutCommand() {
2586
+ const apiKey = await configManager.getApiKey();
2587
+ if (!apiKey) {
2588
+ logger.info("You are not logged in");
2589
+ return;
2590
+ }
2591
+ const { confirm } = await inquirer5.prompt([
2592
+ {
2593
+ type: "confirm",
2594
+ name: "confirm",
2595
+ message: "Are you sure you want to log out?",
2596
+ default: false
2597
+ }
2598
+ ]);
2599
+ if (!confirm) {
2600
+ logger.info("Logout cancelled");
2601
+ return;
2602
+ }
2603
+ await configManager.deleteApiKey();
2604
+ const apiUrl = configManager.getApiUrl();
2605
+ configManager.clear();
2606
+ configManager.setApiUrl(apiUrl);
2607
+ logger.success("Successfully logged out");
2608
+ }
2609
+ async function demoMemoryCommand(action, content) {
2610
+ if (action === "show") {
2611
+ logger.startSpinner("Loading project memory...");
2612
+ await sleep(800);
2613
+ logger.stopSpinner();
2614
+ logger.success(`Found ${DEMO_MEMORIES.length} memory items`);
2615
+ logger.newline();
2616
+ const table = new Table({
2617
+ head: [chalk7.bold("Type"), chalk7.bold("Content"), chalk7.bold("Created")],
2618
+ colWidths: [15, 60, 15],
2619
+ wordWrap: true
2620
+ });
2621
+ for (const memory of DEMO_MEMORIES) {
2622
+ const preview = memory.content.length > 80 ? memory.content.substring(0, 80) + "..." : memory.content;
2623
+ table.push([
2624
+ chalk7.cyan(memory.type),
2625
+ preview,
2626
+ new Date(memory.created_at).toLocaleDateString()
2627
+ ]);
2628
+ }
2629
+ console.log(table.toString());
2630
+ } else if (action === "save") {
2631
+ if (!content) {
2632
+ logger.error("Please provide content to save");
2633
+ return;
2634
+ }
2635
+ const { type } = await inquirer5.prompt([
2636
+ {
2637
+ type: "list",
2638
+ name: "type",
2639
+ message: "What type of memory is this?",
2640
+ choices: [
2641
+ { name: "Context (general information)", value: "context" },
2642
+ { name: "Rule (coding standard or guideline)", value: "rule" },
2643
+ { name: "Decision (architectural decision)", value: "decision" },
2644
+ { name: "Summary (project summary)", value: "summary" }
2645
+ ]
2646
+ }
2647
+ ]);
2648
+ logger.startSpinner("Saving to project memory...");
2649
+ await sleep(1e3);
2650
+ logger.succeedSpinner(`Memory saved as ${type}`);
2651
+ } else if (action === "clear") {
2652
+ const { confirm } = await inquirer5.prompt([
2653
+ {
2654
+ type: "confirm",
2655
+ name: "confirm",
2656
+ message: "Are you sure you want to clear all project memory?",
2657
+ default: false
2658
+ }
2659
+ ]);
2660
+ if (!confirm) {
2661
+ logger.info("Operation cancelled");
2662
+ return;
2663
+ }
2664
+ logger.startSpinner("Clearing project memory...");
2665
+ await sleep(800);
2666
+ logger.succeedSpinner("Project memory cleared");
2667
+ }
2668
+ }
2669
+ async function demoExplainCommand(target) {
2670
+ await requireDemoAuth();
2671
+ await showContextLoading(24, "general");
2672
+ logger.startSpinner("DevWing is thinking...");
2673
+ await sleep(1500);
2674
+ logger.stopSpinner();
2675
+ console.log();
2676
+ await typeLine(chalk7.bold.magenta(`## Explaining: ${target}`));
2677
+ console.log();
2678
+ if (target.includes("auth") || target.includes("middleware")) {
2679
+ await typeLine(`The auth middleware at ${chalk7.cyan(target)} handles request authentication:`);
2680
+ console.log();
2681
+ await typeLine(" 1. Extracts the JWT token from the `Authorization: Bearer` header");
2682
+ await typeLine(" 2. Verifies the token signature using RS256 algorithm");
2683
+ await typeLine(" 3. Checks token expiration and issuer claims");
2684
+ await typeLine(" 4. Loads the user from the database using the `sub` claim");
2685
+ await typeLine(" 5. Attaches the user object to `req.user` for downstream handlers");
2686
+ console.log();
2687
+ await typeLine(chalk7.bold("Key patterns:"));
2688
+ await typeLine(` ${chalk7.green("\u2022")} Uses decorator pattern \u2014 ${chalk7.cyan("@authenticate")} on route handlers`);
2689
+ await typeLine(` ${chalk7.green("\u2022")} Implements token refresh via ${chalk7.cyan("X-Refresh-Token")} header`);
2690
+ await typeLine(` ${chalk7.green("\u2022")} Rate limited to prevent brute force (10 req/min per IP)`);
2691
+ console.log();
2692
+ await typeLine(chalk7.dim("This middleware is critical \u2014 it protects all /api/* routes."));
2693
+ } else {
2694
+ await typeLine(`${chalk7.cyan(target)} is a core component of the system.`);
2695
+ console.log();
2696
+ await typeLine(` ${chalk7.green("\u2022")} Responsible for handling ${target}-related logic`);
2697
+ await typeLine(` ${chalk7.green("\u2022")} Integrates with the main application pipeline`);
2698
+ await typeLine(` ${chalk7.green("\u2022")} Well-structured with clear separation of concerns`);
2699
+ }
2700
+ await showUsage(1200, 680, 45e-4, "general");
2701
+ logger.success("Done!");
2702
+ }
2703
+ async function demoReviewCommand() {
2704
+ await requireDemoAuth();
2705
+ logger.info("Performing code review...");
2706
+ logger.newline();
2707
+ await showContextLoading(38, "general");
2708
+ logger.startSpinner("DevWing is thinking...");
2709
+ await sleep(2e3);
2710
+ logger.stopSpinner();
2711
+ console.log();
2712
+ await typeLine(chalk7.bold.magenta("## Code Review \u2014 Recent Changes"));
2713
+ console.log();
2714
+ await typeLine(chalk7.bold("Files reviewed: 5 | Commits: 3 | Lines changed: +142 / -67"));
2715
+ console.log();
2716
+ await typeLine(chalk7.green.bold(" \u2713 GOOD") + " \u2014 Error handling is consistent across all new endpoints");
2717
+ await typeLine(chalk7.green.bold(" \u2713 GOOD") + " \u2014 Database queries use parameterized statements");
2718
+ await typeLine(chalk7.green.bold(" \u2713 GOOD") + " \u2014 TypeScript strict mode is properly enforced");
2719
+ console.log();
2720
+ await typeLine(chalk7.yellow.bold(" \u25B2 SUGGESTION") + " \u2014 Consider extracting the validation logic at " + chalk7.cyan("user_service.ts:45"));
2721
+ await typeLine(chalk7.gray(" The email regex pattern is duplicated in 3 files. Move to a shared validator."));
2722
+ console.log();
2723
+ await typeLine(chalk7.yellow.bold(" \u25B2 SUGGESTION") + " \u2014 Missing error boundary in " + chalk7.cyan("api_handler.ts:78"));
2724
+ await typeLine(chalk7.gray(" The async handler doesn't catch unhandled promise rejections. Wrap in try/catch."));
2725
+ console.log();
2726
+ await typeLine(chalk7.red.bold(" \u25A0 ISSUE") + " \u2014 Potential memory leak in " + chalk7.cyan("websocket_manager.ts:120"));
2727
+ await typeLine(chalk7.gray(" Event listeners are added on each connection but never removed on disconnect."));
2728
+ console.log();
2729
+ await typeLine(chalk7.bold("Summary: ") + chalk7.green("3 good") + " | " + chalk7.yellow("2 suggestions") + " | " + chalk7.red("1 issue"));
2730
+ await showUsage(2800, 1200, 95e-4, "general");
2731
+ logger.success("Done!");
2732
+ }
2733
+ async function demoPromptCommand(prompt, options) {
2734
+ await requireDemoAuth();
2735
+ const promptLower = prompt.toLowerCase();
2736
+ if (promptLower.includes("refactor") && promptLower.includes("auth")) {
2737
+ await demoBackendRefactor();
2738
+ } else if (promptLower.includes("scan") || promptLower.includes("owasp") || promptLower.includes("vulnerabilit")) {
2739
+ await demoSecurityScan();
2740
+ } else if (promptLower.includes("explain")) {
2741
+ const target = prompt.replace(/explain\s*/i, "").trim() || "this code";
2742
+ await demoExplainCommand(target);
2743
+ } else if (promptLower.includes("review")) {
2744
+ await demoReviewCommand();
2745
+ } else if (promptLower.includes("deploy") || promptLower.includes("docker") || promptLower.includes("kubernetes")) {
2746
+ await demoDeployAssist();
2747
+ } else if (promptLower.includes("fix") || promptLower.includes("bug") || promptLower.includes("error")) {
2748
+ await demoBugFix();
2749
+ } else if (promptLower.includes("test") || promptLower.includes("spec")) {
2750
+ await demoWriteTests();
2751
+ } else {
2752
+ await demoGenericPrompt(prompt, options);
2753
+ }
2754
+ }
2755
+ async function demoChatCommand(options) {
2756
+ await requireDemoAuth();
2757
+ const readline2 = await import('readline');
2758
+ console.clear();
2759
+ logger.box([
2760
+ chalk7.bold.cyan("DevWing AI - Interactive Chat Mode"),
2761
+ "",
2762
+ "Chat with AI about your codebase. Type your message and press Enter.",
2763
+ "",
2764
+ chalk7.dim("Type /help for commands | /exit to quit")
2765
+ ].join("\n"), { title: "Welcome", color: "cyan" });
2766
+ logger.newline();
2767
+ logger.startSpinner("Loading codebase context...");
2768
+ await sleep(1200);
2769
+ logger.succeedSpinner("Context loaded \u2014 34 files");
2770
+ logger.newline();
2771
+ const rl = readline2.createInterface({
2772
+ input: process.stdin,
2773
+ output: process.stdout,
2774
+ prompt: chalk7.bold.green("You: ")
2775
+ });
2776
+ rl.on("SIGINT", () => {
2777
+ logger.newline();
2778
+ logger.info("Exiting chat mode...");
2779
+ rl.close();
2780
+ process.exit(0);
2781
+ });
2782
+ rl.prompt();
2783
+ rl.on("line", async (input) => {
2784
+ const msg = input.trim();
2785
+ if (!msg) {
2786
+ rl.prompt();
2787
+ return;
2788
+ }
2789
+ if (msg === "/exit" || msg === "/quit") {
2790
+ logger.info("Exiting chat mode...");
2791
+ rl.close();
2792
+ return;
2793
+ }
2794
+ if (msg === "/help") {
2795
+ logger.box([
2796
+ chalk7.bold("DevWing Chat Commands:"),
2797
+ "",
2798
+ chalk7.cyan("/help") + " \u2014 Show this message",
2799
+ chalk7.cyan("/exit") + " \u2014 Exit chat mode",
2800
+ chalk7.cyan("/scan") + " \u2014 Security scan",
2801
+ chalk7.cyan("/review") + " \u2014 Code review",
2802
+ chalk7.cyan("/context") + " \u2014 Show loaded context",
2803
+ chalk7.cyan("/memory show") + " \u2014 Show project memory"
2804
+ ].join("\n"), { title: "Commands", color: "blue" });
2805
+ logger.newline();
2806
+ rl.prompt();
2807
+ return;
2808
+ }
2809
+ if (msg === "/context") {
2810
+ logger.box([
2811
+ chalk7.bold("Current Context:"),
2812
+ "",
2813
+ `Working Directory: ${chalk7.cyan(process.cwd())}`,
2814
+ `Shell: zsh | OS: darwin`,
2815
+ `Files: 34 | Git Branch: main`,
2816
+ "",
2817
+ "Top files:",
2818
+ " \u2022 src/auth/auth_controller.ts",
2819
+ " \u2022 src/middleware/jwt.middleware.ts",
2820
+ " \u2022 src/services/user_service.ts",
2821
+ " \u2022 package.json",
2822
+ " ... and 30 more"
2823
+ ].join("\n"), { title: "Context", color: "cyan" });
2824
+ logger.newline();
2825
+ rl.prompt();
2826
+ return;
2827
+ }
2828
+ if (msg === "/memory show") {
2829
+ await demoMemoryCommand("show");
2830
+ logger.newline();
2831
+ rl.prompt();
2832
+ return;
2833
+ }
2834
+ if (msg === "/scan") {
2835
+ logger.newline();
2836
+ await demoSecurityScan();
2837
+ logger.newline();
2838
+ rl.prompt();
2839
+ return;
2840
+ }
2841
+ if (msg === "/review") {
2842
+ logger.newline();
2843
+ await demoReviewCommand();
2844
+ logger.newline();
2845
+ rl.prompt();
2846
+ return;
2847
+ }
2848
+ logger.newline();
2849
+ logger.info(chalk7.dim("DevWing is thinking..."));
2850
+ logger.newline();
2851
+ await demoPromptCommand(msg, options);
2852
+ logger.newline();
2853
+ rl.prompt();
2854
+ });
2855
+ rl.on("close", () => {
2856
+ logger.newline();
2857
+ logger.success("Chat session ended. Goodbye!");
2858
+ process.exit(0);
2859
+ });
2860
+ }
2861
+ async function demoBackendRefactor() {
2862
+ await showContextLoading(47, "backend");
2863
+ logger.startSpinner("DevWing is thinking...");
2864
+ await sleep(2e3);
2865
+ logger.stopSpinner();
2866
+ console.log();
2867
+ await typeLine(chalk7.bold.magenta("## Analysis"));
2868
+ console.log();
2869
+ await typeLine("I've analyzed the auth service across 6 files. Here's what I found:");
2870
+ console.log();
2871
+ await typeLine(` ${chalk7.red("\u2022")} Auth logic, validation, and DB queries are tightly coupled in ${chalk7.cyan("auth_controller.ts")}`);
2872
+ await typeLine(` ${chalk7.red("\u2022")} JWT validation is duplicated across 4 route handlers`);
2873
+ await typeLine(` ${chalk7.red("\u2022")} No rate limiting on login/register endpoints`);
2874
+ await typeLine(` ${chalk7.red("\u2022")} User lookup queries repeated in 3 places`);
2875
+ console.log();
2876
+ await sleep(PAUSE_MEDIUM);
2877
+ await typeLine(chalk7.bold.magenta("## Refactor Plan"));
2878
+ console.log();
2879
+ await typeLine("1. Extract JWT validation into reusable middleware");
2880
+ await typeLine("2. Create `UserRepository` with all DB operations");
2881
+ await typeLine("3. Add `RateLimiter` decorator using sliding window algorithm");
2882
+ await typeLine("4. Separate controller into thin route handlers");
2883
+ console.log();
2884
+ await sleep(PAUSE_MEDIUM);
2885
+ await typeLine(chalk7.bold.magenta("## Executing Refactor"));
2886
+ console.log();
2887
+ await showToolCall("read_file", "src/auth/auth_controller.ts");
2888
+ await showToolResult("Read 156 lines");
2889
+ await showToolCall("read_file", "src/auth/auth_routes.ts");
2890
+ await showToolResult("Read 89 lines");
2891
+ await showToolCall("read_file", "src/middleware/index.ts");
2892
+ await showToolResult("Read 23 lines");
2893
+ await showToolCall("write_file", "src/auth/repositories/user.repository.ts");
2894
+ await sleep(PAUSE_LONG);
2895
+ await showToolResult("Created \u2014 UserRepository with findByEmail, findById, create, updateLastLogin");
2896
+ await showToolCall("write_file", "src/middleware/jwt.middleware.ts");
2897
+ await sleep(PAUSE_MEDIUM);
2898
+ await showToolResult("Created \u2014 JWT validation middleware with token extraction and verification");
2899
+ await showToolCall("write_file", "src/middleware/rate-limiter.ts");
2900
+ await sleep(PAUSE_MEDIUM);
2901
+ await showToolResult("Created \u2014 Sliding window rate limiter: 10 req/min login, 5 req/min register");
2902
+ await showToolCall("write_file", "src/auth/auth_controller.ts");
2903
+ await sleep(PAUSE_LONG);
2904
+ await showToolResult("Refactored \u2014 156 lines \u2192 89 lines, clean separation of concerns");
2905
+ await showToolCall("run_command", "npm test -- --filter auth");
2906
+ await sleep(2e3);
2907
+ await showToolResult("All 12 tests passed");
2908
+ console.log();
2909
+ await sleep(PAUSE_MEDIUM);
2910
+ await typeLine(chalk7.bold.magenta("## Summary"));
2911
+ console.log();
2912
+ await typeLine(chalk7.green("\u2713") + " Extracted JWT validation to dedicated middleware");
2913
+ await typeLine(chalk7.green("\u2713") + " Created UserRepository \u2014 single source for all user DB operations");
2914
+ await typeLine(chalk7.green("\u2713") + " Added rate limiting: 10 req/min (login), 5 req/min (register)");
2915
+ await typeLine(chalk7.green("\u2713") + ` Reduced ${chalk7.red("156")} lines \u2192 ${chalk7.green("89")} lines (${chalk7.cyan("43% reduction")})`);
2916
+ await typeLine(chalk7.green("\u2713") + " All 12 existing tests pass \u2014 no regressions");
2917
+ console.log();
2918
+ await typeLine(chalk7.dim("Files modified: 4 | Files created: 3 | Lines removed: 67"));
2919
+ await showUsage(3420, 1890, 0.0127, "backend");
2920
+ logger.success("Done!");
2921
+ }
2922
+ async function demoSecurityScan() {
2923
+ await showContextLoading(32, "security");
2924
+ logger.startSpinner("DevWing is thinking...");
2925
+ await sleep(1800);
2926
+ logger.stopSpinner();
2927
+ console.log();
2928
+ await typeLine(chalk7.bold.magenta("## OWASP Security Scan \u2014 Auth Service"));
2929
+ console.log();
2930
+ await showToolCall("read_file", "src/auth/auth_controller.ts");
2931
+ await showToolResult("Read 89 lines");
2932
+ await showToolCall("read_file", "src/middleware/jwt.middleware.ts");
2933
+ await showToolResult("Read 34 lines");
2934
+ await showToolCall("read_file", "src/auth/repositories/user.repository.ts");
2935
+ await showToolResult("Read 52 lines");
2936
+ await sleep(PAUSE_LONG);
2937
+ await typeLine(chalk7.bold.red("## Vulnerabilities Found: 3"));
2938
+ console.log();
2939
+ await typeLine(chalk7.red.bold(" \u25A0 CRITICAL") + chalk7.red(" \u2014 Weak JWT Token Configuration"));
2940
+ await typeLine(chalk7.gray(" Location: src/middleware/jwt.middleware.ts:12"));
2941
+ await typeLine(chalk7.gray(" Issue: JWT tokens signed with HS256 and no expiration validation"));
2942
+ await typeLine(chalk7.gray(" OWASP: A2:2021 \u2014 Cryptographic Failures"));
2943
+ console.log();
2944
+ await typeLine(chalk7.yellow.bold(" \u25A0 HIGH") + chalk7.yellow(" \u2014 SQL Injection via User Lookup"));
2945
+ await typeLine(chalk7.gray(" Location: src/auth/repositories/user.repository.ts:18"));
2946
+ await typeLine(chalk7.gray(" Issue: Raw string interpolation in findByEmail query"));
2947
+ await typeLine(chalk7.gray(" OWASP: A3:2021 \u2014 Injection"));
2948
+ console.log();
2949
+ await typeLine(chalk7.yellow.bold(" \u25A0 MEDIUM") + chalk7.yellow(" \u2014 Missing Password Complexity Enforcement"));
2950
+ await typeLine(chalk7.gray(" Location: src/auth/auth_controller.ts:34"));
2951
+ await typeLine(chalk7.gray(" Issue: No minimum length, complexity, or breach database check"));
2952
+ await typeLine(chalk7.gray(" OWASP: A7:2021 \u2014 Identification and Authentication Failures"));
2953
+ console.log();
2954
+ await sleep(PAUSE_MEDIUM);
2955
+ await typeLine(chalk7.bold.magenta("## Applying Security Patches"));
2956
+ console.log();
2957
+ await showToolCall("write_file", "src/middleware/jwt.middleware.ts");
2958
+ await sleep(PAUSE_LONG);
2959
+ await showToolResult("Patched \u2014 Added RS256 signing, exp/iat validation, token rotation support");
2960
+ await showToolCall("write_file", "src/auth/repositories/user.repository.ts");
2961
+ await sleep(PAUSE_MEDIUM);
2962
+ await showToolResult("Patched \u2014 Parameterized queries, input sanitization added");
2963
+ await showToolCall("write_file", "src/auth/validators/password.validator.ts");
2964
+ await sleep(PAUSE_MEDIUM);
2965
+ await showToolResult("Created \u2014 Min 12 chars, uppercase, number, special char, breach check");
2966
+ await showToolCall("run_command", "npm test -- --filter auth");
2967
+ await sleep(1500);
2968
+ await showToolResult("All 15 tests passed (3 new security tests added)");
2969
+ console.log();
2970
+ await typeLine(chalk7.bold.magenta("## Scan Complete"));
2971
+ console.log();
2972
+ await typeLine(chalk7.green("\u2713") + " 3 vulnerabilities found and patched");
2973
+ await typeLine(chalk7.green("\u2713") + " JWT upgraded to RS256 with expiration enforcement");
2974
+ await typeLine(chalk7.green("\u2713") + " SQL injection eliminated via parameterized queries");
2975
+ await typeLine(chalk7.green("\u2713") + " Password policy enforced \u2014 NIST 800-63B compliant");
2976
+ await typeLine(chalk7.green("\u2713") + " 3 new security regression tests added");
2977
+ console.log();
2978
+ await typeLine(chalk7.dim("Severity breakdown: 1 critical, 1 high, 1 medium \u2014 all resolved"));
2979
+ await showUsage(2180, 1450, 89e-4, "security");
2980
+ logger.success("Done!");
2981
+ }
2982
+ async function demoDeployAssist(_prompt) {
2983
+ await showContextLoading(18, "devops");
2984
+ logger.startSpinner("DevWing is thinking...");
2985
+ await sleep(1800);
2986
+ logger.stopSpinner();
2987
+ console.log();
2988
+ await typeLine(chalk7.bold.magenta("## Deployment Analysis"));
2989
+ console.log();
2990
+ await showToolCall("read_file", "Dockerfile");
2991
+ await showToolResult("Read 28 lines");
2992
+ await showToolCall("read_file", "docker-compose.yml");
2993
+ await showToolResult("Read 45 lines");
2994
+ await showToolCall("read_file", ".github/workflows/deploy.yml");
2995
+ await showToolResult("Read 67 lines");
2996
+ await sleep(PAUSE_MEDIUM);
2997
+ await typeLine("Current deployment configuration:");
2998
+ console.log();
2999
+ await typeLine(` ${chalk7.green("\u2022")} Docker image: ${chalk7.cyan("node:20-alpine")} \u2014 multi-stage build`);
3000
+ await typeLine(` ${chalk7.green("\u2022")} Target: Railway (detected from ${chalk7.cyan("railway.toml")})`);
3001
+ await typeLine(` ${chalk7.green("\u2022")} Health check: ${chalk7.cyan("/health")} endpoint configured`);
3002
+ await typeLine(` ${chalk7.green("\u2022")} Environment: 12 vars configured, 3 secrets`);
3003
+ console.log();
3004
+ await typeLine(chalk7.bold.magenta("## Optimizations Applied"));
3005
+ console.log();
3006
+ await showToolCall("write_file", "Dockerfile");
3007
+ await sleep(PAUSE_LONG);
3008
+ await showToolResult("Optimized \u2014 Added layer caching, reduced image size from 340MB to 89MB");
3009
+ await showToolCall("write_file", "docker-compose.yml");
3010
+ await sleep(PAUSE_MEDIUM);
3011
+ await showToolResult("Added health checks, restart policies, resource limits");
3012
+ console.log();
3013
+ await typeLine(chalk7.green("\u2713") + " Docker image optimized: 340MB \u2192 89MB (74% smaller)");
3014
+ await typeLine(chalk7.green("\u2713") + " Added proper health checks and restart policies");
3015
+ await typeLine(chalk7.green("\u2713") + " Build time reduced: ~4min \u2192 ~1.5min with layer caching");
3016
+ await showUsage(1800, 950, 65e-4, "devops");
3017
+ logger.success("Done!");
3018
+ }
3019
+ async function demoBugFix(_prompt) {
3020
+ await showContextLoading(35, "backend");
3021
+ logger.startSpinner("DevWing is thinking...");
3022
+ await sleep(1800);
3023
+ logger.stopSpinner();
3024
+ console.log();
3025
+ await typeLine(chalk7.bold.magenta("## Bug Analysis"));
3026
+ console.log();
3027
+ await showToolCall("read_file", "src/services/user_service.ts");
3028
+ await showToolResult("Read 94 lines");
3029
+ await showToolCall("git_diff", "");
3030
+ await showToolResult("3 files changed, 12 insertions, 4 deletions");
3031
+ await showToolCall("git_log", "last 5 commits");
3032
+ await showToolResult("Loaded recent history");
3033
+ await sleep(PAUSE_MEDIUM);
3034
+ await typeLine("I found the issue. The bug is in " + chalk7.cyan("user_service.ts:67") + ":");
3035
+ console.log();
3036
+ await typeLine(chalk7.red(" - const user = await db.query(`SELECT * FROM users WHERE id = ${userId}`);"));
3037
+ await typeLine(chalk7.green(" + const user = await db.query(`SELECT * FROM users WHERE id = $1`, [userId]);"));
3038
+ console.log();
3039
+ await typeLine("The user ID was being interpolated directly into the SQL query instead of");
3040
+ await typeLine("using parameterized binding. This causes:");
3041
+ await typeLine(" 1. SQL injection vulnerability");
3042
+ await typeLine(" 2. Query failure when ID contains special characters");
3043
+ console.log();
3044
+ await showToolCall("write_file", "src/services/user_service.ts");
3045
+ await sleep(PAUSE_LONG);
3046
+ await showToolResult("Fixed \u2014 Parameterized query binding");
3047
+ await showToolCall("run_command", "npm test -- --filter user");
3048
+ await sleep(1500);
3049
+ await showToolResult("All 8 tests passed");
3050
+ console.log();
3051
+ await typeLine(chalk7.green("\u2713") + " Bug fixed \u2014 parameterized SQL query");
3052
+ await typeLine(chalk7.green("\u2713") + " SQL injection vulnerability closed");
3053
+ await typeLine(chalk7.green("\u2713") + " All tests pass");
3054
+ await showUsage(1650, 890, 62e-4, "backend");
3055
+ logger.success("Done!");
3056
+ }
3057
+ async function demoWriteTests(_prompt) {
3058
+ await showContextLoading(22, "backend");
3059
+ logger.startSpinner("DevWing is thinking...");
3060
+ await sleep(1800);
3061
+ logger.stopSpinner();
3062
+ console.log();
3063
+ await typeLine(chalk7.bold.magenta("## Generating Tests"));
3064
+ console.log();
3065
+ await showToolCall("read_file", "src/auth/auth_controller.ts");
3066
+ await showToolResult("Read 89 lines \u2014 4 functions to test");
3067
+ await showToolCall("read_file", "src/auth/repositories/user.repository.ts");
3068
+ await showToolResult("Read 52 lines \u2014 5 methods to test");
3069
+ await sleep(PAUSE_MEDIUM);
3070
+ await showToolCall("write_file", "tests/auth/auth_controller.test.ts");
3071
+ await sleep(PAUSE_LONG);
3072
+ await showToolResult("Created \u2014 8 test cases: login, register, refresh, logout, edge cases");
3073
+ await showToolCall("write_file", "tests/auth/user_repository.test.ts");
3074
+ await sleep(PAUSE_LONG);
3075
+ await showToolResult("Created \u2014 10 test cases: CRUD operations, error handling, constraints");
3076
+ await showToolCall("run_command", "npm test -- --filter auth");
3077
+ await sleep(2e3);
3078
+ await showToolResult("18 / 18 tests passed");
3079
+ console.log();
3080
+ await typeLine(chalk7.bold.magenta("## Test Coverage"));
3081
+ console.log();
3082
+ await typeLine(" auth_controller.ts: " + chalk7.green("94%") + " (was 0%)");
3083
+ await typeLine(" user.repository.ts: " + chalk7.green("98%") + " (was 0%)");
3084
+ await typeLine(" Overall auth module: " + chalk7.green("96%"));
3085
+ console.log();
3086
+ await typeLine(chalk7.green("\u2713") + " 18 tests generated and passing");
3087
+ await typeLine(chalk7.green("\u2713") + " Covers happy paths, edge cases, and error states");
3088
+ await showUsage(2400, 1680, 98e-4, "backend");
3089
+ logger.success("Done!");
3090
+ }
3091
+ async function demoGenericPrompt(prompt, options) {
3092
+ const mode = options.mode || "general";
3093
+ await showContextLoading(28, mode);
3094
+ logger.startSpinner("DevWing is thinking...");
3095
+ await sleep(1500);
3096
+ logger.stopSpinner();
3097
+ console.log();
3098
+ await typeLine(chalk7.bold.magenta("## Response"));
3099
+ console.log();
3100
+ await typeLine(`Based on your codebase analysis, here's my approach to: "${prompt}"`);
3101
+ console.log();
3102
+ await typeLine(` ${chalk7.green("\u2022")} Analyzed project structure and dependencies`);
3103
+ await typeLine(` ${chalk7.green("\u2022")} Reviewed relevant files based on your prompt`);
3104
+ await typeLine(` ${chalk7.green("\u2022")} Generated solution aligned with existing patterns`);
3105
+ console.log();
3106
+ await showUsage(1100, 620, 41e-4, mode);
3107
+ logger.success("Done!");
3108
+ }
3109
+ async function showToolCall(tool, args) {
3110
+ await sleep(PAUSE_SHORT);
3111
+ console.log();
3112
+ console.log(chalk7.yellow(` \u25B6 ${chalk7.bold(tool)}`));
3113
+ if (args) console.log(chalk7.gray(` ${args}`));
3114
+ await sleep(PAUSE_MEDIUM);
3115
+ }
3116
+ async function showToolResult(result) {
3117
+ console.log(chalk7.green(` \u2713 ${result}`));
3118
+ await sleep(PAUSE_SHORT);
3119
+ }
3120
+ async function showContextLoading(fileCount, mode) {
3121
+ logger.startSpinner("Analyzing codebase...");
3122
+ await sleep(1200);
3123
+ logger.updateSpinner(`Scanning ${fileCount} files...`);
3124
+ await sleep(800);
3125
+ logger.updateSpinner("Building dependency graph...");
3126
+ await sleep(600);
3127
+ logger.updateSpinner("Collecting git context...");
3128
+ await sleep(500);
3129
+ logger.succeedSpinner(`Context loaded \u2014 ${fileCount} files, mode: ${chalk7.cyan(mode)}`);
3130
+ console.log();
3131
+ }
3132
+ async function showUsage(tokensIn, tokensOut, cost, mode) {
3133
+ const modelName = mode === "security" ? "devwing-security-1" : mode === "devops" ? "devwing-devops-1" : mode === "frontend" ? "devwing-frontend-1" : "devwing-backend-1";
3134
+ console.log();
3135
+ console.log(
3136
+ chalk7.gray(
3137
+ `\u{1F4CA} Tokens: ${tokensIn.toLocaleString()} in, ${tokensOut.toLocaleString()} out | Cost: $${cost.toFixed(4)} | Model: ${modelName}`
3138
+ )
3139
+ );
3140
+ console.log();
3141
+ }
3142
+ async function requireDemoAuth() {
3143
+ const apiKey = await configManager.getApiKey();
3144
+ if (!apiKey) {
3145
+ logger.error('Not authenticated. Run "devwing login" first.');
3146
+ process.exit(1);
3147
+ }
3148
+ }
3149
+ function isDemoMode() {
3150
+ return process.env.DEVWING_DEMO === "1" || process.env.DEVWING_DEMO === "true";
3151
+ }
2388
3152
  var program = new Command();
2389
3153
  var __cliFilename = fileURLToPath(import.meta.url);
2390
3154
  var __cliDirname = dirname(__cliFilename);
@@ -2406,42 +3170,82 @@ var VERSION = getVersion();
2406
3170
  program.name("devwing").description("DevWing.ai - Your AI Wingman in the Terminal").version(VERSION, "-v, --version", "Display version number").helpOption("-h, --help", "Display help information");
2407
3171
  program.option("--mode <mode>", "AI mode: general|frontend|backend|security|devops").option("--model <model>", "Specific model to use").option("--project <id>", "Project ID").option("--workspace <id>", "Workspace ID").option("--verbose", "Verbose output for debugging").option("-y, --yes", "Auto-confirm destructive actions");
2408
3172
  program.command("login").description("Authenticate with DevWing").action(async () => {
2409
- await loginCommand();
3173
+ if (isDemoMode()) {
3174
+ await demoLoginCommand();
3175
+ } else {
3176
+ await loginCommand();
3177
+ }
2410
3178
  });
2411
3179
  program.command("logout").description("Clear stored credentials").action(async () => {
2412
- await logoutCommand();
3180
+ if (isDemoMode()) {
3181
+ await demoLogoutCommand();
3182
+ } else {
3183
+ await logoutCommand();
3184
+ }
2413
3185
  });
2414
3186
  program.command("status").description("Show authentication status and profile").action(async () => {
2415
- await statusCommand();
3187
+ if (isDemoMode()) {
3188
+ await demoStatusCommand();
3189
+ } else {
3190
+ await statusCommand();
3191
+ }
2416
3192
  });
2417
3193
  program.command("chat").description("Start interactive chat mode (like Claude Code)").action(async () => {
2418
3194
  const opts = program.opts();
2419
- await chatCommand(opts);
3195
+ if (isDemoMode()) {
3196
+ await demoChatCommand(opts);
3197
+ } else {
3198
+ await chatCommand(opts);
3199
+ }
2420
3200
  });
2421
3201
  program.command("scan").description("Run security vulnerability scan").action(async () => {
2422
3202
  const opts = program.opts();
2423
- await scanCommand(opts);
3203
+ if (isDemoMode()) {
3204
+ await demoPromptCommand("scan auth service for OWASP vulnerabilities", { ...opts, mode: "security" });
3205
+ } else {
3206
+ await scanCommand(opts);
3207
+ }
2424
3208
  });
2425
3209
  program.command("review").description("Perform code review on recent changes").action(async () => {
2426
3210
  const opts = program.opts();
2427
- await reviewCommand(opts);
3211
+ if (isDemoMode()) {
3212
+ await demoReviewCommand();
3213
+ } else {
3214
+ await reviewCommand(opts);
3215
+ }
2428
3216
  });
2429
3217
  program.command("explain <target>").description("Explain code, file, or concept").action(async (target) => {
2430
3218
  const opts = program.opts();
2431
- await explainCommand(target, opts);
3219
+ if (isDemoMode()) {
3220
+ await demoExplainCommand(target);
3221
+ } else {
3222
+ await explainCommand(target, opts);
3223
+ }
2432
3224
  });
2433
3225
  var memoryCmd = program.command("memory").description("Manage project memory");
2434
3226
  memoryCmd.command("save <content>").description("Save information to project memory").action(async (content) => {
2435
3227
  const opts = program.opts();
2436
- await memoryCommand("save", content, opts);
3228
+ if (isDemoMode()) {
3229
+ await demoMemoryCommand("save", content);
3230
+ } else {
3231
+ await memoryCommand("save", content, opts);
3232
+ }
2437
3233
  });
2438
3234
  memoryCmd.command("show").description("Show all project memories").action(async () => {
2439
3235
  const opts = program.opts();
2440
- await memoryCommand("show", void 0, opts);
3236
+ if (isDemoMode()) {
3237
+ await demoMemoryCommand("show");
3238
+ } else {
3239
+ await memoryCommand("show", void 0, opts);
3240
+ }
2441
3241
  });
2442
3242
  memoryCmd.command("clear").description("Clear all project memories").action(async () => {
2443
3243
  const opts = program.opts();
2444
- await memoryCommand("clear", void 0, opts);
3244
+ if (isDemoMode()) {
3245
+ await demoMemoryCommand("clear");
3246
+ } else {
3247
+ await memoryCommand("clear", void 0, opts);
3248
+ }
2445
3249
  });
2446
3250
  var configCmd = program.command("config").description("Manage CLI configuration");
2447
3251
  configCmd.command("list").description("Show all configuration").action(async () => {
@@ -2459,11 +3263,19 @@ program.command("update").description("Check for and install CLI updates").optio
2459
3263
  program.argument("[prompt...]", "Natural language prompt for AI (optional - starts chat mode if empty)").action(async (promptParts) => {
2460
3264
  const opts = program.opts();
2461
3265
  if (promptParts.length === 0) {
2462
- await chatCommand(opts);
3266
+ if (isDemoMode()) {
3267
+ await demoChatCommand(opts);
3268
+ } else {
3269
+ await chatCommand(opts);
3270
+ }
2463
3271
  return;
2464
3272
  }
2465
3273
  const prompt = promptParts.join(" ");
2466
- await promptCommand(prompt, opts);
3274
+ if (isDemoMode()) {
3275
+ await demoPromptCommand(prompt, opts);
3276
+ } else {
3277
+ await promptCommand(prompt, opts);
3278
+ }
2467
3279
  });
2468
3280
  program.exitOverride();
2469
3281
  try {