diff --git a/internal/skills/dep_scanner.go b/internal/skills/dep_scanner.go
index b61c7ebb..446a0107 100644
--- a/internal/skills/dep_scanner.go
+++ b/internal/skills/dep_scanner.go
@@ -120,6 +120,9 @@ var (
nodeRequireRe = regexp.MustCompile(`require\(['"]([\w@][^'"]*)['"]\)`)
nodeESImportRe = regexp.MustCompile(`from\s+['"]([^'"./][^'"]*?)['"]`)
shebangRe = regexp.MustCompile(`^#!\s*/usr/bin/env\s+(\S+)`)
+ // Detects JS ES module pattern: `import X from '...'` or `from '...'`.
+ // Used to skip false positives when JS imports appear inside Python string literals.
+ jsFromStringRe = regexp.MustCompile(`from\s+['"]`)
)
func scanFile(path string, pyImports, nodeImports map[string]bool, binaries map[string]bool) {
@@ -143,7 +146,10 @@ func scanFile(path string, pyImports, nodeImports map[string]bool, binaries map[
for _, line := range strings.Split(content, "\n") {
line = strings.TrimSpace(line)
if m := pyImportRe.FindStringSubmatch(line); len(m) > 1 {
- pyImports[m[1]] = true
+ // Skip JS ES module imports inside string literals (e.g. `import mermaid from '...'`)
+ if !jsFromStringRe.MatchString(line) {
+ pyImports[m[1]] = true
+ }
}
if m := pyFromRe.FindStringSubmatch(line); len(m) > 1 {
pyImports[m[1]] = true
diff --git a/internal/skills/dep_scanner_false_positive_test.go b/internal/skills/dep_scanner_false_positive_test.go
new file mode 100644
index 00000000..806319a4
--- /dev/null
+++ b/internal/skills/dep_scanner_false_positive_test.go
@@ -0,0 +1,91 @@
+package skills
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestScanFile_JSImportInsidePythonFString(t *testing.T) {
+ dir := t.TempDir()
+ pyFile := filepath.Join(dir, "render.py")
+
+ // Python file with JS ES module import inside f-string (issue #544)
+ content := `#!/usr/bin/env python3
+import sys
+import json
+
+def render_html(text):
+ mermaid_init = f"""
+
+"""
+ return f"{text}{mermaid_init}"
+`
+ if err := os.WriteFile(pyFile, []byte(content), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ pyImports := make(map[string]bool)
+ nodeImports := make(map[string]bool)
+ binaries := make(map[string]bool)
+
+ scanFile(pyFile, pyImports, nodeImports, binaries)
+
+ // sys and json are real Python imports — should be detected
+ if !pyImports["sys"] {
+ t.Error("expected sys to be detected as Python import")
+ }
+ if !pyImports["json"] {
+ t.Error("expected json to be detected as Python import")
+ }
+
+ // mermaid is a JS import inside f-string — should NOT be detected
+ if pyImports["mermaid"] {
+ t.Error("FALSE POSITIVE: mermaid detected as Python import — it's a JS import inside f-string")
+ }
+}
+
+func TestScanFile_MultipleJSImportsInsidePythonString(t *testing.T) {
+ dir := t.TempDir()
+ pyFile := filepath.Join(dir, "template.py")
+
+ // Multiple JS imports inside a Python string + real Python imports
+ content := `import os
+import subprocess
+
+TEMPLATE = """
+
+"""
+`
+ if err := os.WriteFile(pyFile, []byte(content), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ pyImports := make(map[string]bool)
+ nodeImports := make(map[string]bool)
+ binaries := make(map[string]bool)
+
+ scanFile(pyFile, pyImports, nodeImports, binaries)
+
+ // Real Python imports
+ if !pyImports["os"] {
+ t.Error("expected os to be detected as Python import")
+ }
+ if !pyImports["subprocess"] {
+ t.Error("expected subprocess to be detected as Python import")
+ }
+
+ // JS imports inside string — should NOT be detected
+ if pyImports["React"] {
+ t.Error("FALSE POSITIVE: React detected as Python import")
+ }
+ if pyImports["lodash"] {
+ t.Error("FALSE POSITIVE: lodash detected as Python import")
+ }
+}
diff --git a/internal/tools/context_file_interceptor_test.go b/internal/tools/context_file_interceptor_test.go
index 62f3cf4b..9a6a10ff 100644
--- a/internal/tools/context_file_interceptor_test.go
+++ b/internal/tools/context_file_interceptor_test.go
@@ -90,6 +90,9 @@ func (s *stubAgentStore) EnsureUserProfile(_ context.Context, _ uuid.UUID, _ str
func (s *stubAgentStore) PropagateContextFile(_ context.Context, _ uuid.UUID, _ string) (int, error) {
return 0, nil
}
+func (s *stubAgentStore) MigrateUserDataOnMerge(_ context.Context, _ []string, _ string) error {
+ return nil
+}
// ---- Tests ----