lazy-gravity 0.1.0 → 0.2.0
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/README.md +18 -6
- package/dist/bin/cli.js +18 -18
- package/dist/bin/commands/doctor.js +2 -1
- package/dist/bin/commands/start.js +25 -2
- package/dist/bot/index.js +346 -152
- package/dist/commands/joinCommandHandler.js +302 -0
- package/dist/commands/joinDetachCommandHandler.js +285 -0
- package/dist/commands/registerSlashCommands.js +35 -0
- package/dist/database/chatSessionRepository.js +10 -0
- package/dist/database/userPreferenceRepository.js +72 -0
- package/dist/events/interactionCreateHandler.js +58 -36
- package/dist/events/messageCreateHandler.js +158 -53
- package/dist/services/antigravityLauncher.js +4 -3
- package/dist/services/approvalDetector.js +6 -0
- package/dist/services/cdpBridgeManager.js +184 -84
- package/dist/services/cdpConnectionPool.js +79 -51
- package/dist/services/cdpService.js +149 -51
- package/dist/services/chatSessionService.js +229 -8
- package/dist/services/errorPopupDetector.js +6 -0
- package/dist/services/planningDetector.js +6 -0
- package/dist/services/responseMonitor.js +125 -24
- package/dist/services/updateCheckService.js +147 -0
- package/dist/services/userMessageDetector.js +221 -0
- package/dist/ui/modeUi.js +11 -1
- package/dist/ui/outputUi.js +30 -0
- package/dist/ui/sessionPickerUi.js +48 -0
- package/dist/utils/antigravityPaths.js +94 -0
- package/dist/utils/configLoader.js +10 -0
- package/dist/utils/discordButtonUtils.js +33 -0
- package/dist/utils/logBuffer.js +47 -0
- package/dist/utils/logger.js +80 -20
- package/dist/utils/pathUtils.js +57 -0
- package/dist/utils/plainTextFormatter.js +70 -0
- package/package.json +4 -4
package/dist/utils/logger.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.logger = exports.COLORS = void 0;
|
|
4
|
+
exports.createLogger = createLogger;
|
|
5
|
+
const logBuffer_1 = require("./logBuffer");
|
|
4
6
|
exports.COLORS = {
|
|
5
7
|
red: '\x1b[31m',
|
|
6
8
|
yellow: '\x1b[33m',
|
|
@@ -10,28 +12,86 @@ exports.COLORS = {
|
|
|
10
12
|
dim: '\x1b[2m',
|
|
11
13
|
reset: '\x1b[0m',
|
|
12
14
|
};
|
|
15
|
+
const LEVEL_PRIORITY = {
|
|
16
|
+
debug: 0,
|
|
17
|
+
info: 1,
|
|
18
|
+
warn: 2,
|
|
19
|
+
error: 3,
|
|
20
|
+
none: 4,
|
|
21
|
+
};
|
|
13
22
|
const getTimestamp = () => {
|
|
14
23
|
const now = new Date();
|
|
15
24
|
const timeString = now.toLocaleTimeString('ja-JP', { hour12: false });
|
|
16
25
|
return `${exports.COLORS.dim}[${timeString}]${exports.COLORS.reset}`;
|
|
17
26
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
27
|
+
function createLogger(initialLevel = 'info') {
|
|
28
|
+
let currentLevel = initialLevel;
|
|
29
|
+
function shouldLog(methodLevel) {
|
|
30
|
+
return LEVEL_PRIORITY[methodLevel] >= LEVEL_PRIORITY[currentLevel];
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
info(...args) {
|
|
34
|
+
if (shouldLog('info')) {
|
|
35
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.cyan}[INFO]${exports.COLORS.reset}`;
|
|
36
|
+
console.info(formatted, ...args);
|
|
37
|
+
logBuffer_1.logBuffer.append('info', `[INFO] ${args.join(' ')}`);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
warn(...args) {
|
|
41
|
+
if (shouldLog('warn')) {
|
|
42
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.yellow}[WARN]${exports.COLORS.reset}`;
|
|
43
|
+
console.warn(formatted, ...args);
|
|
44
|
+
logBuffer_1.logBuffer.append('warn', `[WARN] ${args.join(' ')}`);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
error(...args) {
|
|
48
|
+
if (shouldLog('error')) {
|
|
49
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.red}[ERROR]${exports.COLORS.reset}`;
|
|
50
|
+
console.error(formatted, ...args);
|
|
51
|
+
logBuffer_1.logBuffer.append('error', `[ERROR] ${args.join(' ')}`);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
debug(...args) {
|
|
55
|
+
if (shouldLog('debug')) {
|
|
56
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.dim}[DEBUG]${exports.COLORS.reset}`;
|
|
57
|
+
console.debug(formatted, ...args);
|
|
58
|
+
logBuffer_1.logBuffer.append('debug', `[DEBUG] ${args.join(' ')}`);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
/** Important state transitions - stands out in logs */
|
|
62
|
+
phase(...args) {
|
|
63
|
+
if (shouldLog('info')) {
|
|
64
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.magenta}[PHASE]${exports.COLORS.reset}`;
|
|
65
|
+
console.info(formatted, ...args);
|
|
66
|
+
logBuffer_1.logBuffer.append('info', `[PHASE] ${args.join(' ')}`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
/** Completion-related events - green for success */
|
|
70
|
+
done(...args) {
|
|
71
|
+
if (shouldLog('info')) {
|
|
72
|
+
const formatted = `${getTimestamp()} ${exports.COLORS.green}[DONE]${exports.COLORS.reset}`;
|
|
73
|
+
console.info(formatted, ...args);
|
|
74
|
+
logBuffer_1.logBuffer.append('info', `[DONE] ${args.join(' ')}`);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
/** Section divider with optional label for structured output */
|
|
78
|
+
divider(label) {
|
|
79
|
+
if (shouldLog('info')) {
|
|
80
|
+
if (label) {
|
|
81
|
+
const pad = Math.max(4, 50 - label.length - 4);
|
|
82
|
+
console.info(`${exports.COLORS.green}[DONE]${exports.COLORS.reset} ${exports.COLORS.dim}── ${label} ${'─'.repeat(pad)}${exports.COLORS.reset}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.info(`${exports.COLORS.green}[DONE]${exports.COLORS.reset} ${exports.COLORS.dim}${'─'.repeat(50)}${exports.COLORS.reset}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
setLogLevel(level) {
|
|
90
|
+
currentLevel = level;
|
|
91
|
+
},
|
|
92
|
+
getLogLevel() {
|
|
93
|
+
return currentLevel;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
exports.logger = createLogger('info');
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAntigravityCliPath = getAntigravityCliPath;
|
|
4
|
+
exports.extractProjectNameFromPath = extractProjectNameFromPath;
|
|
5
|
+
exports.getAntigravityCdpHint = getAntigravityCdpHint;
|
|
6
|
+
/**
|
|
7
|
+
* Helper to resolve the correct Antigravity CLI executable path based on the operating system
|
|
8
|
+
* and environment variables.
|
|
9
|
+
*
|
|
10
|
+
* Precedence:
|
|
11
|
+
* 1. process.env.ANTIGRAVITY_PATH (Explicit override)
|
|
12
|
+
* 2. OS-specific default paths (Mac: /Applications/..., Windows: %LOCALAPPDATA%\..., Linux: 'antigravity')
|
|
13
|
+
*/
|
|
14
|
+
function getAntigravityCliPath() {
|
|
15
|
+
// Allow user to set explicit path via ANTIGRAVITY_PATH (especially useful for Linux AppImages)
|
|
16
|
+
if (process.env.ANTIGRAVITY_PATH) {
|
|
17
|
+
return process.env.ANTIGRAVITY_PATH;
|
|
18
|
+
}
|
|
19
|
+
if (process.platform === 'darwin') {
|
|
20
|
+
return '/Applications/Antigravity.app/Contents/Resources/app/bin/antigravity';
|
|
21
|
+
}
|
|
22
|
+
if (process.platform === 'win32') {
|
|
23
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
24
|
+
if (localAppData) {
|
|
25
|
+
return `${localAppData}\\Programs\\Antigravity\\Antigravity.exe`;
|
|
26
|
+
}
|
|
27
|
+
return 'Antigravity.exe'; // Fallback if LOCALAPPDATA is undefined
|
|
28
|
+
}
|
|
29
|
+
// Default for Linux or any unknown OS, assuming 'antigravity' is in the system PATH
|
|
30
|
+
return 'antigravity';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Helper to extract the project name from a full workspace path.
|
|
34
|
+
* Handles both Windows (backslash) and POSIX (forward slash) paths.
|
|
35
|
+
*
|
|
36
|
+
* @param workspacePath The full path to the workspace directory
|
|
37
|
+
* @returns The final folder name
|
|
38
|
+
*/
|
|
39
|
+
function extractProjectNameFromPath(workspacePath) {
|
|
40
|
+
return workspacePath.split(/[/\\]/).filter(Boolean).pop() || '';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get a platform-appropriate hint for starting Antigravity with CDP.
|
|
44
|
+
*
|
|
45
|
+
* Used in user-facing messages (Discord embeds, CLI doctor, logs).
|
|
46
|
+
*/
|
|
47
|
+
function getAntigravityCdpHint(port = 9222) {
|
|
48
|
+
const APP_NAME = 'Antigravity';
|
|
49
|
+
switch (process.platform) {
|
|
50
|
+
case 'darwin':
|
|
51
|
+
return `open -a ${APP_NAME} --args --remote-debugging-port=${port}`;
|
|
52
|
+
case 'win32':
|
|
53
|
+
return `${APP_NAME}.exe --remote-debugging-port=${port}`;
|
|
54
|
+
default:
|
|
55
|
+
return `${APP_NAME.toLowerCase()} --remote-debugging-port=${port}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Format embed-like data as plain text for Discord messages.
|
|
4
|
+
* Used when user has output format set to 'plain'.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.splitPlainText = splitPlainText;
|
|
8
|
+
exports.formatAsPlainText = formatAsPlainText;
|
|
9
|
+
/**
|
|
10
|
+
* Split text into chunks at line boundaries, respecting Discord's 2000 char limit.
|
|
11
|
+
* Uses maxLength of 1900 to leave room for formatting overhead.
|
|
12
|
+
*/
|
|
13
|
+
function splitPlainText(text, maxLength = 1900) {
|
|
14
|
+
if (text.length <= maxLength)
|
|
15
|
+
return [text];
|
|
16
|
+
const lines = text.split('\n');
|
|
17
|
+
const chunks = [];
|
|
18
|
+
let current = '';
|
|
19
|
+
const flush = () => {
|
|
20
|
+
if (!current)
|
|
21
|
+
return;
|
|
22
|
+
chunks.push(current);
|
|
23
|
+
current = '';
|
|
24
|
+
};
|
|
25
|
+
for (const line of lines) {
|
|
26
|
+
const candidate = current ? `${current}\n${line}` : line;
|
|
27
|
+
if (candidate.length <= maxLength) {
|
|
28
|
+
current = candidate;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
flush();
|
|
32
|
+
if (line.length <= maxLength) {
|
|
33
|
+
current = line;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
// Line itself exceeds maxLength — hard-split
|
|
37
|
+
let cursor = 0;
|
|
38
|
+
while (cursor < line.length) {
|
|
39
|
+
chunks.push(line.slice(cursor, cursor + maxLength));
|
|
40
|
+
cursor += maxLength;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
flush();
|
|
44
|
+
return chunks.length > 0 ? chunks : [''];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Convert embed-style data to a plain text string array (chunked for Discord).
|
|
48
|
+
* Format: **{title}**\n{description}\n\n{field.name}: {field.value}\n...\n_{footer}_
|
|
49
|
+
*/
|
|
50
|
+
function formatAsPlainText(input) {
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (input.title) {
|
|
53
|
+
parts.push(`**${input.title}**`);
|
|
54
|
+
}
|
|
55
|
+
if (input.description) {
|
|
56
|
+
parts.push(input.description);
|
|
57
|
+
}
|
|
58
|
+
if (input.fields && input.fields.length > 0) {
|
|
59
|
+
parts.push(''); // blank line separator
|
|
60
|
+
for (const field of input.fields) {
|
|
61
|
+
parts.push(`**${field.name}:** ${field.value}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (input.footerText) {
|
|
65
|
+
parts.push(''); // blank line separator
|
|
66
|
+
parts.push(`_${input.footerText}_`);
|
|
67
|
+
}
|
|
68
|
+
const text = parts.join('\n');
|
|
69
|
+
return splitPlainText(text);
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazy-gravity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
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
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"test:integration": "jest tests/e2e.bot.test.ts",
|
|
24
24
|
"test:watch": "jest --watch",
|
|
25
25
|
"build": "tsc",
|
|
26
|
-
"start": "ts-node src/
|
|
26
|
+
"start": "ts-node src/bin/cli.ts",
|
|
27
27
|
"start:built": "node dist/bin/cli.js",
|
|
28
|
-
"dev": "ts-node-dev --respawn src/
|
|
28
|
+
"dev": "ts-node-dev --respawn src/bin/cli.ts",
|
|
29
29
|
"docs:diagram": "mmdc -i docs/diagrams/architecture.mmd -o docs/images/architecture.svg -b transparent",
|
|
30
30
|
"prepublishOnly": "npm run build && npm run test"
|
|
31
31
|
},
|
|
@@ -69,6 +69,6 @@
|
|
|
69
69
|
"ts-morph": "^27.0.2",
|
|
70
70
|
"ts-node": "^10.9.2",
|
|
71
71
|
"typescript": "^5.9.3",
|
|
72
|
-
"undici": "^
|
|
72
|
+
"undici": "^7.22.0"
|
|
73
73
|
}
|
|
74
74
|
}
|