gemini-coder 0.1.0 → 0.1.2

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/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ const sessionManager = new SessionManager();
10
10
  program
11
11
  .name('gemini')
12
12
  .description('Gemini Coder Pro CLI - Advanced AI Coding Agent')
13
- .version('0.2.0');
13
+ .version('0.1.2');
14
14
  program
15
15
  .command('chat', { isDefault: true })
16
16
  .description('Start an interactive chat session')
@@ -18,7 +18,7 @@ program
18
18
  .option('-c, --continue', 'Continue the most recent session')
19
19
  .option('-m, --model <name>', 'Specify the model to use', 'gemini-3.1-pro-preview')
20
20
  .action(async (options) => {
21
- printBootScreen('Gemini Coder Pro', 'v0.2.0');
21
+ printBootScreen('Gemini Coder Pro', 'v0.1.2');
22
22
  let session;
23
23
  if (options.continue) {
24
24
  session = await sessionManager.getLatestSession();
@@ -1,6 +1,7 @@
1
1
  import { exec } from 'child_process';
2
2
  import { promisify } from 'util';
3
- import { readFile } from 'fs/promises';
3
+ import { readFile, readdir } from 'fs/promises';
4
+ import path from 'path';
4
5
  import { glob } from 'glob';
5
6
  const execAsync = promisify(exec);
6
7
  async function getSignature(filePath) {
@@ -17,15 +18,47 @@ async function getSignature(filePath) {
17
18
  return null;
18
19
  }
19
20
  }
21
+ async function findWorkspaceRoot(startPath) {
22
+ let currentPath = startPath;
23
+ while (currentPath !== path.parse(currentPath).root) {
24
+ try {
25
+ await readFile(path.join(currentPath, 'package.json'), 'utf8');
26
+ return { root: currentPath, isGitRepo: false };
27
+ }
28
+ catch {
29
+ // Keep walking upward.
30
+ }
31
+ try {
32
+ await readFile(path.join(currentPath, '.git'), 'utf8');
33
+ return { root: currentPath, isGitRepo: true };
34
+ }
35
+ catch {
36
+ // Keep walking upward.
37
+ }
38
+ currentPath = path.dirname(currentPath);
39
+ }
40
+ return { root: startPath, isGitRepo: false };
41
+ }
20
42
  export async function getContextMap() {
43
+ const { root, isGitRepo } = await findWorkspaceRoot(process.cwd());
21
44
  let files = [];
22
45
  try {
23
- const { stdout } = await execAsync('git ls-files --cached --others --exclude-standard');
24
- files = stdout.split('\n').filter(f => f.trim().length > 0);
46
+ if (isGitRepo) {
47
+ const { stdout } = await execAsync('git ls-files --cached --others --exclude-standard', { cwd: root });
48
+ files = stdout.split('\n').filter(f => f.trim().length > 0);
49
+ }
50
+ else {
51
+ const entries = await readdir(root, { withFileTypes: true });
52
+ files = entries
53
+ .filter(entry => entry.isFile())
54
+ .map(entry => entry.name)
55
+ .filter(name => ['.ts', '.js', '.json', '.md', '.txt'].some(ext => name.endsWith(ext)));
56
+ }
25
57
  }
26
58
  catch (e) {
27
- // Fallback to glob if not a git repository
28
- files = await glob('**/*', {
59
+ // Final fallback: only inspect the current directory, never the full home tree.
60
+ files = await glob('*', {
61
+ cwd: root,
29
62
  ignore: ['node_modules/**', 'dist/**', '.git/**', 'package-lock.json'],
30
63
  nodir: true
31
64
  });
@@ -35,7 +68,7 @@ export async function getContextMap() {
35
68
  for (let i = 0; i < files.length; i += batchSize) {
36
69
  const batch = files.slice(i, i + batchSize);
37
70
  const batchResults = await Promise.all(batch.map(async (file) => {
38
- const signature = await getSignature(file);
71
+ const signature = await getSignature(path.join(root, file));
39
72
  if (signature) {
40
73
  return `${file}:\n[Signature]\n${signature}\n---`;
41
74
  }
@@ -265,7 +265,15 @@ export class Orchestrator {
265
265
  }
266
266
  catch (err) {
267
267
  spinner.fail(chalk.red('API Error'));
268
- console.error(chalk.red(`\n[API Error]: ${err.message || err}`));
268
+ const message = String(err?.message || err);
269
+ const isOauthDnsIssue = message.includes('oauth2.googleapis.com') ||
270
+ message.includes('ENOTFOUND') ||
271
+ message.includes('EAI_AGAIN') ||
272
+ message.includes('ECONNRESET');
273
+ console.error(chalk.red(`\n[API Error]: ${message}`));
274
+ if (isOauthDnsIssue) {
275
+ console.error(chalk.yellow('\n[Hint]: The CLI could not reach oauth2.googleapis.com to exchange the service-account token. Check network access, DNS, firewall, or proxy settings on this machine, then retry.'));
276
+ }
269
277
  return;
270
278
  }
271
279
  let responseParts = [];
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- const SESSIONS_DIR = path.join(process.cwd(), '.gemini-coder', 'sessions');
3
+ import os from 'os';
4
+ const SESSIONS_DIR = path.join(os.homedir(), '.gemini-coder', 'sessions');
4
5
  export class SessionManager {
5
6
  currentSessionId = null;
6
7
  constructor() {
@@ -29,6 +30,9 @@ export class SessionManager {
29
30
  }
30
31
  async saveSession(session) {
31
32
  const filePath = path.join(SESSIONS_DIR, `${session.id}.json`);
33
+ // Ensure the sessions directory exists before writing (constructor calls
34
+ // ensureDirectory but it's async and may not complete before first write).
35
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
32
36
  await fs.writeFile(filePath, JSON.stringify(session, null, 2));
33
37
  }
34
38
  async loadSession(id) {
@@ -44,14 +48,19 @@ export class SessionManager {
44
48
  }
45
49
  }
46
50
  async getLatestSession() {
47
- const files = await fs.readdir(SESSIONS_DIR);
48
- if (files.length === 0)
51
+ try {
52
+ const files = await fs.readdir(SESSIONS_DIR);
53
+ if (files.length === 0)
54
+ return null;
55
+ const sessions = await Promise.all(files.filter(f => f.endsWith('.json')).map(async (f) => {
56
+ const data = await fs.readFile(path.join(SESSIONS_DIR, f), 'utf8');
57
+ return JSON.parse(data);
58
+ }));
59
+ return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())[0];
60
+ }
61
+ catch (e) {
49
62
  return null;
50
- const sessions = await Promise.all(files.filter(f => f.endsWith('.json')).map(async (f) => {
51
- const data = await fs.readFile(path.join(SESSIONS_DIR, f), 'utf8');
52
- return JSON.parse(data);
53
- }));
54
- return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())[0];
63
+ }
55
64
  }
56
65
  async listSessions() {
57
66
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gemini-coder",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {