Compare commits

..

10 Commits

Author SHA1 Message Date
Castor Regex 700a868a3a feat(logging): add newline to regex.ready and log output to /tmp/regex.log 2025-08-25 17:19:43 -05:00
Castor Regex 94c126029d feat: write sessionId to /tmp/regex.ready 2025-08-25 11:40:11 -05:00
Jeff Carr 4063298293 mktmp ready file 2025-08-25 11:28:17 -05:00
Castor Regex 090986ca5a feat: poll for /tmp/regex.txt and process contents 2025-08-25 10:21:30 -05:00
Castor Regex 2747a978c7 feat(startup): create new chat with incrementing topic 2025-08-24 13:23:01 -05:00
Castor Regex 3f82a60986 feat(startup): create new chat on startup 2025-08-24 13:07:04 -05:00
Castor Regex d12a64368d feat(stats): save stats on exit 2025-08-24 09:30:39 -05:00
Castor Regex 1ff70eeef8 fix(startup): remove erroneous startup command 2025-08-24 09:26:22 -05:00
Castor Regex 0739c5d4d5 feat(stats): run regex --stats on startup 2025-08-24 09:20:22 -05:00
Castor Gemini 9f3cfb0563 feat(stats): pipe session stats to regex 2025-08-24 09:01:07 -05:00
5 changed files with 83 additions and 9 deletions

View File

@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { execFileSync } from 'child_process';
import React from 'react';
import { render } from 'ink';
import { AppWrapper } from './ui/App.js';
@ -133,9 +134,6 @@ ${reason.stack}`
}
export async function main() {
if (!process.env['SANDBOX']) {
console.log("regex --output 'startup'");
}
setupUnhandledRejectionHandler();
const workspaceRoot = process.cwd();
const settings = loadSettings(workspaceRoot);
@ -162,6 +160,15 @@ export async function main() {
argv,
);
// Create a new chat on startup.
try {
const topic = execFileSync('/home/jcarr/go/bin/regex', ['--get-next-auto-topic'], { encoding: 'utf8' });
execFileSync('/home/jcarr/go/bin/regex', ['--new-chat', sessionId, topic.trim()]);
} catch (e) {
console.error(`Error creating new chat: ${e}`);
}
const consolePatcher = new ConsolePatcher({
stderr: true,
debugMode: config.getDebugMode(),

View File

@ -616,6 +616,33 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
[addMessage],
);
useEffect(() => {
const interval = setInterval(() => {
const filePath = '/tmp/regex.txt';
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
fs.appendFileSync('/tmp/gemini-cli.log', content);
if (content.trim().length > 0) {
handleFinalSubmit(content);
}
fs.unlinkSync(filePath);
}
}, 5000); // Check every 5 seconds
return () => clearInterval(interval);
}, [handleFinalSubmit]);
const previousStreamingState = useRef(streamingState);
useEffect(() => {
if (
previousStreamingState.current !== StreamingState.Idle &&
streamingState === StreamingState.Idle
) {
fs.writeFileSync('/tmp/regex.ready', sessionStats.sessionId + '\n');
}
previousStreamingState.current = streamingState;
}, [streamingState, sessionStats.sessionId]);
const handleIdePromptComplete = useCallback(
(result: IdeIntegrationNudgeResult) => {
if (result.userSelection === 'yes') {

View File

@ -4,7 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import React from 'react';
import { execFile } from 'child_process';
import React, { useEffect } from 'react';
import { Box, Text } from 'ink';
import Gradient from 'ink-gradient';
import { theme } from '../semantic-colors.js';
@ -155,6 +156,24 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
const { models, tools, files } = metrics;
const computed = computeSessionStats(metrics);
useEffect(() => {
const statsString = JSON.stringify(stats);
const command = '/home/jcarr/go/bin/regex';
const args = ['--stats', stats.sessionId, statsString];
execFile(command, args, (error, stdout, stderr) => {
if (error) {
console.error(`execFile error: ${error.message}`);
return;
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
});
}, [stats]);
const successThresholds = {
green: TOOL_SUCCESS_RATE_HIGH,
yellow: TOOL_SUCCESS_RATE_MEDIUM,

View File

@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { execFile } from 'child_process';
import { useCallback, useMemo, useEffect, useState } from 'react';
import { type PartListUnion } from '@google/genai';
import process from 'node:process';
@ -403,11 +404,22 @@ export const useSlashCommandProcessor = (
return { type: 'handled' };
}
case 'quit':
setQuittingMessages(result.messages);
setTimeout(async () => {
await runExitCleanup();
process.exit(0);
}, 100);
const statsString = JSON.stringify(session.stats);
const command = '/home/jcarr/go/bin/regex';
const args = ['--stats', session.stats.sessionId, statsString];
execFile(command, args, (error, stdout, stderr) => {
if (error) {
console.error(`execFile error: ${error.message}`);
}
if (stderr) {
console.error(`stderr: ${stderr}`);
}
setQuittingMessages(result.messages);
setTimeout(async () => {
await runExitCleanup();
process.exit(0);
}, 100);
});
return { type: 'handled' };
case 'submit_prompt':

View File

@ -66,6 +66,7 @@ export class Logger {
private messageId = 0; // Instance-specific counter for the next messageId
private initialized = false;
private logs: LogEntry[] = []; // In-memory cache, ideally reflects the last known state of the file
private regexLogFile: fs.FileHandle | undefined;
constructor(
sessionId: string,
@ -156,6 +157,7 @@ export class Logger {
? Math.max(...sessionLogs.map((entry) => entry.messageId)) + 1
: 0;
this.initialized = true;
this.regexLogFile = await fs.open('/tmp/regex.log', 'a');
} catch (err) {
console.error('Failed to initialize logger:', err);
this.initialized = false;
@ -264,6 +266,10 @@ export class Logger {
// If an entry was actually written (not a duplicate skip),
// then this instance can increment its idea of the next messageId for this session.
this.messageId = writtenEntry.messageId + 1;
if (this.regexLogFile) {
const logString = `[${writtenEntry.timestamp}] [${writtenEntry.type}] ${writtenEntry.message}\n`;
await this.regexLogFile.write(logString);
}
}
} catch (_error) {
// Error already logged by _updateLogFile or _readLogFile
@ -431,6 +437,9 @@ export class Logger {
}
close(): void {
if (this.regexLogFile) {
this.regexLogFile.close();
}
this.initialized = false;
this.logFilePath = undefined;
this.logs = [];