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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/dreamcode-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Dreamcode CI

on:
push:
branches: [main, dev]
pull_request:
workflow_dispatch:

env:
CI: true
OPENCODE_DISABLE_SHARE: 1

jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
# Scope typecheck to packages/opencode only — the server (packages/cli)
# has pre-existing Effect-TS v4 HttpApi error-type incompatibilities
# that are unrelated to dreamcode changes.
- name: Typecheck
run: bun run --cwd packages/opencode typecheck

unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- name: Run unit tests (skill package)
run: bun test test/skill/
working-directory: packages/opencode

integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- name: Run integration tests (sensor gate)
run: bun test test/skill/sensor-gate.integration.test.ts
working-directory: packages/opencode
- name: Run integration tests (token predictor)
run: bun test test/skill/token-predictor.integration.test.ts
working-directory: packages/opencode

build:
runs-on: ubuntu-latest
needs: [typecheck, unit-tests, integration-tests]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install --frozen-lockfile
- name: Build dreamcode binary
run: bun run packages/opencode/script/build.ts
- name: Binary smoke test
run: |
chmod +x packages/opencode/dist/dreamcode-linux-x64/bin/dreamcode
packages/opencode/dist/dreamcode-linux-x64/bin/dreamcode --version
packages/opencode/dist/dreamcode-linux-x64/bin/dreamcode --help
- name: Binary regression tests
run: bun test test/build/binary-regression.test.ts
working-directory: packages/opencode
- uses: actions/upload-artifact@v4
with:
name: dreamcode-linux-x64
path: packages/opencode/dist/dreamcode-linux-x64/
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ on:
concurrency:
# Keep every run on dev so cancelled checks do not pollute the default branch
# commit history. PRs and other branches still share a group and cancel stale runs.
group: ${{ case(github.ref == 'refs/heads/dev', format('{0}-{1}', github.workflow, github.run_id), format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref)) }}
# NOTE: `case()` is not a valid GitHub Actions expression function.
# We use &&/|| as a ternary-like alternative:
# dev branch → unique per-run ID (never cancelled)
# PRs/other → shared group key (stale runs cancelled)
group: ${{ github.ref == 'refs/heads/dev' && format('{0}-{1}', github.workflow, github.run_id) || format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref) }}
cancel-in-progress: true

permissions:
Expand Down
5 changes: 2 additions & 3 deletions .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ if (process.versions.bun !== expectedBunVersion) {
console.warn(`Warning: Bun version ${process.versions.bun} differs from expected ${expectedBunVersion}`);
}
'
cd packages/core && bun run typecheck
cd packages/llm && bun run typecheck
cd packages/core && bun run typecheck && cd ../llm && bun run typecheck && cd ../opencode && bun run typecheck
# packages/core and packages/llm do not exist in this fork — skipped.
cd packages/opencode && bun run typecheck
32 changes: 18 additions & 14 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,23 +60,24 @@ if (-not $BuildFromSource) {
$release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "dreamcode-installer" }
$tag = $release.tag_name
Write-Color "Latest release: $tag" $MUTED
} catch {
Write-Color "WARN: Could not fetch latest release. Using v1.3.1." $ORANGE
$tag = "v1.3.1"
}

# Find the windows-x64 asset (build system produces .zip for Windows)
$assetName = "dreamcode-windows-x64.zip"
$downloadUrl = "https://github.com/$OWNER/$REPO/releases/download/$tag/$assetName"
$tempArchive = "$tempDir\$assetName"
$extractDir = "$tempDir\extracted"
# Find the windows-x64 asset (build system produces .zip for Windows)
$assetName = "dreamcode-windows-x64.zip"
$downloadUrl = "https://github.com/$OWNER/$REPO/releases/download/$tag/$assetName"
$tempArchive = "$tempDir\$assetName"
$extractDir = "$tempDir\extracted"

New-Item -ItemType Directory -Force -Path $tempDir, $extractDir | Out-Null
New-Item -ItemType Directory -Force -Path $tempDir, $extractDir | Out-Null

try {
Download-File $downloadUrl $tempArchive
try {
Download-File $downloadUrl $tempArchive
} catch {
Write-Color "ERROR: Failed to download $downloadUrl" $RED
Write-Color "Falling back to source build (requires git + bun)..." $ORANGE
$BuildFromSource = $true
}
} catch {
Write-Color "ERROR: Failed to download $downloadUrl" $RED
Write-Color "ERROR: Failed to fetch latest release from GitHub API." $RED
Write-Color "Falling back to source build (requires git + bun)..." $ORANGE
$BuildFromSource = $true
}
Expand Down Expand Up @@ -165,7 +166,10 @@ if ($BuildFromSource) {
Write-Color "Building version: $VERSION" $MUTED

Set-Location $INSTALL_DIR
bun install
# Windows requires --linker hoisted for symlink compatibility (bun#12385)
$bunInstallArgs = @("install")
if ($env:OS -eq "Windows_NT") { $bunInstallArgs += "--linker", "hoisted" }
& "bun" @bunInstallArgs

Set-Location packages\opencode
bun run build --single --skip-embed-web-ui --skip-install
Expand Down
24 changes: 18 additions & 6 deletions packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ IMPORTANT:
const STRUCTURED_OUTPUT_SYSTEM_PROMPT = `IMPORTANT: The user has requested structured output. You MUST use the StructuredOutput tool to provide your final response. Do NOT respond with plain text - you MUST call the StructuredOutput tool with your answer formatted according to the schema.`

function sanitizeForSystemPrompt(text: string): string {
// Escape HTML/XML metacharacters to prevent prompt injection via tag injection.
// Order matters: & first to avoid double-escaping.
// Strip known dreamcode XML tags before HTML/XML escaping to prevent
// prompt injection via fake system tags (e.g. </sensor-gate>, <chain-gap>).
// Order matters: escape HTML/XML metacharacters, & first to avoid double-escaping.
return text
.replace(/<\/?(sensor-gate|chain-gap|chain-verification|chain-executor-result|skill-result|skill-missing|loaded-skill|neuro-analysis|rate-budget|rate-limit|context-summary|persona-profiles?)\b[^>]*>/gi, "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
Expand Down Expand Up @@ -1558,8 +1560,12 @@ Before every response, verify your reasoning:
}

// Phase 5: Wire orphaned Python scripts — run for any task with 2+ skills
// Note: runFullPipeline() takes no arguments. It uses --dashboard --json internally,
// reading prompt/chain from the orchestrator's dashboards file. The old signature
// (chain, userPrompt) was removed because the dashboard mode is stateless and
// informational — it prints ecosystem health, not per-prompt results.
if (gateResult.complexity === "high" || gateResult.chain.length > 1) {
const pipelineResults = yield* chainExecutor.runFullPipeline(gateResult.chain, userText).pipe(
const pipelineResults = yield* chainExecutor.runFullPipeline().pipe(
Effect.catch((e) => {
console.warn("[chain-executor] runFullPipeline() failed:", e)
return Effect.succeed([])
Expand All @@ -1585,9 +1591,13 @@ Before every response, verify your reasoning:
}

// ─── Chain-Gap Detection ──────────────────────────
// Hard enforcement: warn if any chain skill wasn't executed
// Hard enforcement: warn if any chain skill wasn't executed.
// Only count script-type results as "executed" — content-only (passive SKILL.md
// injection) skills don't count because they don't run any code.
const missingSkills = gateResult.chain.filter(
(name) => !chainResults.some((r) => r.name === name && r.status === "ok"),
(name) => !chainResults.some(
(r) => r.name === name && r.status === "ok" && r.executionType === "script",
),
)
// Mandated skills that MUST execute when in DREAM_INNOVATION mode
const MANDATED_SKILLS = new Set(["breakthrough-overdrive-innovation"])
Expand All @@ -1608,7 +1618,9 @@ Before every response, verify your reasoning:
}
// Update missing list after re-execution — warn about ALL remaining gaps
const stillMissing = gateResult.chain.filter(
(name) => !chainResults.some((r) => r.name === name && r.status === "ok"),
(name) => !chainResults.some(
(r) => r.name === name && r.status === "ok" && r.executionType === "script",
),
)
if (stillMissing.length > 0) {
system.push(
Expand Down
Loading
Loading