ci: launch packaged desktop smoke app#164
Conversation
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 | 🟠 MajorFail fast on
spawn()launch errors.If the packaged executable path is wrong or loses its execute bit,
spawn()fails through the child'serrorevent. This code only watchesexitCode/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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
e99bb47 to
4c8d8d2
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
4c8d8d2 to
cc49ca2
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/desktop-electron/scripts/runtime-import-guard.ts (1)
58-61: 🧹 Nitpick | 🔵 TrivialConsider the ReDoS risk from package.json
exportskeys.The regex is constructed from
exportskeys after escaping. WhileescapeRegExpneutralizes regex metacharacters, a malicious or malformedpackage.jsonwith 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:
- The input comes from workspace
package.jsonfiles under developer control.- 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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
cc49ca2 to
acdd076
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
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 | 🔵 TrivialControl flow is correct with proper cleanup.
The
finallyblock 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 | 🟠 MajorAdd an explicit existence assertion for “Package signed app” before index ordering.
At Line 175,
indexOf(steps.find(...)!)can degrade toindexOf(undefined) === -1and 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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/opencode/test/github/build-workflow.test.ts (1)
174-176:⚠️ Potential issue | 🟡 MinorAssert that
Package signed appexists before comparing step order.If that step is renamed or removed,
steps.find(...)becomesundefined,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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
acdd076 to
950685a
Compare
There was a problem hiding this comment.
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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/opencode/test/github/workflow-parser.ts
950685a to
7706086
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/opencode/test/github/build-workflow.test.ts (1)
174-176:⚠️ Potential issue | 🟡 MinorAssert the packaging step exists before comparing indices.
Line 175 still inlines
steps.find(...)insideindexOf(...). 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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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: UseEffect.gen(function* () { ... })for Effect composition
UseEffect.fn("Domain.method")for named/traced effects andEffect.fnUntracedfor internal helpers; these accept pipeable operators as extra arguments to avoid unnecessary outer.pipe()wrappers
UseEffect.callbackfor callback-based APIs
PreferDateTime.nowAsDateovernew Date(yield* Clock.currentTimeMillis)when you need aDatein Effect code
UseSchema.Classfor multi-field data in Effect schemas
Use branded schemas (Schema.brand) for single-value types in Effect
UseSchema.TaggedErrorClassfor typed errors in Effect schemas
UseSchema.Defectinstead ofunknownfor defect-like causes in Effect code
InEffect.gen/Effect.fn, preferyield* new MyError(...)overyield* Effect.fail(new MyError(...))for direct early-failure branches
UsemakeRuntimefromsrc/effect/run-service.tsfor all services; it returns{ runPromise, runFork, runCallback }backed by a sharedmemoMapthat deduplicates layers
UseInstanceStatefromsrc/effect/instance-state.tsfor per-directory or per-project state that needs per-instance cleanup; do work directly in theInstanceState.makeclosure whereScopedCachehandles run-once semantics
UseEffect.addFinalizerorEffect.acquireReleaseinside theInstanceState.makeclosure for cleanup (subscriptions, process teardown, etc.)
UseEffect.forkScopedinside theInstanceState.makeclosure for background stream consumers — the fiber is interrupted when the instance is disposed
PreferFileSystem.FileSysteminstead of rawfs/promisesfor effectful file I/O in Effect services
PreferChildProcessSpawner.ChildProcessSpawnerwithChildProcess.make(...)instead of custom process wrappers in Effect services
PreferHttpClient.HttpClientinstead of rawfetchin Effect services
PreferPath.Path,Config,Clock, andDateTimeservices when those concerns are already inside Effect code
For backgroun...
Files:
packages/opencode/test/github/workflow-parser.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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 thetmpdirfunction fromfixture/fixture.tsto create temporary directories for tests with automatic cleanup. Useawait usingsyntax to ensure automatic cleanup when the variable goes out of scope.
When using thetmpdirfunction with git repository support, pass thegit: trueoption to initialize a git repo with a root commit.
Use theconfigoption intmpdirto write anopencode.jsonconfig file during test setup by passing a partial Config.Info object.
Use theinitoption intmpdirto define custom setup functions that can return extra data accessible viatmp.extra, and use thedisposeoption for custom cleanup logic.
UsetestEffect(...)fromtest/lib/effect.tsfor tests that exercise Effect services or Effect-based workflows.
Useit.effect(...)when the test should run withTestClockandTestConsole. Useit.live(...)when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
Prefer Effect-aware helpers fromfixture/fixture.tsover building manual runtimes in tests: usetmpdirScoped()for scoped temp directories,provideInstance(dir)(effect)for low-level binding without directory creation,provideTmpdirInstance(...)for single temp instance binding, orprovideTmpdirServer(...)for tests that also need the test LLM server.
Defineconst it = testEffect(...)near the top of the test file and keep the test body insideEffect.gen(function* () { ... }). Yield services directly withyield* MyService.Serviceoryield* MyTool.
Avoid customManagedRuntime,attach(...), or ad hocrun(...)wrappers in Effect tests whentestEffect(...)already provides the runtime.
When a test needs instance-local state, preferprovideTmpdirInstance(...)orprovideInstance(...)over manualInstance.provide(...)inside Promise-style tests.
Files:
packages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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.tspackages/opencode/test/github/build-workflow.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/opencode/test/github/build-workflow.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/opencode/test/github/build-workflow.test.tspackages/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.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/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.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/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.tspackages/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.tspackages/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.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
packages/desktop-electron/scripts/ci-smoke.ts (1)
109-130:⚠️ Potential issue | 🟡 MinorPropagate
spawn()launch failures into the smoke failure path.If the packaged path exists but cannot be executed,
spawn()emitserrorinstead of ever settingexitCode. Right now that event is unhandled, so the Bun process can die beforewaitForCiSmokeReady()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 | 🟠 MajorRe-exported modules still bypass the guard.
export * from "@opencode-ai/..."andexport { ... } from "@opencode-ai/..."resolve the target at module load, butRUNTIME_IMPORT_REstill 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
📒 Files selected for processing (9)
.github/workflows/build.yml.github/workflows/desktop-smoke.ymlpackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/runtime-import-guard.tspackages/opencode/test/github/build-workflow.test.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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: UseEffect.gen(function* () { ... })for Effect composition
UseEffect.fn("Domain.method")for named/traced effects andEffect.fnUntracedfor internal helpers; these accept pipeable operators as extra arguments to avoid unnecessary outer.pipe()wrappers
UseEffect.callbackfor callback-based APIs
PreferDateTime.nowAsDateovernew Date(yield* Clock.currentTimeMillis)when you need aDatein Effect code
UseSchema.Classfor multi-field data in Effect schemas
Use branded schemas (Schema.brand) for single-value types in Effect
UseSchema.TaggedErrorClassfor typed errors in Effect schemas
UseSchema.Defectinstead ofunknownfor defect-like causes in Effect code
InEffect.gen/Effect.fn, preferyield* new MyError(...)overyield* Effect.fail(new MyError(...))for direct early-failure branches
UsemakeRuntimefromsrc/effect/run-service.tsfor all services; it returns{ runPromise, runFork, runCallback }backed by a sharedmemoMapthat deduplicates layers
UseInstanceStatefromsrc/effect/instance-state.tsfor per-directory or per-project state that needs per-instance cleanup; do work directly in theInstanceState.makeclosure whereScopedCachehandles run-once semantics
UseEffect.addFinalizerorEffect.acquireReleaseinside theInstanceState.makeclosure for cleanup (subscriptions, process teardown, etc.)
UseEffect.forkScopedinside theInstanceState.makeclosure for background stream consumers — the fiber is interrupted when the instance is disposed
PreferFileSystem.FileSysteminstead of rawfs/promisesfor effectful file I/O in Effect services
PreferChildProcessSpawner.ChildProcessSpawnerwithChildProcess.make(...)instead of custom process wrappers in Effect services
PreferHttpClient.HttpClientinstead of rawfetchin Effect services
PreferPath.Path,Config,Clock, andDateTimeservices when those concerns are already inside Effect code
For backgroun...
Files:
packages/opencode/test/github/workflow-parser.tspackages/opencode/test/github/build-workflow.test.tspackages/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 thetmpdirfunction fromfixture/fixture.tsto create temporary directories for tests with automatic cleanup. Useawait usingsyntax to ensure automatic cleanup when the variable goes out of scope.
When using thetmpdirfunction with git repository support, pass thegit: trueoption to initialize a git repo with a root commit.
Use theconfigoption intmpdirto write anopencode.jsonconfig file during test setup by passing a partial Config.Info object.
Use theinitoption intmpdirto define custom setup functions that can return extra data accessible viatmp.extra, and use thedisposeoption for custom cleanup logic.
UsetestEffect(...)fromtest/lib/effect.tsfor tests that exercise Effect services or Effect-based workflows.
Useit.effect(...)when the test should run withTestClockandTestConsole. Useit.live(...)when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
Prefer Effect-aware helpers fromfixture/fixture.tsover building manual runtimes in tests: usetmpdirScoped()for scoped temp directories,provideInstance(dir)(effect)for low-level binding without directory creation,provideTmpdirInstance(...)for single temp instance binding, orprovideTmpdirServer(...)for tests that also need the test LLM server.
Defineconst it = testEffect(...)near the top of the test file and keep the test body insideEffect.gen(function* () { ... }). Yield services directly withyield* MyService.Serviceoryield* MyTool.
Avoid customManagedRuntime,attach(...), or ad hocrun(...)wrappers in Effect tests whentestEffect(...)already provides the runtime.
When a test needs instance-local state, preferprovideTmpdirInstance(...)orprovideInstance(...)over manualInstance.provide(...)inside Promise-style tests.
Files:
packages/opencode/test/github/build-workflow.test.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/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.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/opencode/test/github/desktop-smoke-workflow.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/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.tspackages/desktop-electron/scripts/ci-smoke.test.tspackages/desktop-electron/scripts/ci-smoke.tspackages/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.tspackages/desktop-electron/scripts/runtime-import-guard.test.tspackages/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.tspackages/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.tspackages/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.tspackages/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.tspackages/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)
7706086 to
7d19f87
Compare
Summary
@opencode-ai/*imports backed by TypeScript source exports.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.appexecutable that resolvesapp.asar/node_modulesat runtime.Related Issue
Closes #162.
How To Verify
Screenshots or Recordings
Not applicable. CI and release workflow hardening only.
Checklist
dev, and my PR title and commit messages use Conventional Commits in EnglishSummary by CodeRabbit
Tests
Chores