Skip to content

ci: launch packaged desktop smoke app#164

Merged
Astro-Han merged 5 commits into
devfrom
codex/fix-packaged-smoke-guard
Apr 23, 2026
Merged

ci: launch packaged desktop smoke app#164
Astro-Han merged 5 commits into
devfrom
codex/fix-packaged-smoke-guard

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • Parameterize the desktop CI smoke runner so it can launch either raw Electron output or a packaged app executable.
  • Add a runtime import guard for built Electron main and preload output to catch @opencode-ai/* imports backed by TypeScript source exports.
  • Run packaged app startup smoke in PR desktop-smoke and macOS release packaging.

Why

The v0.2.6 startup blocker in #159 escaped because CI launched raw out/main/index.js, then only checked packaged bundle structure. It never launched the .app executable that resolves app.asar/node_modules at runtime.

Related Issue

Closes #162.

How To Verify

cd packages/desktop-electron
bun test scripts/ci-smoke.test.ts scripts/runtime-import-guard.test.ts
bun run build
bun ./scripts/runtime-import-guard.ts
npx electron-builder --mac dir --arm64 --publish never --config electron-builder.config.ts --config.mac.identity=- --config.mac.notarize=false
bun ./scripts/ci-smoke.ts packaged dev "dist/mac-arm64/PawWork Dev.app/Contents/MacOS/PawWork Dev"

cd ../opencode
bun test test/github/desktop-smoke-workflow.test.ts test/github/build-workflow.test.ts

cd ../..
bunx prettier --check .github/workflows/build.yml .github/workflows/desktop-smoke.yml packages/desktop-electron/scripts/ci-smoke.test.ts packages/desktop-electron/scripts/ci-smoke.ts packages/desktop-electron/scripts/runtime-import-guard.test.ts packages/desktop-electron/scripts/runtime-import-guard.ts packages/opencode/test/github/build-workflow.test.ts packages/opencode/test/github/desktop-smoke-workflow.test.ts packages/opencode/test/github/workflow-parser.ts
git diff --check origin/dev..HEAD
bun turbo typecheck
bun turbo test:ci

Screenshots or Recordings

Not applicable. CI and release workflow hardening only.

Checklist

  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I listed the relevant verification steps, including tests when behavior changed
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, or generated/local file changes when relevant
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • Tests

    • Expanded macOS smoke tests to cover packaged (signed) app launches, channel-aware arguments, deterministic executable resolution, hard-fail on unknown channel/arch, and stricter readiness/timeouts. Added end-to-end runtime-import guard tests and workflow assertions for step ordering, working directory, and env propagation.
  • Chores

    • CI now runs a runtime-import validation post-build (skipped during finalize) and an additional macOS packaged-app smoke check before upload/after packaging.

@Astro-Han Astro-Han added bug Something isn't working ci Continuous integration / GitHub Actions P1 High priority platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions labels Apr 22, 2026
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 28 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 6 minutes and 28 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9ec81257-5c03-4f86-b761-cdd7957bf5a7

📥 Commits

Reviewing files that changed from the base of the PR and between 7706086 and 7d19f87.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts
📝 Walkthrough

Walkthrough

Adds a Bun-based runtime-import guard that scans built Electron main/preload outputs for runtime imports resolving to TypeScript sources, updates CI to run that guard post-build (skipped for finalize), and adds a macOS-only packaged-app smoke step that deterministically computes the .app/executable path from channel/arch and runs a packaged ci-smoke with a 2-minute timeout.

Changes

Cohort / File(s) Summary
Workflows
​.github/workflows/build.yml, ​.github/workflows/desktop-smoke.yml
Add Check desktop runtime imports (runs bun ./scripts/runtime-import-guard.ts from packages/desktop-electron when inputs.phase != 'finalize'); add macOS-only Smoke signed macOS app step that sets OPENCODE_CHANNEL, computes .app/executable paths from channel and matrix.arch_label, and invokes bun ./scripts/ci-smoke.ts packaged ... with strict failure and a 2-minute timeout.
Runtime import guard (new)
packages/desktop-electron/scripts/runtime-import-guard.ts, packages/desktop-electron/scripts/runtime-import-guard.test.ts
New scanner extracting runtime import/require specifiers from out/main and out/preload, normalizing @opencode-ai/* specifiers to package names, resolving package.json (node_modules or workspace), evaluating exports (conditions/wildcards) to detect .ts/.tsx targets, exporting helper types/functions, and exiting non-zero on unresolved packages; comprehensive tests added.
CI smoke tooling
packages/desktop-electron/scripts/ci-smoke.ts, packages/desktop-electron/scripts/ci-smoke.test.ts
Introduce typed smoke target types (SmokeChannel, SmokeMode, SmokeTarget), add parseSmokeArgs, appIdForSmoke, resolveLaunchCommand; make env/readiness-file resolution channel-aware; support raw vs packaged run modes and packaged-executable existence validation; tests cover parsing, env propagation, launch command, and readiness-file placement.
Workflow tests & parser
packages/opencode/test/github/build-workflow.test.ts, packages/opencode/test/github/desktop-smoke-workflow.test.ts, packages/opencode/test/github/workflow-parser.ts
Extend release/workflow tests to assert new runtime-guard and packaged-smoke steps (including conditional if, run contents, working-directory, OPENCODE_CHANNEL, EXECUTABLE_PATH branching, and ordering around packaging); add optional "working-directory"?: string to WorkflowStep test type.

Sequence Diagram(s)

sequenceDiagram
    participant CI as GitHub Actions
    participant Builder as Electron Builder
    participant Guard as runtime-import-guard
    participant Exports as package.json Exports Resolver
    participant Signer as macOS packager/codesign
    participant Smoke as ci-smoke (packaged)
    participant App as Packaged .app
    participant Ready as ci-smoke-ready.json

    CI->>Builder: build Electron outputs (out/, mac dir)
    Builder-->>Guard: provide built main/preload files
    Guard->>Exports: resolve package.json exports (workspace-aware)
    Exports-->>Guard: mark subpaths resolving to .ts/.tsx
    alt findings present
        Guard->>CI: print findings and exit(1)
    else
        CI->>Signer: package & sign mac .app
        Signer->>Smoke: run ci-smoke (mode=packaged, channel, EXECUTABLE_PATH)
        Smoke->>App: spawn EXECUTABLE_PATH with env (OPENCODE_CHANNEL, isolated HOME)
        App->>Ready: write ci-smoke-ready.json when ready
        Smoke->>Ready: wait-for-ready (timeout 2m)
        alt ready file appears
            Smoke-->>CI: success
        else
            Smoke-->>CI: fail job
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hopped through built files, nose to the logs,
I sniffed out .ts hiding in packaged fogs.
I traced exports with twitchy, careful paws,
I thumped — CI halted startup-hidden flaws.
Hooray — the app boots clean, now nibble the applause.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ci: launch packaged desktop smoke app' is concise and directly relates to the main change: parameterizing CI to launch packaged app executables and adding smoke tests for packaged apps.
Description check ✅ Passed The PR description comprehensively covers all template sections: summary of changes, rationale for the fix, linked issue, detailed verification steps, checklist completion, and acknowledgment of macOS/Windows impacts.
Linked Issues check ✅ Passed The PR fully implements all coding objectives from #162: parameterizes ci-smoke for raw/packaged modes, adds runtime import guard for @opencode-ai/* imports in TypeScript source files, integrates smoke testing into desktop-smoke and build workflows, and closes the verification gap.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue requirements: smoke parameterization, runtime import guard, workflow integration, and supporting test/type updates. No unrelated modifications detected.

✏️ 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 codex/fix-packaged-smoke-guard

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

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request enhances the CI smoke testing infrastructure to support packaged application runs across different release channels and introduces a runtime import guard to prevent Electron bundles from importing TypeScript source from workspace packages. The smoke test script now includes a 'packaged' mode for launching built executables, while the import guard script scans output files for invalid workspace imports. Feedback suggests improving the import guard's regex to handle template literals and making the repository root resolution more robust by avoiding hardcoded path depths.

Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts Outdated
Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
packages/desktop-electron/scripts/ci-smoke.ts (1)

132-159: ⚠️ Potential issue | 🟠 Major

Fail fast on spawn() launch errors.

If the packaged executable path is wrong or loses its execute bit, spawn() fails through the child's error event. This code only watches exitCode/signalCode, so CI waits the full 60 seconds and reports a timeout instead of the actual launch failure.

Suggested fix
-function launchApp(homeDir: string, target: SmokeTarget) {
+function launchApp(homeDir: string, target: SmokeTarget) {
   const launch = resolveLaunchCommand(target)
-  return spawn(launch.command, launch.args, {
+  const child = spawn(launch.command, launch.args, {
     env: buildSmokeEnv(homeDir, target.channel),
     stdio: ["ignore", "pipe", "pipe"],
   })
+  const launchError = once(child, "error").then(([error]) => {
+    throw error
+  })
+  return { child, launchError }
 }
@@
-  const child = launchApp(homeDir, target)
+  const { child, launchError } = launchApp(homeDir, target)
   const logs = watchChildLogs(child)
 
   try {
-    await waitForCiSmokeReady(homeDir, target, child, logs.recent)
+    await Promise.race([waitForCiSmokeReady(homeDir, target, child, logs.recent), launchError])
   } finally {
     logs.close()
     await stopChild(child)
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-electron/scripts/ci-smoke.ts` around lines 132 - 159, The
spawn() child process can emit an "error" event on launch failures which the
current flow ignores, causing a 60s timeout; update launchApp/main to listen for
the child's "error" and fail fast by rejecting/throwing so the caller can stop
the run immediately: when you create the child in launchApp (or immediately
after in main where child is received), attach a once(child, "error") handler
that captures the Error and rejects a promise or throws so main exits the try
and calls stopChild(child); ensure stopChild still safely handles a child that
emitted "error" (it already checks exitCode/signalCode) and propagate the
original error to the top-level so watchChildLogs/waitForCiSmokeReady receive
the real failure instead of a timeout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build.yml:
- Around line 367-392: Add a call to the runtime import guard in the macOS
packaged workflow so release builds also run the static import check: invoke bun
./scripts/runtime-import-guard.ts packaged "$OPENCODE_CHANNEL" (same args as the
smoke script) in the step that currently runs bun ./scripts/ci-smoke.ts packaged
"$OPENCODE_CHANNEL" "$EXECUTABLE_PATH" (i.e., run the runtime-import-guard.ts
before the ci-smoke.ts invocation), ensuring the env OPENCODE_CHANNEL and
working-directory packages/desktop-electron are used.

In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 53-67: The exportEntryForSubpath function misses the case where
json.exports is a condition map representing the package root (e.g. { import:
"./src/index.ts" }) because it only checks for an explicit "." key; update
exportEntryForSubpath to treat the whole exports object as the "." entry when
subpath === "." and entries contains no dot-prefixed keys (i.e. no keys starting
with ".") — return entries in that case; ensure
packageExportsTypeScriptSourceForSpecifier continues to call
exportEntryForSubpath (no other changes needed) and add a regression test for a
bare import with exports: { import: "./src/index.ts" } to verify the
root-conditional behavior.

---

Outside diff comments:
In `@packages/desktop-electron/scripts/ci-smoke.ts`:
- Around line 132-159: The spawn() child process can emit an "error" event on
launch failures which the current flow ignores, causing a 60s timeout; update
launchApp/main to listen for the child's "error" and fail fast by
rejecting/throwing so the caller can stop the run immediately: when you create
the child in launchApp (or immediately after in main where child is received),
attach a once(child, "error") handler that captures the Error and rejects a
promise or throws so main exits the try and calls stopChild(child); ensure
stopChild still safely handles a child that emitted "error" (it already checks
exitCode/signalCode) and propagate the original error to the top-level so
watchChildLogs/waitForCiSmokeReady receive the real failure instead of a
timeout.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: ae2b524d-5872-4ebd-b51c-c1bbde296780

📥 Commits

Reviewing files that changed from the base of the PR and between 52e46ad and e99bb47.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

Comment thread .github/workflows/build.yml
Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts Outdated
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from e99bb47 to 4c8d8d2 Compare April 22, 2026 19:49
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@packages/desktop-electron/scripts/ci-smoke.ts`:
- Around line 45-47: When parsing argv in ci-smoke.ts, validate that the
provided executablePath actually exists before returning; after retrieving
executablePath (the variable used in the return and the "Packaged smoke requires
an executable path" check), use a filesystem check (e.g., fs.existsSync or
fs.promises.access) and, if missing, throw a new Error that includes the missing
path and a clear message so callers get an actionable error early instead of a
generic spawn failure; keep the check colocated with the existing
executablePath/parseChannel logic.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 48e2858e-7958-4e1b-8e79-b946ce384750

📥 Commits

Reviewing files that changed from the base of the PR and between e99bb47 and 4c8d8d2.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

Comment thread packages/desktop-electron/scripts/ci-smoke.ts
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from 4c8d8d2 to cc49ca2 Compare April 22, 2026 20:55
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/desktop-electron/scripts/runtime-import-guard.ts (1)

58-61: 🧹 Nitpick | 🔵 Trivial

Consider the ReDoS risk from package.json exports keys.

The regex is constructed from exports keys after escaping. While escapeRegExp neutralizes regex metacharacters, a malicious or malformed package.json with an extremely long exports key containing many escaped sequences could still cause slow matching due to the (.+) capture group with backtracking.

In practice, this is low risk since:

  1. The input comes from workspace package.json files under developer control.
  2. Exports keys are typically short (e.g., ./*, ./utils/*).

If you want to harden this, consider adding a length check on the key before regex construction.

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

In `@packages/desktop-electron/scripts/runtime-import-guard.ts` around lines 58 -
61, The loop over Object.entries(entries) that builds a RegExp from wildcard
keys (using escapeRegExp and replacing "\*" with "(.+)") can be vulnerable to
pathological backtracking; mitigate by adding a guard on the key length before
constructing the regex: in the for-loop that iterates over entries (variables:
entries, key, value) skip keys that exceed a reasonable max length (e.g., 200
characters) or otherwise validate the key format, so you only call escapeRegExp
and create pattern for keys that pass the length/format check (pattern and
subpath usage remains unchanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/github/desktop-smoke-workflow.test.ts`:
- Around line 74-76: Ensure the "Build desktop app" step is explicitly asserted
to exist before comparing order: locate where smokeSteps and runtimeGuardStep
are used (the existing expectation comparing
smokeSteps.indexOf(runtimeGuardStep!) to
smokeSteps.indexOf(smokeSteps.find((step) => step.name === "Build desktop
app")!)), assign the result of smokeSteps.find((step) => step.name === "Build
desktop app") to a variable (e.g., buildStep), add an explicit
expect(buildStep).toBeDefined() assertion, then use
smokeSteps.indexOf(buildStep) in the existing order comparison to avoid relying
on indexOf(undefined).

---

Duplicate comments:
In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 58-61: The loop over Object.entries(entries) that builds a RegExp
from wildcard keys (using escapeRegExp and replacing "\*" with "(.+)") can be
vulnerable to pathological backtracking; mitigate by adding a guard on the key
length before constructing the regex: in the for-loop that iterates over entries
(variables: entries, key, value) skip keys that exceed a reasonable max length
(e.g., 200 characters) or otherwise validate the key format, so you only call
escapeRegExp and create pattern for keys that pass the length/format check
(pattern and subpath usage remains unchanged).
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: c594b0aa-6d99-41f2-9e81-ac04f0728cb7

📥 Commits

Reviewing files that changed from the base of the PR and between 4c8d8d2 and cc49ca2.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

Comment thread packages/opencode/test/github/desktop-smoke-workflow.test.ts Outdated
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from cc49ca2 to acdd076 Compare April 22, 2026 21:52
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/desktop-electron/scripts/ci-smoke.ts (1)

153-165: 🧹 Nitpick | 🔵 Trivial

Control flow is correct with proper cleanup.

The finally block ensures log watchers are closed and the child process is stopped even on failure. The temp directory created at line 155 is not cleaned up, which is acceptable for ephemeral CI runners but could accumulate in local development runs.

♻️ Optional: Add temp directory cleanup
+import { existsSync, mkdtempSync, rmSync } from "node:fs"
 
 async function main() {
   const target = parseSmokeArgs(Bun.argv.slice(2))
   const homeDir = mkdtempSync(join(tmpdir(), "pawwork-ci-smoke-"))
   const child = launchApp(homeDir, target)
   const logs = watchChildLogs(child)

   try {
     await waitForCiSmokeReady(homeDir, target, child, logs.recent)
   } finally {
     logs.close()
     await stopChild(child)
+    rmSync(homeDir, { recursive: true, force: true })
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-electron/scripts/ci-smoke.ts` around lines 153 - 165, The
temp directory created by mkdtempSync(homeDir) inside main is never removed;
update the finally block in main to delete homeDir after logs.close() and
stopChild(child) (or before stopping child if preferred) using a safe removal
call (e.g., fs.rmSync(homeDir, { recursive: true, force: true }) or await
fs.promises.rm(homeDir, { recursive: true, force: true })), and wrap that
removal in its own try/catch so any failure to remove the temp dir does not mask
the original error.
♻️ Duplicate comments (1)
packages/opencode/test/github/build-workflow.test.ts (1)

174-176: ⚠️ Potential issue | 🟠 Major

Add an explicit existence assertion for “Package signed app” before index ordering.

At Line 175, indexOf(steps.find(...)!) can degrade to indexOf(undefined) === -1 and let the ordering check pass when the package step is absent.

Proposed fix
+      const packageSignedAppStep = steps.find((step) => step.name === "Package signed app")
+      expect(packageSignedAppStep).toBeDefined()
       expect(steps.indexOf(smokeSignedAppStep!)).toBeGreaterThan(
-        steps.indexOf(steps.find((step) => step.name === "Package signed app")!),
+        steps.indexOf(packageSignedAppStep!),
       )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/github/build-workflow.test.ts` around lines 174 - 176,
Find the step with name "Package signed app" (the current inline find used
inside indexOf) and add an explicit assertion that it exists before performing
the ordering check against smokeSignedAppStep; for example, store the result of
steps.find((step) => step.name === "Package signed app") in a variable (e.g.,
packageSignedAppStep), assert that packageSignedAppStep is defined/not
undefined, then use steps.indexOf(packageSignedAppStep) in the existing expect
comparing index positions with smokeSignedAppStep to avoid false positives when
the package step is absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/desktop-electron/scripts/ci-smoke.ts`:
- Around line 153-165: The temp directory created by mkdtempSync(homeDir) inside
main is never removed; update the finally block in main to delete homeDir after
logs.close() and stopChild(child) (or before stopping child if preferred) using
a safe removal call (e.g., fs.rmSync(homeDir, { recursive: true, force: true })
or await fs.promises.rm(homeDir, { recursive: true, force: true })), and wrap
that removal in its own try/catch so any failure to remove the temp dir does not
mask the original error.

---

Duplicate comments:
In `@packages/opencode/test/github/build-workflow.test.ts`:
- Around line 174-176: Find the step with name "Package signed app" (the current
inline find used inside indexOf) and add an explicit assertion that it exists
before performing the ordering check against smokeSignedAppStep; for example,
store the result of steps.find((step) => step.name === "Package signed app") in
a variable (e.g., packageSignedAppStep), assert that packageSignedAppStep is
defined/not undefined, then use steps.indexOf(packageSignedAppStep) in the
existing expect comparing index positions with smokeSignedAppStep to avoid false
positives when the package step is absent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 06a5dabf-ff42-474c-8e1b-1793b6904d06

📥 Commits

Reviewing files that changed from the base of the PR and between cc49ca2 and acdd076.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/opencode/test/github/build-workflow.test.ts (1)

174-176: ⚠️ Potential issue | 🟡 Minor

Assert that Package signed app exists before comparing step order.

If that step is renamed or removed, steps.find(...) becomes undefined, indexOf(undefined) is -1, and this ordering assertion can still pass.

Suggested fix
+      const packageSignedAppStep = steps.find((step) => step.name === "Package signed app")
+      expect(packageSignedAppStep).toBeDefined()
       expect(steps.indexOf(smokeSignedAppStep!)).toBeGreaterThan(
-        steps.indexOf(steps.find((step) => step.name === "Package signed app")!),
+        steps.indexOf(packageSignedAppStep!),
       )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/github/build-workflow.test.ts` around lines 174 - 176,
The ordering assertion risks passing when the "Package signed app" step is
missing because steps.find(...) can be undefined; fix by first locating and
asserting the presence of that step (e.g., assign const packageSignedAppStep =
steps.find(step => step.name === "Package signed app") and
expect(packageSignedAppStep).toBeDefined()) and then use packageSignedAppStep
when comparing indices with smokeSignedAppStep so indexOf is never called with
undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 170-176: The loop building packageJsonByName silently skips
packages whose readPackageJson(root, packageName) returns undefined, letting
findTsSourceRuntimeImports treat those runtime deps as safe; instead detect
missing packages by collecting packageNames where readPackageJson returned
undefined and fail closed by throwing an Error (or returning a failure) that
lists the unresolved package(s) before calling findTsSourceRuntimeImports—update
the code around packageJsonByName, packageNames, and readPackageJson to perform
this check and error out so unresolved `@opencode-ai/`* packages cannot be
ignored.
- Around line 23-29: extractRuntimeImports currently returns only specifiers and
loses whether a match was an import() or require(), causing incorrect flags for
conditional exports; modify extractRuntimeImports to return objects like {
specifier: string, kind: 'import'|'require' } by updating the regex capture
logic in extractRuntimeImports to record which capture group matched (import vs
require), then update the caller that currently invokes
packageExportsTypeScriptSourceForSpecifier(...) so it passes the kind as an
additional argument (e.g., packageExportsTypeScriptSourceForSpecifier(specifier,
kind)) and adjust that function to use the kind for branch-aware resolution of
conditional exports.

---

Duplicate comments:
In `@packages/opencode/test/github/build-workflow.test.ts`:
- Around line 174-176: The ordering assertion risks passing when the "Package
signed app" step is missing because steps.find(...) can be undefined; fix by
first locating and asserting the presence of that step (e.g., assign const
packageSignedAppStep = steps.find(step => step.name === "Package signed app")
and expect(packageSignedAppStep).toBeDefined()) and then use
packageSignedAppStep when comparing indices with smokeSignedAppStep so indexOf
is never called with undefined.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: aa56b867-710a-4c2c-81bb-36ef4f944f2c

📥 Commits

Reviewing files that changed from the base of the PR and between 0e39c3e and acdd076.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts
Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from acdd076 to 950685a Compare April 23, 2026 01:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@packages/opencode/test/github/build-workflow.test.ts`:
- Around line 174-176: The test currently inlines steps.find((step) => step.name
=== "Package signed app") inside steps.indexOf(...), which can return undefined
and let the order assertion pass; first assign that found step to a variable
(e.g., packageSignedAppStep = steps.find((step) => step.name === "Package signed
app")), assert its existence with an explicit expectation (e.g.,
expect(packageSignedAppStep).toBeDefined() or not.toBeUndefined()), and then use
packageSignedAppStep in the subsequent steps.indexOf(...) comparison against
smokeSignedAppStep to ensure the index comparison is valid.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 46ca5657-2f97-4766-a529-08765081bf09

📥 Commits

Reviewing files that changed from the base of the PR and between acdd076 and 950685a.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts

Comment thread packages/opencode/test/github/build-workflow.test.ts Outdated
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from 950685a to 7706086 Compare April 23, 2026 02:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/opencode/test/github/build-workflow.test.ts (1)

174-176: ⚠️ Potential issue | 🟡 Minor

Assert the packaging step exists before comparing indices.

Line 175 still inlines steps.find(...) inside indexOf(...). If "Package signed app" disappears, indexOf(undefined) becomes -1, and this order check can pass for the wrong reason.

Suggested fix
       const validateSelectedTargetStep = steps.find((step) => step.name === "Validate selected target")
       const smokeSignedAppStep = steps.find((step) => step.name === "Smoke signed macOS app")
+      const packageSignedAppStep = steps.find((step) => step.name === "Package signed app")
@@
+      expect(packageSignedAppStep).toBeDefined()
       expect(steps.indexOf(smokeSignedAppStep!)).toBeGreaterThan(
-        steps.indexOf(steps.find((step) => step.name === "Package signed app")!),
+        steps.indexOf(packageSignedAppStep!),
       )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/github/build-workflow.test.ts` around lines 174 - 176,
Assign the result of steps.find((step) => step.name === "Package signed app") to
a local variable (e.g., packageStep), assert it exists (e.g.,
expect(packageStep).toBeDefined() or throw if null) before doing the index
comparison, then use steps.indexOf(packageStep) when comparing against
smokeSignedAppStep; this prevents indexOf(undefined) returning -1 and the order
assertion passing incorrectly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-electron/scripts/ci-smoke.ts`:
- Around line 133-139: The spawn() child process returned by launchApp (which
uses resolveLaunchCommand and buildSmokeEnv) needs an 'error' listener to catch
execution failures (permission denied, bad binary, etc.) so the process doesn't
crash unhandled; update launchApp to attach proc.on('error', ...) that forwards
a clear error into your existing CI-smoke failure flow (e.g., log via the same
logger and reject/emit a failure that waitForCiSmokeReady() can observe) so
launch failures produce a contextual error instead of an unhandled exception.

In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 27-37: The RUNTIME_IMPORT_RE in runtime-import-guard.ts and the
extractRuntimeImports function miss ESM re-export forms like `export * from "x"`
and `export {a} from "x"`, so update RUNTIME_IMPORT_RE to also match
`export\s+(?:\*\s+from|{[^}]*}\s+from)\s*["']([^"']+)["']` and ensure
extractRuntimeImports still extracts the specifier and sets an appropriate kind
(e.g., treat these as "import"/"export" so they are flagged), then add unit
tests covering both `export * from "@pkg"` and `export { a } from "@pkg"` to
validate detection.

---

Duplicate comments:
In `@packages/opencode/test/github/build-workflow.test.ts`:
- Around line 174-176: Assign the result of steps.find((step) => step.name ===
"Package signed app") to a local variable (e.g., packageStep), assert it exists
(e.g., expect(packageStep).toBeDefined() or throw if null) before doing the
index comparison, then use steps.indexOf(packageStep) when comparing against
smokeSignedAppStep; this prevents indexOf(undefined) returning -1 and the order
assertion passing incorrectly.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: cc08513b-c1bd-45a9-975b-eee5e28e576d

📥 Commits

Reviewing files that changed from the base of the PR and between acdd076 and 950685a.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
packages/opencode/**/*.ts

📄 CodeRabbit inference engine (packages/opencode/AGENTS.md)

packages/opencode/**/*.ts: Use Effect.gen(function* () { ... }) for Effect composition
Use Effect.fn("Domain.method") for named/traced effects and Effect.fnUntraced for internal helpers; these accept pipeable operators as extra arguments to avoid unnecessary outer .pipe() wrappers
Use Effect.callback for callback-based APIs
Prefer DateTime.nowAsDate over new Date(yield* Clock.currentTimeMillis) when you need a Date in Effect code
Use Schema.Class for multi-field data in Effect schemas
Use branded schemas (Schema.brand) for single-value types in Effect
Use Schema.TaggedErrorClass for typed errors in Effect schemas
Use Schema.Defect instead of unknown for defect-like causes in Effect code
In Effect.gen / Effect.fn, prefer yield* new MyError(...) over yield* Effect.fail(new MyError(...)) for direct early-failure branches
Use makeRuntime from src/effect/run-service.ts for all services; it returns { runPromise, runFork, runCallback } backed by a shared memoMap that deduplicates layers
Use InstanceState from src/effect/instance-state.ts for per-directory or per-project state that needs per-instance cleanup; do work directly in the InstanceState.make closure where ScopedCache handles run-once semantics
Use Effect.addFinalizer or Effect.acquireRelease inside the InstanceState.make closure for cleanup (subscriptions, process teardown, etc.)
Use Effect.forkScoped inside the InstanceState.make closure for background stream consumers — the fiber is interrupted when the instance is disposed
Prefer FileSystem.FileSystem instead of raw fs/promises for effectful file I/O in Effect services
Prefer ChildProcessSpawner.ChildProcessSpawner with ChildProcess.make(...) instead of custom process wrappers in Effect services
Prefer HttpClient.HttpClient instead of raw fetch in Effect services
Prefer Path.Path, Config, Clock, and DateTime services when those concerns are already inside Effect code
For backgroun...

Files:

  • packages/opencode/test/github/workflow-parser.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
packages/opencode/test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (packages/opencode/test/AGENTS.md)

packages/opencode/test/**/*.test.{ts,tsx}: Use the tmpdir function from fixture/fixture.ts to create temporary directories for tests with automatic cleanup. Use await using syntax to ensure automatic cleanup when the variable goes out of scope.
When using the tmpdir function with git repository support, pass the git: true option to initialize a git repo with a root commit.
Use the config option in tmpdir to write an opencode.json config file during test setup by passing a partial Config.Info object.
Use the init option in tmpdir to define custom setup functions that can return extra data accessible via tmp.extra, and use the dispose option for custom cleanup logic.
Use testEffect(...) from test/lib/effect.ts for tests that exercise Effect services or Effect-based workflows.
Use it.effect(...) when the test should run with TestClock and TestConsole. Use it.live(...) when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
Prefer Effect-aware helpers from fixture/fixture.ts over building manual runtimes in tests: use tmpdirScoped() for scoped temp directories, provideInstance(dir)(effect) for low-level binding without directory creation, provideTmpdirInstance(...) for single temp instance binding, or provideTmpdirServer(...) for tests that also need the test LLM server.
Define const it = testEffect(...) near the top of the test file and keep the test body inside Effect.gen(function* () { ... }). Yield services directly with yield* MyService.Service or yield* MyTool.
Avoid custom ManagedRuntime, attach(...), or ad hoc run(...) wrappers in Effect tests when testEffect(...) already provides the runtime.
When a test needs instance-local state, prefer provideTmpdirInstance(...) or provideInstance(...) over manual Instance.provide(...) inside Promise-style tests.

Files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
🧠 Learnings (40)
📓 Common learnings
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers in Effect tests when `testEffect(...)` already provides the runtime.
📚 Learning: 2026-04-22T08:49:44.563Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/desktop-electron/src/main/index-sidecar-source.test.ts:3-11
Timestamp: 2026-04-22T08:49:44.563Z
Learning: In `packages/desktop-electron/src/main/index-sidecar-source.test.ts` (Astro-Han/pawwork), the test intentionally uses `expect(source).toContain` / `expect(source).not.toContain` string matching against the raw `index.ts` source text as a lightweight sidecar contract guard. The maintainer has explicitly chosen not to introduce an AST parser (e.g., `babel/parser` or acorn) for this purpose. Do not flag these string-based assertions as fragile or suggest converting them to AST-based matching.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use `testEffect(...)` from `test/lib/effect.ts` for tests that exercise Effect services or Effect-based workflows.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : When validating routing, assert against canonical or resolved workspace slugs using shared helpers from `../actions` to account for Windows canonicalization

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use `it.effect(...)` when the test should run with `TestClock` and `TestConsole`. Use `it.live(...)` when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Prefer Effect-aware helpers from `fixture/fixture.ts` over building manual runtimes in tests: use `tmpdirScoped()` for scoped temp directories, `provideInstance(dir)(effect)` for low-level binding without directory creation, `provideTmpdirInstance(...)` for single temp instance binding, or `provideTmpdirServer(...)` for tests that also need the test LLM server.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `tmpdir` function from `fixture/fixture.ts` to create temporary directories for tests with automatic cleanup. Use `await using` syntax to ensure automatic cleanup when the variable goes out of scope.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : When using the `tmpdir` function with git repository support, pass the `git: true` option to initialize a git repo with a root commit.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Define `const it = testEffect(...)` near the top of the test file and keep the test body inside `Effect.gen(function* () { ... })`. Yield services directly with `yield* MyService.Service` or `yield* MyTool`.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Import test utilities from `../fixtures` instead of `playwright/test`

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : In terminal tests, type through the browser using `runTerminal()` and `waitTerminalReady()` instead of writing to the PTY through the SDK

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-22T09:32:52.806Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/opencode/test/provider/provider.test.ts:64-85
Timestamp: 2026-04-22T09:32:52.806Z
Learning: In `packages/opencode/test/provider/provider.test.ts`, the file intentionally uses AppRuntime-based async helpers (`run`, `list`, `getProvider`, etc.) rather than `testEffect(...)` for all tests. Converting individual tests to `testEffect` while leaving the rest on the async pattern would create internal inconsistency. A full harness migration of this file is the right approach if the pattern needs to change, but that should be a separate PR.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:21:51.047Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 71
File: packages/app/src/components/session/session-status-connections.tsx:146-147
Timestamp: 2026-04-20T14:21:51.047Z
Learning: In the Astro-Han/pawwork repository (SolidJS app), `sync.data.config` is always initialized to `{}` at `packages/app/src/context/global-sync.tsx` line 71 and is never `undefined` at runtime. Non-optional property access like `sync.data.config.plugin` is intentional and consistent with the pattern used in `packages/app/src/components/status-popover-body.tsx` line 243. Do not flag `sync.data.config.plugin` as needing optional chaining.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T12:14:29.062Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 93
File: packages/opencode/test/server/cors-middleware.test.ts:15-23
Timestamp: 2026-04-21T12:14:29.062Z
Learning: In `packages/opencode/test/server/cors-middleware.test.ts` (and similar Hono-based test files), `app.request(...)` on the Hono `Hono` app type returns `Promise<Response> | Response` — a union that includes a non-PromiseLike branch. `Effect.promise(...)` requires a `PromiseLike`, so wrapping with `Promise.resolve(app.request(...))` is necessary to normalize the union type. Removing the wrapper causes a TS2322 typecheck error in `packages/opencode`.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use `expect.poll(...)` for probing mock or backend state rather than transient DOM visibility

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers in Effect tests when `testEffect(...)` already provides the runtime.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use locator assertions like `toBeVisible()`, `toHaveCount(0)`, and `toHaveAttribute(...)` for normal UI state verification

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise in tests

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use lowercase, descriptive test names (e.g., 'sidebar can be toggled')

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Test one feature per test file

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : When a test needs instance-local state, prefer `provideTmpdirInstance(...)` or `provideInstance(...)` over manual `Instance.provide(...)` inside Promise-style tests.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use camelCase for variable names in tests

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/packages/app/src/testing/**/*.ts : Test-only hooks must be inert unless explicitly enabled and should not add normal-runtime listeners, reactive subscriptions, or per-update allocations

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `init` option in `tmpdir` to define custom setup functions that can return extra data accessible via `tmp.extra`, and use the `dispose` option for custom cleanup logic.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use SCREAMING_SNAKE_CASE for constants in tests

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `config` option in `tmpdir` to write an `opencode.json` config file during test setup by passing a partial Config.Info object.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Prefer `ChildProcessSpawner.ChildProcessSpawner` with `ChildProcess.make(...)` instead of custom process wrappers in Effect services

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-20T17:03:37.710Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 73
File: packages/opencode/src/cli/cmd/tui/context/sync.tsx:486-489
Timestamp: 2026-04-20T17:03:37.710Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/cli/cmd/tui/context/sync.tsx`), `sync.ready` returning `true` when `process.env.OPENCODE_FAST_BOOT` is set is intentional. The plugin-facing data properties `state.config` (initialized to `{}`) and `state.provider` (initialized to `[]`) expose safe-empty defaults, so they are safe to access before bootstrap completes. Do not flag these as needing null-guards or conditional patterns to match `vcs` — the difference is intentional because `vcs` starts as `undefined` while the others have initialized defaults. Changing this would alter the plugin API contract without a concrete failing case.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:08.745Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/desktop-electron/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:08.745Z
Learning: Applies to packages/desktop-electron/src/**/*.{ts,tsx,js,jsx} : Renderer process should only call `window.api` from `src/preload`

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:08.745Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/desktop-electron/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:08.745Z
Learning: Applies to packages/desktop-electron/src/main/ipc.ts : Main process should register IPC handlers in `src/main/ipc.ts`

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T16:57:22.813Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 102
File: packages/opencode/src/config/agent.ts:108-119
Timestamp: 2026-04-21T16:57:22.813Z
Learning: In `packages/opencode/src/config/agent.ts` (Astro-Han/pawwork), `ConfigPermission.Info` only accepts permission objects or the three action strings `"ask"`, `"allow"`, `"deny"`, and transforms those action strings into `{ "*": action }` before `normalize()` runs. By the time `normalize()` is reached, `configuredPermission` is always either `undefined` or a `Record<string, Rule>` — never a raw arbitrary string. The `Object.assign(permission, configuredPermission)` pattern is therefore safe. Do not flag it as corrupting string permission references.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-22T09:32:52.535Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/ui/src/theme/context.tsx:11-16
Timestamp: 2026-04-22T09:32:52.535Z
Learning: In Astro-Han/pawwork (`packages/ui/src/theme/context.tsx` and related files), the renaming of localStorage theme keys from `opencode-*` to `pawwork-*` (THEME_ID, COLOR_SCHEME, THEME_CSS_LIGHT, THEME_CSS_DARK) is intentional and should NOT include a migration path from the old keys. Migrating would re-couple PawWork and OpenCode browser storage namespaces, which the PR is explicitly designed to avoid. A reset to the PawWork default theme on upgrade is acceptable by design.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T16:57:20.257Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 102
File: packages/opencode/src/config/command.ts:23-29
Timestamp: 2026-04-21T16:57:20.257Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/config/`), `Schema.Struct` and `Schema.Class` are both valid and intentionally used patterns across config modules (e.g. `formatter.ts`, `provider.ts`, `permission.ts`, `lsp.ts`, `config.ts`, `keybinds.ts`, `command.ts`). Do not flag `Schema.Struct` usage in config schemas as needing conversion to `Schema.Class` — the choice is driven by upstream alignment and local context, not inconsistency.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T13:45:41.773Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 99
File: packages/desktop-electron/src/renderer/i18n/index.ts:30-35
Timestamp: 2026-04-21T13:45:41.773Z
Learning: In Astro-Han/pawwork, the locale normalization helpers in `packages/app/src/context/language.tsx` (`normalizeLocale`) and `packages/desktop-electron/src/renderer/i18n/index.ts` (`parseLocale`) are intentionally kept separate and have different fallback shapes: `normalizeLocale` always returns a concrete `Locale` (falling back to `"en"`), while `parseLocale` returns `Locale | null` so the desktop shell can decide whether to fall back to browser detection. Do not suggest extracting a shared normalization helper across these two runtimes.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-22T05:24:42.404Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 98
File: packages/desktop-electron/src/main/menu-labels.ts:1-2
Timestamp: 2026-04-22T05:24:42.404Z
Learning: In Astro-Han/pawwork, the app i18n layer (`packages/app/src/i18n/`) only contains `en.ts` and `zh.ts`, and `normalizeLocale` (in `packages/app/src/context/language.tsx`) only returns `"en"` or `"zh"`. The desktop `MenuLocale = "en" | "zh"` union in `packages/desktop-electron/src/main/menu-labels.ts` is intentionally limited to these two locales and is not a broader restriction — do not flag it as overly restrictive or suggest adding other locales.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `Schema.Defect` instead of `unknown` for defect-like causes in Effect code

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : In `Effect.gen` / `Effect.fn`, prefer `yield* new MyError(...)` over `yield* Effect.fail(new MyError(...))` for direct early-failure branches

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Prefer `FileSystem.FileSystem` instead of raw `fs/promises` for effectful file I/O in Effect services

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `Effect.addFinalizer` or `Effect.acquireRelease` inside the `InstanceState.make` closure for cleanup (subscriptions, process teardown, etc.)

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `makeRuntime` from `src/effect/run-service.ts` for all services; it returns `{ runPromise, runFork, runCallback }` backed by a shared `memoMap` that deduplicates layers

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
🪛 ast-grep (0.42.1)
packages/desktop-electron/scripts/runtime-import-guard.ts

[warning] 83-83: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escapeRegExp(key).replace("\\*", "(.+)")}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🔇 Additional comments (1)
packages/desktop-electron/scripts/runtime-import-guard.ts (1)

202-215: Fail-closed handling for unresolved package manifests looks good.

Throwing before the scan when an @opencode-ai/* package cannot be resolved closes the earlier blind spot cleanly.

Comment thread packages/desktop-electron/scripts/ci-smoke.ts Outdated
Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/desktop-electron/scripts/ci-smoke.ts (1)

109-130: ⚠️ Potential issue | 🟡 Minor

Propagate spawn() launch failures into the smoke failure path.

If the packaged path exists but cannot be executed, spawn() emits error instead of ever setting exitCode. Right now that event is unhandled, so the Bun process can die before waitForCiSmokeReady() reports the usual contextual smoke failure.

Suggested fix
+type LaunchResult = {
+  child: ChildProcessWithoutNullStreams
+  launchError: { current: Error | undefined }
+}
+
 async function waitForCiSmokeReady(
   homeDir: string,
   target: SmokeTarget,
   child: ChildProcessWithoutNullStreams,
+  launchError: { current: Error | undefined },
   recent: string[],
 ) {
   const readyFile = resolveCiSmokeReadyFile(homeDir, { channel: target.channel, mode: target.mode })
   const timeoutAt = Date.now() + 60_000

   while (Date.now() < timeoutAt) {
+    if (launchError.current) {
+      throw new Error(`Failed to launch desktop app: ${launchError.current.message}`)
+    }
     if (existsSync(readyFile)) return

     if (child.exitCode !== null || child.signalCode !== null) {
       const tail = recent.length ? `\nRecent app output:\n${recent.join("\n")}` : ""
       throw new Error(`Electron exited before reporting CI smoke readiness${tail}`)
@@
-function launchApp(homeDir: string, target: SmokeTarget) {
+function launchApp(homeDir: string, target: SmokeTarget): LaunchResult {
   const launch = resolveLaunchCommand(target)
-  return spawn(launch.command, launch.args, {
+  const child = spawn(launch.command, launch.args, {
     env: buildSmokeEnv(homeDir, target.channel),
     stdio: ["ignore", "pipe", "pipe"],
   })
+  const launchError = { current: undefined as Error | undefined }
+  child.on("error", (error) => {
+    launchError.current = error
+  })
+  return { child, launchError }
 }
@@
-  const child = launchApp(homeDir, target)
+  const { child, launchError } = launchApp(homeDir, target)
   const logs = watchChildLogs(child)

   try {
-    await waitForCiSmokeReady(homeDir, target, child, logs.recent)
+    await waitForCiSmokeReady(homeDir, target, child, launchError, logs.recent)
   } finally {

Also applies to: 133-160

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

In `@packages/desktop-electron/scripts/ci-smoke.ts` around lines 109 - 130, The
child process 'error' event from spawn() is unhandled, so execution failures
(e.g., cannot execute packaged binary) never surface through
waitForCiSmokeReady; add an 'error' handler where you call spawn() that captures
the Error, appends a descriptive message + error.stack to the recent string
array, and sets a visible failure flag (e.g., set a local boolean spawnError or
assign to a new property on the child like child.spawnError = true) so
waitForCiSmokeReady can detect it the same way it checks
child.exitCode/child.signalCode and immediately throw a contextual error; apply
the same change for the second spawn site mentioned (the other block at lines
133-160).
packages/desktop-electron/scripts/runtime-import-guard.ts (1)

27-36: ⚠️ Potential issue | 🟠 Major

Re-exported modules still bypass the guard.

export * from "@opencode-ai/..." and export { ... } from "@opencode-ai/..." resolve the target at module load, but RUNTIME_IMPORT_RE still ignores those forms. That leaves a false-negative path where packaged startup can fail even though this guard passes. Add the re-export forms here and cover them in the Bun regression tests.

#!/bin/bash
python3 <<'PY'
import re

pattern = re.compile(
    r"""\bimport\s+(?!type\b)(?:[^'"`]*?\s+from\s*)?["']([^"']+)["']|\bimport\s*\(\s*(?:["']([^"']+)["']|`([^`$]*)`)\s*\)|\brequire\s*\(\s*["']([^"']+)["']\s*\)"""
)

cases = [
    'export * from "@opencode-ai/foo"',
    'export { foo } from "@opencode-ai/bar"',
    'import "@opencode-ai/baz"',
    'require("@opencode-ai/qux")',
]

for case in cases:
    match = pattern.search(case)
    print(f"{case:<45} -> {'matched' if match else 'missed'}")
PY
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-electron/scripts/runtime-import-guard.ts` around lines 27 -
36, The regex RUNTIME_IMPORT_RE used by extractRuntimeImports currently misses
re-export forms like "export * from '...'" and "export { x } from '...'", so
update RUNTIME_IMPORT_RE to include patterns that capture export-from specifiers
(e.g. match \bexport\s+(?:\*\s+from|\{[^}]*\}\s+from)\s*["']([^"']+)["'] or a
unified alternative) and adjust extractRuntimeImports to treat those matches
(set specifier from the new capture group and set kind to "export" or reuse
"import"/"require" as appropriate); add Bun regression tests covering
export-from and export-named-from cases to ensure the guard flags re-exports the
same way as import/require.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 77-87: The exportEntryForSubpath function currently returns the
first wildcard match but must pick the most specific (longest) matching key per
Node.js rules; update the wildcard loop in exportEntryForSubpath to test all
wildcard keys and track the best match by longest key (e.g., keep bestKey and
bestValue, compare key.length) using the same RegExp construction
(escapeRegExp(...).replace("\\*", "(.+)")), then after the loop return the value
for the longest matching key (or undefined if none); ensure exact-match branch
(Object.hasOwn) remains unchanged and that you still return entries when subpath
=== "." as currently implemented.

---

Duplicate comments:
In `@packages/desktop-electron/scripts/ci-smoke.ts`:
- Around line 109-130: The child process 'error' event from spawn() is
unhandled, so execution failures (e.g., cannot execute packaged binary) never
surface through waitForCiSmokeReady; add an 'error' handler where you call
spawn() that captures the Error, appends a descriptive message + error.stack to
the recent string array, and sets a visible failure flag (e.g., set a local
boolean spawnError or assign to a new property on the child like
child.spawnError = true) so waitForCiSmokeReady can detect it the same way it
checks child.exitCode/child.signalCode and immediately throw a contextual error;
apply the same change for the second spawn site mentioned (the other block at
lines 133-160).

In `@packages/desktop-electron/scripts/runtime-import-guard.ts`:
- Around line 27-36: The regex RUNTIME_IMPORT_RE used by extractRuntimeImports
currently misses re-export forms like "export * from '...'" and "export { x }
from '...'", so update RUNTIME_IMPORT_RE to include patterns that capture
export-from specifiers (e.g. match
\bexport\s+(?:\*\s+from|\{[^}]*\}\s+from)\s*["']([^"']+)["'] or a unified
alternative) and adjust extractRuntimeImports to treat those matches (set
specifier from the new capture group and set kind to "export" or reuse
"import"/"require" as appropriate); add Bun regression tests covering
export-from and export-named-from cases to ensure the guard flags re-exports the
same way as import/require.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 1c5560f4-e0ee-4eb3-85c8-d160d5fa8237

📥 Commits

Reviewing files that changed from the base of the PR and between 950685a and 7706086.

📒 Files selected for processing (9)
  • .github/workflows/build.yml
  • .github/workflows/desktop-smoke.yml
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/opencode/test/github/workflow-parser.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: unit-windows-opencode-config-project
  • GitHub Check: unit-windows-opencode-server-tools
  • GitHub Check: unit-windows-desktop
  • GitHub Check: unit-windows-opencode-session
🧰 Additional context used
📓 Path-based instructions (2)
packages/opencode/**/*.ts

📄 CodeRabbit inference engine (packages/opencode/AGENTS.md)

packages/opencode/**/*.ts: Use Effect.gen(function* () { ... }) for Effect composition
Use Effect.fn("Domain.method") for named/traced effects and Effect.fnUntraced for internal helpers; these accept pipeable operators as extra arguments to avoid unnecessary outer .pipe() wrappers
Use Effect.callback for callback-based APIs
Prefer DateTime.nowAsDate over new Date(yield* Clock.currentTimeMillis) when you need a Date in Effect code
Use Schema.Class for multi-field data in Effect schemas
Use branded schemas (Schema.brand) for single-value types in Effect
Use Schema.TaggedErrorClass for typed errors in Effect schemas
Use Schema.Defect instead of unknown for defect-like causes in Effect code
In Effect.gen / Effect.fn, prefer yield* new MyError(...) over yield* Effect.fail(new MyError(...)) for direct early-failure branches
Use makeRuntime from src/effect/run-service.ts for all services; it returns { runPromise, runFork, runCallback } backed by a shared memoMap that deduplicates layers
Use InstanceState from src/effect/instance-state.ts for per-directory or per-project state that needs per-instance cleanup; do work directly in the InstanceState.make closure where ScopedCache handles run-once semantics
Use Effect.addFinalizer or Effect.acquireRelease inside the InstanceState.make closure for cleanup (subscriptions, process teardown, etc.)
Use Effect.forkScoped inside the InstanceState.make closure for background stream consumers — the fiber is interrupted when the instance is disposed
Prefer FileSystem.FileSystem instead of raw fs/promises for effectful file I/O in Effect services
Prefer ChildProcessSpawner.ChildProcessSpawner with ChildProcess.make(...) instead of custom process wrappers in Effect services
Prefer HttpClient.HttpClient instead of raw fetch in Effect services
Prefer Path.Path, Config, Clock, and DateTime services when those concerns are already inside Effect code
For backgroun...

Files:

  • packages/opencode/test/github/workflow-parser.ts
  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
packages/opencode/test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (packages/opencode/test/AGENTS.md)

packages/opencode/test/**/*.test.{ts,tsx}: Use the tmpdir function from fixture/fixture.ts to create temporary directories for tests with automatic cleanup. Use await using syntax to ensure automatic cleanup when the variable goes out of scope.
When using the tmpdir function with git repository support, pass the git: true option to initialize a git repo with a root commit.
Use the config option in tmpdir to write an opencode.json config file during test setup by passing a partial Config.Info object.
Use the init option in tmpdir to define custom setup functions that can return extra data accessible via tmp.extra, and use the dispose option for custom cleanup logic.
Use testEffect(...) from test/lib/effect.ts for tests that exercise Effect services or Effect-based workflows.
Use it.effect(...) when the test should run with TestClock and TestConsole. Use it.live(...) when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
Prefer Effect-aware helpers from fixture/fixture.ts over building manual runtimes in tests: use tmpdirScoped() for scoped temp directories, provideInstance(dir)(effect) for low-level binding without directory creation, provideTmpdirInstance(...) for single temp instance binding, or provideTmpdirServer(...) for tests that also need the test LLM server.
Define const it = testEffect(...) near the top of the test file and keep the test body inside Effect.gen(function* () { ... }). Yield services directly with yield* MyService.Service or yield* MyTool.
Avoid custom ManagedRuntime, attach(...), or ad hoc run(...) wrappers in Effect tests when testEffect(...) already provides the runtime.
When a test needs instance-local state, prefer provideTmpdirInstance(...) or provideInstance(...) over manual Instance.provide(...) inside Promise-style tests.

Files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
🧠 Learnings (40)
📚 Learning: 2026-04-22T08:49:44.563Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/desktop-electron/src/main/index-sidecar-source.test.ts:3-11
Timestamp: 2026-04-22T08:49:44.563Z
Learning: In `packages/desktop-electron/src/main/index-sidecar-source.test.ts` (Astro-Han/pawwork), the test intentionally uses `expect(source).toContain` / `expect(source).not.toContain` string matching against the raw `index.ts` source text as a lightweight sidecar contract guard. The maintainer has explicitly chosen not to introduce an AST parser (e.g., `babel/parser` or acorn) for this purpose. Do not flag these string-based assertions as fragile or suggest converting them to AST-based matching.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use `testEffect(...)` from `test/lib/effect.ts` for tests that exercise Effect services or Effect-based workflows.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:21:51.047Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 71
File: packages/app/src/components/session/session-status-connections.tsx:146-147
Timestamp: 2026-04-20T14:21:51.047Z
Learning: In the Astro-Han/pawwork repository (SolidJS app), `sync.data.config` is always initialized to `{}` at `packages/app/src/context/global-sync.tsx` line 71 and is never `undefined` at runtime. Non-optional property access like `sync.data.config.plugin` is intentional and consistent with the pattern used in `packages/app/src/components/status-popover-body.tsx` line 243. Do not flag `sync.data.config.plugin` as needing optional chaining.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T12:14:29.062Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 93
File: packages/opencode/test/server/cors-middleware.test.ts:15-23
Timestamp: 2026-04-21T12:14:29.062Z
Learning: In `packages/opencode/test/server/cors-middleware.test.ts` (and similar Hono-based test files), `app.request(...)` on the Hono `Hono` app type returns `Promise<Response> | Response` — a union that includes a non-PromiseLike branch. `Effect.promise(...)` requires a `PromiseLike`, so wrapping with `Promise.resolve(app.request(...))` is necessary to normalize the union type. Removing the wrapper causes a TS2322 typecheck error in `packages/opencode`.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use locator assertions like `toBeVisible()`, `toHaveCount(0)`, and `toHaveAttribute(...)` for normal UI state verification

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use camelCase for variable names in tests

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : When validating routing, assert against canonical or resolved workspace slugs using shared helpers from `../actions` to account for Windows canonicalization

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use lowercase, descriptive test names (e.g., 'sidebar can be toggled')

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Test files should be named with the pattern `feature-name.spec.ts`

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Test one feature per test file

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `tmpdir` function from `fixture/fixture.ts` to create temporary directories for tests with automatic cleanup. Use `await using` syntax to ensure automatic cleanup when the variable goes out of scope.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-22T09:32:52.806Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/opencode/test/provider/provider.test.ts:64-85
Timestamp: 2026-04-22T09:32:52.806Z
Learning: In `packages/opencode/test/provider/provider.test.ts`, the file intentionally uses AppRuntime-based async helpers (`run`, `list`, `getProvider`, etc.) rather than `testEffect(...)` for all tests. Converting individual tests to `testEffect` while leaving the rest on the async pattern would create internal inconsistency. A full harness migration of this file is the right approach if the pattern needs to change, but that should be a separate PR.

Applied to files:

  • packages/opencode/test/github/build-workflow.test.ts
  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Prefer Effect-aware helpers from `fixture/fixture.ts` over building manual runtimes in tests: use `tmpdirScoped()` for scoped temp directories, `provideInstance(dir)(effect)` for low-level binding without directory creation, `provideTmpdirInstance(...)` for single temp instance binding, or `provideTmpdirServer(...)` for tests that also need the test LLM server.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use `it.effect(...)` when the test should run with `TestClock` and `TestConsole`. Use `it.live(...)` when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Define `const it = testEffect(...)` near the top of the test file and keep the test body inside `Effect.gen(function* () { ... })`. Yield services directly with `yield* MyService.Service` or `yield* MyTool`.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : In terminal tests, type through the browser using `runTerminal()` and `waitTerminalReady()` instead of writing to the PTY through the SDK

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Import test utilities from `../fixtures` instead of `playwright/test`

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : When using the `tmpdir` function with git repository support, pass the `git: true` option to initialize a git repo with a root commit.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use `expect.poll(...)` for probing mock or backend state rather than transient DOM visibility

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers in Effect tests when `testEffect(...)` already provides the runtime.

Applied to files:

  • packages/opencode/test/github/desktop-smoke-workflow.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise in tests

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use SCREAMING_SNAKE_CASE for constants in tests

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `init` option in `tmpdir` to define custom setup functions that can return extra data accessible via `tmp.extra`, and use the `dispose` option for custom cleanup logic.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use the `config` option in `tmpdir` to write an `opencode.json` config file during test setup by passing a partial Config.Info object.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : When a test needs instance-local state, prefer `provideTmpdirInstance(...)` or `provideInstance(...)` over manual `Instance.provide(...)` inside Promise-style tests.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/packages/app/src/testing/**/*.ts : Test-only hooks must be inert unless explicitly enabled and should not add normal-runtime listeners, reactive subscriptions, or per-update allocations

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.test.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Prefer `ChildProcessSpawner.ChildProcessSpawner` with `ChildProcess.make(...)` instead of custom process wrappers in Effect services

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.ts
📚 Learning: 2026-04-20T17:03:37.710Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 73
File: packages/opencode/src/cli/cmd/tui/context/sync.tsx:486-489
Timestamp: 2026-04-20T17:03:37.710Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/cli/cmd/tui/context/sync.tsx`), `sync.ready` returning `true` when `process.env.OPENCODE_FAST_BOOT` is set is intentional. The plugin-facing data properties `state.config` (initialized to `{}`) and `state.provider` (initialized to `[]`) expose safe-empty defaults, so they are safe to access before bootstrap completes. Do not flag these as needing null-guards or conditional patterns to match `vcs` — the difference is intentional because `vcs` starts as `undefined` while the others have initialized defaults. Changing this would alter the plugin API contract without a concrete failing case.

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:08.745Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/desktop-electron/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:08.745Z
Learning: Applies to packages/desktop-electron/src/main/ipc.ts : Main process should register IPC handlers in `src/main/ipc.ts`

Applied to files:

  • packages/desktop-electron/scripts/ci-smoke.ts
  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:08.745Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/desktop-electron/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:08.745Z
Learning: Applies to packages/desktop-electron/src/**/*.{ts,tsx,js,jsx} : Renderer process should only call `window.api` from `src/preload`

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T16:57:22.813Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 102
File: packages/opencode/src/config/agent.ts:108-119
Timestamp: 2026-04-21T16:57:22.813Z
Learning: In `packages/opencode/src/config/agent.ts` (Astro-Han/pawwork), `ConfigPermission.Info` only accepts permission objects or the three action strings `"ask"`, `"allow"`, `"deny"`, and transforms those action strings into `{ "*": action }` before `normalize()` runs. By the time `normalize()` is reached, `configuredPermission` is always either `undefined` or a `Record<string, Rule>` — never a raw arbitrary string. The `Object.assign(permission, configuredPermission)` pattern is therefore safe. Do not flag it as corrupting string permission references.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-22T09:32:52.535Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/ui/src/theme/context.tsx:11-16
Timestamp: 2026-04-22T09:32:52.535Z
Learning: In Astro-Han/pawwork (`packages/ui/src/theme/context.tsx` and related files), the renaming of localStorage theme keys from `opencode-*` to `pawwork-*` (THEME_ID, COLOR_SCHEME, THEME_CSS_LIGHT, THEME_CSS_DARK) is intentional and should NOT include a migration path from the old keys. Migrating would re-couple PawWork and OpenCode browser storage namespaces, which the PR is explicitly designed to avoid. A reset to the PawWork default theme on upgrade is acceptable by design.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T16:57:20.257Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 102
File: packages/opencode/src/config/command.ts:23-29
Timestamp: 2026-04-21T16:57:20.257Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/config/`), `Schema.Struct` and `Schema.Class` are both valid and intentionally used patterns across config modules (e.g. `formatter.ts`, `provider.ts`, `permission.ts`, `lsp.ts`, `config.ts`, `keybinds.ts`, `command.ts`). Do not flag `Schema.Struct` usage in config schemas as needing conversion to `Schema.Class` — the choice is driven by upstream alignment and local context, not inconsistency.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-21T13:45:41.773Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 99
File: packages/desktop-electron/src/renderer/i18n/index.ts:30-35
Timestamp: 2026-04-21T13:45:41.773Z
Learning: In Astro-Han/pawwork, the locale normalization helpers in `packages/app/src/context/language.tsx` (`normalizeLocale`) and `packages/desktop-electron/src/renderer/i18n/index.ts` (`parseLocale`) are intentionally kept separate and have different fallback shapes: `normalizeLocale` always returns a concrete `Locale` (falling back to `"en"`), while `parseLocale` returns `Locale | null` so the desktop shell can decide whether to fall back to browser detection. Do not suggest extracting a shared normalization helper across these two runtimes.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-22T05:24:42.404Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 98
File: packages/desktop-electron/src/main/menu-labels.ts:1-2
Timestamp: 2026-04-22T05:24:42.404Z
Learning: In Astro-Han/pawwork, the app i18n layer (`packages/app/src/i18n/`) only contains `en.ts` and `zh.ts`, and `normalizeLocale` (in `packages/app/src/context/language.tsx`) only returns `"en"` or `"zh"`. The desktop `MenuLocale = "en" | "zh"` union in `packages/desktop-electron/src/main/menu-labels.ts` is intentionally limited to these two locales and is not a broader restriction — do not flag it as overly restrictive or suggest adding other locales.

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `Schema.Defect` instead of `unknown` for defect-like causes in Effect code

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : In `Effect.gen` / `Effect.fn`, prefer `yield* new MyError(...)` over `yield* Effect.fail(new MyError(...))` for direct early-failure branches

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Prefer `FileSystem.FileSystem` instead of raw `fs/promises` for effectful file I/O in Effect services

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `Effect.addFinalizer` or `Effect.acquireRelease` inside the `InstanceState.make` closure for cleanup (subscriptions, process teardown, etc.)

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
📚 Learning: 2026-04-20T14:36:21.274Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:21.274Z
Learning: Applies to packages/opencode/**/*.ts : Use `makeRuntime` from `src/effect/run-service.ts` for all services; it returns `{ runPromise, runFork, runCallback }` backed by a shared `memoMap` that deduplicates layers

Applied to files:

  • packages/desktop-electron/scripts/runtime-import-guard.ts
🪛 ast-grep (0.42.1)
packages/desktop-electron/scripts/runtime-import-guard.ts

[warning] 83-83: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escapeRegExp(key).replace("\\*", "(.+)")}$)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

Comment thread packages/desktop-electron/scripts/runtime-import-guard.ts Outdated
@Astro-Han Astro-Han force-pushed the codex/fix-packaged-smoke-guard branch from 7706086 to 7d19f87 Compare April 23, 2026 02:33
@Astro-Han Astro-Han merged commit 4274751 into dev Apr 23, 2026
23 checks passed
@Astro-Han Astro-Han deleted the codex/fix-packaged-smoke-guard branch April 23, 2026 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ci Continuous integration / GitHub Actions P1 High priority platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Packaged desktop smoke does not launch the built app bundle

1 participant