lazy-gravity 0.0.4 → 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 +22 -7
- package/dist/bin/cli.js +18 -18
- package/dist/bin/commands/doctor.js +25 -19
- package/dist/bin/commands/start.js +25 -2
- package/dist/bot/index.js +445 -126
- package/dist/commands/joinCommandHandler.js +302 -0
- package/dist/commands/joinDetachCommandHandler.js +285 -0
- package/dist/commands/registerSlashCommands.js +40 -0
- package/dist/commands/workspaceCommandHandler.js +17 -28
- package/dist/database/chatSessionRepository.js +10 -0
- package/dist/database/userPreferenceRepository.js +72 -0
- package/dist/events/interactionCreateHandler.js +338 -30
- package/dist/events/messageCreateHandler.js +161 -47
- package/dist/services/antigravityLauncher.js +4 -3
- package/dist/services/approvalDetector.js +7 -0
- package/dist/services/assistantDomExtractor.js +339 -0
- package/dist/services/cdpBridgeManager.js +323 -39
- package/dist/services/cdpConnectionPool.js +117 -33
- package/dist/services/cdpService.js +149 -53
- package/dist/services/chatSessionService.js +229 -8
- package/dist/services/errorPopupDetector.js +271 -0
- package/dist/services/planningDetector.js +318 -0
- package/dist/services/responseMonitor.js +308 -70
- package/dist/services/retryStore.js +46 -0
- package/dist/services/updateCheckService.js +147 -0
- package/dist/services/userMessageDetector.js +221 -0
- package/dist/ui/buttonUtils.js +33 -0
- package/dist/ui/modeUi.js +11 -1
- package/dist/ui/modelsUi.js +24 -13
- package/dist/ui/outputUi.js +30 -0
- package/dist/ui/projectListUi.js +83 -0
- package/dist/ui/sessionPickerUi.js +48 -0
- package/dist/utils/antigravityPaths.js +94 -0
- package/dist/utils/configLoader.js +18 -0
- package/dist/utils/discordButtonUtils.js +33 -0
- package/dist/utils/discordFormatter.js +149 -16
- package/dist/utils/htmlToDiscordMarkdown.js +184 -0
- package/dist/utils/logBuffer.js +47 -0
- package/dist/utils/logFileTransport.js +147 -0
- package/dist/utils/logger.js +86 -21
- package/dist/utils/pathUtils.js +57 -0
- package/dist/utils/plainTextFormatter.js +70 -0
- package/dist/utils/processLogBuffer.js +4 -0
- package/package.json +4 -4
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LogFileTransportImpl = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const DEFAULT_LOG_DIR = path.join(os.homedir(), '.lazy-gravity', 'logs');
|
|
41
|
+
const LOG_FILE_PREFIX = 'lazy-gravity-';
|
|
42
|
+
const LOG_FILE_EXT = '.log';
|
|
43
|
+
/** Maximum number of log files to keep (default 14 days). */
|
|
44
|
+
const DEFAULT_MAX_FILES = 14;
|
|
45
|
+
/** Maximum size in bytes for a single log file (default 10 MB). */
|
|
46
|
+
const DEFAULT_MAX_SIZE_BYTES = 10 * 1024 * 1024;
|
|
47
|
+
function formatDate(date) {
|
|
48
|
+
const y = date.getFullYear();
|
|
49
|
+
const m = String(date.getMonth() + 1).padStart(2, '0');
|
|
50
|
+
const d = String(date.getDate()).padStart(2, '0');
|
|
51
|
+
return `${y}-${m}-${d}`;
|
|
52
|
+
}
|
|
53
|
+
function buildFileName(dateStr) {
|
|
54
|
+
return `${LOG_FILE_PREFIX}${dateStr}${LOG_FILE_EXT}`;
|
|
55
|
+
}
|
|
56
|
+
class LogFileTransportImpl {
|
|
57
|
+
logDir;
|
|
58
|
+
currentDate;
|
|
59
|
+
currentFilePath;
|
|
60
|
+
constructor(logDir = DEFAULT_LOG_DIR) {
|
|
61
|
+
this.logDir = logDir;
|
|
62
|
+
this.currentDate = formatDate(new Date());
|
|
63
|
+
this.currentFilePath = path.join(this.logDir, buildFileName(this.currentDate));
|
|
64
|
+
this.ensureDir();
|
|
65
|
+
this.scheduleCleanup();
|
|
66
|
+
}
|
|
67
|
+
write(level, timestamp, message) {
|
|
68
|
+
this.rollIfNeeded();
|
|
69
|
+
const line = `${timestamp} [${level}] ${message}\n`;
|
|
70
|
+
try {
|
|
71
|
+
fs.appendFileSync(this.currentFilePath, line, 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Silently ignore write errors to avoid crashing the bot
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Remove old log files that exceed maxFiles count or maxSizeBytes per file.
|
|
79
|
+
* Runs asynchronously to avoid blocking startup.
|
|
80
|
+
*/
|
|
81
|
+
cleanup(maxFiles = DEFAULT_MAX_FILES, maxSizeBytes = DEFAULT_MAX_SIZE_BYTES) {
|
|
82
|
+
setImmediate(() => {
|
|
83
|
+
try {
|
|
84
|
+
this.cleanupSync(maxFiles, maxSizeBytes);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Silently ignore cleanup errors
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** Synchronous cleanup for testability. */
|
|
92
|
+
cleanupSync(maxFiles = DEFAULT_MAX_FILES, maxSizeBytes = DEFAULT_MAX_SIZE_BYTES) {
|
|
93
|
+
if (!fs.existsSync(this.logDir))
|
|
94
|
+
return;
|
|
95
|
+
const entries = fs
|
|
96
|
+
.readdirSync(this.logDir)
|
|
97
|
+
.filter((f) => f.startsWith(LOG_FILE_PREFIX) && f.endsWith(LOG_FILE_EXT))
|
|
98
|
+
.sort(); // chronological order (YYYY-MM-DD sorts naturally)
|
|
99
|
+
// Remove files exceeding size limit
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
const filePath = path.join(this.logDir, entry);
|
|
102
|
+
try {
|
|
103
|
+
const stat = fs.statSync(filePath);
|
|
104
|
+
if (stat.size > maxSizeBytes) {
|
|
105
|
+
fs.unlinkSync(filePath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Ignore stat/unlink errors
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Re-read after size-based cleanup
|
|
113
|
+
const remaining = fs
|
|
114
|
+
.readdirSync(this.logDir)
|
|
115
|
+
.filter((f) => f.startsWith(LOG_FILE_PREFIX) && f.endsWith(LOG_FILE_EXT))
|
|
116
|
+
.sort();
|
|
117
|
+
// Remove oldest files if count exceeds limit
|
|
118
|
+
const excess = remaining.length - maxFiles;
|
|
119
|
+
if (excess > 0) {
|
|
120
|
+
for (let i = 0; i < excess; i++) {
|
|
121
|
+
const filePath = path.join(this.logDir, remaining[i]);
|
|
122
|
+
try {
|
|
123
|
+
fs.unlinkSync(filePath);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Ignore unlink errors
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
ensureDir() {
|
|
132
|
+
if (!fs.existsSync(this.logDir)) {
|
|
133
|
+
fs.mkdirSync(this.logDir, { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
rollIfNeeded() {
|
|
137
|
+
const today = formatDate(new Date());
|
|
138
|
+
if (today !== this.currentDate) {
|
|
139
|
+
this.currentDate = today;
|
|
140
|
+
this.currentFilePath = path.join(this.logDir, buildFileName(today));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
scheduleCleanup() {
|
|
144
|
+
this.cleanup();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.LogFileTransportImpl = LogFileTransportImpl;
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.logger = void 0;
|
|
4
|
-
|
|
3
|
+
exports.logger = exports.COLORS = void 0;
|
|
4
|
+
exports.createLogger = createLogger;
|
|
5
|
+
const logBuffer_1 = require("./logBuffer");
|
|
6
|
+
exports.COLORS = {
|
|
5
7
|
red: '\x1b[31m',
|
|
6
8
|
yellow: '\x1b[33m',
|
|
7
9
|
cyan: '\x1b[36m',
|
|
@@ -10,23 +12,86 @@ const COLORS = {
|
|
|
10
12
|
dim: '\x1b[2m',
|
|
11
13
|
reset: '\x1b[0m',
|
|
12
14
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
},
|
|
15
|
+
const LEVEL_PRIORITY = {
|
|
16
|
+
debug: 0,
|
|
17
|
+
info: 1,
|
|
18
|
+
warn: 2,
|
|
19
|
+
error: 3,
|
|
20
|
+
none: 4,
|
|
32
21
|
};
|
|
22
|
+
const getTimestamp = () => {
|
|
23
|
+
const now = new Date();
|
|
24
|
+
const timeString = now.toLocaleTimeString('ja-JP', { hour12: false });
|
|
25
|
+
return `${exports.COLORS.dim}[${timeString}]${exports.COLORS.reset}`;
|
|
26
|
+
};
|
|
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
|
+
}
|
|
@@ -30,6 +30,10 @@ function pickEmoji(entry) {
|
|
|
30
30
|
return '🚀';
|
|
31
31
|
if (/^[a-z0-9._-]+\s*\/\s*[a-z0-9._-]+$/i.test(entry))
|
|
32
32
|
return '🛠️';
|
|
33
|
+
if (/^(?:analy[sz]ed|read|wrote|created|updated|deleted|built|compiled|installed|resolved|downloaded|connected|fetched)\b/i.test(entry))
|
|
34
|
+
return '📄';
|
|
35
|
+
if (/^(?:analy[sz]ing|reading|writing|running|searching|fetching|checking|scanning|creating|updating|deleting|building|compiling|deploying|parsing|resolving|downloading|uploading|connecting|installing|executing|testing|debugging|processing|loading)\b/i.test(entry))
|
|
36
|
+
return '🔍';
|
|
33
37
|
if (/^title:\s/.test(lower) && /\surl:\s/.test(lower))
|
|
34
38
|
return '🔎';
|
|
35
39
|
if (/^(json|javascript|typescript|python|bash|sh|html|css|xml|yaml|yml|toml|sql|graphql|markdown|text|plaintext|log)$/i.test(entry))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazy-gravity",
|
|
3
|
-
"version": "0.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
|
}
|