Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ Nem tudo do upstream deve vir pra cá. Antes de aplicar algo, pergunte:

Quando em dúvida sobre uma mudança específica, mostre o diff resumido pro usuário e pergunte antes de aplicar — não presuma.

**Cuidado com correções já parcialmente portadas**: este fork às vezes tem a mesma lógica duplicada em dois lugares — uma versão "canônica" num pacote core (ex.: `packages/core/src/plugin/provider/amazon-bedrock.ts`, `packages/core/src/aisdk.ts`) e uma cópia legada dentro de `packages/opencode/src/provider/provider.ts` (o loader "custom" antigo e seu próprio `wrapSSE()`). Uma sessão de sync anterior pode ter corrigido só a cópia canônica e esquecido a duplicada — antes de assumir que uma correção específica já foi trazida, dê um `grep` pelo padrão corrigido no repo inteiro, não só no arquivo que o commit do upstream tocou (foi o caso de PR #241, que completou os ports de `ac1758c0e6` e `69c172e8a7` feitos por PR #199/commits `d66cefea74`/`ac3b15ba8d`).

## 3. Aplicar

Duas rotas, dependendo do tamanho:
Expand Down Expand Up @@ -86,3 +88,4 @@ Depois de sincronizar `dev`, propague pra `batuta`/`breniac`/`prod` seguindo o m
- Se a mudança trazida do upstream tocar em algo que este fork também modificou (ex.: um arquivo em `packages/app/src/pages/session.tsx`, que já teve fixes próprios deste fork nesta sessão), teste manualmente antes de considerar terminado — merge automático não garante que as duas mudanças coexistem bem em runtime, só que o texto não colidiu.
- Depois de sincronizar, deixe uma nota rápida aqui (ou em `fork-map.md`) se descobrir algo relevante sobre o estado do upstream que provavelmente importa de novo no futuro (ex.: "upstream mudou o formato do evento SSE em tal versão", "upstream removeu tal flag do CLI") — isso evita redescobrir a mesma coisa do zero na próxima sincronização.
- **Ambientes sandbox (sessões remotas/cloud) costumam bloquear certas fontes de dependência via proxy** — `pkg.pr.new` e tarballs diretos de `api.github.com/repos/.../tarball/...` retornam 403 nesses ambientes, o que quebra a instalação/typecheck de pacotes que fixam dependências nessas fontes (ex.: `ghostty-web`, `@solidjs/start` em `packages/app` e `packages/enterprise`). Se `bun turbo typecheck` falhar nesses pacotes, confirme com `git stash` se a falha já existe em HEAD limpo antes de assumir que é regressão sua — normalmente é limitação do ambiente, não do código. Nunca "corrija" isso removendo a dependência real do `package.json` — é só um workaround de sandbox, não uma correção de verdade (já aconteceu de um agente propor isso por engano).
- **O bloqueio do `@solidjs/start` é mais sério do que parece à primeira vista**: não é só uma falha de install isolada — três pacotes (`console-support`, `console-app`, `stats-app`) importam `@solidjs/start` de verdade no código-fonte (não é só uma entrada solta no `package.json`), então nenhum workaround de `package.json` resolve, e trocar o pin por uma versão real do npm (`2.0.5`, testado em 2026-09-15) também não resolve — a API difere da build de preview (`pkg.pr.new/@solidjs/start@dfb2020`) que está pinada. Na prática isso significa que **`bun typecheck`/`git push` local nunca vai passar neste sandbox para nenhuma branch**, não importa a versão do bun (mesmo instalando `bun@1.3.14` via npm registry, que funciona e resolve o gate de versão do hook — o bloqueio real é o `@solidjs/start`, não o bun). Pra mudanças de código real nesse cenário, a única rota é a API do GitHub (`create_or_update_file`/`push_files`), commitando o conteúdo final igual a alguém editando pela web UI — depois de qualquer push assim, confirme que o SHA do blob publicado bate exatamente com `git rev-parse <commit-local>:<arquivo>` antes de seguir em frente, pra garantir que nada foi transcrito errado na tentativa.
8 changes: 4 additions & 4 deletions packages/app/src/pages/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,14 @@ export const StatsPage: Component = () => {
<KpiCard
label={language.t("stats.kpi.totalDuration")}
value={formatDuration(stats().totalDurationMs)}
fullValue={formatMinutes(stats().totalDurationMs)}
subtext={formatMinutes(stats().totalDurationMs)}
fullValue={formatMinutes(stats().totalDurationMs, language.intl())}
subtext={formatMinutes(stats().totalDurationMs, language.intl())}
accent="blue"
/>
<KpiCard
label={language.t("stats.kpi.longestDuration")}
value={formatDuration(stats().longestDurationMs)}
fullValue={formatMinutes(stats().longestDurationMs)}
fullValue={formatMinutes(stats().longestDurationMs, language.intl())}
subtext={stats().longestSessionTitle ? `${stats().longestSessionTitle}` : language.t("stats.kpi.longestDuration.sub")}
accent="amber"
/>
Expand Down Expand Up @@ -453,7 +453,7 @@ export const StatsPage: Component = () => {
<td class="py-2.5 pr-2 text-right font-mono text-11-medium text-v2-text-text-base">
{compactFmt().format(s.tokensTotal)}
</td>
<td class="py-2.5 pr-2 text-right font-mono text-11-medium text-blue-400" title={formatMinutes(s.durationMs)}>
<td class="py-2.5 pr-2 text-right font-mono text-11-medium text-blue-400" title={formatMinutes(s.durationMs, language.intl())}>
{s.durationFormatted}
</td>
<td class="py-2.5 pr-2 text-right font-mono text-11-regular text-v2-text-text-muted">
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/pages/stats/stats-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ describe("formatDuration", () => {
})

test("formatMinutes formats total minutes", () => {
expect(formatMinutes(3600000)).toBe("60 min")
expect(formatMinutes(3619620000)).toBe("60.327 min")
expect(formatMinutes(3600000, "pt-BR")).toBe("60 min")
expect(formatMinutes(3619620000, "pt-BR")).toBe("60.327 min")
})
})

Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/pages/stats/stats-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ export function formatDuration(ms: number): string {
return remHours > 0 ? `${days}d ${remHours}h` : `${days}d`
}

export function formatMinutes(ms: number): string {
export function formatMinutes(ms: number, locale?: string): string {
if (!Number.isFinite(ms) || ms <= 0) return "0 min"
const mins = Math.round(ms / 60000)
return `${mins.toLocaleString()} min`
return `${mins.toLocaleString(locale)} min`
}

export function getCutoffTime(range: StatsDateRange, now = Date.now()): number {
Expand Down
28 changes: 25 additions & 3 deletions packages/core/schema.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"version": "7",
"dialect": "sqlite",
"id": "7d1f95cf-b536-437e-9f8a-8594750305e7",
"id": "c184339e-6ab6-4608-a9d2-eb36759ce9cb",
"prevIds": [
"f14a9b18-8207-487e-a3d3-227e629ba9ad"
"7d1f95cf-b536-437e-9f8a-8594750305e7"
],
"ddl": [
{
Expand Down Expand Up @@ -2260,6 +2260,28 @@
"entityType": "indexes",
"table": "session"
},
{
"columns": [
{
"value": "directory",
"isExpression": false
},
{
"value": "time_created",
"isExpression": false
},
{
"value": "id",
"isExpression": false
}
],
"isUnique": false,
"where": null,
"origin": "manual",
"name": "session_directory_time_created_id_idx",
"entityType": "indexes",
"table": "session"
},
{
"columns": [
{
Expand All @@ -2276,4 +2298,4 @@
}
],
"renames": []
}
}
1 change: 1 addition & 0 deletions packages/core/src/database/migration.gen.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Effect } from "effect"
import type { DatabaseMigration } from "../migration"

export default {
id: "20260915022715_tearful_micromax",
up(tx) {
return Effect.gen(function* () {
yield* tx.run(
`CREATE INDEX \`session_directory_time_created_id_idx\` ON \`session\` (\`directory\`,\`time_created\`,\`id\`);`,
)
})
},
} satisfies DatabaseMigration.Migration
3 changes: 3 additions & 0 deletions packages/core/src/database/schema.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ export default {
yield* tx.run(`CREATE INDEX \`session_project_idx\` ON \`session\` (\`project_id\`);`)
yield* tx.run(`CREATE INDEX \`session_workspace_idx\` ON \`session\` (\`workspace_id\`);`)
yield* tx.run(`CREATE INDEX \`session_parent_idx\` ON \`session\` (\`parent_id\`);`)
yield* tx.run(
`CREATE INDEX \`session_directory_time_created_id_idx\` ON \`session\` (\`directory\`,\`time_created\`,\`id\`);`,
)
yield* tx.run(`CREATE INDEX \`todo_session_idx\` ON \`todo\` (\`session_id\`);`)
})
},
Expand Down
8 changes: 6 additions & 2 deletions packages/opencode/src/provider/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function wrapSSE(res: Response, ms: number, ctl: AbortController) {
const id = setTimeout(() => {
const err = new ProviderError.ResponseStreamError("SSE read timed out")
ctl.abort(err)
void reader.cancel(err)
reader.cancel(err).catch(() => {})
reject(err)
}, ms)

Expand Down Expand Up @@ -417,6 +417,10 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
async getModel(sdk: any, modelID: string, options?: Record<string, any>, model?: Model) {
if (model?.api.npm === "@ai-sdk/amazon-bedrock/mantle") return selectBedrockMantleLanguageModel(sdk, modelID)

if (modelID.startsWith("arn:")) {
return sdk.languageModel(modelID)
}

// Skip region prefixing if model already has a cross-region inference profile prefix
// Models from models.dev may already include prefixes like us., eu., global., etc.
const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."]
Expand All @@ -441,7 +445,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
"nova-premier",
"nova-2",
"claude",
"deepseek",
"deepseek.r1",
].some((m) => modelID.includes(m))
const isGovCloud = region.startsWith("us-gov")
if (modelRequiresPrefix && !isGovCloud) {
Expand Down
Loading