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