Skip to content

Feat/i18n and ssh naming#6

Merged
Jamkris merged 6 commits into
mainfrom
feat/i18n-and-ssh-naming
Apr 9, 2026
Merged

Feat/i18n and ssh naming#6
Jamkris merged 6 commits into
mainfrom
feat/i18n-and-ssh-naming

Conversation

@Jamkris

@Jamkris Jamkris commented Apr 9, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Automatic shell completion setup during initialization: detects shell (falls back to bash if unknown), attempts to install completion, and reports status (installed, already installed, unsupported, or failed) with rc file path and guidance for manual activation.
  • Localization

    • Clarified SSH key prompt wording.
    • Added localized messages for completion statuses: installed, already installed, failed (with rc file and eval instruction), and unsupported.

@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an idempotent shell-completion installer: exports COMPLETION_MARKER, InstallResult and installCompletion() to detect the user shell (with fallback), pick an rc file, and append a marked bootstrap block if missing. init now invokes completion setup. i18n strings updated and SSH key prompt made generic.

Changes

Cohort / File(s) Summary
Completion installation & command
src/commands/completion.ts, src/commands/init.ts
Added exported COMPLETION_MARKER, InstallResult type, and installCompletion() which detects shell (may be null), maps to rc files (~/.zshrc/~/.bashrc), checks for marker, appends an eval bootstrap block idempotently, and returns installed/already_installed/unsupported/failed. registerCompletionCommand now falls back to 'bash' when no --shell and detection is absent. init calls a new setupCompletion() to run installer and log localized outcomes.
Internationalization
src/i18n/locales/en.ts, src/i18n/locales/ko.ts, src/i18n/types.ts
Changed SSH key prompt from “ed25519” to “SSH key”. Added localized messages and types: completionInstalled(rcFile), completionAlreadyInstalled, completionFailed(rcFile), and completionUnsupported; updated Messages interface accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

security, breaking

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and doesn't clearly convey the main change. 'Feat/i18n and ssh naming' uses branch-like naming and is too generic to understand the primary contribution. Revise the title to be more descriptive, such as 'Add shell completion installation with i18n support' or 'Implement automatic completion setup and update SSH key messaging'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/i18n-and-ssh-naming

Comment @coderabbitai help to get the list of available commands and usage tips.

Jamkris added 2 commits April 9, 2026 10:32
Change "Generate new ed25519 key" to "Generate new SSH key" in both
en and ko locale messages. The actual keygen still uses ed25519
internally.
- Add installCompletion() that appends eval line to ~/.zshrc or ~/.bashrc
- Uses marker comment to avoid duplicate installation
- Called automatically during ghem init
- Add i18n messages for completion install status
@Jamkris Jamkris force-pushed the feat/i18n-and-ssh-naming branch from e345969 to 7e2ded7 Compare April 9, 2026 01:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/commands/completion.ts (1)

3-7: ⚠️ Potential issue | 🟡 Minor

detectShell() silently falls back to bash for unsupported shells.

Fish, PowerShell, and other shell users will see a success message but get non-functional completion. Consider either:

  1. Returning null for unsupported shells and skipping installation
  2. Warning users that only bash/zsh are supported
Possible fix to skip unsupported shells
-function detectShell(): string {
+function detectShell(): string | null {
   const shell = process.env.SHELL ?? '';
   if (shell.includes('zsh')) return 'zsh';
-  return 'bash';
+  if (shell.includes('bash')) return 'bash';
+  return null;
 }

Then update installCompletion() to handle null.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/completion.ts` around lines 3 - 7, detectShell() currently
returns 'bash' for any unknown SHELL which silently gives non-functional
completions for shells like fish or PowerShell; change detectShell() to return
null for unsupported shells instead of defaulting to 'bash', and update
installCompletion() to check for a null return from detectShell() and skip
installation while printing a clear warning that only bash/zsh are supported (or
provide instructions/exit code). Use the functions detectShell and
installCompletion to locate where to implement the null return and the
early-skip/warning behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/completion.ts`:
- Around line 127-129: Wrap the appendFileSync call in
src/commands/completion.ts in a try/catch so a filesystem permission error
doesn't throw out of setupCompletion() in init.ts after config is written; catch
the error from appendFileSync, log the error (include the thrown error object)
and return a non-success result (e.g., { installed: false, shell, rcFile } or
similar) instead of rethrowing so init flow can handle the failure gracefully.
Ensure you reference the appendFileSync invocation and adjust the caller
behavior in setupCompletion() if it expects a boolean/installed flag so failures
are propagated without crashing.
- Around line 110-112: Replace the inline CommonJS require calls for built-ins
by adding top-level ESM imports for existsSync, readFileSync, appendFileSync
from 'node:fs', join from 'node:path', and homedir from 'node:os' and remove the
three inline require lines (the ones that declare
existsSync/readFileSync/appendFileSync, join, and homedir) in completion.ts;
update any usages to rely on those imported bindings so the file uses standard
ESM imports instead of runtime require().

---

Outside diff comments:
In `@src/commands/completion.ts`:
- Around line 3-7: detectShell() currently returns 'bash' for any unknown SHELL
which silently gives non-functional completions for shells like fish or
PowerShell; change detectShell() to return null for unsupported shells instead
of defaulting to 'bash', and update installCompletion() to check for a null
return from detectShell() and skip installation while printing a clear warning
that only bash/zsh are supported (or provide instructions/exit code). Use the
functions detectShell and installCompletion to locate where to implement the
null return and the early-skip/warning behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a5e9208a-fc6d-4de8-a9e7-cb85271ad2a8

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce006b and e345969.

📒 Files selected for processing (5)
  • src/commands/completion.ts
  • src/commands/init.ts
  • src/i18n/locales/en.ts
  • src/i18n/locales/ko.ts
  • src/i18n/types.ts

Comment thread src/commands/completion.ts Outdated
Comment thread src/commands/completion.ts Outdated
- Replace inline require() with top-level ESM imports
- Wrap appendFileSync in try/catch to prevent init abort on permission errors

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
src/commands/completion.ts (2)

110-112: ⚠️ Potential issue | 🔴 Critical

Replace inline require() with top-level ESM imports.

Line 110-112 uses CommonJS require() inside a TypeScript ESM module, which is a runtime hazard in Node ESM (require may be undefined).

Suggested fix
 import type { Command } from 'commander';
+import { appendFileSync, existsSync, readFileSync } from 'node:fs';
+import { homedir } from 'node:os';
+import { join } from 'node:path';
@@
 export function installCompletion(): { installed: boolean; shell: string; rcFile: string } {
-  const { existsSync, readFileSync, appendFileSync } = require('node:fs') as typeof import('node:fs');
-  const { join } = require('node:path') as typeof import('node:path');
-  const { homedir } = require('node:os') as typeof import('node:os');
-
   const shell = detectShell();
#!/bin/bash
set -euo pipefail

echo "== package.json module type =="
fd -HI '^package\.json$' -x sh -c 'echo "--- $1"; rg -n "\"type\"\\s*:\\s*\"module\"" "$1" || true' sh {}

echo "== tsconfig module settings =="
fd -HI '^tsconfig.*\.json$' -x sh -c 'echo "--- $1"; rg -n "\"module\"|\"moduleResolution\"|\"target\"" "$1" || true' sh {}

echo "== inline require usage in completion command =="
rg -n "require\\('node:(fs|path|os)'\\)" src/commands/completion.ts

As per coding guidelines: **/*.ts: TypeScript ESM project targeting Node.js 20+ and built-ins should be imported with node: modules.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/completion.ts` around lines 110 - 112, The inline CommonJS
requires for node built-ins (existsSync, readFileSync, appendFileSync, join,
homedir) inside src/commands/completion.ts should be converted to top-level ESM
imports; remove the require(...) expressions and add equivalent imports at the
top of the module like: import { existsSync, readFileSync, appendFileSync } from
'node:fs' and import { join } from 'node:path' and import { homedir } from
'node:os' so the code uses proper ESM semantics and avoids runtime undefined
require in Node ESM.

120-129: ⚠️ Potential issue | 🟠 Major

Guard filesystem reads/writes to prevent partial init failure.

readFileSync/appendFileSync can throw (permissions, I/O errors). That exception currently bubbles and can abort init after config has already been written.

Suggested fix
-export function installCompletion(): { installed: boolean; shell: string; rcFile: string } {
+export function installCompletion():
+  | { status: 'installed'; shell: string; rcFile: string }
+  | { status: 'already-installed'; shell: string; rcFile: string }
+  | { status: 'failed'; shell: string; rcFile: string; error: Error } {
@@
-  if (existsSync(rcFile)) {
-    const content = readFileSync(rcFile, 'utf-8');
-    if (content.includes(COMPLETION_MARKER)) {
-      return { installed: false, shell, rcFile };
-    }
-  }
-
-  const line = `\n${COMPLETION_MARKER}\neval "$(ghem completion --shell ${shell})"\n`;
-  appendFileSync(rcFile, line, 'utf-8');
-  return { installed: true, shell, rcFile };
+  try {
+    if (existsSync(rcFile)) {
+      const content = readFileSync(rcFile, 'utf-8');
+      if (content.includes(COMPLETION_MARKER)) {
+        return { status: 'already-installed', shell, rcFile };
+      }
+    }
+
+    const line = `\n${COMPLETION_MARKER}\neval "$(ghem completion --shell ${shell})"\n`;
+    appendFileSync(rcFile, line, 'utf-8');
+    return { status: 'installed', shell, rcFile };
+  } catch (error) {
+    return {
+      status: 'failed',
+      shell,
+      rcFile,
+      error: error instanceof Error ? error : new Error(String(error)),
+    };
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/completion.ts` around lines 120 - 129, The completion rc-file
read/write is unguarded (uses existsSync/readFileSync/appendFileSync) and can
throw, causing init to fail after config is written; wrap the filesystem
operations that check and append COMPLETION_MARKER (the
existsSync/readFileSync/appendFileSync sequence around rcFile) in a try/catch,
and on error avoid throwing—log or surface a non-fatal warning and return a safe
result (e.g., { installed: false, shell, rcFile }) so init continues without a
partial-failure; ensure the catch references the same rcFile and
COMPLETION_MARKER so the behavior is explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/commands/completion.ts`:
- Around line 110-112: The inline CommonJS requires for node built-ins
(existsSync, readFileSync, appendFileSync, join, homedir) inside
src/commands/completion.ts should be converted to top-level ESM imports; remove
the require(...) expressions and add equivalent imports at the top of the module
like: import { existsSync, readFileSync, appendFileSync } from 'node:fs' and
import { join } from 'node:path' and import { homedir } from 'node:os' so the
code uses proper ESM semantics and avoids runtime undefined require in Node ESM.
- Around line 120-129: The completion rc-file read/write is unguarded (uses
existsSync/readFileSync/appendFileSync) and can throw, causing init to fail
after config is written; wrap the filesystem operations that check and append
COMPLETION_MARKER (the existsSync/readFileSync/appendFileSync sequence around
rcFile) in a try/catch, and on error avoid throwing—log or surface a non-fatal
warning and return a safe result (e.g., { installed: false, shell, rcFile }) so
init continues without a partial-failure; ensure the catch references the same
rcFile and COMPLETION_MARKER so the behavior is explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: aaf8f0ae-104c-437f-a171-fdb156b73228

📥 Commits

Reviewing files that changed from the base of the PR and between e345969 and 7e2ded7.

📒 Files selected for processing (5)
  • src/commands/completion.ts
  • src/commands/init.ts
  • src/i18n/locales/en.ts
  • src/i18n/locales/ko.ts
  • src/i18n/types.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/completion.ts`:
- Around line 112-131: The installCompletion function currently conflates
"already installed" with I/O failures and leaves readFileSync uncaught; update
installCompletion so that when the rc file already contains COMPLETION_MARKER it
returns { installed: true, shell, rcFile } (idempotent success), wrap the
readFileSync call in a try/catch and convert any read errors into a PersonaError
(include the original error message), and likewise convert failures from
appendFileSync into a PersonaError instead of returning { installed: false };
reference the installCompletion function, COMPLETION_MARKER symbol, and use
PersonaError so init.ts/logger can correctly distinguish and display real I/O
errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 987925cf-a431-49fc-939c-c61687e4402e

📥 Commits

Reviewing files that changed from the base of the PR and between 7e2ded7 and 642b837.

📒 Files selected for processing (1)
  • src/commands/completion.ts

Comment thread src/commands/completion.ts Outdated
- Return status union type (installed/already_installed/failed) instead
  of boolean to differentiate I/O errors from idempotent skips
- Wrap readFileSync in same try/catch to handle read permission errors
- Add completionFailed i18n message with manual install hint

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/completion.ts`:
- Around line 117-134: installCompletion currently treats any non-'zsh' shell as
'bash' via detectShell and unconditionally writes to rcFile; change this so that
detectShell (or installCompletion) returns a distinct unsupported/ambiguous
value for shells other than 'bash' or 'zsh' and have installCompletion return an
explicit status like 'unsupported_shell' or 'ambiguous_shell' (include the
detected shell string and null/undefined rcFile) instead of defaulting to
~/.bashrc; do not append or modify any file for unsupported shells (use
COMPLETION_MARKER, installCompletion, detectShell, and InstallResult to
implement the new status) and ensure the caller uses that status to tell the
user to run `ghem completion --shell <bash|zsh>` explicitly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 90d698da-0dde-47ae-a501-58b195425243

📥 Commits

Reviewing files that changed from the base of the PR and between 642b837 and e93ae7b.

📒 Files selected for processing (5)
  • src/commands/completion.ts
  • src/commands/init.ts
  • src/i18n/locales/en.ts
  • src/i18n/locales/ko.ts
  • src/i18n/types.ts

Comment thread src/commands/completion.ts
- detectShell() now returns null for unrecognized shells (fish, nushell, etc.)
- installCompletion() returns 'unsupported' status instead of silently
  writing to ~/.bashrc for wrong shell
- Add completionUnsupported i18n message guiding manual setup
@Jamkris Jamkris merged commit 0ad79ef into main Apr 9, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant