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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,45 @@ jobs:
run: bun install

- name: Run tests
run: bun test --timeout 30000
working-directory: packages/opencode
# Cloud E2E tests (Snowflake, BigQuery, Databricks) auto-skip when
# ALTIMATE_CODE_CONN_* env vars are not set. Docker E2E tests auto-skip
# when Docker is not available. No exclusion needed — skipIf handles it.
# --timeout 30000: matches package.json "test" script; prevents 5s default
# from cutting off tests that run bun install or bootstrap git instances.
#
# Bun 1.3.x has a known segfault during process cleanup after all tests
# pass (exit code 143/SIGTERM or 134/SIGABRT). We capture test output and
# check for real failures vs Bun crashes to avoid false CI failures.
shell: bash
run: |
# Redirect bun output to file, then cat it for CI visibility.
# This avoids tee/pipe issues where SIGTERM kills tee before flush.
bun test --timeout 30000 > /tmp/test-output.txt 2>&1 || true
cat /tmp/test-output.txt

# Extract pass/fail counts from Bun test summary (e.g., " 5362 pass")
PASS_COUNT=$(awk '/^ *[0-9]+ pass$/{print $1}' /tmp/test-output.txt || true)
FAIL_COUNT=$(awk '/^ *[0-9]+ fail$/{print $1}' /tmp/test-output.txt || true)

echo ""
echo "--- Test Summary ---"
echo "pass=${PASS_COUNT:-none} fail=${FAIL_COUNT:-none}"

# Real test failures — always fail CI
if [ -n "$FAIL_COUNT" ] && [ "$FAIL_COUNT" != "0" ]; then
echo "::error::$FAIL_COUNT test(s) failed"
exit 1
fi

# Tests passed (we have a pass count and zero/no failures)
if [ -n "$PASS_COUNT" ] && [ "$PASS_COUNT" -gt 0 ] 2>/dev/null; then
exit 0
fi

# No test summary at all — Bun crashed before running tests
echo "::error::No test results found in output — Bun may have crashed before running tests"
exit 1

# ---------------------------------------------------------------------------
# Driver E2E tests — only when driver code changes.
Expand Down
5 changes: 4 additions & 1 deletion packages/dbt-tools/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import type { DBTProjectIntegrationAdapter, CommandProcessResult } from "@altima

export async function build(adapter: DBTProjectIntegrationAdapter, args: string[]) {
const model = flag(args, "model")
if (!model) return project(adapter)
const downstream = args.includes("--downstream")
if (!model) {
if (downstream) return { error: "--downstream requires --model" }
return project(adapter)
}
const result = await adapter.unsafeBuildModelImmediately({
plusOperatorLeft: "",
modelName: model,
Expand Down
8 changes: 8 additions & 0 deletions packages/dbt-tools/test/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ describe("build command", () => {
})
})

test("build --downstream without --model returns error", async () => {
const adapter = makeAdapter()
const result = await build(adapter, ["--downstream"])
expect(result).toEqual({ error: "--downstream requires --model" })
expect(adapter.unsafeBuildProjectImmediately).not.toHaveBeenCalled()
expect(adapter.unsafeBuildModelImmediately).not.toHaveBeenCalled()
})

test("build surfaces stderr as error", async () => {
const adapter = makeAdapter({
unsafeBuildProjectImmediately: mock(() =>
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/cli/cmd/tui/routes/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function Home() {
return Object.values(sync.data.mcp).filter((x) => x.status === "connected").length
})

// altimate_change start — fix race condition: don't show beginner UI until sessions loaded
// altimate_change start — upstream_fix: race condition shows beginner UI flash before sessions loaded
const isFirstTimeUser = createMemo(() => {
// Don't evaluate until sessions have actually loaded (avoid flash of beginner UI)
// Return undefined to represent "loading" state
Expand Down
5 changes: 3 additions & 2 deletions packages/opencode/src/command/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ export namespace Command {
const result: string[] = []
const numbered = template.match(/\$\d+/g)
if (numbered) {
// altimate_change start — fix lexicographic sort of multi-digit placeholders ($10 before $2)
for (const match of [...new Set(numbered)].sort((a, b) => parseInt(a.slice(1), 10) - parseInt(b.slice(1), 10))) result.push(match)
// altimate_change start — upstream_fix: lexicographic sort of multi-digit placeholders ($10 sorted before $2)
for (const match of [...new Set(numbered)].sort((a, b) => parseInt(a.slice(1), 10) - parseInt(b.slice(1), 10)))
result.push(match)
// altimate_change end
}
if (template.includes("$ARGUMENTS")) result.push("$ARGUMENTS")
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/skill/followups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export namespace SkillFollowups {
skill: string // skill name to suggest
label: string // short display label
description: string // why this is a good next step
condition?: string // optional: when this suggestion applies
}

// Map from skill name to follow-up suggestions
Expand Down Expand Up @@ -151,7 +150,8 @@ export namespace SkillFollowups {
}

// A special warehouse nudge for users who haven't connected yet
const WAREHOUSE_NUDGE = "**Tip:** Connect a warehouse to validate against real data. Run `/discover` to auto-detect your connections."
const WAREHOUSE_NUDGE =
"**Tip:** Connect a warehouse to validate against real data. Run `/discover` to auto-detect your connections."

export function get(skillName: string): readonly Suggestion[] {
return Object.freeze(FOLLOWUPS[skillName] ?? [])
Expand Down
2 changes: 2 additions & 0 deletions packages/opencode/src/util/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ export namespace Locale {
const minutes = Math.floor((input % 3600000) / 60000)
return `${hours}h ${minutes}m`
}
// altimate_change start — upstream_fix: days/hours calculation were swapped (hours used total, not remainder)
const days = Math.floor(input / 86400000)
const hours = Math.floor((input % 86400000) / 3600000)
// altimate_change end
return `${days}d ${hours}h`
}

Expand Down
38 changes: 38 additions & 0 deletions script/upstream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,44 @@ When we modify upstream files (not fully custom ones), we wrap our changes with

These help during conflict resolution — you can see exactly what we changed vs upstream code. The `analyze.ts` script audits for unclosed marker blocks.

### Upstream Bug Fixes (`upstream_fix:` tag)

When fixing a **bug in upstream code** (not adding a feature), use the `upstream_fix:` tag in the marker description:

```typescript
// altimate_change start — upstream_fix: days/hours calculation were swapped
const days = Math.floor(input / 86400000)
const hours = Math.floor((input % 86400000) / 3600000)
// altimate_change end
```

**Why this matters:** Regular `altimate_change` markers protect features we added — they're permanent. But upstream bug fixes are **temporary**: once upstream ships their own fix, we should drop our marker and accept theirs.

Without the `upstream_fix:` tag:
- If upstream fixes the same bug, the merge creates a conflict (good — forces review)
- But the reviewer doesn't know our change was a bug fix vs a feature, so they may keep both

With the `upstream_fix:` tag:
- Before each merge, run `--audit-fixes` to see all bug fixes we're carrying
- During conflict resolution, reviewers know to check "did upstream fix this?" and can safely drop our version
- After merge, any remaining `upstream_fix:` markers represent bugs upstream hasn't fixed yet

**When to use which:**

| Scenario | Marker |
|----------|--------|
| New feature/custom code | `// altimate_change start — description` |
| Fix bug in upstream code | `// altimate_change start — upstream_fix: description` |
| Branding change | No marker (handled by branding transforms) |
| Code in `keepOurs` files | No marker needed |

**Audit before merging:**

```bash
# List all upstream bug fixes we're carrying
bun run script/upstream/analyze.ts --audit-fixes
```

## File Organization

```
Expand Down
12 changes: 12 additions & 0 deletions script/upstream/analyze.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,18 @@ describe("parseDiffForMarkerWarnings", () => {
expect(warnings[0].context).toContain("first")
})

test("upstream_fix: tagged markers are recognized as valid markers", () => {
const diff = makeDiff(
`@@ -50,4 +50,6 @@
const existing = true
+// altimate_change start — upstream_fix: days/hours were swapped
+const days = Math.floor(input / 86400000)
+// altimate_change end
const more = true`,
)
expect(parseDiffForMarkerWarnings("file.ts", diff)).toEqual([])
})

test("real-world scenario: upgrade indicator in footer.tsx", () => {
// Simulates the exact diff that leaked: UpgradeIndicator added to
// session footer without markers, adjacent to existing yolo marker block.
Expand Down
Loading
Loading