Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ jobs:
- name: Run companion tests
run: |
cd companion && npm test || true

- name: Setup chrome-extension Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: chrome-extension/package-lock.json

- name: Build + typecheck chrome-extension (audit H7)
run: |
cd chrome-extension && npm ci && npm run build
2 changes: 1 addition & 1 deletion chrome-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"postinstall": "node scripts/patch-vfile.mjs",
"test": "node -e \"require('fs').rmSync('.test-dist',{recursive:true,force:true})\" && tsc -p tsconfig.test.json && node --test .test-dist/tests/**/*.test.js",
"prebuild": "node scripts/generate-icons.mjs",
"build": "plasmo build",
"build": "tsc --noEmit && plasmo build",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether Plasmo generates .plasmo/index.d.ts during npm ci or only during build/dev.
# Look for postinstall/prepare scripts in package.json and plasmo's package.json
cat chrome-extension/package.json | jq '.scripts'
# Check if .plasmo exists after install
ls -la chrome-extension/.plasmo/ 2>/dev/null || echo ".plasmo directory not found"

Repository: nehcuh/cmspark

Length of output: 1246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant files =="
git ls-files chrome-extension/package.json chrome-extension/tsconfig*.json chrome-extension/.plasmo/index.d.ts || true

echo
echo "== package.json =="
cat -n chrome-extension/package.json | sed -n '1,120p'

echo
echo "== tsconfig files =="
for f in chrome-extension/tsconfig.json chrome-extension/tsconfig.*.json; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  cat -n "$f" | sed -n '1,220p'
done

echo
echo "== search for plasmo-generated type usage =="
rg -n "Plasmo|\.plasmo/index\.d\.ts|declare global|CSConfig|chrome-extension/.plasmo" chrome-extension -g '!chrome-extension/.plasmo/**' || true

Repository: nehcuh/cmspark

Length of output: 3995


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== lockfiles / workspace files =="
git ls-files | rg '(^|/)(package-lock\.json|pnpm-lock\.yaml|yarn.lock|npm-shrinkwrap\.json|package\.json)$' || true

echo
echo "== root package.json if present =="
[ -f package.json ] && cat -n package.json | sed -n '1,220p' || echo "no root package.json"

echo
echo "== plasmo-generated file contents =="
[ -f chrome-extension/.plasmo/index.d.ts ] && cat -n chrome-extension/.plasmo/index.d.ts | sed -n '1,160p' || echo "no chrome-extension/.plasmo/index.d.ts"

echo
echo "== plasmo package metadata if installed =="
if [ -f chrome-extension/node_modules/plasmo/package.json ]; then
  cat -n chrome-extension/node_modules/plasmo/package.json | sed -n '1,220p'
else
  echo "chrome-extension/node_modules/plasmo/package.json not found"
fi

Repository: nehcuh/cmspark

Length of output: 3165


🌐 Web query:

Plasmo .plasmo/index.d.ts generated during npm install or only plasmo build dev

💡 Result:

The.plasmo/index.d.ts file and other generated type definition files are not created during the npm install process [1][2][3]. Instead, these files are generated by the Plasmo framework during the development (plasmo dev) or production build (plasmo build) processes [2][4][5]. Plasmo uses these generated files to provide type-safety, manage import resolution, and handle auto-generated metadata for features like messaging [2][3]. Since they are dynamically created as part of the build tool's execution, they do not exist until the framework runs its internal build/dev scripts [2][4]. If you encounter issues related to these files (such as TypeScript errors or missing definitions), ensure that you have run the development server at least once, as this triggers the generation of the.plasmo directory and its contents [2][4]. You should generally not manually edit files inside the.plasmo directory, as they will be overwritten by the framework [2].

Citations:


Generate Plasmo types before tsc --noEmit. npm ci doesn’t create .plasmo/index.d.ts; Plasmo generates it during plasmo dev/plasmo build, so this script can type-check a clean checkout without those ambient declarations and miss errors they would catch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@chrome-extension/package.json` at line 12, Update the package.json build
script to run Plasmo’s type generation before tsc --noEmit, ensuring
.plasmo/index.d.ts exists during type-checking; use the existing build command
as the target and preserve the subsequent plasmo build step.

"package": "plasmo package"
},
"dependencies": {
Expand Down
19 changes: 12 additions & 7 deletions chrome-extension/src/background/browser-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ interface ToolResult {
error?: string
}

// chrome.scripting.InjectionResult in @types/chrome omits the runtime `error` field that Chrome
// sets when an injection fails; include it locally so the fallback-on-injection-error logic in
// scriptingExecute type-checks (audit H7 — the build was shipping with these tsc errors).
type ScriptingResult = chrome.scripting.InjectionResult<any> & { error?: string }

// Dangerous API patterns — kept in sync with companion/src/security.ts
const DANGEROUS_API_PATTERNS: Array<{ name: string; pattern: RegExp }> = [
// Direct API calls
Expand Down Expand Up @@ -196,23 +201,23 @@ export class BrowserBridge {
await chrome.debugger.sendCommand({ tabId }, "DOM.enable")
} catch { /* ignore */ }

const { root } = await chrome.debugger.sendCommand({ tabId }, "DOM.getDocument", {
const { root } = await this.sendCdp(tabId, "DOM.getDocument", {
depth: -1,
pierce: true,
})
if (!root?.nodeId) throw new Error("Could not retrieve DOM root")

let nodeId = root.nodeId
if (selector) {
const result = await chrome.debugger.sendCommand({ tabId }, "DOM.querySelector", {
const result = await this.sendCdp(tabId, "DOM.querySelector", {
nodeId: root.nodeId,
selector,
})
if (!result.nodeId) throw new Error(`Element not found: ${selector}`)
nodeId = result.nodeId
}

const { outerHTML } = await chrome.debugger.sendCommand({ tabId }, "DOM.getOuterHTML", { nodeId })
const { outerHTML } = await this.sendCdp(tabId, "DOM.getOuterHTML", { nodeId })
return String(outerHTML || "").substring(0, 500000)
}

Expand All @@ -225,7 +230,7 @@ export class BrowserBridge {

// Strategy 1: ISOLATED world
try {
let results: chrome.scripting.InjectionResult<any>[] | undefined
let results: ScriptingResult[] | undefined
if (bodyTextExpr) {
results = await chrome.scripting.executeScript({
target: { tabId }, injectImmediately: true,
Expand All @@ -249,7 +254,7 @@ export class BrowserBridge {

// Strategy 2: MAIN world (subject to page CSP)
try {
let results: chrome.scripting.InjectionResult<any>[] | undefined
let results: ScriptingResult[] | undefined
if (bodyTextExpr) {
results = await chrome.scripting.executeScript({
target: { tabId }, injectImmediately: true, world: "MAIN",
Expand Down Expand Up @@ -892,10 +897,10 @@ export class BrowserBridge {
if (!params.selector || !params.filePath) throw new Error("selector and filePath are required")
await this.ensureAttached(tabId)
try {
const { root } = await chrome.debugger.sendCommand({ tabId }, "DOM.getDocument", {})
const { root } = await this.sendCdp(tabId, "DOM.getDocument", {})
if (!root?.nodeId) throw new Error("Could not retrieve DOM Document root")

const { nodeId } = await chrome.debugger.sendCommand({ tabId }, "DOM.querySelector", {
const { nodeId } = await this.sendCdp(tabId, "DOM.querySelector", {
nodeId: root.nodeId,
selector: params.selector,
})
Expand Down
4 changes: 2 additions & 2 deletions chrome-extension/src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ function saveExtensionConfig(cfg: Record<string, unknown>) {

const next: ExtensionConfig = {
// Skip masked/empty API keys to keep the existing value
api_key: (llm.api_key as string) && !isMaskedApiKey(llm.api_key)
? (llm.api_key as string)
api_key: typeof llm.api_key === "string" && llm.api_key && !isMaskedApiKey(llm.api_key)
? llm.api_key
: (extensionConfig?.api_key || ""),
base_url: String(llm.base_url ?? extensionConfig?.base_url ?? ""),
model_name: String(llm.model_name ?? extensionConfig?.model_name ?? ""),
Expand Down
Loading