Skip to content

fix: clipboard copy in dialog + CLI --help handling#209

Merged
thebtf merged 2 commits into
mainfrom
fix/v6-followup-167-help
Apr 26, 2026
Merged

fix: clipboard copy in dialog + CLI --help handling#209
thebtf merged 2 commits into
mainfrom
fix/v6-followup-167-help

Conversation

@thebtf
Copy link
Copy Markdown
Owner

@thebtf thebtf commented Apr 26, 2026

Summary

Two v6 follow-up fixes in one PR:

1. Fix clipboard copy in TokenCreated dialog (closes #167 via engram issue tracker)

The "Copy" button in the token creation modal silently failed on HTTP sites
(e.g. http://host:37777). Root cause:

  • navigator.clipboard.writeText() requires a secure context (HTTPS/localhost)
  • The legacy execCommand('copy') fallback was missing textarea.focus() before
    textarea.select() — Radix Dialog's focus trap prevented the textarea from
    receiving focus
  • Off-screen positioning (left:-9999px) caused some browsers to skip the element

Fix: Skip Clipboard API on non-secure contexts via window.isSecureContext,
add textarea.focus(), use in-viewport transparent positioning.

2. Handle --help / --version CLI flags

Previously engram --help fell through to startupGate() which exits with
FATAL: ENGRAM_TOKEN is empty if the token isn't configured. Now prints
version, purpose, and env var reference.

Testing

  • Clipboard: manual verification on HTTP dashboard in Chrome/Edge
  • CLI: engram --help prints usage, engram --version prints version
  • Go build: go build ./cmd/engram/ — clean

Summary by CodeRabbit

Новые функции

  • Добавлена поддержка флагов --help и --version для быстрого получения информации о приложении и выхода перед инициализацией.

Исправления ошибок

  • Улучшена функциональность копирования в буфер обмена с повышенными проверками безопасности и расширенной совместимостью с браузерами.

thebtf added 2 commits April 26, 2026 22:04
The legacy execCommand fallback failed inside Radix Dialog because:
1. textarea.focus() was missing before textarea.select()
2. off-screen positioning (left:-9999px) prevented focus in some browsers

Also skip Clipboard API entirely on non-secure contexts (HTTP)
via window.isSecureContext check instead of catching the DOMException.
Previously running `engram --help` or `engram -h` fell through to
startupGate() which exits with FATAL if ENGRAM_TOKEN is unset.
Now prints version, purpose, and env var reference.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

Обзор

Добавлена ранняя проверка аргументов командной строки в точку входа приложения для вывода справки и версии перед инициализацией. Модифицирован механизм копирования в буфер обмена для требования безопасного контекста и улучшены операции со скрытым текстовым полем.

Изменения

Когорта / Файл(ы) Краткое описание
Инициализация CLI
cmd/engram/main.go
Добавлена ранняя проверка флагов --help/-h и --version/-v перед вызовом startupGate, выводящая версию демона, инструкции и значения переменных окружения.
Утилиты буфера обмена
ui/src/utils/clipboard.ts
Добавлена проверка безопасного контекста (window.isSecureContext) перед использованием Clipboard API; в резервной ветке execCommand('copy') заменено позиционирование на скрытые стили с явным cssText и добавлен вызов focus().

Оценка сложности проверки кода

🎯 1 (Тривиальное) | ⏱️ ~5 минут

Стихотворение

🐰 Флаги помощи летят с ветерком,
Буфер обмена — безопаснее пусть,
Фокус на деле, забот ни с грустью,
Контекст надёжен, а стили — с умом,
Малые правки — большой ладный гром! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning PR changes (clipboard + CLI help) are unrelated to issue #167 objectives (Loom module integration). Verify this PR should be linked to issue #167 or link to correct issue addressing clipboard and CLI help fixes.
Out of Scope Changes check ⚠️ Warning Changes to clipboard and CLI help are out of scope for issue #167 (Loom module integration). Either link this PR to the correct issue or remove issue #167 from linked issues and associate with appropriate issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR title accurately describes the two main changes: clipboard copy fix in dialog and CLI --help handling.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v6-followup-167-help

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces basic command-line flag handling for the engram daemon and improves the clipboard utility's reliability and security. The clipboard utility now checks for a secure context before using the modern API and includes a more robust legacy fallback. Feedback was provided regarding the CLI flags, suggesting that the --version flag should output only the version string to support programmatic usage and that a switch statement would improve the code's maintainability.

Comment thread cmd/engram/main.go
Comment on lines +67 to +77
if len(os.Args) > 1 && (os.Args[1] == "--help" || os.Args[1] == "-h" || os.Args[1] == "--version" || os.Args[1] == "-v") {
fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
fmt.Println()
fmt.Println("This binary is invoked automatically by the engram plugin.")
fmt.Println("It is not intended to be run directly.")
fmt.Println()
fmt.Println("Environment:")
fmt.Printf(" %-28s Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
fmt.Printf(" %-28s Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
os.Exit(0)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The implementation currently returns the full help text for both --help and --version flags. It is standard practice for --version to only output the version string, which facilitates programmatic usage (e.g., version checks in scripts). Using a switch statement also improves readability and makes it easier to add more flags in the future.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
ui/src/utils/clipboard.ts (1)

11-22: ⚠️ Potential issue | 🟡 Minor

Сделайте очистку textarea гарантированной через finally.

Если исключение произойдёт после appendChild, текущий removeChild не выполнится и скрытый элемент останется в DOM.

Предлагаемое исправление
 export async function copyToClipboard(text: string): Promise<boolean> {
   if (window.isSecureContext && navigator.clipboard?.writeText) {
@@
-  try {
-    const textarea = document.createElement('textarea')
+  const textarea = document.createElement('textarea')
+  try {
     textarea.value = text
     textarea.setAttribute('readonly', '')
     textarea.style.cssText =
       'position:fixed;top:0;left:0;width:1px;height:1px;padding:0;border:none;outline:none;opacity:0;'
     document.body.appendChild(textarea)
     textarea.focus()
     textarea.select()
-    const success = document.execCommand('copy')
-    document.body.removeChild(textarea)
-    return success
+    return document.execCommand('copy')
   } catch {
     return false
+  } finally {
+    textarea.remove()
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/utils/clipboard.ts` around lines 11 - 22, The hidden textarea created
in the copy routine can remain in the DOM if an exception occurs after
document.body.appendChild(textarea); update the copy logic (the block that
creates textarea, sets value/attributes, calls textarea.select() and
document.execCommand('copy')) to ensure document.body.removeChild(textarea) is
executed in a finally block and that a default return value (e.g., false) is
used if an exception occurs; reference the textarea variable and the
document.execCommand('copy') call so you move removeChild into finally and
preserve/return the copy success state safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/engram/main.go`:
- Around line 67-77: Split the combined help/version branch so that when
os.Args[1] is "--version" or "-v" the program prints just the version
(daemonVersion) and exits, and only when os.Args[1] is "--help" or "-h" it
prints the full help text; update the conditional around os.Args handling in
main (the block that currently checks os.Args[1] for "--help" || "-h" ||
"--version" || "-v") to check version flags first and call fmt.Printf("%s\n",
daemonVersion) (or similar) then os.Exit(0), otherwise fall through to the
existing help-printing code that references config.EnvServerURL and
config.EnvWorkstationToken.

---

Outside diff comments:
In `@ui/src/utils/clipboard.ts`:
- Around line 11-22: The hidden textarea created in the copy routine can remain
in the DOM if an exception occurs after document.body.appendChild(textarea);
update the copy logic (the block that creates textarea, sets value/attributes,
calls textarea.select() and document.execCommand('copy')) to ensure
document.body.removeChild(textarea) is executed in a finally block and that a
default return value (e.g., false) is used if an exception occurs; reference the
textarea variable and the document.execCommand('copy') call so you move
removeChild into finally and preserve/return the copy success state safely.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64c25cab-086b-4812-8c6f-619085e3a95b

📥 Commits

Reviewing files that changed from the base of the PR and between e229fbf and 9256ad6.

📒 Files selected for processing (2)
  • cmd/engram/main.go
  • ui/src/utils/clipboard.ts

Comment thread cmd/engram/main.go
Comment on lines +67 to +77
if len(os.Args) > 1 && (os.Args[1] == "--help" || os.Args[1] == "-h" || os.Args[1] == "--version" || os.Args[1] == "-v") {
fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
fmt.Println()
fmt.Println("This binary is invoked automatically by the engram plugin.")
fmt.Println("It is not intended to be run directly.")
fmt.Println()
fmt.Println("Environment:")
fmt.Printf(" %-28s Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
fmt.Printf(" %-28s Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
os.Exit(0)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

--version сейчас выводит help-текст вместо только версии.

На Line 67-77 --help и --version объединены в одну ветку, поэтому engram --version печатает длинный справочный вывод. Это ломает ожидаемый формат для скриптов и расходится с целевым поведением PR.

Предлагаемое исправление
-	if len(os.Args) > 1 && (os.Args[1] == "--help" || os.Args[1] == "-h" || os.Args[1] == "--version" || os.Args[1] == "-v") {
-		fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
-		fmt.Println()
-		fmt.Println("This binary is invoked automatically by the engram plugin.")
-		fmt.Println("It is not intended to be run directly.")
-		fmt.Println()
-		fmt.Println("Environment:")
-		fmt.Printf("  %-28s  Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
-		fmt.Printf("  %-28s  Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
-		os.Exit(0)
-	}
+	if len(os.Args) > 1 {
+		switch os.Args[1] {
+		case "--version", "-v":
+			fmt.Printf("engram %s\n", daemonVersion)
+			os.Exit(0)
+		case "--help", "-h":
+			fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
+			fmt.Println()
+			fmt.Println("This binary is invoked automatically by the engram plugin.")
+			fmt.Println("It is not intended to be run directly.")
+			fmt.Println()
+			fmt.Println("Environment:")
+			fmt.Printf("  %-28s  Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
+			fmt.Printf("  %-28s  Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
+			os.Exit(0)
+		}
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(os.Args) > 1 && (os.Args[1] == "--help" || os.Args[1] == "-h" || os.Args[1] == "--version" || os.Args[1] == "-v") {
fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
fmt.Println()
fmt.Println("This binary is invoked automatically by the engram plugin.")
fmt.Println("It is not intended to be run directly.")
fmt.Println()
fmt.Println("Environment:")
fmt.Printf(" %-28s Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
fmt.Printf(" %-28s Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
os.Exit(0)
}
if len(os.Args) > 1 {
switch os.Args[1] {
case "--version", "-v":
fmt.Printf("engram %s\n", daemonVersion)
os.Exit(0)
case "--help", "-h":
fmt.Printf("engram %s — stdio MCP daemon for Claude Code\n", daemonVersion)
fmt.Println()
fmt.Println("This binary is invoked automatically by the engram plugin.")
fmt.Println("It is not intended to be run directly.")
fmt.Println()
fmt.Println("Environment:")
fmt.Printf(" %-28s Server URL (e.g. http://host:37777)\n", config.EnvServerURL)
fmt.Printf(" %-28s Workstation keycard (issued via dashboard /tokens)\n", config.EnvWorkstationToken)
os.Exit(0)
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/engram/main.go` around lines 67 - 77, Split the combined help/version
branch so that when os.Args[1] is "--version" or "-v" the program prints just
the version (daemonVersion) and exits, and only when os.Args[1] is "--help" or
"-h" it prints the full help text; update the conditional around os.Args
handling in main (the block that currently checks os.Args[1] for "--help" ||
"-h" || "--version" || "-v") to check version flags first and call
fmt.Printf("%s\n", daemonVersion) (or similar) then os.Exit(0), otherwise fall
through to the existing help-printing code that references config.EnvServerURL
and config.EnvWorkstationToken.

@thebtf thebtf merged commit c078422 into main Apr 26, 2026
8 checks passed
@thebtf thebtf deleted the fix/v6-followup-167-help branch April 26, 2026 19:18
thebtf added a commit that referenced this pull request May 7, 2026
5 fixes since v6.0.0:
- clipboard copy fix in dialog + CLI --help/--version flags (#209)
- gitleaks-friendly placeholder in setup.md example (e229fbf)
- bump muxcore v0.21.6 -> v0.21.19 (#210)
- inset sidebar with rounded content panel (#211)
- brand assets + sync infrastructure (#212)
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