lovecode-ai 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 +384 -269
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
|
|
83
83
|
// src/index.ts
|
|
84
84
|
import { Command as Command17 } from "commander";
|
|
85
|
-
import
|
|
85
|
+
import chalk44 from "chalk";
|
|
86
86
|
|
|
87
87
|
// src/commands/chat.ts
|
|
88
88
|
import { Command } from "commander";
|
|
@@ -4990,8 +4990,121 @@ configCommand.action(cmdShow);
|
|
|
4990
4990
|
|
|
4991
4991
|
// src/commands/env.ts
|
|
4992
4992
|
import { Command as Command5 } from "commander";
|
|
4993
|
-
import
|
|
4993
|
+
import chalk25 from "chalk";
|
|
4994
4994
|
import inquirer from "inquirer";
|
|
4995
|
+
|
|
4996
|
+
// src/platform/detect.ts
|
|
4997
|
+
import * as fs17 from "fs";
|
|
4998
|
+
import * as os from "os";
|
|
4999
|
+
var _isTermux = null;
|
|
5000
|
+
var _isCodespaces = null;
|
|
5001
|
+
var _isTouch = null;
|
|
5002
|
+
function isTermux() {
|
|
5003
|
+
if (_isTermux !== null) return _isTermux;
|
|
5004
|
+
_isTermux = fs17.existsSync("/data/data/com.termux") || process.env.PREFIX === "/data/data/com.termux/files/usr" || !!process.env.TERMUX_VERSION || process.env.TERMUX_APK_RELEASE !== void 0 || false;
|
|
5005
|
+
return _isTermux;
|
|
5006
|
+
}
|
|
5007
|
+
function isTouchDevice() {
|
|
5008
|
+
if (_isTouch !== null) return _isTouch;
|
|
5009
|
+
_isTouch = isTermux() || process.env.LOVECODE_TOUCH === "true" || process.env.TERMUX_VERSION !== void 0 || false;
|
|
5010
|
+
return _isTouch;
|
|
5011
|
+
}
|
|
5012
|
+
function isCodespaces() {
|
|
5013
|
+
if (_isCodespaces !== null) return _isCodespaces;
|
|
5014
|
+
_isCodespaces = process.env.CODESPACES === "true" || !!process.env.CODESPACE_NAME || fs17.existsSync("/.codespaces") || false;
|
|
5015
|
+
return _isCodespaces;
|
|
5016
|
+
}
|
|
5017
|
+
function lowRamMode() {
|
|
5018
|
+
const totalMem = os.totalmem();
|
|
5019
|
+
const memMb = totalMem / (1024 * 1024);
|
|
5020
|
+
return memMb < 1024 || process.env.LOVECODE_LOW_RAM === "true" || isTermux();
|
|
5021
|
+
}
|
|
5022
|
+
function recommendedMaxMemory() {
|
|
5023
|
+
const totalMem = os.totalmem();
|
|
5024
|
+
const memMb = totalMem / (1024 * 1024);
|
|
5025
|
+
if (isTermux()) return 128;
|
|
5026
|
+
if (memMb < 1024) return 128;
|
|
5027
|
+
if (memMb < 2048) return 256;
|
|
5028
|
+
if (memMb < 4096) return 512;
|
|
5029
|
+
return 1024;
|
|
5030
|
+
}
|
|
5031
|
+
function termuxInfo() {
|
|
5032
|
+
if (!isTermux()) return [];
|
|
5033
|
+
const info = [];
|
|
5034
|
+
info.push(`Termux version: ${process.env.TERMUX_VERSION || "unknown"}`);
|
|
5035
|
+
info.push(`Touch optimized: ${isTouchDevice() ? "yes" : "no"}`);
|
|
5036
|
+
info.push(`Low RAM mode: ${lowRamMode() ? "enabled" : "disabled"}`);
|
|
5037
|
+
info.push(`Max memory: ${recommendedMaxMemory()}MB`);
|
|
5038
|
+
info.push(`Cache TTL: ${cacheTTL()}ms`);
|
|
5039
|
+
return info;
|
|
5040
|
+
}
|
|
5041
|
+
function cacheTTL() {
|
|
5042
|
+
return isTermux() ? 12e4 : 3e5;
|
|
5043
|
+
}
|
|
5044
|
+
function platformInfo() {
|
|
5045
|
+
const info = [];
|
|
5046
|
+
info.push(`OS: ${os.platform()} ${os.release()}`);
|
|
5047
|
+
info.push(`CPU: ${os.cpus().length} cores`);
|
|
5048
|
+
info.push(`RAM: ${(os.totalmem() / 1024 ** 3).toFixed(1)} GB total, ${(os.freemem() / 1024 ** 3).toFixed(1)} GB free`);
|
|
5049
|
+
info.push(`Node: ${process.version}`);
|
|
5050
|
+
if (isTermux()) info.push(`Platform: Termux (Android) ${process.env.TERMUX_VERSION || ""}`);
|
|
5051
|
+
if (isCodespaces()) info.push("Platform: GitHub Codespaces");
|
|
5052
|
+
return info;
|
|
5053
|
+
}
|
|
5054
|
+
|
|
5055
|
+
// src/utils/select.ts
|
|
5056
|
+
import * as readline5 from "readline";
|
|
5057
|
+
import chalk24 from "chalk";
|
|
5058
|
+
async function numberedSelect(choices, options) {
|
|
5059
|
+
const termux = options?.termux ?? isTermux();
|
|
5060
|
+
const pageSize = options?.pageSize || 15;
|
|
5061
|
+
const message = options?.message || "Select an option:";
|
|
5062
|
+
console.log(`
|
|
5063
|
+
${chalk24.bold(message)}
|
|
5064
|
+
`);
|
|
5065
|
+
const display = choices.slice(0, pageSize);
|
|
5066
|
+
for (let i = 0; i < display.length; i++) {
|
|
5067
|
+
const num = chalk24.cyan(`${i + 1}`.padStart(3));
|
|
5068
|
+
const desc = display[i].description ? chalk24.dim(` \u2014 ${display[i].description}`) : "";
|
|
5069
|
+
console.log(` ${num}. ${display[i].name}${desc}`);
|
|
5070
|
+
}
|
|
5071
|
+
if (choices.length > pageSize) {
|
|
5072
|
+
console.log(` ${chalk24.dim(`... and ${choices.length - pageSize} more. Use \`lovecode env set\` directly.`)}`);
|
|
5073
|
+
}
|
|
5074
|
+
const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
|
|
5075
|
+
return new Promise((resolve5) => {
|
|
5076
|
+
const prompt = termux ? `
|
|
5077
|
+
${chalk24.cyan("?")} Enter number (1-${display.length}): ` : `
|
|
5078
|
+
${chalk24.cyan("?")} Enter number (1-${display.length}), or press Enter for 1: `;
|
|
5079
|
+
rl.question(prompt, (answer) => {
|
|
5080
|
+
rl.close();
|
|
5081
|
+
const trimmed = answer.trim();
|
|
5082
|
+
if (!trimmed && !termux) {
|
|
5083
|
+
resolve5(display[0].value);
|
|
5084
|
+
return;
|
|
5085
|
+
}
|
|
5086
|
+
const num = parseInt(trimmed, 10);
|
|
5087
|
+
if (isNaN(num) || num < 1 || num > display.length) {
|
|
5088
|
+
console.log(chalk24.red(` Invalid selection. Please enter a number between 1 and ${display.length}.`));
|
|
5089
|
+
resolve5(numberedSelect(choices, options));
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
resolve5(display[num - 1].value);
|
|
5093
|
+
});
|
|
5094
|
+
});
|
|
5095
|
+
}
|
|
5096
|
+
async function promptInput(question, defaultValue) {
|
|
5097
|
+
const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
|
|
5098
|
+
const prompt = defaultValue ? ` ${chalk24.cyan("?")} ${question} ${chalk24.dim(`(${defaultValue})`)}: ` : ` ${chalk24.cyan("?")} ${question}: `;
|
|
5099
|
+
return new Promise((resolve5) => {
|
|
5100
|
+
rl.question(prompt, (answer) => {
|
|
5101
|
+
rl.close();
|
|
5102
|
+
resolve5(answer.trim() || defaultValue || "");
|
|
5103
|
+
});
|
|
5104
|
+
});
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5107
|
+
// src/commands/env.ts
|
|
4995
5108
|
async function cmdEnvShow(options) {
|
|
4996
5109
|
console.log(formatEnvStatus(options.dir));
|
|
4997
5110
|
}
|
|
@@ -4999,46 +5112,65 @@ async function cmdEnvSet(key, value, options) {
|
|
|
4999
5112
|
const vars = loadEnv(options.dir);
|
|
5000
5113
|
vars[key.toUpperCase()] = value;
|
|
5001
5114
|
saveEnv(vars, options.dir);
|
|
5002
|
-
console.log(
|
|
5115
|
+
console.log(chalk25.green(`Set ${key.toUpperCase()}`));
|
|
5003
5116
|
console.log(formatEnvStatus(options.dir));
|
|
5004
5117
|
}
|
|
5005
5118
|
async function cmdEnvUnset(key, options) {
|
|
5006
5119
|
const vars = loadEnv(options.dir);
|
|
5007
5120
|
delete vars[key.toUpperCase()];
|
|
5008
5121
|
saveEnv(vars, options.dir);
|
|
5009
|
-
console.log(
|
|
5122
|
+
console.log(chalk25.yellow(`Unset ${key.toUpperCase()}`));
|
|
5010
5123
|
}
|
|
5011
5124
|
async function cmdEnvSelect(options) {
|
|
5012
5125
|
const vars = loadEnv(options.dir);
|
|
5013
5126
|
const choices = KNOWN_ENV_VARS.map((v) => {
|
|
5014
5127
|
const current = vars[v.key] || process.env[v.key] || "";
|
|
5015
|
-
const status = current ?
|
|
5128
|
+
const status = current ? chalk25.green("\u2713 set") : chalk25.dim("\u25CB empty");
|
|
5016
5129
|
const masked = current && v.key.includes("KEY") ? current.slice(0, 8) + "*".repeat(Math.min(current.length - 8, 12)) : current || "";
|
|
5017
5130
|
return {
|
|
5018
|
-
name: `${v.key.padEnd(28)} ${status}
|
|
5131
|
+
name: `${v.key.padEnd(28)} ${status}`,
|
|
5019
5132
|
value: v.key,
|
|
5020
|
-
|
|
5133
|
+
description: masked ? `${v.description} (${masked})` : v.description
|
|
5021
5134
|
};
|
|
5022
5135
|
});
|
|
5023
|
-
const
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5136
|
+
const useTermuxStyle = isTermux() || isTouchDevice();
|
|
5137
|
+
let key;
|
|
5138
|
+
if (useTermuxStyle) {
|
|
5139
|
+
key = await numberedSelect(choices, {
|
|
5140
|
+
message: "Select an environment variable to set:",
|
|
5141
|
+
termux: true
|
|
5142
|
+
});
|
|
5143
|
+
} else {
|
|
5144
|
+
const result = await inquirer.prompt([{
|
|
5145
|
+
type: "list",
|
|
5146
|
+
name: "key",
|
|
5147
|
+
message: "Select an environment variable to set:",
|
|
5148
|
+
choices: choices.map((c) => ({ name: c.name, value: c.value })),
|
|
5149
|
+
pageSize: 15
|
|
5150
|
+
}]);
|
|
5151
|
+
key = result.key;
|
|
5152
|
+
}
|
|
5030
5153
|
const existing = vars[key] || "";
|
|
5031
5154
|
const description = KNOWN_ENV_VARS.find((v) => v.key === key)?.description || "";
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5155
|
+
let value;
|
|
5156
|
+
if (useTermuxStyle) {
|
|
5157
|
+
value = await promptInput(`Enter value for ${key} (${description})`, existing || void 0);
|
|
5158
|
+
} else {
|
|
5159
|
+
const result = await inquirer.prompt([{
|
|
5160
|
+
type: "input",
|
|
5161
|
+
name: "value",
|
|
5162
|
+
message: `Enter value for ${chalk25.cyan(key)} (${description}):`,
|
|
5163
|
+
default: existing || void 0
|
|
5164
|
+
}]);
|
|
5165
|
+
value = result.value;
|
|
5166
|
+
}
|
|
5167
|
+
if (!value) {
|
|
5168
|
+
console.log(chalk25.yellow("\nNo value entered. Skipping."));
|
|
5169
|
+
return;
|
|
5170
|
+
}
|
|
5039
5171
|
vars[key] = value;
|
|
5040
5172
|
saveEnv(vars, options.dir);
|
|
5041
|
-
console.log(
|
|
5173
|
+
console.log(chalk25.green(`
|
|
5042
5174
|
\u2713 ${key} saved`));
|
|
5043
5175
|
console.log(formatEnvStatus(options.dir));
|
|
5044
5176
|
}
|
|
@@ -5048,6 +5180,8 @@ var envCommand = new Command5("env").alias("environment").description("Manage en
|
|
|
5048
5180
|
lovecode env select Interactive variable selection
|
|
5049
5181
|
lovecode env set GROQ_API_KEY gsk_xxx
|
|
5050
5182
|
lovecode env unset GROQ_API_KEY
|
|
5183
|
+
|
|
5184
|
+
On Termux/Android: uses numbered input instead of arrow keys
|
|
5051
5185
|
`);
|
|
5052
5186
|
envCommand.command("set").description("Set an environment variable").argument("<key>", "Variable name").argument("<value>", "Variable value").option("--dir <path>", "Project directory").action(cmdEnvSet);
|
|
5053
5187
|
envCommand.command("unset").description("Remove an environment variable").argument("<key>", "Variable name").option("--dir <path>", "Project directory").action(cmdEnvUnset);
|
|
@@ -5058,57 +5192,28 @@ envCommand.action(cmdEnvShow);
|
|
|
5058
5192
|
import { Command as Command6 } from "commander";
|
|
5059
5193
|
|
|
5060
5194
|
// src/platform/optimize.ts
|
|
5061
|
-
import
|
|
5062
|
-
|
|
5063
|
-
// src/platform/detect.ts
|
|
5064
|
-
import * as fs17 from "fs";
|
|
5065
|
-
import * as os from "os";
|
|
5066
|
-
var _isTermux = null;
|
|
5067
|
-
var _isCodespaces = null;
|
|
5068
|
-
function isTermux() {
|
|
5069
|
-
if (_isTermux !== null) return _isTermux;
|
|
5070
|
-
_isTermux = fs17.existsSync("/data/data/com.termux") || process.env.PREFIX === "/data/data/com.termux/files/usr" || !!process.env.TERMUX_VERSION;
|
|
5071
|
-
return _isTermux;
|
|
5072
|
-
}
|
|
5073
|
-
function isCodespaces() {
|
|
5074
|
-
if (_isCodespaces !== null) return _isCodespaces;
|
|
5075
|
-
_isCodespaces = process.env.CODESPACES === "true" || !!process.env.CODESPACE_NAME || fs17.existsSync("/.codespaces");
|
|
5076
|
-
return _isCodespaces;
|
|
5077
|
-
}
|
|
5078
|
-
function lowRamMode() {
|
|
5079
|
-
const totalMem = os.totalmem();
|
|
5080
|
-
const memMb = totalMem / (1024 * 1024);
|
|
5081
|
-
return memMb < 1024 || process.env.LOVECODE_LOW_RAM === "true" || isTermux();
|
|
5082
|
-
}
|
|
5083
|
-
function recommendedMaxMemory() {
|
|
5084
|
-
const totalMem = os.totalmem();
|
|
5085
|
-
const memMb = totalMem / (1024 * 1024);
|
|
5086
|
-
if (memMb < 1024) return 128;
|
|
5087
|
-
if (memMb < 2048) return 256;
|
|
5088
|
-
if (memMb < 4096) return 512;
|
|
5089
|
-
return 1024;
|
|
5090
|
-
}
|
|
5091
|
-
function platformInfo() {
|
|
5092
|
-
const info = [];
|
|
5093
|
-
info.push(`OS: ${os.platform()} ${os.release()}`);
|
|
5094
|
-
info.push(`CPU: ${os.cpus().length} cores`);
|
|
5095
|
-
info.push(`RAM: ${(os.totalmem() / 1024 ** 3).toFixed(1)} GB total, ${(os.freemem() / 1024 ** 3).toFixed(1)} GB free`);
|
|
5096
|
-
info.push(`Node: ${process.version}`);
|
|
5097
|
-
if (isTermux()) info.push("Platform: Termux (Android)");
|
|
5098
|
-
if (isCodespaces()) info.push("Platform: GitHub Codespaces");
|
|
5099
|
-
return info;
|
|
5100
|
-
}
|
|
5101
|
-
|
|
5102
|
-
// src/platform/optimize.ts
|
|
5195
|
+
import chalk26 from "chalk";
|
|
5103
5196
|
function formatPlatformStatus() {
|
|
5104
|
-
const lines = [
|
|
5105
|
-
lines.push(` Termux:
|
|
5106
|
-
lines.push(`
|
|
5107
|
-
lines.push(`
|
|
5108
|
-
lines.push(`
|
|
5197
|
+
const lines = [chalk26.bold("\n Platform Status")];
|
|
5198
|
+
lines.push(` Termux: ${isTermux() ? chalk26.green("\u2713") : chalk26.dim("\u2014")}`);
|
|
5199
|
+
lines.push(` Touch: ${isTouchDevice() ? chalk26.green("\u2713") : chalk26.dim("\u2014")}`);
|
|
5200
|
+
lines.push(` Codespaces: ${isCodespaces() ? chalk26.green("\u2713") : chalk26.dim("\u2014")}`);
|
|
5201
|
+
lines.push(` Low RAM: ${lowRamMode() ? chalk26.yellow("active") : chalk26.dim("no")}`);
|
|
5202
|
+
lines.push(` Max Mem: ${recommendedMaxMemory()}MB`);
|
|
5109
5203
|
lines.push("");
|
|
5204
|
+
if (isTermux()) {
|
|
5205
|
+
lines.push(chalk26.bold(" Termux Details:"));
|
|
5206
|
+
for (const t of termuxInfo()) {
|
|
5207
|
+
lines.push(` ${t}`);
|
|
5208
|
+
}
|
|
5209
|
+
lines.push("");
|
|
5210
|
+
}
|
|
5110
5211
|
for (const line of platformInfo()) {
|
|
5111
|
-
lines.push(` ${
|
|
5212
|
+
lines.push(` ${chalk26.dim(line)}`);
|
|
5213
|
+
}
|
|
5214
|
+
if (isTouchDevice()) {
|
|
5215
|
+
lines.push("");
|
|
5216
|
+
lines.push(chalk26.dim(" Tip: Use numbered selections instead of arrow keys"));
|
|
5112
5217
|
}
|
|
5113
5218
|
return lines.join("\n");
|
|
5114
5219
|
}
|
|
@@ -5121,14 +5226,14 @@ var platformCommand = new Command6("platform").alias("sys").alias("info").descri
|
|
|
5121
5226
|
|
|
5122
5227
|
// src/commands/telemetry.ts
|
|
5123
5228
|
import { Command as Command7 } from "commander";
|
|
5124
|
-
import
|
|
5229
|
+
import chalk28 from "chalk";
|
|
5125
5230
|
|
|
5126
5231
|
// src/telemetry/telemetry.ts
|
|
5127
5232
|
import * as fs18 from "fs";
|
|
5128
5233
|
import * as path17 from "path";
|
|
5129
5234
|
import * as os2 from "os";
|
|
5130
5235
|
import { createRequire as createRequire2 } from "module";
|
|
5131
|
-
import
|
|
5236
|
+
import chalk27 from "chalk";
|
|
5132
5237
|
var _require2 = createRequire2(import.meta.url);
|
|
5133
5238
|
var TELEMETRY_DIR = ".lovecode/telemetry";
|
|
5134
5239
|
var _enabled = null;
|
|
@@ -5209,16 +5314,16 @@ function clearTelemetryData(rootDir) {
|
|
|
5209
5314
|
}
|
|
5210
5315
|
}
|
|
5211
5316
|
function formatTelemetryStatus(enabled, data) {
|
|
5212
|
-
const lines = [
|
|
5213
|
-
lines.push(` Status: ${enabled ?
|
|
5317
|
+
const lines = [chalk27.bold("\n Telemetry Status")];
|
|
5318
|
+
lines.push(` Status: ${enabled ? chalk27.yellow("ENABLED") : chalk27.green("DISABLED")}`);
|
|
5214
5319
|
lines.push(` Events: ${data.events.length}`);
|
|
5215
5320
|
lines.push(` Crashes: ${data.crashes.length}`);
|
|
5216
5321
|
if (data.events.length > 0) {
|
|
5217
|
-
lines.push(
|
|
5322
|
+
lines.push(chalk27.dim(`
|
|
5218
5323
|
Recent Events:`));
|
|
5219
5324
|
for (const e of data.events.slice(-5)) {
|
|
5220
5325
|
const date = new Date(e.timestamp).toLocaleString();
|
|
5221
|
-
lines.push(` ${
|
|
5326
|
+
lines.push(` ${chalk27.dim(date)} ${e.event}`);
|
|
5222
5327
|
}
|
|
5223
5328
|
}
|
|
5224
5329
|
return lines.join("\n");
|
|
@@ -5232,17 +5337,17 @@ async function cmdTelemetryStatus(options) {
|
|
|
5232
5337
|
}
|
|
5233
5338
|
async function cmdTelemetryEnable(options) {
|
|
5234
5339
|
enableTelemetry(options.dir);
|
|
5235
|
-
console.log(
|
|
5236
|
-
console.log(
|
|
5237
|
-
console.log(
|
|
5340
|
+
console.log(chalk28.yellow("Telemetry enabled."));
|
|
5341
|
+
console.log(chalk28.dim(" Anonymous usage data will be collected to improve LoveCode."));
|
|
5342
|
+
console.log(chalk28.dim(" No personal or project data is ever sent."));
|
|
5238
5343
|
}
|
|
5239
5344
|
async function cmdTelemetryDisable(options) {
|
|
5240
5345
|
disableTelemetry(options.dir);
|
|
5241
|
-
console.log(
|
|
5346
|
+
console.log(chalk28.green("Telemetry disabled."));
|
|
5242
5347
|
}
|
|
5243
5348
|
async function cmdTelemetryClear(options) {
|
|
5244
5349
|
clearTelemetryData(options.dir);
|
|
5245
|
-
console.log(
|
|
5350
|
+
console.log(chalk28.green("Telemetry data cleared."));
|
|
5246
5351
|
}
|
|
5247
5352
|
var telemetryCommand = new Command7("telemetry").alias("analytics").description("Manage anonymous telemetry and crash reporting").option("--dir <path>", "Project directory", process.cwd()).addHelpText("after", `
|
|
5248
5353
|
Privacy-first by default. Telemetry is disabled unless explicitly enabled.
|
|
@@ -5260,13 +5365,13 @@ telemetryCommand.action(cmdTelemetryStatus);
|
|
|
5260
5365
|
|
|
5261
5366
|
// src/commands/install.ts
|
|
5262
5367
|
import { Command as Command8 } from "commander";
|
|
5263
|
-
import
|
|
5368
|
+
import chalk30 from "chalk";
|
|
5264
5369
|
|
|
5265
5370
|
// src/installers/install.ts
|
|
5266
5371
|
import * as fs19 from "fs";
|
|
5267
5372
|
import * as path18 from "path";
|
|
5268
5373
|
import { execSync as execSync4 } from "child_process";
|
|
5269
|
-
import
|
|
5374
|
+
import chalk29 from "chalk";
|
|
5270
5375
|
function detectInstallMethod() {
|
|
5271
5376
|
if (process.env.npm_config_user_agent?.startsWith("npm")) return "npm";
|
|
5272
5377
|
if (process.env.npm_config_user_agent?.startsWith("yarn")) return "yarn";
|
|
@@ -5292,16 +5397,26 @@ function isGloballyInstalled() {
|
|
|
5292
5397
|
}
|
|
5293
5398
|
}
|
|
5294
5399
|
function printInstallInstructions() {
|
|
5295
|
-
console.log(
|
|
5296
|
-
console.log(
|
|
5297
|
-
console.log(` ${
|
|
5400
|
+
console.log(chalk29.bold.cyan("\n LoveCode AI - Installation\n"));
|
|
5401
|
+
console.log(chalk29.bold(" Quick Install:\n"));
|
|
5402
|
+
console.log(` ${chalk29.green("NPM:")}`);
|
|
5298
5403
|
console.log(` npm install -g lovecode-ai
|
|
5299
5404
|
`);
|
|
5300
|
-
console.log(` ${
|
|
5405
|
+
console.log(` ${chalk29.green("Curl:")}`);
|
|
5301
5406
|
console.log(` curl -fsSL https://lovecode.sh | bash
|
|
5302
5407
|
`);
|
|
5303
|
-
console.log(` ${
|
|
5408
|
+
console.log(` ${chalk29.green("Verify:")}`);
|
|
5304
5409
|
console.log(` lovecode --version
|
|
5410
|
+
`);
|
|
5411
|
+
console.log(chalk29.bold(" Termux (Android):\n"));
|
|
5412
|
+
console.log(` pkg install nodejs`);
|
|
5413
|
+
console.log(` npm install -g lovecode-ai`);
|
|
5414
|
+
console.log(` lovecode init
|
|
5415
|
+
`);
|
|
5416
|
+
console.log(` ${chalk29.dim("LoveCode auto-detects Termux and enables:")}`);
|
|
5417
|
+
console.log(` ${chalk29.dim(" \u2022 Low RAM mode (128MB max)")}`);
|
|
5418
|
+
console.log(` ${chalk29.dim(" \u2022 Touch-optimized input")}`);
|
|
5419
|
+
console.log(` ${chalk29.dim(" \u2022 Reduced cache TTL (120s)")}
|
|
5305
5420
|
`);
|
|
5306
5421
|
}
|
|
5307
5422
|
function createInstallScript(rootDir) {
|
|
@@ -5374,20 +5489,20 @@ echo ""
|
|
|
5374
5489
|
async function cmdInstallStatus() {
|
|
5375
5490
|
const info = getInstallerInfo();
|
|
5376
5491
|
const global = isGloballyInstalled();
|
|
5377
|
-
console.log(
|
|
5378
|
-
console.log(` Method: ${
|
|
5492
|
+
console.log(chalk30.bold("\n Install Status"));
|
|
5493
|
+
console.log(` Method: ${chalk30.cyan(info.method)}`);
|
|
5379
5494
|
console.log(` Version: ${info.version}`);
|
|
5380
5495
|
console.log(` Node: ${info.nodeVersion}`);
|
|
5381
5496
|
console.log(` Platform: ${info.platform}`);
|
|
5382
|
-
console.log(` Global CLI: ${global ?
|
|
5497
|
+
console.log(` Global CLI: ${global ? chalk30.green("\u2713") : chalk30.dim("\u2014")}`);
|
|
5383
5498
|
}
|
|
5384
5499
|
async function cmdInstallGuide() {
|
|
5385
5500
|
printInstallInstructions();
|
|
5386
5501
|
}
|
|
5387
5502
|
async function cmdInstallScript(options) {
|
|
5388
5503
|
createInstallScript(options.dir);
|
|
5389
|
-
console.log(
|
|
5390
|
-
console.log(
|
|
5504
|
+
console.log(chalk30.green(` \u2713 install.sh created in ${options.dir || process.cwd()}`));
|
|
5505
|
+
console.log(chalk30.dim(" Run: bash install.sh"));
|
|
5391
5506
|
}
|
|
5392
5507
|
var installCommand = new Command8("install").alias("installer").description("Installation management and instructions").option("--dir <path>", "Project directory", process.cwd()).addHelpText("after", `
|
|
5393
5508
|
Examples:
|
|
@@ -5401,7 +5516,7 @@ installCommand.action(cmdInstallStatus);
|
|
|
5401
5516
|
|
|
5402
5517
|
// src/commands/models.ts
|
|
5403
5518
|
import { Command as Command9 } from "commander";
|
|
5404
|
-
import
|
|
5519
|
+
import chalk31 from "chalk";
|
|
5405
5520
|
var modelsCommand = new Command9("models").description("Manage AI models and providers").addCommand(
|
|
5406
5521
|
new Command9("list").alias("ls").description("List all available models and providers").action(() => {
|
|
5407
5522
|
console.log(printProviders());
|
|
@@ -5410,8 +5525,8 @@ var modelsCommand = new Command9("models").description("Manage AI models and pro
|
|
|
5410
5525
|
new Command9("use").description("Set the default model to use").argument("<model>", "Model name or provider name").action((model) => {
|
|
5411
5526
|
const result = setDefaultModel(model);
|
|
5412
5527
|
if (result) {
|
|
5413
|
-
console.log(
|
|
5414
|
-
\u2713 Default set to ${
|
|
5528
|
+
console.log(chalk31.green(`
|
|
5529
|
+
\u2713 Default set to ${chalk31.cyan(result.provider)}/${chalk31.cyan(result.model)}
|
|
5415
5530
|
`));
|
|
5416
5531
|
}
|
|
5417
5532
|
})
|
|
@@ -5420,20 +5535,20 @@ var modelsCommand = new Command9("models").description("Manage AI models and pro
|
|
|
5420
5535
|
if (provider) {
|
|
5421
5536
|
const entry = getProvider(provider);
|
|
5422
5537
|
if (!entry) {
|
|
5423
|
-
console.log(
|
|
5538
|
+
console.log(chalk31.red(`
|
|
5424
5539
|
Unknown provider: "${provider}"
|
|
5425
5540
|
`));
|
|
5426
5541
|
return;
|
|
5427
5542
|
}
|
|
5428
|
-
const tag = entry.local ?
|
|
5543
|
+
const tag = entry.local ? chalk31.green(" LOCAL ") : chalk31.blue(" CLOUD ");
|
|
5429
5544
|
console.log(`
|
|
5430
|
-
${tag} ${
|
|
5431
|
-
console.log(
|
|
5432
|
-
console.log(
|
|
5433
|
-
console.log(
|
|
5545
|
+
${tag} ${chalk31.cyan(entry.name)}`);
|
|
5546
|
+
console.log(chalk31.dim(` Default model: ${entry.defaultModel}`));
|
|
5547
|
+
console.log(chalk31.dim(` Priority: ${entry.priority}`));
|
|
5548
|
+
console.log(chalk31.dim(` Models:`));
|
|
5434
5549
|
for (const m of entry.models) {
|
|
5435
5550
|
const isDefault = m === entry.defaultModel;
|
|
5436
|
-
console.log(` ${isDefault ?
|
|
5551
|
+
console.log(` ${isDefault ? chalk31.green("\u2605") : " "} ${m}${isDefault ? chalk31.dim(" (default)") : ""}`);
|
|
5437
5552
|
}
|
|
5438
5553
|
console.log("");
|
|
5439
5554
|
} else {
|
|
@@ -5444,13 +5559,13 @@ var modelsCommand = new Command9("models").description("Manage AI models and pro
|
|
|
5444
5559
|
new Command9("test").description("Test a provider connection").argument("[provider]", "Provider name to test", "ollama").option("-m, --model <name>", "Model to test with").action(async (provider, options) => {
|
|
5445
5560
|
const entry = getProvider(provider);
|
|
5446
5561
|
if (!entry) {
|
|
5447
|
-
console.log(
|
|
5562
|
+
console.log(chalk31.red(`
|
|
5448
5563
|
Unknown provider: "${provider}"
|
|
5449
5564
|
`));
|
|
5450
5565
|
return;
|
|
5451
5566
|
}
|
|
5452
5567
|
const model = options.model || entry.defaultModel;
|
|
5453
|
-
console.log(
|
|
5568
|
+
console.log(chalk31.dim(`
|
|
5454
5569
|
Testing ${entry.name}/${model}...`));
|
|
5455
5570
|
try {
|
|
5456
5571
|
const config = entry.getConfig?.(model) || {
|
|
@@ -5463,9 +5578,9 @@ var modelsCommand = new Command9("models").description("Manage AI models and pro
|
|
|
5463
5578
|
[{ role: "user", content: "Reply with exactly: OK" }],
|
|
5464
5579
|
config
|
|
5465
5580
|
);
|
|
5466
|
-
console.log(
|
|
5581
|
+
console.log(chalk31.green(` \u2713 ${entry.name}/${model} responded: ${result.slice(0, 50)}`));
|
|
5467
5582
|
} catch (err) {
|
|
5468
|
-
console.log(
|
|
5583
|
+
console.log(chalk31.red(` \u2717 ${entry.name}/${model} failed: ${err.message}`));
|
|
5469
5584
|
}
|
|
5470
5585
|
console.log("");
|
|
5471
5586
|
})
|
|
@@ -5473,12 +5588,12 @@ var modelsCommand = new Command9("models").description("Manage AI models and pro
|
|
|
5473
5588
|
|
|
5474
5589
|
// src/commands/analyze.ts
|
|
5475
5590
|
import { Command as Command10 } from "commander";
|
|
5476
|
-
import
|
|
5591
|
+
import chalk33 from "chalk";
|
|
5477
5592
|
|
|
5478
5593
|
// src/repo/search.ts
|
|
5479
5594
|
import * as fs20 from "fs";
|
|
5480
5595
|
import * as path19 from "path";
|
|
5481
|
-
import
|
|
5596
|
+
import chalk32 from "chalk";
|
|
5482
5597
|
function chunkFile(content, maxLines = 50) {
|
|
5483
5598
|
const lines = content.split("\n");
|
|
5484
5599
|
const chunks = [];
|
|
@@ -5611,23 +5726,23 @@ function readFileSafe(filePath) {
|
|
|
5611
5726
|
}
|
|
5612
5727
|
}
|
|
5613
5728
|
function printSemanticResults(results, query) {
|
|
5614
|
-
const lines = [
|
|
5729
|
+
const lines = [chalk32.bold(`
|
|
5615
5730
|
Semantic Search: "${query}"`), ""];
|
|
5616
5731
|
if (results.length === 0) {
|
|
5617
|
-
lines.push(
|
|
5732
|
+
lines.push(chalk32.dim(" No results found."));
|
|
5618
5733
|
lines.push("");
|
|
5619
5734
|
return lines.join("\n");
|
|
5620
5735
|
}
|
|
5621
5736
|
for (let i = 0; i < results.length; i++) {
|
|
5622
5737
|
const r = results[i];
|
|
5623
5738
|
const barLen = Math.round(r.score * 30);
|
|
5624
|
-
const bar =
|
|
5625
|
-
lines.push(` ${
|
|
5626
|
-
lines.push(` ${bar} ${
|
|
5739
|
+
const bar = chalk32.cyan("\u2588".repeat(barLen)) + chalk32.dim("\u2591".repeat(30 - barLen));
|
|
5740
|
+
lines.push(` ${chalk32.cyan(String(i + 1).padEnd(3))} ${chalk32.dim(r.relativePath)}`);
|
|
5741
|
+
lines.push(` ${bar} ${chalk32.bold(String(Math.round(r.score * 100)))}%`);
|
|
5627
5742
|
if (r.matches.length > 0) {
|
|
5628
5743
|
const top = r.matches.slice(0, 2);
|
|
5629
5744
|
for (const m of top) {
|
|
5630
|
-
lines.push(` ${
|
|
5745
|
+
lines.push(` ${chalk32.dim(`L${m.line}:`)} ${m.content.slice(0, 100)}`);
|
|
5631
5746
|
}
|
|
5632
5747
|
}
|
|
5633
5748
|
}
|
|
@@ -5643,27 +5758,27 @@ var analyzeCommand = new Command10("analyze").alias("a").description("Analyze an
|
|
|
5643
5758
|
})
|
|
5644
5759
|
).addCommand(
|
|
5645
5760
|
new Command10("deps").alias("d").description("Analyze dependencies and import graph").option("--dir <path>", "Project directory", process.cwd()).action((options) => {
|
|
5646
|
-
console.log(
|
|
5761
|
+
console.log(chalk33.dim("\n Analyzing dependencies..."));
|
|
5647
5762
|
const graph = analyzeDependencies(options.dir);
|
|
5648
5763
|
console.log(printDepGraph(graph));
|
|
5649
5764
|
const circles = findCircularDeps(graph);
|
|
5650
5765
|
if (circles.length > 0) {
|
|
5651
|
-
console.log(
|
|
5766
|
+
console.log(chalk33.yellow(` \u26A0 Found ${circles.length} circular dependenc${circles.length > 1 ? "ies" : "y"}`));
|
|
5652
5767
|
for (const circle of circles.slice(0, 5)) {
|
|
5653
|
-
console.log(` ${
|
|
5768
|
+
console.log(` ${chalk33.red("\u21BB")} ${circle.join(" \u2192 ")}`);
|
|
5654
5769
|
}
|
|
5655
5770
|
console.log("");
|
|
5656
5771
|
}
|
|
5657
5772
|
})
|
|
5658
5773
|
).addCommand(
|
|
5659
5774
|
new Command10("summary").alias("s").description("Generate a full repo architecture summary").option("--dir <path>", "Project directory", process.cwd()).action((options) => {
|
|
5660
|
-
console.log(
|
|
5775
|
+
console.log(chalk33.dim("\n Generating repository summary...\n"));
|
|
5661
5776
|
const summary = generateSummary(options.dir);
|
|
5662
5777
|
console.log(printSummary(summary));
|
|
5663
5778
|
})
|
|
5664
5779
|
).addCommand(
|
|
5665
5780
|
new Command10("search").alias("q").description("Semantically search code in the repository").argument("<query>", "The search query").option("--dir <path>", "Project directory", process.cwd()).option("--max <number>", "Maximum results", "10").action(async (query, options) => {
|
|
5666
|
-
console.log(
|
|
5781
|
+
console.log(chalk33.dim(`
|
|
5667
5782
|
Searching for: "${query}"
|
|
5668
5783
|
`));
|
|
5669
5784
|
const results = await semanticSearch2(options.dir, query, {
|
|
@@ -5689,36 +5804,36 @@ var analyzeCommand = new Command10("analyze").alias("a").description("Analyze an
|
|
|
5689
5804
|
|
|
5690
5805
|
// src/commands/memory.ts
|
|
5691
5806
|
import { Command as Command11 } from "commander";
|
|
5692
|
-
import
|
|
5807
|
+
import chalk34 from "chalk";
|
|
5693
5808
|
async function cmdSessions(options) {
|
|
5694
5809
|
const sessions = listSessions(options.dir);
|
|
5695
5810
|
if (sessions.length === 0) {
|
|
5696
|
-
console.log(
|
|
5811
|
+
console.log(chalk34.yellow("No sessions found."));
|
|
5697
5812
|
return;
|
|
5698
5813
|
}
|
|
5699
|
-
console.log(
|
|
5814
|
+
console.log(chalk34.bold(`
|
|
5700
5815
|
Sessions (${sessions.length}):
|
|
5701
5816
|
`));
|
|
5702
5817
|
for (const s of sessions) {
|
|
5703
5818
|
const date = new Date(s.updated).toLocaleString();
|
|
5704
5819
|
const msgCount = s.entries.length;
|
|
5705
|
-
console.log(` ${
|
|
5706
|
-
console.log(` ${
|
|
5820
|
+
console.log(` ${chalk34.cyan(s.id.slice(0, 12))} ${chalk34.bold(s.title)}`);
|
|
5821
|
+
console.log(` ${chalk34.dim(`${msgCount} msgs \u2022 ${date} \u2022 ${s.model}`)}`);
|
|
5707
5822
|
}
|
|
5708
5823
|
}
|
|
5709
5824
|
async function cmdShowSession(id, options) {
|
|
5710
5825
|
const session = loadSession(id, options.dir);
|
|
5711
5826
|
if (!session) {
|
|
5712
|
-
console.log(
|
|
5827
|
+
console.log(chalk34.red(`Session "${id}" not found.`));
|
|
5713
5828
|
return;
|
|
5714
5829
|
}
|
|
5715
|
-
console.log(
|
|
5830
|
+
console.log(chalk34.bold(`
|
|
5716
5831
|
Session: ${session.title}`));
|
|
5717
|
-
console.log(
|
|
5718
|
-
console.log(
|
|
5832
|
+
console.log(chalk34.dim(` ID: ${session.id} \u2022 Model: ${session.model} \u2022 ${session.entries.length} messages`));
|
|
5833
|
+
console.log(chalk34.dim(` Created: ${new Date(session.created).toLocaleString()}`));
|
|
5719
5834
|
console.log("");
|
|
5720
5835
|
for (const entry of session.entries.slice(-20)) {
|
|
5721
|
-
const role = entry.role === "user" ?
|
|
5836
|
+
const role = entry.role === "user" ? chalk34.green("You") : entry.role === "assistant" ? chalk34.cyan("LoveCode") : chalk34.yellow("System");
|
|
5722
5837
|
const preview = entry.content.length > 200 ? entry.content.slice(0, 200) + "..." : entry.content;
|
|
5723
5838
|
console.log(` ${role}: ${preview}
|
|
5724
5839
|
`);
|
|
@@ -5727,15 +5842,15 @@ async function cmdShowSession(id, options) {
|
|
|
5727
5842
|
async function cmdSearchSessions(query, options) {
|
|
5728
5843
|
const results = searchSessions(query, options.dir);
|
|
5729
5844
|
if (results.length === 0) {
|
|
5730
|
-
console.log(
|
|
5845
|
+
console.log(chalk34.yellow(`No sessions matching "${query}".`));
|
|
5731
5846
|
return;
|
|
5732
5847
|
}
|
|
5733
|
-
console.log(
|
|
5848
|
+
console.log(chalk34.bold(`
|
|
5734
5849
|
Search results for "${query}" (${results.length}):
|
|
5735
5850
|
`));
|
|
5736
5851
|
for (const s of results) {
|
|
5737
5852
|
const date = new Date(s.updated).toLocaleString();
|
|
5738
|
-
console.log(` ${
|
|
5853
|
+
console.log(` ${chalk34.cyan(s.id.slice(0, 12))} ${chalk34.bold(s.title)} ${chalk34.dim(date)}`);
|
|
5739
5854
|
}
|
|
5740
5855
|
}
|
|
5741
5856
|
async function cmdPreferences(options) {
|
|
@@ -5755,7 +5870,7 @@ async function cmdPreferences(options) {
|
|
|
5755
5870
|
else prefs[k] = v;
|
|
5756
5871
|
}
|
|
5757
5872
|
const saved = savePreferences(prefs, options.dir);
|
|
5758
|
-
console.log(
|
|
5873
|
+
console.log(chalk34.green("Preferences updated:"));
|
|
5759
5874
|
console.log(formatPreferences(saved));
|
|
5760
5875
|
} else {
|
|
5761
5876
|
const prefs = getPreferences(options.dir);
|
|
@@ -5765,7 +5880,7 @@ async function cmdPreferences(options) {
|
|
|
5765
5880
|
async function cmdRepoMemory(options) {
|
|
5766
5881
|
if (options.note) {
|
|
5767
5882
|
const updated = addRepoNote(options.note, options.dir);
|
|
5768
|
-
console.log(
|
|
5883
|
+
console.log(chalk34.green("Note added to repo memory."));
|
|
5769
5884
|
console.log(formatRepoMemory(updated));
|
|
5770
5885
|
} else {
|
|
5771
5886
|
const mem = getRepoMemory(options.dir);
|
|
@@ -5785,31 +5900,31 @@ async function cmdWorkflows(options) {
|
|
|
5785
5900
|
used: Date.now()
|
|
5786
5901
|
};
|
|
5787
5902
|
saveWorkflow(workflow, options.dir);
|
|
5788
|
-
console.log(
|
|
5903
|
+
console.log(chalk34.green(`Workflow "${options.name}" saved (${steps.length} steps).`));
|
|
5789
5904
|
return;
|
|
5790
5905
|
}
|
|
5791
5906
|
if (options.delete) {
|
|
5792
5907
|
const ok = deleteWorkflow(options.delete, options.dir);
|
|
5793
|
-
console.log(ok ?
|
|
5908
|
+
console.log(ok ? chalk34.green(`Workflow "${options.delete}" deleted.`) : chalk34.yellow(`Workflow "${options.delete}" not found.`));
|
|
5794
5909
|
return;
|
|
5795
5910
|
}
|
|
5796
5911
|
if (wf.workflows.length === 0) {
|
|
5797
|
-
console.log(
|
|
5912
|
+
console.log(chalk34.yellow("No saved workflows."));
|
|
5798
5913
|
return;
|
|
5799
5914
|
}
|
|
5800
|
-
console.log(
|
|
5915
|
+
console.log(chalk34.bold(`
|
|
5801
5916
|
Workflows (${wf.workflows.length}):
|
|
5802
5917
|
`));
|
|
5803
5918
|
for (const w of wf.workflows) {
|
|
5804
5919
|
const date = new Date(w.used).toLocaleString();
|
|
5805
|
-
console.log(` ${
|
|
5806
|
-
console.log(` ${
|
|
5920
|
+
console.log(` ${chalk34.cyan(w.name)} ${chalk34.dim(w.description || "(no description)")}`);
|
|
5921
|
+
console.log(` ${chalk34.dim(`${w.steps.length} steps \u2022 last used ${date}`)}`);
|
|
5807
5922
|
}
|
|
5808
5923
|
}
|
|
5809
5924
|
async function cmdVectorStore(options) {
|
|
5810
5925
|
if (options.clear) {
|
|
5811
5926
|
clearVectors(options.dir);
|
|
5812
|
-
console.log(
|
|
5927
|
+
console.log(chalk34.green("Vector memory cleared."));
|
|
5813
5928
|
return;
|
|
5814
5929
|
}
|
|
5815
5930
|
if (options.count) {
|
|
@@ -5818,8 +5933,8 @@ async function cmdVectorStore(options) {
|
|
|
5818
5933
|
}
|
|
5819
5934
|
if (options.store) {
|
|
5820
5935
|
const entry = await storeVector(options.store, {}, options.dir);
|
|
5821
|
-
console.log(
|
|
5822
|
-
console.log(
|
|
5936
|
+
console.log(chalk34.green(`Stored: "${options.store.slice(0, 80)}..."`));
|
|
5937
|
+
console.log(chalk34.dim(` ID: ${entry.id}`));
|
|
5823
5938
|
return;
|
|
5824
5939
|
}
|
|
5825
5940
|
if (options.query) {
|
|
@@ -5827,32 +5942,32 @@ async function cmdVectorStore(options) {
|
|
|
5827
5942
|
console.log(formatVectorResults(results));
|
|
5828
5943
|
return;
|
|
5829
5944
|
}
|
|
5830
|
-
console.log(
|
|
5945
|
+
console.log(chalk34.yellow("Specify --query, --store, --count, or --clear."));
|
|
5831
5946
|
}
|
|
5832
5947
|
async function cmdChatLogs(options) {
|
|
5833
5948
|
const logs = listChatLogs(options.dir);
|
|
5834
5949
|
if (logs.length === 0) {
|
|
5835
|
-
console.log(
|
|
5950
|
+
console.log(chalk34.yellow("No chat logs found."));
|
|
5836
5951
|
return;
|
|
5837
5952
|
}
|
|
5838
5953
|
const totalSize = logs.reduce((acc, l) => acc + l.size, 0);
|
|
5839
5954
|
const sizeStr = totalSize > 1024 ? `${(totalSize / 1024).toFixed(1)} KB` : `${totalSize} B`;
|
|
5840
|
-
console.log(
|
|
5955
|
+
console.log(chalk34.bold(`
|
|
5841
5956
|
Chat Logs (${logs.length}, ${sizeStr}):
|
|
5842
5957
|
`));
|
|
5843
5958
|
for (const log of logs.slice(0, 20)) {
|
|
5844
5959
|
const date = log.modified.toLocaleString();
|
|
5845
5960
|
const size = log.size > 1024 ? `${(log.size / 1024).toFixed(1)} KB` : `${log.size} B`;
|
|
5846
|
-
console.log(` ${
|
|
5961
|
+
console.log(` ${chalk34.dim(log.name.slice(0, 50).padEnd(52))} ${chalk34.yellow(size.padStart(8))} ${chalk34.dim(date)}`);
|
|
5847
5962
|
}
|
|
5848
5963
|
if (logs.length > 20) {
|
|
5849
|
-
console.log(
|
|
5964
|
+
console.log(chalk34.dim(` ... and ${logs.length - 20} more`));
|
|
5850
5965
|
}
|
|
5851
5966
|
}
|
|
5852
5967
|
async function cmdClearAll(options) {
|
|
5853
5968
|
clearAllMemory(options.dir);
|
|
5854
5969
|
clearVectors(options.dir);
|
|
5855
|
-
console.log(
|
|
5970
|
+
console.log(chalk34.green("All memory data cleared."));
|
|
5856
5971
|
}
|
|
5857
5972
|
var memoryCommand = new Command11("memory").alias("mem").description("Manage sessions, memory, and chat logs").option("--dir <path>", "Project directory", process.cwd()).addCommand(
|
|
5858
5973
|
new Command11("sessions").alias("s").description("List all persistent sessions").option("--dir <path>", "Project directory").action(cmdSessions)
|
|
@@ -5894,14 +6009,14 @@ var memoryCommand = new Command11("memory").alias("mem").description("Manage ses
|
|
|
5894
6009
|
|
|
5895
6010
|
// src/commands/git.ts
|
|
5896
6011
|
import { Command as Command12 } from "commander";
|
|
5897
|
-
import
|
|
6012
|
+
import chalk35 from "chalk";
|
|
5898
6013
|
function requireGit(cwd) {
|
|
5899
6014
|
if (!isGitAvailable()) {
|
|
5900
|
-
console.log(
|
|
6015
|
+
console.log(chalk35.red(" \u2717 Git is not installed or not in PATH."));
|
|
5901
6016
|
return false;
|
|
5902
6017
|
}
|
|
5903
6018
|
if (!isRepo(cwd)) {
|
|
5904
|
-
console.log(
|
|
6019
|
+
console.log(chalk35.red(" \u2717 Not a git repository."));
|
|
5905
6020
|
return false;
|
|
5906
6021
|
}
|
|
5907
6022
|
return true;
|
|
@@ -5915,39 +6030,39 @@ async function cmdCommit(opts) {
|
|
|
5915
6030
|
}
|
|
5916
6031
|
const status = getStatus(root || dir);
|
|
5917
6032
|
if (status.clean && !opts.message) {
|
|
5918
|
-
console.log(
|
|
6033
|
+
console.log(chalk35.yellow(" Nothing to commit. Working tree clean."));
|
|
5919
6034
|
return;
|
|
5920
6035
|
}
|
|
5921
6036
|
let commitMessage = opts.message;
|
|
5922
6037
|
if (!commitMessage && opts.generate) {
|
|
5923
|
-
console.log(
|
|
6038
|
+
console.log(chalk35.dim(" Generating commit message..."));
|
|
5924
6039
|
commitMessage = await generateCommitMessage();
|
|
5925
|
-
console.log(
|
|
6040
|
+
console.log(chalk35.cyan(` Generated: ${commitMessage.split("\n")[0]}
|
|
5926
6041
|
`));
|
|
5927
6042
|
}
|
|
5928
6043
|
if (!commitMessage) {
|
|
5929
|
-
console.log(
|
|
5930
|
-
console.log(
|
|
5931
|
-
console.log(
|
|
5932
|
-
console.log(
|
|
6044
|
+
console.log(chalk35.yellow(" No commit message provided. Use --message or --generate."));
|
|
6045
|
+
console.log(chalk35.dim(" Examples:"));
|
|
6046
|
+
console.log(chalk35.dim(' lovecode commit -m "feat: add login"'));
|
|
6047
|
+
console.log(chalk35.dim(" lovecode commit --generate"));
|
|
5933
6048
|
return;
|
|
5934
6049
|
}
|
|
5935
6050
|
if (opts.all) {
|
|
5936
|
-
console.log(
|
|
6051
|
+
console.log(chalk35.dim(" Staging all changes..."));
|
|
5937
6052
|
}
|
|
5938
6053
|
const result = commit(commitMessage, root || dir);
|
|
5939
6054
|
if (result.success) {
|
|
5940
|
-
console.log(
|
|
6055
|
+
console.log(chalk35.green(` \u2713 Committed${result.hash ? ` (${result.hash.slice(0, 8)})` : ""}`));
|
|
5941
6056
|
if (result.output) {
|
|
5942
6057
|
const lines = result.output.split("\n").filter(Boolean);
|
|
5943
6058
|
for (const line of lines) {
|
|
5944
6059
|
if (line.includes("changed") || line.includes("insertion") || line.includes("deletion")) {
|
|
5945
|
-
console.log(
|
|
6060
|
+
console.log(chalk35.dim(` ${line}`));
|
|
5946
6061
|
}
|
|
5947
6062
|
}
|
|
5948
6063
|
}
|
|
5949
6064
|
} else {
|
|
5950
|
-
console.log(
|
|
6065
|
+
console.log(chalk35.red(` \u2717 ${result.output}`));
|
|
5951
6066
|
}
|
|
5952
6067
|
}
|
|
5953
6068
|
async function cmdStatus(options) {
|
|
@@ -5955,8 +6070,8 @@ async function cmdStatus(options) {
|
|
|
5955
6070
|
const dir = options.dir || process.cwd();
|
|
5956
6071
|
const root = getGitRoot(dir);
|
|
5957
6072
|
const status = getStatus(root || dir);
|
|
5958
|
-
console.log(
|
|
5959
|
-
Git Status \u2014 ${
|
|
6073
|
+
console.log(chalk35.bold(`
|
|
6074
|
+
Git Status \u2014 ${chalk35.cyan(status.branch)}`));
|
|
5960
6075
|
console.log(` ${formatStatus(status)}`);
|
|
5961
6076
|
console.log("");
|
|
5962
6077
|
}
|
|
@@ -5966,39 +6081,39 @@ async function cmdBranch(action, name, options) {
|
|
|
5966
6081
|
const gitRoot = getGitRoot(dir);
|
|
5967
6082
|
if (!action || action === "list") {
|
|
5968
6083
|
const branches = getBranches(gitRoot || dir);
|
|
5969
|
-
console.log(
|
|
6084
|
+
console.log(chalk35.bold(`
|
|
5970
6085
|
Branches (${branches.length}):`));
|
|
5971
6086
|
console.log(` ${formatBranches(branches)}`);
|
|
5972
6087
|
console.log("");
|
|
5973
6088
|
return;
|
|
5974
6089
|
}
|
|
5975
6090
|
if (!name) {
|
|
5976
|
-
console.log(
|
|
6091
|
+
console.log(chalk35.yellow(" Branch name required."));
|
|
5977
6092
|
return;
|
|
5978
6093
|
}
|
|
5979
6094
|
switch (action) {
|
|
5980
6095
|
case "create": {
|
|
5981
6096
|
const ok = createBranch(name, gitRoot || dir);
|
|
5982
|
-
console.log(ok ?
|
|
6097
|
+
console.log(ok ? chalk35.green(` \u2713 Created and switched to "${name}"`) : chalk35.red(` \u2717 Failed to create branch "${name}"`));
|
|
5983
6098
|
break;
|
|
5984
6099
|
}
|
|
5985
6100
|
case "switch": {
|
|
5986
6101
|
const result = switchBranch(name, gitRoot || dir);
|
|
5987
|
-
console.log(result.success ?
|
|
6102
|
+
console.log(result.success ? chalk35.green(` \u2713 Switched to "${name}"`) : chalk35.red(` \u2717 ${result.output}`));
|
|
5988
6103
|
break;
|
|
5989
6104
|
}
|
|
5990
6105
|
case "delete": {
|
|
5991
6106
|
const result = deleteBranch(name, options.force, gitRoot || dir);
|
|
5992
|
-
console.log(result.success ?
|
|
6107
|
+
console.log(result.success ? chalk35.green(` \u2713 Deleted branch "${name}"`) : chalk35.red(` \u2717 ${result.output}`));
|
|
5993
6108
|
break;
|
|
5994
6109
|
}
|
|
5995
6110
|
case "cleanup": {
|
|
5996
|
-
console.log(
|
|
6111
|
+
console.log(chalk35.dim(" Cleaning up merged branches..."));
|
|
5997
6112
|
const deleted = cleanupMergedBranches(gitRoot || dir);
|
|
5998
6113
|
if (deleted.length === 0) {
|
|
5999
|
-
console.log(
|
|
6114
|
+
console.log(chalk35.yellow(" No merged branches to clean up."));
|
|
6000
6115
|
} else {
|
|
6001
|
-
console.log(
|
|
6116
|
+
console.log(chalk35.green(` \u2713 Deleted ${deleted.length} merged branc${deleted.length > 1 ? "hes" : "h"}:`));
|
|
6002
6117
|
for (const b of deleted) {
|
|
6003
6118
|
console.log(` \u2022 ${b}`);
|
|
6004
6119
|
}
|
|
@@ -6006,7 +6121,7 @@ async function cmdBranch(action, name, options) {
|
|
|
6006
6121
|
break;
|
|
6007
6122
|
}
|
|
6008
6123
|
default:
|
|
6009
|
-
console.log(
|
|
6124
|
+
console.log(chalk35.yellow(` Unknown action: ${action}. Use: create, switch, delete, cleanup, or list.`));
|
|
6010
6125
|
}
|
|
6011
6126
|
}
|
|
6012
6127
|
async function cmdLog(options) {
|
|
@@ -6016,10 +6131,10 @@ async function cmdLog(options) {
|
|
|
6016
6131
|
const count = parseInt(options.count || "10", 10);
|
|
6017
6132
|
const log = getLog(count, root || dir);
|
|
6018
6133
|
if (log.length === 0) {
|
|
6019
|
-
console.log(
|
|
6134
|
+
console.log(chalk35.yellow(" No commits found."));
|
|
6020
6135
|
return;
|
|
6021
6136
|
}
|
|
6022
|
-
console.log(
|
|
6137
|
+
console.log(chalk35.bold(`
|
|
6023
6138
|
Recent Commits (${log.length}):`));
|
|
6024
6139
|
console.log(` ${formatLog(log)}`);
|
|
6025
6140
|
console.log("");
|
|
@@ -6027,7 +6142,7 @@ async function cmdLog(options) {
|
|
|
6027
6142
|
async function cmdPRSummary(baseBranch, options) {
|
|
6028
6143
|
if (!requireGit(options.dir)) return;
|
|
6029
6144
|
const base = baseBranch || "main";
|
|
6030
|
-
console.log(
|
|
6145
|
+
console.log(chalk35.dim(` Generating PR summary (${base}...HEAD)...`));
|
|
6031
6146
|
const summary = await generatePRSummary(base);
|
|
6032
6147
|
console.log(`
|
|
6033
6148
|
${summary}
|
|
@@ -6053,19 +6168,19 @@ async function cmdDiff(options) {
|
|
|
6053
6168
|
const root = getGitRoot(dir);
|
|
6054
6169
|
const diff = options.staged ? (await import("./git-FZPRJVFI.js")).getStagedDiff(root || dir) : getDiff(root || dir);
|
|
6055
6170
|
if (!diff) {
|
|
6056
|
-
console.log(
|
|
6171
|
+
console.log(chalk35.yellow(" No changes to show."));
|
|
6057
6172
|
return;
|
|
6058
6173
|
}
|
|
6059
6174
|
const lines = diff.split("\n");
|
|
6060
6175
|
for (const line of lines) {
|
|
6061
6176
|
if (line.startsWith("+")) {
|
|
6062
|
-
process.stdout.write(
|
|
6177
|
+
process.stdout.write(chalk35.green(line) + "\n");
|
|
6063
6178
|
} else if (line.startsWith("-")) {
|
|
6064
|
-
process.stdout.write(
|
|
6179
|
+
process.stdout.write(chalk35.red(line) + "\n");
|
|
6065
6180
|
} else if (line.startsWith("@@")) {
|
|
6066
|
-
process.stdout.write(
|
|
6181
|
+
process.stdout.write(chalk35.cyan(line) + "\n");
|
|
6067
6182
|
} else if (line.startsWith("diff --git")) {
|
|
6068
|
-
process.stdout.write(
|
|
6183
|
+
process.stdout.write(chalk35.bold(line) + "\n");
|
|
6069
6184
|
} else {
|
|
6070
6185
|
process.stdout.write(line + "\n");
|
|
6071
6186
|
}
|
|
@@ -6109,7 +6224,7 @@ gitCommand.command("diff").description("Show diff").option("--staged", "Show sta
|
|
|
6109
6224
|
|
|
6110
6225
|
// src/commands/tui.ts
|
|
6111
6226
|
import { Command as Command13 } from "commander";
|
|
6112
|
-
import
|
|
6227
|
+
import chalk36 from "chalk";
|
|
6113
6228
|
|
|
6114
6229
|
// src/tui/index.ts
|
|
6115
6230
|
import React4 from "react";
|
|
@@ -6946,12 +7061,12 @@ async function loadAIProvider() {
|
|
|
6946
7061
|
loadEnv2();
|
|
6947
7062
|
const cfg = loadConfig2();
|
|
6948
7063
|
if (!cfg.provider) {
|
|
6949
|
-
console.log(
|
|
7064
|
+
console.log(chalk36.yellow("No AI provider configured. Use `lovecode init` to set one up."));
|
|
6950
7065
|
return null;
|
|
6951
7066
|
}
|
|
6952
7067
|
const resolved = resolveModel(cfg.provider);
|
|
6953
7068
|
if (!resolved) {
|
|
6954
|
-
console.log(
|
|
7069
|
+
console.log(chalk36.yellow(`Provider "${cfg.provider}" not found. Use \`lovecode init\` to reconfigure.`));
|
|
6955
7070
|
return null;
|
|
6956
7071
|
}
|
|
6957
7072
|
const provider = resolved.entry.provider;
|
|
@@ -6964,7 +7079,7 @@ async function loadAIProvider() {
|
|
|
6964
7079
|
};
|
|
6965
7080
|
return { provider, config };
|
|
6966
7081
|
} catch (err) {
|
|
6967
|
-
console.log(
|
|
7082
|
+
console.log(chalk36.red(`Failed to load AI provider: ${err.message}`));
|
|
6968
7083
|
return null;
|
|
6969
7084
|
}
|
|
6970
7085
|
}
|
|
@@ -7150,7 +7265,7 @@ async function getTool2(name) {
|
|
|
7150
7265
|
}
|
|
7151
7266
|
async function cmdTUI(options) {
|
|
7152
7267
|
const workingDir = options.dir || process.cwd();
|
|
7153
|
-
console.log(
|
|
7268
|
+
console.log(chalk36.dim("Starting LoveCode TUI..."));
|
|
7154
7269
|
if (options.theme) {
|
|
7155
7270
|
const mod = await import("./theme-ZRZYRB2Q.js");
|
|
7156
7271
|
const names = mod.getThemeNames();
|
|
@@ -7234,7 +7349,7 @@ var tuiCommand = new Command13("tui").alias("ui").description("Launch the Termin
|
|
|
7234
7349
|
|
|
7235
7350
|
// src/commands/plugin.ts
|
|
7236
7351
|
import { Command as Command14 } from "commander";
|
|
7237
|
-
import
|
|
7352
|
+
import chalk37 from "chalk";
|
|
7238
7353
|
async function cmdListPlugins() {
|
|
7239
7354
|
const { listPlugins: listPlugins2, formatPluginList } = await import("./registry-MW5ISDO7.js");
|
|
7240
7355
|
const plugins = listPlugins2();
|
|
@@ -7243,12 +7358,12 @@ async function cmdListPlugins() {
|
|
|
7243
7358
|
async function cmdEnablePlugin(name) {
|
|
7244
7359
|
const { enablePlugin: enablePlugin2 } = await import("./registry-MW5ISDO7.js");
|
|
7245
7360
|
const ok = enablePlugin2(name);
|
|
7246
|
-
console.log(ok ?
|
|
7361
|
+
console.log(ok ? chalk37.green(`Enabled plugin: ${name}`) : chalk37.red(`Plugin not found: ${name}`));
|
|
7247
7362
|
}
|
|
7248
7363
|
async function cmdDisablePlugin(name) {
|
|
7249
7364
|
const { disablePlugin: disablePlugin2 } = await import("./registry-MW5ISDO7.js");
|
|
7250
7365
|
const ok = disablePlugin2(name);
|
|
7251
|
-
console.log(ok ?
|
|
7366
|
+
console.log(ok ? chalk37.yellow(`Disabled plugin: ${name}`) : chalk37.red(`Plugin not found: ${name}`));
|
|
7252
7367
|
}
|
|
7253
7368
|
async function cmdSearchMarketplace(query) {
|
|
7254
7369
|
const { searchMarketplace, formatMarketplace } = await import("./registry-MW5ISDO7.js");
|
|
@@ -7269,37 +7384,37 @@ pluginCommand.command("search").description("Search plugin marketplace").argumen
|
|
|
7269
7384
|
|
|
7270
7385
|
// src/commands/browser.ts
|
|
7271
7386
|
import { Command as Command15 } from "commander";
|
|
7272
|
-
import
|
|
7387
|
+
import chalk38 from "chalk";
|
|
7273
7388
|
async function cmdStart(options) {
|
|
7274
7389
|
const { launchBrowser } = await import("./playwright-N7OAVW2N.js");
|
|
7275
7390
|
try {
|
|
7276
7391
|
await launchBrowser({ headless: options.headless !== false });
|
|
7277
|
-
console.log(
|
|
7392
|
+
console.log(chalk38.green("Browser launched."));
|
|
7278
7393
|
} catch (err) {
|
|
7279
|
-
console.log(
|
|
7394
|
+
console.log(chalk38.red(`Failed: ${err.message}`));
|
|
7280
7395
|
}
|
|
7281
7396
|
}
|
|
7282
7397
|
async function cmdStop() {
|
|
7283
7398
|
const { closeBrowser } = await import("./playwright-N7OAVW2N.js");
|
|
7284
7399
|
await closeBrowser();
|
|
7285
|
-
console.log(
|
|
7400
|
+
console.log(chalk38.yellow("Browser closed."));
|
|
7286
7401
|
}
|
|
7287
7402
|
async function cmdGoto(url) {
|
|
7288
7403
|
const { goto: goto2 } = await import("./playwright-N7OAVW2N.js");
|
|
7289
7404
|
try {
|
|
7290
7405
|
const result = await goto2(url);
|
|
7291
|
-
console.log(
|
|
7406
|
+
console.log(chalk38.green(result));
|
|
7292
7407
|
} catch (err) {
|
|
7293
|
-
console.log(
|
|
7408
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7294
7409
|
}
|
|
7295
7410
|
}
|
|
7296
7411
|
async function cmdClick(selector) {
|
|
7297
7412
|
const { click: click2 } = await import("./playwright-N7OAVW2N.js");
|
|
7298
7413
|
try {
|
|
7299
7414
|
const result = await click2(selector);
|
|
7300
|
-
console.log(
|
|
7415
|
+
console.log(chalk38.green(result));
|
|
7301
7416
|
} catch (err) {
|
|
7302
|
-
console.log(
|
|
7417
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7303
7418
|
}
|
|
7304
7419
|
}
|
|
7305
7420
|
async function cmdType(selector, text, options) {
|
|
@@ -7307,18 +7422,18 @@ async function cmdType(selector, text, options) {
|
|
|
7307
7422
|
const value = text || options.text || "";
|
|
7308
7423
|
try {
|
|
7309
7424
|
const result = await type2(selector, value);
|
|
7310
|
-
console.log(
|
|
7425
|
+
console.log(chalk38.green(result));
|
|
7311
7426
|
} catch (err) {
|
|
7312
|
-
console.log(
|
|
7427
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7313
7428
|
}
|
|
7314
7429
|
}
|
|
7315
7430
|
async function cmdScreenshot(options) {
|
|
7316
7431
|
const { screenshot: screenshot2, formatScreenshotResult: formatScreenshotResult2 } = await import("./playwright-N7OAVW2N.js");
|
|
7317
7432
|
try {
|
|
7318
7433
|
const result = await screenshot2(options.name);
|
|
7319
|
-
console.log(
|
|
7434
|
+
console.log(chalk38.green(formatScreenshotResult2(result)));
|
|
7320
7435
|
} catch (err) {
|
|
7321
|
-
console.log(
|
|
7436
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7322
7437
|
}
|
|
7323
7438
|
}
|
|
7324
7439
|
async function cmdInspect(selector) {
|
|
@@ -7328,10 +7443,10 @@ async function cmdInspect(selector) {
|
|
|
7328
7443
|
if (el) {
|
|
7329
7444
|
console.log(formatDOMElement2(el));
|
|
7330
7445
|
} else {
|
|
7331
|
-
console.log(
|
|
7446
|
+
console.log(chalk38.yellow(`Element not found: ${selector}`));
|
|
7332
7447
|
}
|
|
7333
7448
|
} catch (err) {
|
|
7334
|
-
console.log(
|
|
7449
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7335
7450
|
}
|
|
7336
7451
|
}
|
|
7337
7452
|
async function cmdActions(actions, options) {
|
|
@@ -7347,10 +7462,10 @@ async function cmdActions(actions, options) {
|
|
|
7347
7462
|
try {
|
|
7348
7463
|
const results = await runActions(parsedActions);
|
|
7349
7464
|
for (const r of results) {
|
|
7350
|
-
console.log(
|
|
7465
|
+
console.log(chalk38.cyan(` \u2192 ${r.slice(0, 200)}`));
|
|
7351
7466
|
}
|
|
7352
7467
|
} catch (err) {
|
|
7353
|
-
console.log(
|
|
7468
|
+
console.log(chalk38.red(`Error: ${err.message}`));
|
|
7354
7469
|
}
|
|
7355
7470
|
}
|
|
7356
7471
|
var browserCommand = new Command15("browser").alias("br").description("Browser automation \u2014 Playwright-powered").addHelpText("after", `
|
|
@@ -7377,10 +7492,10 @@ browserCommand.command("actions").description("Run a sequence of browser actions
|
|
|
7377
7492
|
|
|
7378
7493
|
// src/commands/security.ts
|
|
7379
7494
|
import { Command as Command16 } from "commander";
|
|
7380
|
-
import
|
|
7495
|
+
import chalk43 from "chalk";
|
|
7381
7496
|
|
|
7382
7497
|
// src/security/risk.ts
|
|
7383
|
-
import
|
|
7498
|
+
import chalk39 from "chalk";
|
|
7384
7499
|
var COMMAND_RULES = [
|
|
7385
7500
|
{ pattern: /^rm\s+-rf\s+(\/|\/\w+|\.)/, score: 100, reason: "Destructive recursive delete" },
|
|
7386
7501
|
{ pattern: /^rm\s+-rf/, score: 80, reason: "Recursive force delete" },
|
|
@@ -7491,21 +7606,21 @@ function scoreToAction(score) {
|
|
|
7491
7606
|
}
|
|
7492
7607
|
function formatRisk(risk) {
|
|
7493
7608
|
const colors = {
|
|
7494
|
-
safe:
|
|
7495
|
-
low:
|
|
7496
|
-
medium:
|
|
7497
|
-
high:
|
|
7498
|
-
critical:
|
|
7609
|
+
safe: chalk39.green,
|
|
7610
|
+
low: chalk39.cyan,
|
|
7611
|
+
medium: chalk39.yellow,
|
|
7612
|
+
high: chalk39.red,
|
|
7613
|
+
critical: chalk39.bgRed.white
|
|
7499
7614
|
};
|
|
7500
|
-
const color = colors[risk.level] ||
|
|
7615
|
+
const color = colors[risk.level] || chalk39.dim;
|
|
7501
7616
|
const label = risk.level.toUpperCase().padEnd(10);
|
|
7502
|
-
const action = risk.suggestedAction === "auto" ?
|
|
7503
|
-
return ` ${color(label)} score=${risk.score} action=${action} ${
|
|
7617
|
+
const action = risk.suggestedAction === "auto" ? chalk39.green(risk.suggestedAction) : risk.suggestedAction === "confirm" ? chalk39.yellow(risk.suggestedAction) : chalk39.bgRed.white(` ${risk.suggestedAction} `);
|
|
7618
|
+
return ` ${color(label)} score=${risk.score} action=${action} ${chalk39.dim(risk.reasons.join(", "))}`;
|
|
7504
7619
|
}
|
|
7505
7620
|
|
|
7506
7621
|
// src/security/secrets.ts
|
|
7507
7622
|
import * as fs21 from "fs";
|
|
7508
|
-
import
|
|
7623
|
+
import chalk40 from "chalk";
|
|
7509
7624
|
var SECRET_RULES = [
|
|
7510
7625
|
{ type: "aws_key", pattern: /(?:AKIA|ASIA)[0-9A-Z]{16}/g, severity: "critical", description: "AWS Access Key ID" },
|
|
7511
7626
|
{ type: "gcp_key", pattern: /AIza[0-9A-Za-z\-_]{35}/g, severity: "critical", description: "GCP API Key" },
|
|
@@ -7590,30 +7705,30 @@ function scanDirectory2(dirPath, maxFiles = 100) {
|
|
|
7590
7705
|
}
|
|
7591
7706
|
function formatSecretMatch(match) {
|
|
7592
7707
|
const severityColor = {
|
|
7593
|
-
low:
|
|
7594
|
-
medium:
|
|
7595
|
-
high:
|
|
7596
|
-
critical:
|
|
7708
|
+
low: chalk40.cyan,
|
|
7709
|
+
medium: chalk40.yellow,
|
|
7710
|
+
high: chalk40.red,
|
|
7711
|
+
critical: chalk40.bgRed.white
|
|
7597
7712
|
};
|
|
7598
|
-
const sev = severityColor[match.severity] ||
|
|
7599
|
-
const fileInfo = match.file ? `${
|
|
7713
|
+
const sev = severityColor[match.severity] || chalk40.dim;
|
|
7714
|
+
const fileInfo = match.file ? `${chalk40.dim(match.file)}:${match.line}:${match.column}` : `line ${match.line}:${match.column}`;
|
|
7600
7715
|
return ` ${sev(match.severity.toUpperCase().padEnd(10))} ${match.type.padEnd(20)} ${match.value.padEnd(30)} ${fileInfo}
|
|
7601
|
-
${
|
|
7716
|
+
${chalk40.dim(match.context)}`;
|
|
7602
7717
|
}
|
|
7603
7718
|
function formatSecretSummary(matches) {
|
|
7604
|
-
if (matches.length === 0) return
|
|
7719
|
+
if (matches.length === 0) return chalk40.green("No secrets detected.");
|
|
7605
7720
|
const bySeverity = /* @__PURE__ */ new Map();
|
|
7606
7721
|
for (const m of matches) {
|
|
7607
7722
|
const arr = bySeverity.get(m.severity) || [];
|
|
7608
7723
|
arr.push(m);
|
|
7609
7724
|
bySeverity.set(m.severity, arr);
|
|
7610
7725
|
}
|
|
7611
|
-
const lines = [
|
|
7726
|
+
const lines = [chalk40.bold(`
|
|
7612
7727
|
Secrets Detected (${matches.length}):`)];
|
|
7613
7728
|
for (const [severity, ms] of bySeverity) {
|
|
7614
7729
|
const label = severity.toUpperCase();
|
|
7615
7730
|
lines.push(`
|
|
7616
|
-
${
|
|
7731
|
+
${chalk40.bold(label)} (${ms.length}):`);
|
|
7617
7732
|
for (const m of ms.slice(0, 10)) {
|
|
7618
7733
|
lines.push(formatSecretMatch(m));
|
|
7619
7734
|
}
|
|
@@ -7623,7 +7738,7 @@ function formatSecretSummary(matches) {
|
|
|
7623
7738
|
}
|
|
7624
7739
|
|
|
7625
7740
|
// src/security/sandbox.ts
|
|
7626
|
-
import
|
|
7741
|
+
import chalk41 from "chalk";
|
|
7627
7742
|
var PROFILES = {
|
|
7628
7743
|
isolated: {
|
|
7629
7744
|
name: "isolated",
|
|
@@ -7752,10 +7867,10 @@ function checkCommand(command, cwd, profileName) {
|
|
|
7752
7867
|
return { allowed: true };
|
|
7753
7868
|
}
|
|
7754
7869
|
function formatProfile(profile) {
|
|
7755
|
-
const yes =
|
|
7756
|
-
const no =
|
|
7870
|
+
const yes = chalk41.green("\u2713");
|
|
7871
|
+
const no = chalk41.red("\u2717");
|
|
7757
7872
|
return [
|
|
7758
|
-
`${
|
|
7873
|
+
`${chalk41.bold(profile.name.toUpperCase())}`,
|
|
7759
7874
|
` Network: ${profile.allowNetwork ? yes : no}`,
|
|
7760
7875
|
` File Read: ${profile.allowFileRead ? yes : no}`,
|
|
7761
7876
|
` File Write: ${profile.allowFileWrite ? yes : no}`,
|
|
@@ -7769,7 +7884,7 @@ function formatProfile(profile) {
|
|
|
7769
7884
|
// src/security/permissions.ts
|
|
7770
7885
|
import * as fs22 from "fs";
|
|
7771
7886
|
import * as path20 from "path";
|
|
7772
|
-
import
|
|
7887
|
+
import chalk42 from "chalk";
|
|
7773
7888
|
var PERMISSION_FILE = ".lovecode/permissions.json";
|
|
7774
7889
|
var DEFAULT_PERMISSIONS = {
|
|
7775
7890
|
version: 1,
|
|
@@ -7882,24 +7997,24 @@ function resetPermissions(rootDir) {
|
|
|
7882
7997
|
cachedPermissions = null;
|
|
7883
7998
|
}
|
|
7884
7999
|
function formatPermissions(perms) {
|
|
7885
|
-
const lines = [
|
|
7886
|
-
lines.push(` ${
|
|
7887
|
-
lines.push(` ${
|
|
7888
|
-
lines.push(` ${
|
|
7889
|
-
lines.push(` ${
|
|
7890
|
-
lines.push(` ${
|
|
8000
|
+
const lines = [chalk42.bold("\n Permission Settings")];
|
|
8001
|
+
lines.push(` ${chalk42.dim("File Read:")} ${formatAction(perms.defaults.fileRead)}`);
|
|
8002
|
+
lines.push(` ${chalk42.dim("File Write:")} ${formatAction(perms.defaults.fileWrite)}`);
|
|
8003
|
+
lines.push(` ${chalk42.dim("Network:")} ${formatAction(perms.defaults.networkAccess)}`);
|
|
8004
|
+
lines.push(` ${chalk42.dim("Commands:")} ${formatAction(perms.defaults.commandExecution)}`);
|
|
8005
|
+
lines.push(` ${chalk42.dim("Environment:")} ${formatAction(perms.defaults.environmentAccess)}`);
|
|
7891
8006
|
if (perms.entries.length > 0) {
|
|
7892
8007
|
lines.push(`
|
|
7893
|
-
${
|
|
8008
|
+
${chalk42.bold("Specific Permissions:")}`);
|
|
7894
8009
|
for (const e of perms.entries) {
|
|
7895
|
-
lines.push(` ${formatAction(e.action)} ${e.resource}${e.reason ? ` ${
|
|
8010
|
+
lines.push(` ${formatAction(e.action)} ${e.resource}${e.reason ? ` ${chalk42.dim(`(${e.reason})`)}` : ""}`);
|
|
7896
8011
|
}
|
|
7897
8012
|
}
|
|
7898
8013
|
if (perms.trustedSources.length > 0) {
|
|
7899
8014
|
lines.push(`
|
|
7900
|
-
${
|
|
8015
|
+
${chalk42.bold("Trusted Sources:")}`);
|
|
7901
8016
|
for (const s of perms.trustedSources) {
|
|
7902
|
-
lines.push(` ${
|
|
8017
|
+
lines.push(` ${chalk42.green("\u2713")} ${s}`);
|
|
7903
8018
|
}
|
|
7904
8019
|
}
|
|
7905
8020
|
return lines.join("\n");
|
|
@@ -7907,11 +8022,11 @@ function formatPermissions(perms) {
|
|
|
7907
8022
|
function formatAction(action) {
|
|
7908
8023
|
switch (action) {
|
|
7909
8024
|
case "allow":
|
|
7910
|
-
return
|
|
8025
|
+
return chalk42.green("ALLOW");
|
|
7911
8026
|
case "deny":
|
|
7912
|
-
return
|
|
8027
|
+
return chalk42.red("DENY");
|
|
7913
8028
|
case "ask":
|
|
7914
|
-
return
|
|
8029
|
+
return chalk42.yellow("ASK");
|
|
7915
8030
|
}
|
|
7916
8031
|
}
|
|
7917
8032
|
|
|
@@ -7920,8 +8035,8 @@ async function cmdAssessRisk(command, options) {
|
|
|
7920
8035
|
if (command) {
|
|
7921
8036
|
const risk = assessCommandRisk(command);
|
|
7922
8037
|
console.log(`
|
|
7923
|
-
${
|
|
7924
|
-
console.log(` ${
|
|
8038
|
+
${chalk43.bold("Command Risk Assessment")}`);
|
|
8039
|
+
console.log(` ${chalk43.dim(command)}`);
|
|
7925
8040
|
console.log(formatRisk(risk));
|
|
7926
8041
|
} else if (options.tool) {
|
|
7927
8042
|
let args;
|
|
@@ -7934,11 +8049,11 @@ async function cmdAssessRisk(command, options) {
|
|
|
7934
8049
|
}
|
|
7935
8050
|
const risk = assessToolRisk(options.tool, args);
|
|
7936
8051
|
console.log(`
|
|
7937
|
-
${
|
|
7938
|
-
console.log(` ${
|
|
8052
|
+
${chalk43.bold("Tool Risk Assessment")}`);
|
|
8053
|
+
console.log(` ${chalk43.dim(`${options.tool}${args ? " " + JSON.stringify(args) : ""}`)}`);
|
|
7939
8054
|
console.log(formatRisk(risk));
|
|
7940
8055
|
} else {
|
|
7941
|
-
console.log(
|
|
8056
|
+
console.log(chalk43.yellow("Provide a command string or --tool."));
|
|
7942
8057
|
}
|
|
7943
8058
|
}
|
|
7944
8059
|
async function cmdScanSecrets(options) {
|
|
@@ -7947,16 +8062,16 @@ async function cmdScanSecrets(options) {
|
|
|
7947
8062
|
console.log(formatSecretSummary(matches));
|
|
7948
8063
|
} else if (options.dir) {
|
|
7949
8064
|
const max = parseInt(options.max || "100", 10);
|
|
7950
|
-
console.log(
|
|
8065
|
+
console.log(chalk43.dim(`Scanning ${options.dir} for secrets...`));
|
|
7951
8066
|
const matches = scanDirectory2(options.dir, max);
|
|
7952
8067
|
console.log(formatSecretSummary(matches));
|
|
7953
8068
|
} else {
|
|
7954
|
-
console.log(
|
|
8069
|
+
console.log(chalk43.yellow("Provide --text or --dir."));
|
|
7955
8070
|
}
|
|
7956
8071
|
}
|
|
7957
8072
|
async function cmdProfiles() {
|
|
7958
8073
|
const profiles = listProfiles();
|
|
7959
|
-
console.log(
|
|
8074
|
+
console.log(chalk43.bold("\n Sandbox Profiles:\n"));
|
|
7960
8075
|
for (const p of profiles) {
|
|
7961
8076
|
console.log(formatProfile(p));
|
|
7962
8077
|
console.log("");
|
|
@@ -7965,35 +8080,35 @@ async function cmdProfiles() {
|
|
|
7965
8080
|
async function cmdSandbox(command, options) {
|
|
7966
8081
|
const result = checkCommand(command, process.cwd(), options.profile);
|
|
7967
8082
|
if (result.allowed) {
|
|
7968
|
-
console.log(
|
|
7969
|
-
Allowed: ${
|
|
8083
|
+
console.log(chalk43.green(`
|
|
8084
|
+
Allowed: ${chalk43.dim(command)}`));
|
|
7970
8085
|
} else {
|
|
7971
|
-
console.log(
|
|
7972
|
-
Blocked: ${
|
|
7973
|
-
console.log(` ${
|
|
8086
|
+
console.log(chalk43.red(`
|
|
8087
|
+
Blocked: ${chalk43.dim(command)}`));
|
|
8088
|
+
console.log(` ${chalk43.yellow(result.reason)}`);
|
|
7974
8089
|
}
|
|
7975
8090
|
}
|
|
7976
8091
|
async function cmdPermissions(options) {
|
|
7977
8092
|
if (options.set && options.action) {
|
|
7978
8093
|
const defaults = ["fileRead", "fileWrite", "networkAccess", "commandExecution", "environmentAccess"];
|
|
7979
8094
|
if (!defaults.includes(options.set)) {
|
|
7980
|
-
console.log(
|
|
8095
|
+
console.log(chalk43.red(`Invalid default: ${options.set}. Options: ${defaults.join(", ")}`));
|
|
7981
8096
|
return;
|
|
7982
8097
|
}
|
|
7983
8098
|
const perms = setDefault(options.set, options.action, options.dir);
|
|
7984
|
-
console.log(
|
|
8099
|
+
console.log(chalk43.green(`Default "${options.set}" set to "${options.action}".`));
|
|
7985
8100
|
console.log(formatPermissions(perms));
|
|
7986
8101
|
} else if (options.add && options.action) {
|
|
7987
8102
|
const action = options.action;
|
|
7988
8103
|
const perms = addPermission(options.add, action, void 0, options.dir);
|
|
7989
|
-
console.log(
|
|
8104
|
+
console.log(chalk43.green(`Permission added: ${options.add} \u2192 ${action}`));
|
|
7990
8105
|
console.log(formatPermissions(perms));
|
|
7991
8106
|
} else if (options.remove) {
|
|
7992
8107
|
const ok = removePermission(options.remove, options.dir);
|
|
7993
|
-
console.log(ok ?
|
|
8108
|
+
console.log(ok ? chalk43.green(`Removed permission: ${options.remove}`) : chalk43.yellow(`Permission not found: ${options.remove}`));
|
|
7994
8109
|
} else if (options.source) {
|
|
7995
8110
|
addTrustedSource(options.source, options.dir);
|
|
7996
|
-
console.log(
|
|
8111
|
+
console.log(chalk43.green(`Trusted source added: ${options.source}`));
|
|
7997
8112
|
} else {
|
|
7998
8113
|
const perms = loadPermissions(options.dir);
|
|
7999
8114
|
console.log(formatPermissions(perms));
|
|
@@ -8002,16 +8117,16 @@ async function cmdPermissions(options) {
|
|
|
8002
8117
|
async function cmdCheckPermission(resource, options) {
|
|
8003
8118
|
const category = options.category || "fileRead";
|
|
8004
8119
|
const result = checkPermission(resource, category, options.dir);
|
|
8005
|
-
const color = result === "allow" ?
|
|
8006
|
-
console.log(` ${color(result.toUpperCase())} ${
|
|
8120
|
+
const color = result === "allow" ? chalk43.green : result === "deny" ? chalk43.red : chalk43.yellow;
|
|
8121
|
+
console.log(` ${color(result.toUpperCase())} ${chalk43.dim(resource)} (${category})`);
|
|
8007
8122
|
}
|
|
8008
8123
|
async function cmdReset(options) {
|
|
8009
8124
|
resetPermissions(options.dir);
|
|
8010
|
-
console.log(
|
|
8125
|
+
console.log(chalk43.green("Permissions reset to defaults."));
|
|
8011
8126
|
}
|
|
8012
8127
|
async function cmdRemoveSource(source, options) {
|
|
8013
8128
|
const ok = removeTrustedSource(source, options.dir);
|
|
8014
|
-
console.log(ok ?
|
|
8129
|
+
console.log(ok ? chalk43.green(`Removed trusted source: ${source}`) : chalk43.yellow(`Source not found: ${source}`));
|
|
8015
8130
|
}
|
|
8016
8131
|
var securityCommand = new Command16("security").alias("sec").alias("secure").description("Security tools: risk assessment, secret detection, sandbox, permissions").addHelpText("after", `
|
|
8017
8132
|
Examples:
|
|
@@ -8046,7 +8161,7 @@ var pkg = {
|
|
|
8046
8161
|
description: "Terminal-native autonomous coding agent powered by free AI models"
|
|
8047
8162
|
};
|
|
8048
8163
|
var program = new Command17();
|
|
8049
|
-
program.name(pkg.name).description(
|
|
8164
|
+
program.name(pkg.name).description(chalk44.cyan(pkg.description)).version(pkg.version, "-v, --version", "Output the current version");
|
|
8050
8165
|
program.addCommand(chatCommand);
|
|
8051
8166
|
program.addCommand(runCommand);
|
|
8052
8167
|
program.addCommand(initCommand);
|