Adding some wiring to allow the Ink app to warn if there are local development changes that haven't been captured in the recent build of the Gemini CLI.
This commit is contained in:
parent
e0339993ae
commit
1bfc62dcc2
|
@ -9,7 +9,7 @@
|
|||
"scripts": {
|
||||
"build": "npm run build --workspaces",
|
||||
"test": "npm run test --workspaces",
|
||||
"start": "npm run start --workspace=gemini-code-cli -- \"$@\"",
|
||||
"start": "node ./scripts/check-build-status.js && npm run start --workspace=gemini-code-cli -- \"$@\"",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"type": "module",
|
||||
"main": "dist/gemini.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build": "tsc && touch dist/.last_build",
|
||||
"start": "node dist/gemini.js",
|
||||
"debug": "node --inspect-brk dist/gemini.js",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
Content,
|
||||
} from '@google/genai';
|
||||
import { getApiKey } from '../config/env.js';
|
||||
import { getModel } from '../config/globalConfig.js';
|
||||
import { getModel } from '../config/globalConfig.js';
|
||||
import { CoreSystemPrompt } from './prompts.js';
|
||||
import {
|
||||
type ToolCallEvent,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import type { HistoryItem } from './types.js';
|
||||
import { useGeminiStream } from './hooks/useGeminiStream.js';
|
||||
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
||||
|
@ -12,6 +15,8 @@ import Footer from './components/Footer.js';
|
|||
import { StreamingState } from '../core/gemini-stream.js';
|
||||
import { PartListUnion } from '@google/genai';
|
||||
|
||||
const warningsFilePath = path.join(os.tmpdir(), 'gemini-code-cli-warnings.txt');
|
||||
|
||||
interface AppProps {
|
||||
directory: string;
|
||||
}
|
||||
|
@ -19,11 +24,31 @@ interface AppProps {
|
|||
const App = ({ directory }: AppProps) => {
|
||||
const [query, setQuery] = useState('');
|
||||
const [history, setHistory] = useState<HistoryItem[]>([]);
|
||||
const [startupWarnings, setStartupWarnings] = useState<string[]>([]);
|
||||
const { streamingState, submitQuery, initError } =
|
||||
useGeminiStream(setHistory);
|
||||
const { elapsedTime, currentLoadingPhrase } =
|
||||
useLoadingIndicator(streamingState);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (fs.existsSync(warningsFilePath)) {
|
||||
console.log('[App] Found warnings file:', warningsFilePath);
|
||||
const warningsContent = fs.readFileSync(warningsFilePath, 'utf-8');
|
||||
setStartupWarnings(warningsContent.split('\n').filter(line => line.trim() !== ''));
|
||||
try {
|
||||
fs.unlinkSync(warningsFilePath);
|
||||
} catch (unlinkErr: any) {
|
||||
console.warn(`[App] Warning: Could not delete warnings file: ${unlinkErr.message}`);
|
||||
}
|
||||
} else {
|
||||
console.log('[App] No warnings file found.');
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(`[App] Error checking/reading warnings file: ${err.message}`);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleInputSubmit = (value: PartListUnion) => {
|
||||
submitQuery(value)
|
||||
.then(() => {
|
||||
|
@ -63,6 +88,22 @@ const App = ({ directory }: AppProps) => {
|
|||
<Box flexDirection="column" padding={1} marginBottom={1} width="100%">
|
||||
<Header cwd={directory} />
|
||||
|
||||
{startupWarnings.length > 0 && (
|
||||
<Box
|
||||
borderStyle="round"
|
||||
borderColor="yellow"
|
||||
paddingX={1}
|
||||
marginY={1}
|
||||
flexDirection="column"
|
||||
>
|
||||
{startupWarnings.map((warning, index) => (
|
||||
<Text key={index} color="yellow">
|
||||
{warning}
|
||||
</Text>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Tips />
|
||||
|
||||
{initError &&
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os'; // Import os module
|
||||
|
||||
// --- Configuration ---
|
||||
const cliPackageDir = path.resolve('packages', 'cli'); // Base directory for the CLI package
|
||||
const buildTimestampPath = path.join(cliPackageDir, 'dist', '.last_build'); // Path to the timestamp file within the CLI package
|
||||
const sourceDirs = [path.join(cliPackageDir, 'src')]; // Source directory within the CLI package
|
||||
const filesToWatch = [path.join(cliPackageDir, 'package.json'), path.join(cliPackageDir, 'tsconfig.json')]; // Specific files within the CLI package
|
||||
const buildDir = path.join(cliPackageDir, 'dist'); // Build output directory within the CLI package
|
||||
const warningsFilePath = path.join(os.tmpdir(), 'gemini-code-cli-warnings.txt'); // Temp file for warnings
|
||||
// ---------------------
|
||||
|
||||
function getMtime(filePath) {
|
||||
try {
|
||||
return fs.statSync(filePath).mtimeMs; // Use mtimeMs for higher precision
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return null; // File doesn't exist
|
||||
}
|
||||
console.error(`Error getting stats for ${filePath}:`, err);
|
||||
process.exit(1); // Exit on unexpected errors getting stats
|
||||
}
|
||||
}
|
||||
|
||||
function findSourceFiles(dir, allFiles = []) {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
// Simple check to avoid recursing into node_modules or build dir itself
|
||||
if (entry.isDirectory() && entry.name !== 'node_modules' && fullPath !== buildDir) {
|
||||
findSourceFiles(fullPath, allFiles);
|
||||
} else if (entry.isFile()) {
|
||||
allFiles.push(fullPath);
|
||||
}
|
||||
}
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
console.log('Checking build status...');
|
||||
|
||||
// Clean up old warnings file before check
|
||||
try {
|
||||
if (fs.existsSync(warningsFilePath)) {
|
||||
fs.unlinkSync(warningsFilePath);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`[Check Script] Warning: Could not delete previous warnings file: ${err.message}`);
|
||||
}
|
||||
|
||||
const buildMtime = getMtime(buildTimestampPath);
|
||||
if (!buildMtime) {
|
||||
// If build is missing, write that as a warning and exit(0) so app can display it
|
||||
const errorMessage = `ERROR: Build timestamp file (${path.relative(process.cwd(), buildTimestampPath)}) not found. Run \`npm run build\` first.`;
|
||||
console.error(errorMessage); // Still log error here
|
||||
try {
|
||||
fs.writeFileSync(warningsFilePath, errorMessage);
|
||||
} catch (writeErr) {
|
||||
console.error(`[Check Script] Error writing missing build warning file: ${writeErr.message}`);
|
||||
}
|
||||
process.exit(0); // Allow app to start and show the error
|
||||
}
|
||||
|
||||
let newerSourceFileFound = false;
|
||||
const warningMessages = []; // Collect warnings here
|
||||
const allSourceFiles = [];
|
||||
|
||||
// Collect files from specified directories
|
||||
sourceDirs.forEach((dir) => {
|
||||
const dirPath = path.resolve(dir);
|
||||
if (fs.existsSync(dirPath)) {
|
||||
findSourceFiles(dirPath, allSourceFiles);
|
||||
} else {
|
||||
console.warn(`Warning: Source directory "${dir}" not found.`);
|
||||
}
|
||||
});
|
||||
|
||||
// Add specific files
|
||||
filesToWatch.forEach((file) => {
|
||||
const filePath = path.resolve(file);
|
||||
if (fs.existsSync(filePath)) {
|
||||
allSourceFiles.push(filePath);
|
||||
} else {
|
||||
console.warn(`Warning: Watched file "${file}" not found.`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check modification times
|
||||
for (const file of allSourceFiles) {
|
||||
const sourceMtime = getMtime(file);
|
||||
const relativePath = path.relative(process.cwd(), file);
|
||||
const isNewer = sourceMtime && sourceMtime > buildMtime;
|
||||
|
||||
if (isNewer) {
|
||||
const warning = `Warning: Source file "${relativePath}" has been modified since the last build.`;
|
||||
console.warn(warning); // Keep console warning for script debugging
|
||||
warningMessages.push(warning);
|
||||
newerSourceFileFound = true;
|
||||
// break; // Uncomment to stop checking after the first newer file
|
||||
}
|
||||
}
|
||||
|
||||
if (newerSourceFileFound) {
|
||||
const finalWarning = '\nRun "npm run build" to incorporate changes before starting.';
|
||||
warningMessages.push(finalWarning);
|
||||
console.warn(finalWarning);
|
||||
|
||||
// Write warnings to the temp file
|
||||
try {
|
||||
fs.writeFileSync(warningsFilePath, warningMessages.join('\n'));
|
||||
// Removed debug log
|
||||
} catch (err) {
|
||||
console.error(`[Check Script] Error writing warnings file: ${err.message}`);
|
||||
// Proceed without writing, app won't show warnings
|
||||
}
|
||||
} else {
|
||||
console.log('Build is up-to-date.');
|
||||
// Ensure no stale warning file exists if build is ok
|
||||
try {
|
||||
if (fs.existsSync(warningsFilePath)) {
|
||||
fs.unlinkSync(warningsFilePath);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`[Check Script] Warning: Could not delete previous warnings file: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
process.exit(0); // Always exit successfully so the app starts
|
Loading…
Reference in New Issue