lazy-gravity 0.0.2 → 0.0.3
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/LICENSE +21 -0
- package/README.md +224 -0
- package/dist/bin/cli.js +79 -0
- package/dist/bin/commands/doctor.js +156 -0
- package/dist/bin/commands/open.js +145 -0
- package/dist/bin/commands/setup.js +366 -0
- package/dist/bin/commands/start.js +15 -0
- package/dist/bot/index.js +914 -0
- package/dist/commands/chatCommandHandler.js +145 -0
- package/dist/commands/cleanupCommandHandler.js +396 -0
- package/dist/commands/messageParser.js +28 -0
- package/dist/commands/registerSlashCommands.js +149 -0
- package/dist/commands/slashCommandHandler.js +104 -0
- package/dist/commands/workspaceCommandHandler.js +230 -0
- package/dist/database/chatSessionRepository.js +88 -0
- package/dist/database/scheduleRepository.js +119 -0
- package/dist/database/templateRepository.js +103 -0
- package/dist/database/workspaceBindingRepository.js +109 -0
- package/dist/events/interactionCreateHandler.js +286 -0
- package/dist/events/messageCreateHandler.js +154 -0
- package/dist/index.js +10 -0
- package/dist/middleware/auth.js +10 -0
- package/dist/middleware/sanitize.js +20 -0
- package/dist/services/antigravityLauncher.js +89 -0
- package/dist/services/approvalDetector.js +384 -0
- package/dist/services/autoAcceptService.js +80 -0
- package/dist/services/cdpBridgeManager.js +204 -0
- package/dist/services/cdpConnectionPool.js +157 -0
- package/dist/services/cdpService.js +1311 -0
- package/dist/services/channelManager.js +118 -0
- package/dist/services/chatSessionService.js +516 -0
- package/dist/services/modeService.js +73 -0
- package/dist/services/modelService.js +63 -0
- package/dist/services/processManager.js +61 -0
- package/dist/services/progressSender.js +61 -0
- package/dist/services/promptDispatcher.js +17 -0
- package/dist/services/quotaService.js +185 -0
- package/dist/services/responseMonitor.js +645 -0
- package/dist/services/scheduleService.js +134 -0
- package/dist/services/screenshotService.js +85 -0
- package/dist/services/titleGeneratorService.js +113 -0
- package/dist/services/workspaceService.js +64 -0
- package/dist/ui/autoAcceptUi.js +34 -0
- package/dist/ui/modeUi.js +34 -0
- package/dist/ui/modelsUi.js +97 -0
- package/dist/ui/screenshotUi.js +51 -0
- package/dist/ui/templateUi.js +67 -0
- package/dist/utils/cdpPorts.js +5 -0
- package/dist/utils/config.js +20 -0
- package/dist/utils/configLoader.js +160 -0
- package/dist/utils/discordFormatter.js +167 -0
- package/dist/utils/i18n.js +77 -0
- package/dist/utils/imageHandler.js +154 -0
- package/dist/utils/lockfile.js +113 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logo.js +13 -0
- package/dist/utils/metadataExtractor.js +15 -0
- package/dist/utils/processLogBuffer.js +98 -0
- package/dist/utils/streamMessageFormatter.js +90 -0
- package/package.json +73 -5
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.acquireLock = acquireLock;
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const LOCK_FILE = path_1.default.resolve(process.cwd(), '.bot.lock');
|
|
11
|
+
/**
|
|
12
|
+
* Check if a process with the given PID is running
|
|
13
|
+
*/
|
|
14
|
+
function isProcessRunning(pid) {
|
|
15
|
+
try {
|
|
16
|
+
process.kill(pid, 0);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Stop an existing process and wait for it to exit
|
|
25
|
+
*/
|
|
26
|
+
function killExistingProcess(pid) {
|
|
27
|
+
logger_1.logger.error(`🔄 Stopping existing Bot process (PID: ${pid})...`);
|
|
28
|
+
try {
|
|
29
|
+
process.kill(pid, 'SIGTERM');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Ignore if already terminated
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Wait up to 5 seconds for process to exit
|
|
36
|
+
const deadline = Date.now() + 5000;
|
|
37
|
+
while (Date.now() < deadline) {
|
|
38
|
+
if (!isProcessRunning(pid)) {
|
|
39
|
+
logger_1.logger.error(`✅ Existing process (PID: ${pid}) stopped`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Wait 50ms (busy wait)
|
|
43
|
+
const waitUntil = Date.now() + 50;
|
|
44
|
+
while (Date.now() < waitUntil) { /* spin */ }
|
|
45
|
+
}
|
|
46
|
+
// Timeout: force kill with SIGKILL
|
|
47
|
+
logger_1.logger.error(`⚠️ Process did not exit with SIGTERM, force killing (SIGKILL)`);
|
|
48
|
+
try {
|
|
49
|
+
process.kill(pid, 'SIGKILL');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// ignore
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Acquire a lockfile to prevent duplicate bot instances.
|
|
57
|
+
* If another process is already running, stop it before starting.
|
|
58
|
+
*
|
|
59
|
+
* @returns A function to release the lock
|
|
60
|
+
*/
|
|
61
|
+
function acquireLock() {
|
|
62
|
+
// Check existing lock file
|
|
63
|
+
if (fs_1.default.existsSync(LOCK_FILE)) {
|
|
64
|
+
const content = fs_1.default.readFileSync(LOCK_FILE, 'utf-8').trim();
|
|
65
|
+
const existingPid = parseInt(content, 10);
|
|
66
|
+
if (!isNaN(existingPid) && existingPid !== process.pid && isProcessRunning(existingPid)) {
|
|
67
|
+
// Stop existing process and restart
|
|
68
|
+
killExistingProcess(existingPid);
|
|
69
|
+
}
|
|
70
|
+
else if (!isNaN(existingPid) && !isProcessRunning(existingPid)) {
|
|
71
|
+
logger_1.logger.warn(`⚠️ Stale lock file detected (PID: ${existingPid} has exited). Cleaning up.`);
|
|
72
|
+
}
|
|
73
|
+
// Remove stale lock file
|
|
74
|
+
try {
|
|
75
|
+
fs_1.default.unlinkSync(LOCK_FILE);
|
|
76
|
+
}
|
|
77
|
+
catch { /* ignore */ }
|
|
78
|
+
}
|
|
79
|
+
// Create new lock file
|
|
80
|
+
fs_1.default.writeFileSync(LOCK_FILE, String(process.pid), 'utf-8');
|
|
81
|
+
logger_1.logger.error(`🔒 Lock acquired (PID: ${process.pid})`);
|
|
82
|
+
// Cleanup function
|
|
83
|
+
const releaseLock = () => {
|
|
84
|
+
try {
|
|
85
|
+
if (fs_1.default.existsSync(LOCK_FILE)) {
|
|
86
|
+
const content = fs_1.default.readFileSync(LOCK_FILE, 'utf-8').trim();
|
|
87
|
+
if (parseInt(content, 10) === process.pid) {
|
|
88
|
+
fs_1.default.unlinkSync(LOCK_FILE);
|
|
89
|
+
logger_1.logger.error(`🔓 Lock released (PID: ${process.pid})`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Ignore errors during cleanup
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
// Auto cleanup on process exit
|
|
98
|
+
process.on('exit', releaseLock);
|
|
99
|
+
process.on('SIGINT', () => {
|
|
100
|
+
releaseLock();
|
|
101
|
+
process.exit(0);
|
|
102
|
+
});
|
|
103
|
+
process.on('SIGTERM', () => {
|
|
104
|
+
releaseLock();
|
|
105
|
+
process.exit(0);
|
|
106
|
+
});
|
|
107
|
+
process.on('uncaughtException', (err) => {
|
|
108
|
+
logger_1.logger.error('Uncaught exception:', err);
|
|
109
|
+
releaseLock();
|
|
110
|
+
process.exit(1);
|
|
111
|
+
});
|
|
112
|
+
return releaseLock;
|
|
113
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
const COLORS = {
|
|
5
|
+
red: '\x1b[31m',
|
|
6
|
+
yellow: '\x1b[33m',
|
|
7
|
+
cyan: '\x1b[36m',
|
|
8
|
+
green: '\x1b[32m',
|
|
9
|
+
magenta: '\x1b[35m',
|
|
10
|
+
dim: '\x1b[2m',
|
|
11
|
+
reset: '\x1b[0m',
|
|
12
|
+
};
|
|
13
|
+
exports.logger = {
|
|
14
|
+
info: (...args) => console.info(`${COLORS.cyan}[INFO]${COLORS.reset}`, ...args),
|
|
15
|
+
warn: (...args) => console.warn(`${COLORS.yellow}[WARN]${COLORS.reset}`, ...args),
|
|
16
|
+
error: (...args) => console.error(`${COLORS.red}[ERROR]${COLORS.reset}`, ...args),
|
|
17
|
+
debug: (...args) => console.debug(`${COLORS.dim}[DEBUG]${COLORS.reset}`, ...args),
|
|
18
|
+
/** Important state transitions — stands out in logs */
|
|
19
|
+
phase: (...args) => console.info(`${COLORS.magenta}[PHASE]${COLORS.reset}`, ...args),
|
|
20
|
+
/** Completion-related events — green for success */
|
|
21
|
+
done: (...args) => console.info(`${COLORS.green}[DONE]${COLORS.reset}`, ...args),
|
|
22
|
+
/** Section divider with optional label for structured output */
|
|
23
|
+
divider: (label) => {
|
|
24
|
+
if (label) {
|
|
25
|
+
const pad = Math.max(4, 50 - label.length - 4);
|
|
26
|
+
console.info(`${COLORS.green}[DONE]${COLORS.reset} ${COLORS.dim}── ${label} ${'─'.repeat(pad)}${COLORS.reset}`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.info(`${COLORS.green}[DONE]${COLORS.reset} ${COLORS.dim}${'─'.repeat(50)}${COLORS.reset}`);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LOGO = void 0;
|
|
4
|
+
exports.LOGO = `
|
|
5
|
+
. * .
|
|
6
|
+
/\\___/\\ z Z
|
|
7
|
+
* ( - . - )____________z *
|
|
8
|
+
\\_ __)
|
|
9
|
+
\\_ \\________/ / .
|
|
10
|
+
\\__) \\__)
|
|
11
|
+
|
|
12
|
+
~ Booting... LazyGravity ~
|
|
13
|
+
`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractMetadataFromFooter = extractMetadataFromFooter;
|
|
4
|
+
function extractMetadataFromFooter(footerText) {
|
|
5
|
+
const result = {};
|
|
6
|
+
const taskIdMatch = footerText.match(/TaskID:\s*([^\s|]+)/i);
|
|
7
|
+
if (taskIdMatch && taskIdMatch[1]) {
|
|
8
|
+
result.taskId = taskIdMatch[1];
|
|
9
|
+
}
|
|
10
|
+
const dirMatch = footerText.match(/Dir:\s*([^\s|]+)/i);
|
|
11
|
+
if (dirMatch && dirMatch[1]) {
|
|
12
|
+
result.directory = dirMatch[1];
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProcessLogBuffer = void 0;
|
|
4
|
+
const DEFAULT_MAX_CHARS = 3500;
|
|
5
|
+
const DEFAULT_MAX_ENTRIES = 120;
|
|
6
|
+
const DEFAULT_MAX_ENTRY_LENGTH = 260;
|
|
7
|
+
function collapseWhitespace(text) {
|
|
8
|
+
return (text || '').replace(/\r/g, '').replace(/\s+/g, ' ').trim();
|
|
9
|
+
}
|
|
10
|
+
function parseBlocks(raw) {
|
|
11
|
+
const normalized = (raw || '').replace(/\r/g, '').trim();
|
|
12
|
+
if (!normalized)
|
|
13
|
+
return [];
|
|
14
|
+
const blocks = normalized
|
|
15
|
+
.split(/\n{2,}/)
|
|
16
|
+
.map((chunk) => collapseWhitespace(chunk))
|
|
17
|
+
.filter((chunk) => chunk.length > 0);
|
|
18
|
+
if (blocks.length > 0)
|
|
19
|
+
return blocks;
|
|
20
|
+
return normalized
|
|
21
|
+
.split('\n')
|
|
22
|
+
.map((line) => collapseWhitespace(line))
|
|
23
|
+
.filter((line) => line.length > 0);
|
|
24
|
+
}
|
|
25
|
+
function pickEmoji(entry) {
|
|
26
|
+
const lower = entry.toLowerCase();
|
|
27
|
+
if (/^thought for\b/.test(lower) || /^thinking\b/.test(lower))
|
|
28
|
+
return '🧠';
|
|
29
|
+
if (/^initiating\b/.test(lower) || /^starting\b/.test(lower))
|
|
30
|
+
return '🚀';
|
|
31
|
+
if (/^[a-z0-9._-]+\s*\/\s*[a-z0-9._-]+$/i.test(entry))
|
|
32
|
+
return '🛠️';
|
|
33
|
+
if (/^title:\s/.test(lower) && /\surl:\s/.test(lower))
|
|
34
|
+
return '🔎';
|
|
35
|
+
if (/^(json|javascript|typescript|python|bash|sh|html|css|xml|yaml|yml|toml|sql|graphql|markdown|text|plaintext|log)$/i.test(entry))
|
|
36
|
+
return '📦';
|
|
37
|
+
return '•';
|
|
38
|
+
}
|
|
39
|
+
function toDisplayEntry(rawEntry, maxEntryLength) {
|
|
40
|
+
const trimmed = collapseWhitespace(rawEntry);
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return '';
|
|
43
|
+
const clipped = trimmed.length > maxEntryLength
|
|
44
|
+
? `${trimmed.slice(0, Math.max(0, maxEntryLength - 3))}...`
|
|
45
|
+
: trimmed;
|
|
46
|
+
return `${pickEmoji(clipped)} ${clipped}`;
|
|
47
|
+
}
|
|
48
|
+
class ProcessLogBuffer {
|
|
49
|
+
maxChars;
|
|
50
|
+
maxEntries;
|
|
51
|
+
maxEntryLength;
|
|
52
|
+
entries = [];
|
|
53
|
+
seen = new Set();
|
|
54
|
+
constructor(options = {}) {
|
|
55
|
+
this.maxChars = options.maxChars ?? DEFAULT_MAX_CHARS;
|
|
56
|
+
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
57
|
+
this.maxEntryLength = options.maxEntryLength ?? DEFAULT_MAX_ENTRY_LENGTH;
|
|
58
|
+
}
|
|
59
|
+
append(raw) {
|
|
60
|
+
const blocks = parseBlocks(raw);
|
|
61
|
+
for (const block of blocks) {
|
|
62
|
+
const display = toDisplayEntry(block, this.maxEntryLength);
|
|
63
|
+
if (!display)
|
|
64
|
+
continue;
|
|
65
|
+
const key = display.toLowerCase();
|
|
66
|
+
if (this.seen.has(key))
|
|
67
|
+
continue;
|
|
68
|
+
this.entries.push(display);
|
|
69
|
+
this.seen.add(key);
|
|
70
|
+
}
|
|
71
|
+
this.trim();
|
|
72
|
+
return this.snapshot();
|
|
73
|
+
}
|
|
74
|
+
snapshot() {
|
|
75
|
+
return this.entries.join('\n');
|
|
76
|
+
}
|
|
77
|
+
trim() {
|
|
78
|
+
while (this.entries.length > this.maxEntries) {
|
|
79
|
+
this.dropOldest();
|
|
80
|
+
}
|
|
81
|
+
while (this.entries.length > 1 && this.snapshot().length > this.maxChars) {
|
|
82
|
+
this.dropOldest();
|
|
83
|
+
}
|
|
84
|
+
if (this.entries.length === 1 && this.entries[0].length > this.maxChars) {
|
|
85
|
+
const only = this.entries[0];
|
|
86
|
+
this.entries[0] = `${only.slice(0, Math.max(0, this.maxChars - 3))}...`;
|
|
87
|
+
this.seen.clear();
|
|
88
|
+
this.seen.add(this.entries[0].toLowerCase());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
dropOldest() {
|
|
92
|
+
const removed = this.entries.shift();
|
|
93
|
+
if (!removed)
|
|
94
|
+
return;
|
|
95
|
+
this.seen.delete(removed.toLowerCase());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.ProcessLogBuffer = ProcessLogBuffer;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildModeModelLines = buildModeModelLines;
|
|
4
|
+
exports.shouldSkipActivityLog = shouldSkipActivityLog;
|
|
5
|
+
exports.splitForEmbedDescription = splitForEmbedDescription;
|
|
6
|
+
exports.fitForSingleEmbedDescription = fitForSingleEmbedDescription;
|
|
7
|
+
/**
|
|
8
|
+
* Generate mode/model lines for initial status display.
|
|
9
|
+
* Consolidates into a single line if Fast and Plan models are the same.
|
|
10
|
+
*/
|
|
11
|
+
function buildModeModelLines(modeName, fastModel, planModel) {
|
|
12
|
+
const lines = [`Current Mode: ${modeName}`];
|
|
13
|
+
if (fastModel.trim().toLowerCase() === planModel.trim().toLowerCase()) {
|
|
14
|
+
lines.push(`Model: ${fastModel}`);
|
|
15
|
+
return lines;
|
|
16
|
+
}
|
|
17
|
+
lines.push(`Fast Model: ${fastModel}`);
|
|
18
|
+
lines.push(`Plan Model: ${planModel}`);
|
|
19
|
+
return lines;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Filter out activity logs that tend to be noise in Discord display.
|
|
23
|
+
*/
|
|
24
|
+
function shouldSkipActivityLog(activity, modeName, modelName) {
|
|
25
|
+
const normalized = activity.trim().toLowerCase();
|
|
26
|
+
if (!normalized)
|
|
27
|
+
return true;
|
|
28
|
+
const modeLower = modeName.trim().toLowerCase();
|
|
29
|
+
const modelLower = modelName.trim().toLowerCase();
|
|
30
|
+
if (normalized === modeLower || normalized === modelLower)
|
|
31
|
+
return true;
|
|
32
|
+
if (/^(?:fast|planning|plan|generating\.*|thinking\.*|processing\.*|working\.*)$/.test(normalized)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
// Single-word logs that tend to be noise (create / ready / pull. etc.)
|
|
36
|
+
if (/^[a-z][a-z0-9_-]{1,24}[.!…]?$/.test(normalized)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Detailed trace for file reading operations (Analyzed....)
|
|
40
|
+
if (/^analyzed/.test(normalized)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Split text into multiple chunks for Embed description.
|
|
47
|
+
*/
|
|
48
|
+
function splitForEmbedDescription(text, maxLength = 3500) {
|
|
49
|
+
if (text.length <= maxLength)
|
|
50
|
+
return [text];
|
|
51
|
+
const lines = text.split('\n');
|
|
52
|
+
const chunks = [];
|
|
53
|
+
let current = '';
|
|
54
|
+
const flush = () => {
|
|
55
|
+
if (!current)
|
|
56
|
+
return;
|
|
57
|
+
chunks.push(current);
|
|
58
|
+
current = '';
|
|
59
|
+
};
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const candidate = current ? `${current}\n${line}` : line;
|
|
62
|
+
if (candidate.length <= maxLength) {
|
|
63
|
+
current = candidate;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
flush();
|
|
67
|
+
if (line.length <= maxLength) {
|
|
68
|
+
current = line;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
let cursor = 0;
|
|
72
|
+
while (cursor < line.length) {
|
|
73
|
+
chunks.push(line.slice(cursor, cursor + maxLength));
|
|
74
|
+
cursor += maxLength;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
flush();
|
|
78
|
+
return chunks.length > 0 ? chunks : [''];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Fit text within the limit for a single Embed description.
|
|
82
|
+
* When exceeding the limit, truncate the beginning and prioritize displaying the tail (most recent part).
|
|
83
|
+
*/
|
|
84
|
+
function fitForSingleEmbedDescription(text, maxLength = 3500) {
|
|
85
|
+
if (text.length <= maxLength)
|
|
86
|
+
return text;
|
|
87
|
+
const prefix = '... (beginning truncated)\n';
|
|
88
|
+
const tailLength = Math.max(0, maxLength - prefix.length);
|
|
89
|
+
return `${prefix}${text.slice(-tailLength)}`;
|
|
90
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "lazy-gravity",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Control Antigravity from anywhere — a local, secure Discord Bot that lets you remotely operate Antigravity on your home PC from your smartphone's Discord app.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lazy-gravity": "dist/bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"directories": {
|
|
18
|
+
"doc": "docs"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "npm run test:unit",
|
|
22
|
+
"test:unit": "jest",
|
|
23
|
+
"test:integration": "jest tests/e2e.bot.test.ts",
|
|
24
|
+
"test:watch": "jest --watch",
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"start": "ts-node src/index.ts",
|
|
27
|
+
"start:built": "node dist/bin/cli.js",
|
|
28
|
+
"dev": "ts-node-dev --respawn src/index.ts",
|
|
29
|
+
"docs:diagram": "mmdc -i docs/diagrams/architecture.mmd -o docs/images/architecture.svg -b transparent",
|
|
30
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"discord",
|
|
34
|
+
"bot",
|
|
35
|
+
"ai",
|
|
36
|
+
"antigravity",
|
|
37
|
+
"remote-control"
|
|
38
|
+
],
|
|
39
|
+
"author": "LazyGravity Contributors",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/tokyoweb3/LazyGravity.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/tokyoweb3/LazyGravity/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/tokyoweb3/LazyGravity#readme",
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"better-sqlite3": "^12.6.2",
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
|
+
"discord.js": "^14.25.1",
|
|
53
|
+
"dotenv": "^17.3.1",
|
|
54
|
+
"node-cron": "^4.2.1",
|
|
55
|
+
"ws": "^8.19.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@mermaid-js/mermaid-cli": "^11.12.0",
|
|
59
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
60
|
+
"@types/jest": "^30.0.0",
|
|
61
|
+
"@types/node": "^25.3.0",
|
|
62
|
+
"@types/node-cron": "^3.0.11",
|
|
63
|
+
"@types/ws": "^8.18.1",
|
|
64
|
+
"jest": "^30.2.0",
|
|
65
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
66
|
+
"jsdom": "^28.1.0",
|
|
67
|
+
"minimatch": "^10.2.1",
|
|
68
|
+
"ts-jest": "^29.4.6",
|
|
69
|
+
"ts-morph": "^27.0.2",
|
|
70
|
+
"ts-node": "^10.9.2",
|
|
71
|
+
"typescript": "^5.9.3",
|
|
72
|
+
"undici": "^6.23.0"
|
|
73
|
+
}
|
|
74
|
+
}
|