diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/brain-data.ts b/packages/app-bundle/overlay/packages/ui/src/amicode/brain-data.ts
index 2e264336..1ad2d7e3 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/brain-data.ts
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/brain-data.ts
@@ -11,4 +11,4 @@ export type BrainDataEdge = { s: string; t: string; kind: string }
export type BrainDataTrace = { id: string; title: string; steps: { node: string; status: string; fanout?: string[] }[] }
export type BrainData = { nodes: BrainDataNode[]; edges: BrainDataEdge[]; traces: BrainDataTrace[] }
-export const BRAIN_DATA: BrainData = {"nodes":[{"id":"strategy","label":"STRATEGY","type":"charter"},{"id":"philosophy","label":"PHILOSOPHY","type":"charter"},{"id":"roadmap","label":"ROADMAP","type":"charter"},{"id":"charter-research-loop","label":"charter: research loop","type":"charter"},{"id":"charter-pulse-catalog","label":"charter: pulse catalog","type":"charter"},{"id":"charter-agents-skills","label":"charter: agents & skills","type":"charter"},{"id":"insight-linear-over-cubic","label":"insight: linear>cubic spline","type":"insight"},{"id":"insight-linear51-fix","label":"insight: linear51 fix","type":"insight"},{"id":"insight-shorter-duration","label":"insight: shorter T0 helps","type":"insight"},{"id":"insight-warmstart-regression","label":"insight: warmstart regress","type":"insight"},{"id":"insight-y-coldstart-variance","label":"insight: Y coldstart var","type":"insight"},{"id":"insight-crosstalk","label":"insight: drive crosstalk","type":"insight"},{"id":"insight-free-phase-2q","label":"insight: free-phase 2q","type":"insight"},{"id":"insight-gn-hessian-fails","label":"insight: GN Hessian fails","type":"insight"},{"id":"insight-stagnation-dominant","label":"insight: stagnation dominant","type":"insight"},{"id":"insight-jit-multistart-thrash","label":"insight: JIT lock thrash","type":"insight"},{"id":"insight-warmstart-taxonomy","label":"insight: warm-start taxonomy","type":"insight"},{"id":"insight-coldstart-dominates","label":"insight: coldstart dominates","type":"insight"},{"id":"insight-free-phase-untried","label":"insight: free-phase untried","type":"insight"},{"id":"insight-mintime-2q","label":"insight: mintime improves 2q","type":"insight"},{"id":"insight-eagle-heron","label":"insight: eagle-heron OC","type":"insight"},{"id":"exp-flux-x-192727","label":"exp: fluxonium X (192727)","type":"experiment"},{"id":"exp-flux-x-193328","label":"exp: fluxonium X (193328)","type":"experiment"},{"id":"exp-flux-x-194147","label":"exp: fluxonium X (194147)","type":"experiment"},{"id":"exp-flux-y-194147","label":"exp: fluxonium Y","type":"experiment"},{"id":"exp-flux-h-194147","label":"exp: fluxonium H","type":"experiment"},{"id":"exp-flux-t-194147","label":"exp: fluxonium T","type":"experiment"},{"id":"exp-flux-y-020343","label":"exp: fluxonium Y (020343)","type":"experiment"},{"id":"exp-flux-sqrtx-020343","label":"exp: fluxonium sqrtX","type":"experiment"},{"id":"exp-flux-x-021602","label":"exp: fluxonium X (021602)","type":"experiment"},{"id":"exp-flux-y-021602","label":"exp: fluxonium Y (021602)","type":"experiment"},{"id":"exp-flux-x-v3","label":"exp: fluxonium X v3","type":"experiment"},{"id":"exp-flux-y-v3","label":"exp: fluxonium Y v3","type":"experiment"},{"id":"exp-flux-t-v3","label":"exp: fluxonium T v3","type":"experiment"},{"id":"exp-flux-y-q200k","label":"exp: fluxonium Y Q200k","type":"experiment"},{"id":"exp-flux-y-retry","label":"exp: fluxonium Y retry","type":"experiment"},{"id":"exp-rydberg-cz","label":"exp: rydberg CZ v1","type":"experiment"},{"id":"exp-flux-x-basis-comp","label":"exp: X basis comparison","type":"experiment"},{"id":"hyp-free-phase-gap","label":"hyp: free-phase flux gap","type":"note"},{"id":"hyp-dressed-goal-kets","label":"hyp: dressed kets unlock 2q","type":"note"},{"id":"hyp-augmented-gn","label":"hyp: augmented controls GN","type":"note"},{"id":"method-warm-start","label":"method: warm-start workflow","type":"note"},{"id":"method-cold-start","label":"method: cold-start 4-phase","type":"note"},{"id":"method-cubic-spline","label":"method: cubic-spline pulses","type":"note"},{"id":"method-free-phase","label":"method: free-phase 2q gates","type":"note"},{"id":"method-crosstalk-gates","label":"method: crosstalk-robust","type":"note"},{"id":"method-basis-comparison","label":"method: eigen vs fock basis","type":"note"},{"id":"method-presolve-diag","label":"method: pre-solve diag","type":"note"},{"id":"spec-analytic-derivatives","label":"spec: analytic derivatives","type":"note"},{"id":"brief-analog-magic","label":"brief: analog magic states","type":"note"},{"id":"pulse-flux-x-v1","label":"pulse: fluxonium-X-v1","type":"catalog"},{"id":"pulse-flux-x-v2","label":"pulse: fluxonium-X-v2","type":"catalog"},{"id":"pulse-flux-x-v3","label":"pulse: fluxonium-X-v3","type":"catalog"},{"id":"pulse-flux-y-v3","label":"pulse: fluxonium-Y-v3","type":"catalog"},{"id":"pulse-flux-t-v3","label":"pulse: fluxonium-T-v3","type":"catalog"},{"id":"pulse-rydberg-cz-v1","label":"pulse: rydberg-CZ-v1","type":"catalog"},{"id":"pulse-transmon-cz-v1","label":"pulse: transmon-CZ-v1","type":"catalog"},{"id":"pulse-transmon-x-v1","label":"pulse: transmon-X-v1","type":"catalog"},{"id":"local-workstation","label":"local-workstation","type":"resource"},{"id":"stanford-fluxonium-chip","label":"stanford fluxonium chip","type":"resource"},{"id":"hermes","label":"hermes","type":"resource"},{"id":"fluxonium-half-flux","label":"fluxonium @ half flux","type":"resource"},{"id":"transmon-two-qubit","label":"transmon two-qubit","type":"resource"},{"id":"rydberg-global","label":"rydberg global drive","type":"resource"},{"id":"using-amico","label":"using-amico","type":"skill"},{"id":"brainstorming","label":"brainstorming","type":"skill"},{"id":"debugging","label":"debugging","type":"skill"},{"id":"verification","label":"verification","type":"skill"},{"id":"tdd","label":"tdd","type":"skill"},{"id":"code-review","label":"code-review","type":"skill"},{"id":"setup","label":"setup","type":"skill"},{"id":"solve","label":"solve","type":"skill"},{"id":"demo","label":"demo","type":"skill"},{"id":"plot","label":"plot","type":"skill"},{"id":"analyze","label":"analyze","type":"skill"},{"id":"benchmark","label":"benchmark","type":"skill"},{"id":"ingest","label":"ingest","type":"skill"},{"id":"multistart","label":"multistart","type":"skill"},{"id":"objectives","label":"objectives","type":"skill"},{"id":"structural-analysis","label":"structural-analysis","type":"skill"},{"id":"hypothesis-review","label":"hypothesis-review","type":"skill"},{"id":"transmon","label":"transmon","type":"skill"},{"id":"fluxonium","label":"fluxonium","type":"skill"},{"id":"atoms","label":"atoms","type":"skill"},{"id":"ions","label":"ions","type":"skill"},{"id":"bosonic","label":"bosonic","type":"skill"},{"id":"amico-vault","label":"amico-vault","type":"skill"},{"id":"amico-catalog","label":"amico-catalog","type":"skill"},{"id":"amico-lab","label":"amico-lab","type":"skill"},{"id":"amico-strategy","label":"amico-strategy","type":"skill"},{"id":"amico-route","label":"amico-route","type":"skill"},{"id":"piccolo-dev","label":"piccolo-dev","type":"skill"},{"id":"piccolissimo-dev","label":"piccolissimo-dev","type":"skill"},{"id":"intonato-dev","label":"intonato-dev","type":"skill"},{"id":"legato-dev","label":"legato-dev","type":"skill"},{"id":"pr","label":"pr","type":"skill"},{"id":"test","label":"test","type":"skill"},{"id":"dream","label":"dream","type":"skill"},{"id":"dream-distill","label":"dream-distill","type":"skill"},{"id":"dream-connect","label":"dream-connect","type":"skill"},{"id":"dream-prune","label":"dream-prune","type":"skill"},{"id":"dream-synthesize","label":"dream-synthesize","type":"skill"},{"id":"dream-reflect","label":"dream-reflect","type":"skill"},{"id":"meeting","label":"meeting","type":"skill"},{"id":"hopper","label":"hopper","type":"skill"},{"id":"researcher","label":"researcher","type":"agent"},{"id":"experimenter","label":"experimenter","type":"agent"},{"id":"orchestrator","label":"orchestrator","type":"agent"},{"id":"dispatcher","label":"dispatcher","type":"agent"},{"id":"librarian","label":"librarian","type":"agent"},{"id":"engineer","label":"engineer","type":"agent"},{"id":"dreamer","label":"dreamer","type":"agent"},{"id":"piccolo-jl","label":"Piccolo.jl","type":"package"},{"id":"piccolissimo-jl","label":"Piccolissimo.jl","type":"package"},{"id":"intonato-jl","label":"Intonato.jl","type":"package"},{"id":"legato-jl","label":"Legato.jl","type":"package"},{"id":"namedtrajectories-jl","label":"NamedTrajectories.jl","type":"package"},{"id":"directtrajopt-jl","label":"DirectTrajOpt.jl","type":"package"},{"id":"altissimo-jl","label":"Altissimo.jl","type":"package"}],"edges":[{"s":"insight-linear-over-cubic","t":"exp-flux-x-192727","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"exp-flux-x-194147","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"pulse-flux-x-v1","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-x-194147","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-y-194147","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-sqrtx-020343","kind":"wikilink"},{"s":"insight-linear51-fix","t":"insight-linear-over-cubic","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-sqrtx-020343","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-shorter-duration","t":"insight-linear51-fix","kind":"wikilink"},{"s":"insight-warmstart-regression","t":"exp-flux-x-021602","kind":"wikilink"},{"s":"insight-warmstart-regression","t":"exp-flux-y-021602","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-q200k","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-retry","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-021602","kind":"wikilink"},{"s":"insight-crosstalk","t":"insight-eagle-heron","kind":"wikilink"},{"s":"insight-crosstalk","t":"method-crosstalk-gates","kind":"wikilink"},{"s":"insight-free-phase-2q","t":"method-free-phase","kind":"wikilink"},{"s":"insight-free-phase-2q","t":"transmon-two-qubit","kind":"wikilink"},{"s":"insight-gn-hessian-fails","t":"hyp-augmented-gn","kind":"wikilink"},{"s":"insight-gn-hessian-fails","t":"spec-analytic-derivatives","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-h-194147","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-t-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-x-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-q200k","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-retry","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-y-coldstart-variance","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-warmstart-regression","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-coldstart-dominates","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-free-phase-untried","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-warmstart-taxonomy","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"strategy","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"exp-flux-x-192727","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"pulse-flux-x-v1","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v3","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"exp-flux-y-194147","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"pulse-flux-y-v3","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"exp-flux-t-194147","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"pulse-flux-t-v3","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-rydberg-cz","t":"pulse-rydberg-cz-v1","kind":"wikilink"},{"s":"exp-rydberg-cz","t":"rydberg-global","kind":"wikilink"},{"s":"exp-flux-x-basis-comp","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-basis-comp","t":"method-basis-comparison","kind":"wikilink"},{"s":"hyp-free-phase-gap","t":"insight-free-phase-2q","kind":"wikilink"},{"s":"researcher","t":"amico-strategy","kind":"dispatch"},{"s":"researcher","t":"hypothesis-review","kind":"dispatch"},{"s":"researcher","t":"structural-analysis","kind":"dispatch"},{"s":"researcher","t":"brainstorming","kind":"dispatch"},{"s":"researcher","t":"objectives","kind":"dispatch"},{"s":"experimenter","t":"setup","kind":"dispatch"},{"s":"experimenter","t":"solve","kind":"dispatch"},{"s":"experimenter","t":"transmon","kind":"dispatch"},{"s":"experimenter","t":"fluxonium","kind":"dispatch"},{"s":"experimenter","t":"atoms","kind":"dispatch"},{"s":"experimenter","t":"ions","kind":"dispatch"},{"s":"experimenter","t":"bosonic","kind":"dispatch"},{"s":"experimenter","t":"multistart","kind":"dispatch"},{"s":"experimenter","t":"benchmark","kind":"dispatch"},{"s":"experimenter","t":"demo","kind":"dispatch"},{"s":"experimenter","t":"plot","kind":"dispatch"},{"s":"librarian","t":"amico-vault","kind":"dispatch"},{"s":"librarian","t":"amico-catalog","kind":"dispatch"},{"s":"librarian","t":"analyze","kind":"dispatch"},{"s":"librarian","t":"ingest","kind":"dispatch"},{"s":"librarian","t":"hopper","kind":"dispatch"},{"s":"dreamer","t":"dream","kind":"dispatch"},{"s":"dreamer","t":"dream-distill","kind":"dispatch"},{"s":"dreamer","t":"dream-connect","kind":"dispatch"},{"s":"dreamer","t":"dream-prune","kind":"dispatch"},{"s":"dreamer","t":"dream-synthesize","kind":"dispatch"},{"s":"dreamer","t":"dream-reflect","kind":"dispatch"},{"s":"engineer","t":"piccolo-dev","kind":"dispatch"},{"s":"engineer","t":"piccolissimo-dev","kind":"dispatch"},{"s":"engineer","t":"intonato-dev","kind":"dispatch"},{"s":"engineer","t":"legato-dev","kind":"dispatch"},{"s":"engineer","t":"tdd","kind":"dispatch"},{"s":"engineer","t":"test","kind":"dispatch"},{"s":"engineer","t":"pr","kind":"dispatch"},{"s":"engineer","t":"code-review","kind":"dispatch"},{"s":"engineer","t":"debugging","kind":"dispatch"},{"s":"engineer","t":"verification","kind":"dispatch"},{"s":"orchestrator","t":"using-amico","kind":"dispatch"},{"s":"orchestrator","t":"amico-route","kind":"dispatch"},{"s":"orchestrator","t":"meeting","kind":"dispatch"},{"s":"dispatcher","t":"amico-lab","kind":"dispatch"},{"s":"dispatcher","t":"solve","kind":"dispatch"},{"s":"dispatcher","t":"multistart","kind":"dispatch"},{"s":"piccolo-dev","t":"piccolo-jl","kind":"uses"},{"s":"piccolissimo-dev","t":"piccolissimo-jl","kind":"uses"},{"s":"intonato-dev","t":"intonato-jl","kind":"uses"},{"s":"legato-dev","t":"legato-jl","kind":"uses"},{"s":"solve","t":"piccolo-jl","kind":"uses"},{"s":"solve","t":"piccolissimo-jl","kind":"uses"},{"s":"setup","t":"piccolo-jl","kind":"uses"},{"s":"benchmark","t":"piccolo-jl","kind":"uses"},{"s":"objectives","t":"piccolo-jl","kind":"uses"},{"s":"plot","t":"piccolo-jl","kind":"uses"},{"s":"piccolo-jl","t":"namedtrajectories-jl","kind":"uses"},{"s":"piccolo-jl","t":"directtrajopt-jl","kind":"uses"},{"s":"directtrajopt-jl","t":"namedtrajectories-jl","kind":"uses"},{"s":"piccolissimo-jl","t":"altissimo-jl","kind":"uses"},{"s":"intonato-jl","t":"piccolo-jl","kind":"uses"},{"s":"amico-strategy","t":"strategy","kind":"uses"},{"s":"amico-strategy","t":"roadmap","kind":"uses"},{"s":"using-amico","t":"philosophy","kind":"uses"},{"s":"amico-route","t":"charter-agents-skills","kind":"uses"},{"s":"amico-catalog","t":"charter-pulse-catalog","kind":"uses"},{"s":"dream","t":"charter-research-loop","kind":"uses"},{"s":"dream","t":"dream-distill","kind":"uses"},{"s":"dream","t":"dream-reflect","kind":"uses"},{"s":"dream","t":"dream-connect","kind":"uses"},{"s":"dream","t":"dream-prune","kind":"uses"},{"s":"dream","t":"dream-synthesize","kind":"uses"},{"s":"amico-lab","t":"local-workstation","kind":"uses"},{"s":"amico-lab","t":"hermes","kind":"uses"},{"s":"amico-lab","t":"stanford-fluxonium-chip","kind":"uses"},{"s":"fluxonium","t":"fluxonium-half-flux","kind":"uses"},{"s":"fluxonium","t":"stanford-fluxonium-chip","kind":"uses"},{"s":"transmon","t":"transmon-two-qubit","kind":"uses"},{"s":"atoms","t":"rydberg-global","kind":"uses"},{"s":"setup","t":"method-cold-start","kind":"uses"},{"s":"setup","t":"method-cubic-spline","kind":"uses"},{"s":"amico-catalog","t":"method-warm-start","kind":"uses"},{"s":"structural-analysis","t":"method-presolve-diag","kind":"uses"},{"s":"structural-analysis","t":"insight-stagnation-dominant","kind":"uses"},{"s":"debugging","t":"method-presolve-diag","kind":"uses"},{"s":"multistart","t":"insight-jit-multistart-thrash","kind":"uses"},{"s":"multistart","t":"method-cold-start","kind":"uses"},{"s":"hypothesis-review","t":"hyp-free-phase-gap","kind":"uses"},{"s":"hypothesis-review","t":"hyp-dressed-goal-kets","kind":"uses"},{"s":"hypothesis-review","t":"hyp-augmented-gn","kind":"uses"},{"s":"amico-catalog","t":"pulse-flux-x-v2","kind":"uses"},{"s":"amico-catalog","t":"pulse-flux-y-v3","kind":"uses"},{"s":"amico-catalog","t":"pulse-transmon-cz-v1","kind":"uses"},{"s":"amico-catalog","t":"pulse-transmon-x-v1","kind":"uses"},{"s":"exp-flux-x-194147","t":"insight-linear-over-cubic","kind":"produces"},{"s":"exp-flux-y-q200k","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"exp-flux-y-retry","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"exp-flux-x-021602","t":"insight-warmstart-regression","kind":"produces"},{"s":"exp-flux-y-021602","t":"insight-warmstart-regression","kind":"produces"},{"s":"exp-flux-y-020343","t":"insight-linear51-fix","kind":"produces"},{"s":"exp-flux-y-v3","t":"insight-shorter-duration","kind":"produces"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v3","kind":"produces"},{"s":"exp-flux-y-v3","t":"pulse-flux-y-v3","kind":"produces"},{"s":"exp-flux-t-v3","t":"pulse-flux-t-v3","kind":"produces"},{"s":"exp-rydberg-cz","t":"pulse-rydberg-cz-v1","kind":"produces"},{"s":"ingest","t":"exp-rydberg-cz","kind":"produces"},{"s":"ingest","t":"exp-flux-x-basis-comp","kind":"produces"},{"s":"dream-synthesize","t":"insight-stagnation-dominant","kind":"produces"},{"s":"dream-synthesize","t":"insight-warmstart-taxonomy","kind":"produces"},{"s":"dream-synthesize","t":"insight-coldstart-dominates","kind":"produces"},{"s":"dream-synthesize","t":"insight-free-phase-untried","kind":"produces"},{"s":"dream-distill","t":"insight-jit-multistart-thrash","kind":"produces"},{"s":"dream-distill","t":"hyp-dressed-goal-kets","kind":"produces"},{"s":"analyze","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"researcher","t":"brief-analog-magic","kind":"produces"}],"traces":[{"id":"fluxonium-x-gate","title":"optimize a fluxonium X gate","steps":[{"node":"using-amico","status":"loading using-amico: skill map + conventions","fanout":["amico-route"]},{"node":"brainstorming","status":"clarifying target: X gate, 99.99% fidelity goal","fanout":["objectives","demo"]},{"node":"fluxonium","status":"loading fluxonium hamiltonian + drive selection","fanout":["transmon","stanford-fluxonium-chip"]},{"node":"amico-catalog","status":"warm-start lookup: catalog/pulses/fluxonium-X\u2026","fanout":["pulse-flux-x-v1","charter-pulse-catalog"]},{"node":"pulse-flux-x-v2","status":"found fluxonium-X-v2: best prior pulse","fanout":["pulse-flux-x-v1","pulse-flux-x-v3"]},{"node":"insight-linear-over-cubic","status":"reading insight: linear splines beat cubic","fanout":["insight-linear51-fix","method-cubic-spline"]},{"node":"insight-shorter-duration","status":"checking insight: shorter T0 improves fidelity","fanout":["insight-warmstart-regression"]},{"node":"setup","status":"building SplinePulseProblem: linear, 51 knots","fanout":["method-cold-start","objectives"]},{"node":"piccolo-jl","status":"assembling Piccolo problem + GL4 integrator","fanout":["namedtrajectories-jl","directtrajopt-jl"]},{"node":"solve","status":"solving: iter 120, inf_pr 3.2e-9, fid 99.99%","fanout":["local-workstation"]},{"node":"analyze","status":"analyzing run: no stagnation, clean convergence","fanout":["plot","benchmark"]},{"node":"librarian","status":"dispatching librarian to record results","fanout":["amico-vault"]},{"node":"exp-flux-x-v3","status":"writing experiments/exp-\u2026-fluxonium-X-v3","fanout":["strategy"]},{"node":"amico-catalog","status":"ingesting pulse: fluxonium-X-v3 into catalog","fanout":["pulse-flux-x-v3","ingest"]}]},{"id":"debug-stagnation","title":"debug solver stagnation","steps":[{"node":"debugging","status":"reproducing: inf_pr stuck at 0.289 after 200 it","fanout":["verification"]},{"node":"structural-analysis","status":"predicting: free-phase? warm-start? integrator?","fanout":["method-presolve-diag"]},{"node":"insight-stagnation-dominant","status":"reading synthesis: stagnation dominant failure","fanout":["insight-warmstart-taxonomy","insight-coldstart-dominates"]},{"node":"insight-y-coldstart-variance","status":"matching pattern: Y-gate cold-start variance","fanout":["exp-flux-y-q200k","exp-flux-y-retry"]},{"node":"insight-warmstart-regression","status":"ruling out warm-start regression path","fanout":["exp-flux-x-021602"]},{"node":"multistart","status":"dispatching K=8 parallel cold starts","fanout":["dispatcher","insight-jit-multistart-thrash"]},{"node":"insight-jit-multistart-thrash","status":"checking JIT cache-lock thrash mitigation","fanout":["local-workstation"]},{"node":"piccolissimo-jl","status":"inspecting Piccolissimo GL4 jacobian path","fanout":["altissimo-jl"]},{"node":"solve","status":"re-solving best seed: inf_pr 1.1e-8, converged","fanout":["local-workstation"]},{"node":"verification","status":"verifying fidelity claim against rollout","fanout":["analyze"]}]},{"id":"dream-cycle","title":"dream cycle","steps":[{"node":"dreamer","status":"waking dreamer: nightly consolidation","fanout":["dream"]},{"node":"dream","status":"orchestrating distill, connect, prune, synth","fanout":["charter-research-loop"]},{"node":"dream-distill","status":"distilling 14 session transcripts into notes","fanout":["amico-vault"]},{"node":"dream-reflect","status":"writing retrospectives for solver sessions","fanout":["insight-jit-multistart-thrash"]},{"node":"dream-connect","status":"densifying graph: scanning insights for links","fanout":["insight-linear-over-cubic","insight-shorter-duration","insight-crosstalk","insight-free-phase-2q"]},{"node":"dream-connect","status":"linking exp notes to pulse catalog entries","fanout":["exp-flux-y-v3","exp-flux-t-v3","pulse-flux-y-v3","pulse-flux-t-v3"]},{"node":"dream-connect","status":"cross-linking hypotheses to evidence","fanout":["hyp-free-phase-gap","hyp-augmented-gn","insight-gn-hessian-fails","spec-analytic-derivatives"]},{"node":"dream-prune","status":"resolving TBDs, fixing frontmatter drift","fanout":["exp-flux-y-retry","exp-flux-y-q200k"]},{"node":"dream-synthesize","status":"hunting cross-platform patterns in 40+ runs","fanout":["insight-mintime-2q","insight-eagle-heron","exp-rydberg-cz"]},{"node":"insight-coldstart-dominates","status":"new insight: cold start dominates fluxonium","fanout":["insight-free-phase-untried"]},{"node":"insight-warmstart-taxonomy","status":"new insight: warm-start failure taxonomy","fanout":["insight-stagnation-dominant"]},{"node":"amico-vault","status":"committing vault: 3 new notes, 12 new links","fanout":["librarian"]}]},{"id":"morning-briefing","title":"morning research briefing","steps":[{"node":"amico-strategy","status":"loading current research strategy","fanout":["roadmap"]},{"node":"strategy","status":"reading STRATEGY: P2 fluxonium gate suite","fanout":["philosophy","roadmap"]},{"node":"hypothesis-review","status":"ranking open hypotheses by testability","fanout":["researcher"]},{"node":"hyp-free-phase-gap","status":"checking hyp: free-phase fluxonium gap","fanout":["insight-free-phase-2q"]},{"node":"hyp-dressed-goal-kets","status":"checking hyp: dressed kets unlock 2q gates","fanout":["hyp-augmented-gn"]},{"node":"exp-flux-x-v3","status":"scanning recent runs: X v3 hit 99.99%","fanout":["exp-flux-y-v3","exp-flux-t-v3"]},{"node":"insight-stagnation-dominant","status":"surfacing blocker: stagnation on cold starts","fanout":["multistart"]},{"node":"researcher","status":"drafting briefing with researcher agent","fanout":["amico-vault"]},{"node":"brief-analog-magic","status":"writing research-briefs entry for today","fanout":["strategy"]}]},{"id":"benchmark-rydberg-cz","title":"benchmark a rydberg CZ pulse","steps":[{"node":"using-amico","status":"loading skill map + path conventions","fanout":["amico-route"]},{"node":"atoms","status":"loading rydberg physics: blockade, global drive","fanout":["ions","bosonic"]},{"node":"amico-catalog","status":"warm-start lookup: catalog/pulses/rydberg-CZ-v1","fanout":["pulse-rydberg-cz-v1","pulse-transmon-cz-v1"]},{"node":"exp-rydberg-cz","status":"reading exp: rydberg CZ v1 provenance","fanout":["rydberg-global"]},{"node":"benchmark","status":"recomputing fidelity with current Piccolo","fanout":["piccolo-jl"]},{"node":"piccolo-jl","status":"rebuilding system: rydberg global drive","fanout":["namedtrajectories-jl"]},{"node":"solve","status":"rollout: fidelity matches recorded to 1e-4","fanout":["local-workstation"]},{"node":"plot","status":"plotting pulse + population transfer","fanout":["demo"]},{"node":"amico-vault","status":"appending benchmark table to exp note","fanout":["librarian"]}]}]}
+export const BRAIN_DATA: BrainData = {"nodes":[{"id":"strategy","label":"STRATEGY","type":"charter"},{"id":"philosophy","label":"PHILOSOPHY","type":"charter"},{"id":"roadmap","label":"ROADMAP","type":"charter"},{"id":"charter-research-loop","label":"charter: research loop","type":"charter"},{"id":"charter-pulse-catalog","label":"charter: pulse catalog","type":"charter"},{"id":"charter-agents-skills","label":"charter: agents & skills","type":"charter"},{"id":"insight-linear-over-cubic","label":"insight: linear>cubic spline","type":"insight"},{"id":"insight-linear51-fix","label":"insight: linear51 fix","type":"insight"},{"id":"insight-shorter-duration","label":"insight: shorter T0 helps","type":"insight"},{"id":"insight-warmstart-regression","label":"insight: warmstart regress","type":"insight"},{"id":"insight-y-coldstart-variance","label":"insight: Y coldstart var","type":"insight"},{"id":"insight-crosstalk","label":"insight: drive crosstalk","type":"insight"},{"id":"insight-free-phase-2q","label":"insight: free-phase 2q","type":"insight"},{"id":"insight-gn-hessian-fails","label":"insight: GN Hessian fails","type":"insight"},{"id":"insight-stagnation-dominant","label":"insight: stagnation dominant","type":"insight"},{"id":"insight-jit-multistart-thrash","label":"insight: JIT lock thrash","type":"insight"},{"id":"insight-warmstart-taxonomy","label":"insight: warm-start taxonomy","type":"insight"},{"id":"insight-coldstart-dominates","label":"insight: coldstart dominates","type":"insight"},{"id":"insight-free-phase-untried","label":"insight: free-phase untried","type":"insight"},{"id":"insight-mintime-2q","label":"insight: mintime improves 2q","type":"insight"},{"id":"insight-eagle-heron","label":"insight: eagle-heron OC","type":"insight"},{"id":"exp-flux-x-192727","label":"exp: fluxonium X (192727)","type":"experiment"},{"id":"exp-flux-x-193328","label":"exp: fluxonium X (193328)","type":"experiment"},{"id":"exp-flux-x-194147","label":"exp: fluxonium X (194147)","type":"experiment"},{"id":"exp-flux-y-194147","label":"exp: fluxonium Y","type":"experiment"},{"id":"exp-flux-h-194147","label":"exp: fluxonium H","type":"experiment"},{"id":"exp-flux-t-194147","label":"exp: fluxonium T","type":"experiment"},{"id":"exp-flux-y-020343","label":"exp: fluxonium Y (020343)","type":"experiment"},{"id":"exp-flux-sqrtx-020343","label":"exp: fluxonium sqrtX","type":"experiment"},{"id":"exp-flux-x-021602","label":"exp: fluxonium X (021602)","type":"experiment"},{"id":"exp-flux-y-021602","label":"exp: fluxonium Y (021602)","type":"experiment"},{"id":"exp-flux-x-v3","label":"exp: fluxonium X v3","type":"experiment"},{"id":"exp-flux-y-v3","label":"exp: fluxonium Y v3","type":"experiment"},{"id":"exp-flux-t-v3","label":"exp: fluxonium T v3","type":"experiment"},{"id":"exp-flux-y-q200k","label":"exp: fluxonium Y Q200k","type":"experiment"},{"id":"exp-flux-y-retry","label":"exp: fluxonium Y retry","type":"experiment"},{"id":"exp-rydberg-cz","label":"exp: rydberg CZ v1","type":"experiment"},{"id":"exp-flux-x-basis-comp","label":"exp: X basis comparison","type":"experiment"},{"id":"hyp-free-phase-gap","label":"hyp: free-phase flux gap","type":"note"},{"id":"hyp-dressed-goal-kets","label":"hyp: dressed kets unlock 2q","type":"note"},{"id":"hyp-augmented-gn","label":"hyp: augmented controls GN","type":"note"},{"id":"method-warm-start","label":"method: warm-start workflow","type":"note"},{"id":"method-cold-start","label":"method: cold-start 4-phase","type":"note"},{"id":"method-cubic-spline","label":"method: cubic-spline pulses","type":"note"},{"id":"method-free-phase","label":"method: free-phase 2q gates","type":"note"},{"id":"method-crosstalk-gates","label":"method: crosstalk-robust","type":"note"},{"id":"method-basis-comparison","label":"method: eigen vs fock basis","type":"note"},{"id":"method-presolve-diag","label":"method: pre-solve diag","type":"note"},{"id":"spec-analytic-derivatives","label":"spec: analytic derivatives","type":"note"},{"id":"brief-analog-magic","label":"brief: analog magic states","type":"note"},{"id":"pulse-flux-x-v1","label":"pulse: fluxonium-X-v1","type":"catalog"},{"id":"pulse-flux-x-v2","label":"pulse: fluxonium-X-v2","type":"catalog"},{"id":"pulse-flux-x-v3","label":"pulse: fluxonium-X-v3","type":"catalog"},{"id":"pulse-flux-y-v3","label":"pulse: fluxonium-Y-v3","type":"catalog"},{"id":"pulse-flux-t-v3","label":"pulse: fluxonium-T-v3","type":"catalog"},{"id":"pulse-rydberg-cz-v1","label":"pulse: rydberg-CZ-v1","type":"catalog"},{"id":"pulse-transmon-cz-v1","label":"pulse: transmon-CZ-v1","type":"catalog"},{"id":"pulse-transmon-x-v1","label":"pulse: transmon-X-v1","type":"catalog"},{"id":"local-workstation","label":"local-workstation","type":"resource"},{"id":"stanford-fluxonium-chip","label":"stanford fluxonium chip","type":"resource"},{"id":"hermes","label":"hermes","type":"resource"},{"id":"fluxonium-half-flux","label":"fluxonium @ half flux","type":"resource"},{"id":"transmon-two-qubit","label":"transmon two-qubit","type":"resource"},{"id":"rydberg-global","label":"rydberg global drive","type":"resource"},{"id":"using-amico","label":"using-amico","type":"skill"},{"id":"brainstorming","label":"brainstorming","type":"skill"},{"id":"debugging","label":"debugging","type":"skill"},{"id":"verification","label":"verification","type":"skill"},{"id":"tdd","label":"tdd","type":"skill"},{"id":"code-review","label":"code-review","type":"skill"},{"id":"setup","label":"setup","type":"skill"},{"id":"solve","label":"solve","type":"skill"},{"id":"demo","label":"demo","type":"skill"},{"id":"plot","label":"plot","type":"skill"},{"id":"analyze","label":"analyze","type":"skill"},{"id":"benchmark","label":"benchmark","type":"skill"},{"id":"ingest","label":"ingest","type":"skill"},{"id":"multistart","label":"multistart","type":"skill"},{"id":"objectives","label":"objectives","type":"skill"},{"id":"structural-analysis","label":"structural-analysis","type":"skill"},{"id":"hypothesis-review","label":"hypothesis-review","type":"skill"},{"id":"transmon","label":"transmon","type":"skill"},{"id":"fluxonium","label":"fluxonium","type":"skill"},{"id":"atoms","label":"atoms","type":"skill"},{"id":"ions","label":"ions","type":"skill"},{"id":"bosonic","label":"bosonic","type":"skill"},{"id":"amico-vault","label":"amico-vault","type":"skill"},{"id":"amico-catalog","label":"amico-catalog","type":"skill"},{"id":"amico-lab","label":"amico-lab","type":"skill"},{"id":"amico-strategy","label":"amico-strategy","type":"skill"},{"id":"amico-route","label":"amico-route","type":"skill"},{"id":"piccolo-dev","label":"piccolo-dev","type":"skill"},{"id":"piccolissimo-dev","label":"piccolissimo-dev","type":"skill"},{"id":"intonato-dev","label":"intonato-dev","type":"skill"},{"id":"stretto-dev","label":"stretto-dev","type":"skill"},{"id":"pr","label":"pr","type":"skill"},{"id":"test","label":"test","type":"skill"},{"id":"dream","label":"dream","type":"skill"},{"id":"dream-distill","label":"dream-distill","type":"skill"},{"id":"dream-connect","label":"dream-connect","type":"skill"},{"id":"dream-prune","label":"dream-prune","type":"skill"},{"id":"dream-synthesize","label":"dream-synthesize","type":"skill"},{"id":"dream-reflect","label":"dream-reflect","type":"skill"},{"id":"meeting","label":"meeting","type":"skill"},{"id":"hopper","label":"hopper","type":"skill"},{"id":"researcher","label":"researcher","type":"agent"},{"id":"experimenter","label":"experimenter","type":"agent"},{"id":"orchestrator","label":"orchestrator","type":"agent"},{"id":"dispatcher","label":"dispatcher","type":"agent"},{"id":"librarian","label":"librarian","type":"agent"},{"id":"engineer","label":"engineer","type":"agent"},{"id":"dreamer","label":"dreamer","type":"agent"},{"id":"piccolo-jl","label":"Piccolo.jl","type":"package"},{"id":"piccolissimo-jl","label":"Piccolissimo.jl","type":"package"},{"id":"intonato-jl","label":"Intonato.jl","type":"package"},{"id":"stretto-jl","label":"Stretto.jl","type":"package"},{"id":"namedtrajectories-jl","label":"NamedTrajectories.jl","type":"package"},{"id":"directtrajopt-jl","label":"DirectTrajOpt.jl","type":"package"},{"id":"altissimo-jl","label":"Altissimo.jl","type":"package"}],"edges":[{"s":"insight-linear-over-cubic","t":"exp-flux-x-192727","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"exp-flux-x-194147","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"pulse-flux-x-v1","kind":"wikilink"},{"s":"insight-linear-over-cubic","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-x-194147","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-y-194147","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"insight-linear51-fix","t":"exp-flux-sqrtx-020343","kind":"wikilink"},{"s":"insight-linear51-fix","t":"insight-linear-over-cubic","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-sqrtx-020343","kind":"wikilink"},{"s":"insight-shorter-duration","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-shorter-duration","t":"insight-linear51-fix","kind":"wikilink"},{"s":"insight-warmstart-regression","t":"exp-flux-x-021602","kind":"wikilink"},{"s":"insight-warmstart-regression","t":"exp-flux-y-021602","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-q200k","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-retry","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-y-coldstart-variance","t":"exp-flux-y-021602","kind":"wikilink"},{"s":"insight-crosstalk","t":"insight-eagle-heron","kind":"wikilink"},{"s":"insight-crosstalk","t":"method-crosstalk-gates","kind":"wikilink"},{"s":"insight-free-phase-2q","t":"method-free-phase","kind":"wikilink"},{"s":"insight-free-phase-2q","t":"transmon-two-qubit","kind":"wikilink"},{"s":"insight-gn-hessian-fails","t":"hyp-augmented-gn","kind":"wikilink"},{"s":"insight-gn-hessian-fails","t":"spec-analytic-derivatives","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-h-194147","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-t-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-x-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-q200k","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-retry","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"exp-flux-y-v3","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-y-coldstart-variance","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-warmstart-regression","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-coldstart-dominates","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-free-phase-untried","kind":"wikilink"},{"s":"insight-stagnation-dominant","t":"insight-warmstart-taxonomy","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"strategy","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"exp-flux-x-192727","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"exp-flux-x-193328","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"pulse-flux-x-v1","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-194147","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v2","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v3","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"exp-flux-y-194147","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"exp-flux-y-020343","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"pulse-flux-y-v3","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-y-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"strategy","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"exp-flux-t-194147","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"pulse-flux-t-v3","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-t-v3","t":"local-workstation","kind":"wikilink"},{"s":"exp-rydberg-cz","t":"pulse-rydberg-cz-v1","kind":"wikilink"},{"s":"exp-rydberg-cz","t":"rydberg-global","kind":"wikilink"},{"s":"exp-flux-x-basis-comp","t":"fluxonium-half-flux","kind":"wikilink"},{"s":"exp-flux-x-basis-comp","t":"method-basis-comparison","kind":"wikilink"},{"s":"hyp-free-phase-gap","t":"insight-free-phase-2q","kind":"wikilink"},{"s":"researcher","t":"amico-strategy","kind":"dispatch"},{"s":"researcher","t":"hypothesis-review","kind":"dispatch"},{"s":"researcher","t":"structural-analysis","kind":"dispatch"},{"s":"researcher","t":"brainstorming","kind":"dispatch"},{"s":"researcher","t":"objectives","kind":"dispatch"},{"s":"experimenter","t":"setup","kind":"dispatch"},{"s":"experimenter","t":"solve","kind":"dispatch"},{"s":"experimenter","t":"transmon","kind":"dispatch"},{"s":"experimenter","t":"fluxonium","kind":"dispatch"},{"s":"experimenter","t":"atoms","kind":"dispatch"},{"s":"experimenter","t":"ions","kind":"dispatch"},{"s":"experimenter","t":"bosonic","kind":"dispatch"},{"s":"experimenter","t":"multistart","kind":"dispatch"},{"s":"experimenter","t":"benchmark","kind":"dispatch"},{"s":"experimenter","t":"demo","kind":"dispatch"},{"s":"experimenter","t":"plot","kind":"dispatch"},{"s":"librarian","t":"amico-vault","kind":"dispatch"},{"s":"librarian","t":"amico-catalog","kind":"dispatch"},{"s":"librarian","t":"analyze","kind":"dispatch"},{"s":"librarian","t":"ingest","kind":"dispatch"},{"s":"librarian","t":"hopper","kind":"dispatch"},{"s":"dreamer","t":"dream","kind":"dispatch"},{"s":"dreamer","t":"dream-distill","kind":"dispatch"},{"s":"dreamer","t":"dream-connect","kind":"dispatch"},{"s":"dreamer","t":"dream-prune","kind":"dispatch"},{"s":"dreamer","t":"dream-synthesize","kind":"dispatch"},{"s":"dreamer","t":"dream-reflect","kind":"dispatch"},{"s":"engineer","t":"piccolo-dev","kind":"dispatch"},{"s":"engineer","t":"piccolissimo-dev","kind":"dispatch"},{"s":"engineer","t":"intonato-dev","kind":"dispatch"},{"s":"engineer","t":"stretto-dev","kind":"dispatch"},{"s":"engineer","t":"tdd","kind":"dispatch"},{"s":"engineer","t":"test","kind":"dispatch"},{"s":"engineer","t":"pr","kind":"dispatch"},{"s":"engineer","t":"code-review","kind":"dispatch"},{"s":"engineer","t":"debugging","kind":"dispatch"},{"s":"engineer","t":"verification","kind":"dispatch"},{"s":"orchestrator","t":"using-amico","kind":"dispatch"},{"s":"orchestrator","t":"amico-route","kind":"dispatch"},{"s":"orchestrator","t":"meeting","kind":"dispatch"},{"s":"dispatcher","t":"amico-lab","kind":"dispatch"},{"s":"dispatcher","t":"solve","kind":"dispatch"},{"s":"dispatcher","t":"multistart","kind":"dispatch"},{"s":"piccolo-dev","t":"piccolo-jl","kind":"uses"},{"s":"piccolissimo-dev","t":"piccolissimo-jl","kind":"uses"},{"s":"intonato-dev","t":"intonato-jl","kind":"uses"},{"s":"stretto-dev","t":"stretto-jl","kind":"uses"},{"s":"solve","t":"piccolo-jl","kind":"uses"},{"s":"solve","t":"piccolissimo-jl","kind":"uses"},{"s":"setup","t":"piccolo-jl","kind":"uses"},{"s":"benchmark","t":"piccolo-jl","kind":"uses"},{"s":"objectives","t":"piccolo-jl","kind":"uses"},{"s":"plot","t":"piccolo-jl","kind":"uses"},{"s":"piccolo-jl","t":"namedtrajectories-jl","kind":"uses"},{"s":"piccolo-jl","t":"directtrajopt-jl","kind":"uses"},{"s":"directtrajopt-jl","t":"namedtrajectories-jl","kind":"uses"},{"s":"piccolissimo-jl","t":"altissimo-jl","kind":"uses"},{"s":"intonato-jl","t":"piccolo-jl","kind":"uses"},{"s":"amico-strategy","t":"strategy","kind":"uses"},{"s":"amico-strategy","t":"roadmap","kind":"uses"},{"s":"using-amico","t":"philosophy","kind":"uses"},{"s":"amico-route","t":"charter-agents-skills","kind":"uses"},{"s":"amico-catalog","t":"charter-pulse-catalog","kind":"uses"},{"s":"dream","t":"charter-research-loop","kind":"uses"},{"s":"dream","t":"dream-distill","kind":"uses"},{"s":"dream","t":"dream-reflect","kind":"uses"},{"s":"dream","t":"dream-connect","kind":"uses"},{"s":"dream","t":"dream-prune","kind":"uses"},{"s":"dream","t":"dream-synthesize","kind":"uses"},{"s":"amico-lab","t":"local-workstation","kind":"uses"},{"s":"amico-lab","t":"hermes","kind":"uses"},{"s":"amico-lab","t":"stanford-fluxonium-chip","kind":"uses"},{"s":"fluxonium","t":"fluxonium-half-flux","kind":"uses"},{"s":"fluxonium","t":"stanford-fluxonium-chip","kind":"uses"},{"s":"transmon","t":"transmon-two-qubit","kind":"uses"},{"s":"atoms","t":"rydberg-global","kind":"uses"},{"s":"setup","t":"method-cold-start","kind":"uses"},{"s":"setup","t":"method-cubic-spline","kind":"uses"},{"s":"amico-catalog","t":"method-warm-start","kind":"uses"},{"s":"structural-analysis","t":"method-presolve-diag","kind":"uses"},{"s":"structural-analysis","t":"insight-stagnation-dominant","kind":"uses"},{"s":"debugging","t":"method-presolve-diag","kind":"uses"},{"s":"multistart","t":"insight-jit-multistart-thrash","kind":"uses"},{"s":"multistart","t":"method-cold-start","kind":"uses"},{"s":"hypothesis-review","t":"hyp-free-phase-gap","kind":"uses"},{"s":"hypothesis-review","t":"hyp-dressed-goal-kets","kind":"uses"},{"s":"hypothesis-review","t":"hyp-augmented-gn","kind":"uses"},{"s":"amico-catalog","t":"pulse-flux-x-v2","kind":"uses"},{"s":"amico-catalog","t":"pulse-flux-y-v3","kind":"uses"},{"s":"amico-catalog","t":"pulse-transmon-cz-v1","kind":"uses"},{"s":"amico-catalog","t":"pulse-transmon-x-v1","kind":"uses"},{"s":"exp-flux-x-194147","t":"insight-linear-over-cubic","kind":"produces"},{"s":"exp-flux-y-q200k","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"exp-flux-y-retry","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"exp-flux-x-021602","t":"insight-warmstart-regression","kind":"produces"},{"s":"exp-flux-y-021602","t":"insight-warmstart-regression","kind":"produces"},{"s":"exp-flux-y-020343","t":"insight-linear51-fix","kind":"produces"},{"s":"exp-flux-y-v3","t":"insight-shorter-duration","kind":"produces"},{"s":"exp-flux-x-v3","t":"pulse-flux-x-v3","kind":"produces"},{"s":"exp-flux-y-v3","t":"pulse-flux-y-v3","kind":"produces"},{"s":"exp-flux-t-v3","t":"pulse-flux-t-v3","kind":"produces"},{"s":"exp-rydberg-cz","t":"pulse-rydberg-cz-v1","kind":"produces"},{"s":"ingest","t":"exp-rydberg-cz","kind":"produces"},{"s":"ingest","t":"exp-flux-x-basis-comp","kind":"produces"},{"s":"dream-synthesize","t":"insight-stagnation-dominant","kind":"produces"},{"s":"dream-synthesize","t":"insight-warmstart-taxonomy","kind":"produces"},{"s":"dream-synthesize","t":"insight-coldstart-dominates","kind":"produces"},{"s":"dream-synthesize","t":"insight-free-phase-untried","kind":"produces"},{"s":"dream-distill","t":"insight-jit-multistart-thrash","kind":"produces"},{"s":"dream-distill","t":"hyp-dressed-goal-kets","kind":"produces"},{"s":"analyze","t":"insight-y-coldstart-variance","kind":"produces"},{"s":"researcher","t":"brief-analog-magic","kind":"produces"}],"traces":[{"id":"fluxonium-x-gate","title":"optimize a fluxonium X gate","steps":[{"node":"using-amico","status":"loading using-amico: skill map + conventions","fanout":["amico-route"]},{"node":"brainstorming","status":"clarifying target: X gate, 99.99% fidelity goal","fanout":["objectives","demo"]},{"node":"fluxonium","status":"loading fluxonium hamiltonian + drive selection","fanout":["transmon","stanford-fluxonium-chip"]},{"node":"amico-catalog","status":"warm-start lookup: catalog/pulses/fluxonium-X\u2026","fanout":["pulse-flux-x-v1","charter-pulse-catalog"]},{"node":"pulse-flux-x-v2","status":"found fluxonium-X-v2: best prior pulse","fanout":["pulse-flux-x-v1","pulse-flux-x-v3"]},{"node":"insight-linear-over-cubic","status":"reading insight: linear splines beat cubic","fanout":["insight-linear51-fix","method-cubic-spline"]},{"node":"insight-shorter-duration","status":"checking insight: shorter T0 improves fidelity","fanout":["insight-warmstart-regression"]},{"node":"setup","status":"building SplinePulseProblem: linear, 51 knots","fanout":["method-cold-start","objectives"]},{"node":"piccolo-jl","status":"assembling Piccolo problem + GL4 integrator","fanout":["namedtrajectories-jl","directtrajopt-jl"]},{"node":"solve","status":"solving: iter 120, inf_pr 3.2e-9, fid 99.99%","fanout":["local-workstation"]},{"node":"analyze","status":"analyzing run: no stagnation, clean convergence","fanout":["plot","benchmark"]},{"node":"librarian","status":"dispatching librarian to record results","fanout":["amico-vault"]},{"node":"exp-flux-x-v3","status":"writing experiments/exp-\u2026-fluxonium-X-v3","fanout":["strategy"]},{"node":"amico-catalog","status":"ingesting pulse: fluxonium-X-v3 into catalog","fanout":["pulse-flux-x-v3","ingest"]}]},{"id":"debug-stagnation","title":"debug solver stagnation","steps":[{"node":"debugging","status":"reproducing: inf_pr stuck at 0.289 after 200 it","fanout":["verification"]},{"node":"structural-analysis","status":"predicting: free-phase? warm-start? integrator?","fanout":["method-presolve-diag"]},{"node":"insight-stagnation-dominant","status":"reading synthesis: stagnation dominant failure","fanout":["insight-warmstart-taxonomy","insight-coldstart-dominates"]},{"node":"insight-y-coldstart-variance","status":"matching pattern: Y-gate cold-start variance","fanout":["exp-flux-y-q200k","exp-flux-y-retry"]},{"node":"insight-warmstart-regression","status":"ruling out warm-start regression path","fanout":["exp-flux-x-021602"]},{"node":"multistart","status":"dispatching K=8 parallel cold starts","fanout":["dispatcher","insight-jit-multistart-thrash"]},{"node":"insight-jit-multistart-thrash","status":"checking JIT cache-lock thrash mitigation","fanout":["local-workstation"]},{"node":"piccolissimo-jl","status":"inspecting Piccolissimo GL4 jacobian path","fanout":["altissimo-jl"]},{"node":"solve","status":"re-solving best seed: inf_pr 1.1e-8, converged","fanout":["local-workstation"]},{"node":"verification","status":"verifying fidelity claim against rollout","fanout":["analyze"]}]},{"id":"dream-cycle","title":"dream cycle","steps":[{"node":"dreamer","status":"waking dreamer: nightly consolidation","fanout":["dream"]},{"node":"dream","status":"orchestrating distill, connect, prune, synth","fanout":["charter-research-loop"]},{"node":"dream-distill","status":"distilling 14 session transcripts into notes","fanout":["amico-vault"]},{"node":"dream-reflect","status":"writing retrospectives for solver sessions","fanout":["insight-jit-multistart-thrash"]},{"node":"dream-connect","status":"densifying graph: scanning insights for links","fanout":["insight-linear-over-cubic","insight-shorter-duration","insight-crosstalk","insight-free-phase-2q"]},{"node":"dream-connect","status":"linking exp notes to pulse catalog entries","fanout":["exp-flux-y-v3","exp-flux-t-v3","pulse-flux-y-v3","pulse-flux-t-v3"]},{"node":"dream-connect","status":"cross-linking hypotheses to evidence","fanout":["hyp-free-phase-gap","hyp-augmented-gn","insight-gn-hessian-fails","spec-analytic-derivatives"]},{"node":"dream-prune","status":"resolving TBDs, fixing frontmatter drift","fanout":["exp-flux-y-retry","exp-flux-y-q200k"]},{"node":"dream-synthesize","status":"hunting cross-platform patterns in 40+ runs","fanout":["insight-mintime-2q","insight-eagle-heron","exp-rydberg-cz"]},{"node":"insight-coldstart-dominates","status":"new insight: cold start dominates fluxonium","fanout":["insight-free-phase-untried"]},{"node":"insight-warmstart-taxonomy","status":"new insight: warm-start failure taxonomy","fanout":["insight-stagnation-dominant"]},{"node":"amico-vault","status":"committing vault: 3 new notes, 12 new links","fanout":["librarian"]}]},{"id":"morning-briefing","title":"morning research briefing","steps":[{"node":"amico-strategy","status":"loading current research strategy","fanout":["roadmap"]},{"node":"strategy","status":"reading STRATEGY: P2 fluxonium gate suite","fanout":["philosophy","roadmap"]},{"node":"hypothesis-review","status":"ranking open hypotheses by testability","fanout":["researcher"]},{"node":"hyp-free-phase-gap","status":"checking hyp: free-phase fluxonium gap","fanout":["insight-free-phase-2q"]},{"node":"hyp-dressed-goal-kets","status":"checking hyp: dressed kets unlock 2q gates","fanout":["hyp-augmented-gn"]},{"node":"exp-flux-x-v3","status":"scanning recent runs: X v3 hit 99.99%","fanout":["exp-flux-y-v3","exp-flux-t-v3"]},{"node":"insight-stagnation-dominant","status":"surfacing blocker: stagnation on cold starts","fanout":["multistart"]},{"node":"researcher","status":"drafting briefing with researcher agent","fanout":["amico-vault"]},{"node":"brief-analog-magic","status":"writing research-briefs entry for today","fanout":["strategy"]}]},{"id":"benchmark-rydberg-cz","title":"benchmark a rydberg CZ pulse","steps":[{"node":"using-amico","status":"loading skill map + path conventions","fanout":["amico-route"]},{"node":"atoms","status":"loading rydberg physics: blockade, global drive","fanout":["ions","bosonic"]},{"node":"amico-catalog","status":"warm-start lookup: catalog/pulses/rydberg-CZ-v1","fanout":["pulse-rydberg-cz-v1","pulse-transmon-cz-v1"]},{"node":"exp-rydberg-cz","status":"reading exp: rydberg CZ v1 provenance","fanout":["rydberg-global"]},{"node":"benchmark","status":"recomputing fidelity with current Piccolo","fanout":["piccolo-jl"]},{"node":"piccolo-jl","status":"rebuilding system: rydberg global drive","fanout":["namedtrajectories-jl"]},{"node":"solve","status":"rollout: fidelity matches recorded to 1e-4","fanout":["local-workstation"]},{"node":"plot","status":"plotting pulse + population transfer","fanout":["demo"]},{"node":"amico-vault","status":"appending benchmark table to exp note","fanout":["librarian"]}]}]}
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/card.tsx b/packages/app-bundle/overlay/packages/ui/src/amicode/card.tsx
index c8fc6072..932f4d15 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/card.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/card.tsx
@@ -9,7 +9,6 @@ import { parseDiffSentinel, receiptParts, INLINE_KINDS } from "./receipt"
import { receiptIsCurrent } from "./receipt-currency"
import { systemReceiptPieces, formulationReceiptPieces } from "./facets"
import { compositeChip, chipText } from "./problem"
-import { AmicoMark } from "./spinner"
import {
openAmicodeEntity,
amicodeProblemView,
@@ -118,14 +117,15 @@ function Chip(props: { tool: string; status?: string; output?: string; count?: n
// (
) shells. Split so the shell can be a real button only when there is
// an entity to open — a bare
@@ -278,8 +276,7 @@ function Chip(props: { tool: string; status?: string; output?: string; count?: n
export function AmicoSkillChip(props: { kind: string; name?: string; status?: string; path?: string }) {
const running = () => props.status === "pending" || props.status === "running"
const errored = () => props.status === "error" || props.status === "failed"
- const state = () =>
- errored() ? "error" : running() ? "running" : props.status === "completed" ? "done" : "idle"
+ const state = () => (errored() ? "error" : running() ? "running" : props.status === "completed" ? "done" : "idle")
const open = (event: MouseEvent) => {
event.preventDefault()
@@ -289,10 +286,6 @@ export function AmicoSkillChip(props: { kind: string; name?: string; status?: st
const inner = (
<>
-
-
-
-
{props.kind}
@@ -303,24 +296,19 @@ export function AmicoSkillChip(props: { kind: string; name?: string; status?: st
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
>
)
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.test.ts b/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.test.ts
index 51ef1222..5e342488 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.test.ts
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"
-import { buildContextTree, contextKind, vaultNodeLocked, vaultRefFromPath, type ContextTurn } from "./context-tree-data"
+import { buildContextTree, contextKind, vaultRefFromPath, type ContextTurn } from "./context-tree-data"
const turn = (id: string, refs: ContextTurn["refs"], busy = false): ContextTurn => ({
id,
@@ -28,35 +28,6 @@ describe("vaultRefFromPath", () => {
})
})
-// amicode#447: a vault path names the mount by its DIRECTORY segment, which
-// the /amicode/vaults wire may key differently (marker `name`) — the lock
-// decision must reconcile through the wire's dirName before failing closed.
-describe("vaultNodeLocked", () => {
- const mounts = [
- { id: "aaron", browsable: true, dirName: "armonia-aaron-trowbridge" },
- { id: "armonissima", browsable: false, dirName: "armonissima" },
- ]
-
- test("dir≠name mounts unlock through their dirName identity", () => {
- expect(vaultNodeLocked({ mounts, vaultDir: "armonia-aaron-trowbridge" })).toBe(false)
- })
-
- test("non-browsable mounts lock through either identity; unknown locks", () => {
- expect(vaultNodeLocked({ mounts, vaultDir: "armonissima" })).toBe(true)
- expect(vaultNodeLocked({ mounts, vaultDir: "secret-mount" })).toBe(true)
- })
-
- test("an id-keyed wire without dirName still locks/unlocks by id", () => {
- const legacy = [{ id: "armonissima", browsable: false }]
- expect(vaultNodeLocked({ mounts: legacy, vaultDir: "armonissima" })).toBe(true)
- expect(vaultNodeLocked({ mounts: legacy, vaultDir: "armonia-aaron-trowbridge" })).toBe(true) // unknown → fail closed
- })
-
- test("no wire data never locks — the server still enforces the real gate", () => {
- expect(vaultNodeLocked({ mounts: undefined, vaultDir: "armonia-aaron-trowbridge" })).toBe(false)
- })
-})
-
describe("buildContextTree", () => {
test("root → turns → leaves; roman numerals only — never prompt text", () => {
const tree = buildContextTree([
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.ts b/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.ts
index 0caa032b..25ee6739 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.ts
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/context-tree-data.ts
@@ -54,43 +54,13 @@ export function contextKind(ref: ContextRef): ContextTreeKind {
}
/** A path inside an attached vault mount → {mount, rel} so the host can open
- * it through the Vault panel instead of a project file tab. The mount here is
- * the vault's DIRECTORY identity (the path segment), which the /amicode/vaults
- * wire may key differently (marker `name`) — resolve through vaultNodeLocked
- * / the wire's dirName before treating it as a mount id (amicode#447). */
+ * it through the Vault panel instead of a project file tab. */
export function vaultRefFromPath(path: string): { mount: string; rel: string } | undefined {
const m = path.match(/\/\.amico\/vaults\/([^/]+)\/(.+)$/)
if (m) return { mount: m[1], rel: m[2] }
return undefined
}
-/** One mount on the /amicode/vaults wire: the marker-name `id`, whether the
- * mount allows browsing, and the DIRECTORY identity its file paths carry
- * (emitted by the server since amicode#447). */
-export type VaultMountStatus = { id: string; browsable?: boolean; dirName?: string }
-
-/** The click-lock decision for a vault node in the context tree (the
- * Obsidian-style knowledge graph). `vaultDir` is the identity the node's path
- * carries (vaultRefFromPath: the vault directory segment), which may differ
- * from the marker-name id the wire keys — reconcile through `dirName` first,
- * then by id. A mount known to refuse browsing locks, an identity no wire
- * mount claims locks (fail-closed — a proprietary mount we can't see), and
- * NO wire data at all doesn't (the fetch failed; the server still enforces
- * the real gate, so a click may try). */
-export function vaultNodeLocked(input: {
- mounts: readonly VaultMountStatus[] | undefined
- vaultDir: string
-}): boolean {
- const list = input.mounts
- if (!list) return false
- const byDir = new Map(
- list.filter((m) => typeof m.dirName === "string" && m.dirName).map((m) => [m.dirName as string, m]),
- )
- const mount = byDir.get(input.vaultDir) ?? list.find((m) => m.id === input.vaultDir)
- if (!mount) return true
- return mount.browsable === false
-}
-
const dedupKey = (ref: ContextRef, kind: ContextTreeKind) =>
ref.path ? `p:${ref.path}` : `${kind}:${ref.label.toLowerCase()}`
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/entity-rail.tsx b/packages/app-bundle/overlay/packages/ui/src/amicode/entity-rail.tsx
index 5bd5a475..fc6e61c8 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/entity-rail.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/entity-rail.tsx
@@ -44,9 +44,9 @@ const RUN_POLL_MS = 2500
function pendingHint(kind: string): string {
switch (kind) {
case "pulse":
- return "No result artifact yet — a completed run produces one"
+ return "No pulse banked yet — a completed run produces one"
case "device_session":
- return "No device session yet — appears when a result targets hardware"
+ return "No device session yet — appears when a pulse targets hardware"
case "run":
return "No run yet — solve the formulation to create one"
case "formulation":
@@ -205,7 +205,7 @@ export function AmicodeEntityRail(props: {
if (snapshot.kind !== "ready") return []
return mergeChips(snapshot.view.entities, snapshot.view.scoreStages)
})
- // Which chips hand off to the Run Inspector instead of the entity dialog.
+ // Which chips hand off to the Pulse Inspector instead of the entity dialog.
// Only the pulse chip, and only when the host actually wired an inspector —
// standalone opencode has none, so there the chip keeps its dialog behavior.
// The pulse chip is the ONLY inspector entry on the rail — the separate
@@ -252,7 +252,7 @@ export function AmicodeEntityRail(props: {
{(chip) => (
@@ -344,7 +344,7 @@ export function AmicodeEntityRail(props: {
"font-weight": "600",
cursor: "pointer",
}}
- title="Open the Run Inspector panel"
+ title="Open the Pulse Inspector panel"
onClick={() => props.onInspectRun?.()}
>
Inspect Run
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-dot.tsx b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-dot.tsx
new file mode 100644
index 00000000..ce5161fd
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-dot.tsx
@@ -0,0 +1,84 @@
+// packages/ui/src/amicode/harmonic-dot.tsx
+// AMICODE: the spherical-harmonic morphing dot — shown on the thought rail's active
+// (running) node. Cycles through Y_l^m silhouettes with a pulse rhythm:
+// sphere → shape → sphere → shape → ... (the sphere is home base).
+//
+// DONUT PATH: A single filled path using fill-rule="evenodd" — the outer contour
+// draws the harmonic shape clockwise, an inner contour draws a circle counter-
+// clockwise to punch the hole. When the inner radius is 0, the hole collapses
+// and the shape is solid. SMIL interpolates between donut (ring) and solid
+// (harmonic) point-by-point — the ring smoothly closes as the shape blooms.
+//
+// A background circle sits BEHIND the donut path (but inside the SVG) to mask
+// the rail line that runs behind the SVG element. Without it, the line would
+// show through the evenodd hole. The circle matches INNER_R so it exactly fills
+// the ring's interior during the sphere state and shrinks with it during morphs.
+//
+// RANDOMIZED: each mount picks fresh random rotation angles.
+// Under prefers-reduced-motion the SMIL animates are hidden — static ring.
+
+import { type ComponentProps } from "solid-js"
+import {
+ HARMONIC_SIZE,
+ INNER_R,
+ CIRCLE_DONUT_PATH,
+ randomPulseSequence,
+ buildSmil,
+} from "./harmonic-geometry"
+
+export function HarmonicDot(props: {
+ class?: string
+ style?: ComponentProps<"svg">["style"]
+}) {
+ const sequence = randomPulseSequence()
+ const smil = buildSmil(sequence)
+
+ return (
+
+ )
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.test.ts b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.test.ts
new file mode 100644
index 00000000..fb5ef69f
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.test.ts
@@ -0,0 +1,365 @@
+// packages/ui/src/amicode/harmonic-geometry.test.ts
+import { describe, expect, test } from "bun:test"
+import {
+ HARMONIC_SIZE,
+ HARMONIC_SAMPLES,
+ SPHERE_HOLD_MS,
+ MORPH_MS,
+ SHAPE_HOLD_MS,
+ PULSE_MS,
+ PULSE_COUNT,
+ CYCLE_MS,
+ MODE_COUNT,
+ HARMONIC_PATHS,
+ CIRCLE_PATH,
+ CIRCLE_DONUT_PATH,
+ PULSE_PATHS,
+ PULSE_DONUT_PATHS,
+ PULSE_SEQUENCE,
+ PULSE_MODES,
+ SMIL,
+ harmonicRadius,
+ harmonicPath,
+ randomPulseSequence,
+ buildSmil,
+} from "./harmonic-geometry"
+
+describe("constants", () => {
+ test("HARMONIC_SIZE is 13px — fits inside the 24px content gutter", () => {
+ expect(HARMONIC_SIZE).toBe(13)
+ })
+
+ test("HARMONIC_SAMPLES is 64 — enough for smooth curves at 13px", () => {
+ expect(HARMONIC_SAMPLES).toBe(64)
+ })
+
+ test("MODE_COUNT is 8 — circle + 7 shapes (dumbbell kept but constrained)", () => {
+ expect(MODE_COUNT).toBe(8)
+ })
+})
+
+describe("pulse timing", () => {
+ test("one pulse is sphere-hold + morph-out + shape-hold + morph-back", () => {
+ expect(PULSE_MS).toBe(SPHERE_HOLD_MS + MORPH_MS + SHAPE_HOLD_MS + MORPH_MS)
+ })
+
+ test("pulse timing is ~1.2s (snappy, energetic)", () => {
+ expect(PULSE_MS).toBe(1200)
+ })
+
+ test("full cycle is 10 pulses = 12s", () => {
+ expect(CYCLE_MS).toBe(PULSE_MS * PULSE_COUNT)
+ expect(CYCLE_MS).toBe(12000)
+ })
+
+ test("timing breakdown: 350 + 175 + 500 + 175 = 1200", () => {
+ expect(SPHERE_HOLD_MS).toBe(350)
+ expect(MORPH_MS).toBe(175)
+ expect(SHAPE_HOLD_MS).toBe(500)
+ })
+})
+
+describe("harmonicRadius", () => {
+ test("mode 0 is a circle — constant radius at all angles", () => {
+ const radii = Array.from({ length: 64 }, (_, i) => harmonicRadius(0, (i / 64) * 2 * Math.PI))
+ const first = radii[0]
+ for (const r of radii) {
+ expect(r).toBeCloseTo(first, 6)
+ }
+ })
+
+ test("mode 1 (dumbbell) has maxima at 0 and pi, minima at pi/2 and 3pi/2", () => {
+ const top = harmonicRadius(1, 0)
+ const bottom = harmonicRadius(1, Math.PI)
+ const side = harmonicRadius(1, Math.PI / 2)
+ expect(top).toBeCloseTo(bottom, 4)
+ expect(top).toBeGreaterThan(side)
+ })
+
+ test("mode 2 (pinched) has distinct shape from mode 1", () => {
+ const r2_side = harmonicRadius(2, Math.PI / 2)
+ const r1_side = harmonicRadius(1, Math.PI / 2)
+ expect(r2_side).not.toBeCloseTo(r1_side, 2)
+ })
+
+ test("mode 3 (clover) has four-fold symmetry", () => {
+ // |cos(2θ)| has lobes at 0, π/2, π, 3π/2 and nodes at π/4, 3π/4, etc.
+ const r0 = harmonicRadius(3, 0)
+ const r90 = harmonicRadius(3, Math.PI / 2)
+ const r180 = harmonicRadius(3, Math.PI)
+ const r270 = harmonicRadius(3, 3 * Math.PI / 2)
+ // Four-fold symmetry: all cardinal directions equal
+ expect(r0).toBeCloseTo(r90, 4)
+ expect(r90).toBeCloseTo(r180, 4)
+ expect(r180).toBeCloseTo(r270, 4)
+ // Nodes at 45° are smaller than lobes at 0°
+ const node = harmonicRadius(3, Math.PI / 4)
+ expect(r0).toBeGreaterThan(node)
+ })
+
+ test("mode 4 (rosette) has six-fold symmetry", () => {
+ // |cos(3θ)| has 6 lobes at 0, 60°, 120°, 180°, 240°, 300°
+ const r0 = harmonicRadius(4, 0)
+ const r60 = harmonicRadius(4, Math.PI / 3)
+ const r120 = harmonicRadius(4, 2 * Math.PI / 3)
+ expect(r0).toBeCloseTo(r60, 4)
+ expect(r60).toBeCloseTo(r120, 4)
+ // Nodes at 30°
+ const node = harmonicRadius(4, Math.PI / 6)
+ expect(r0).toBeGreaterThan(node)
+ })
+
+ test("mode 6 (star-8) has eight-fold symmetry", () => {
+ // |cos(4θ)| has 8 lobes at 0, 45°, 90°, 135°, etc.
+ const r0 = harmonicRadius(6, 0)
+ const r45 = harmonicRadius(6, Math.PI / 4)
+ const r90 = harmonicRadius(6, Math.PI / 2)
+ expect(r0).toBeCloseTo(r45, 4)
+ expect(r45).toBeCloseTo(r90, 4)
+ // Nodes at 22.5°
+ const node = harmonicRadius(6, Math.PI / 8)
+ expect(r0).toBeGreaterThan(node)
+ })
+
+ test("mode 7 (double pinch) has two-fold symmetry with multiple lobes", () => {
+ // |P_4^0(cosθ)| — symmetric about both axes, with 4 lobes along polar axis
+ const r0 = harmonicRadius(7, 0)
+ const rPi = harmonicRadius(7, Math.PI)
+ const r90 = harmonicRadius(7, Math.PI / 2)
+ expect(r0).toBeCloseTo(rPi, 4)
+ expect(r90).toBeGreaterThan(0.2)
+ const rNode = harmonicRadius(7, Math.PI * 30.6 / 180)
+ expect(r0).toBeGreaterThan(rNode)
+ expect(r90).toBeGreaterThan(rNode)
+ })
+
+ test("all modes have radii in (0, 1] — never zero, never exceeds unit", () => {
+ for (let mode = 0; mode < MODE_COUNT; mode++) {
+ for (let i = 0; i < 256; i++) {
+ const theta = (i / 256) * 2 * Math.PI
+ const r = harmonicRadius(mode, theta)
+ expect(r).toBeGreaterThan(0)
+ expect(r).toBeLessThanOrEqual(1.0001)
+ }
+ }
+ })
+})
+
+describe("harmonicPath", () => {
+ test("produces a closed SVG path starting with M and ending with Z", () => {
+ for (let mode = 0; mode < MODE_COUNT; mode++) {
+ const path = harmonicPath(mode)
+ expect(path.startsWith("M")).toBe(true)
+ expect(path.endsWith("Z")).toBe(true)
+ }
+ })
+
+ test("all modes produce paths with HARMONIC_SAMPLES - 1 L commands", () => {
+ for (let mode = 0; mode < MODE_COUNT; mode++) {
+ const path = harmonicPath(mode)
+ expect((path.match(/L/g) || []).length).toBe(HARMONIC_SAMPLES - 1)
+ }
+ })
+
+ test("identical command structure across modes — required for SMIL interpolation", () => {
+ const structures = Array.from({ length: MODE_COUNT }, (_, mode) =>
+ harmonicPath(mode).replace(/[-\d.,\s]/g, ""),
+ )
+ for (const struct of structures) {
+ expect(struct).toBe(structures[0])
+ }
+ })
+
+ test("all coordinates stay within the viewBox (0, 0, SIZE, SIZE)", () => {
+ for (let mode = 0; mode < MODE_COUNT; mode++) {
+ const coords = harmonicPath(mode).match(/-?[\d.]+/g)!.map(Number)
+ for (const c of coords) {
+ expect(c).toBeGreaterThanOrEqual(-0.01)
+ expect(c).toBeLessThanOrEqual(HARMONIC_SIZE + 0.01)
+ }
+ }
+ })
+
+ test("rotation shifts the shape without changing structure", () => {
+ const p0 = harmonicPath(1, 0)
+ const p90 = harmonicPath(1, 90)
+ // Same structure (command letters)
+ expect(p90.replace(/[-\d.,\s]/g, "")).toBe(p0.replace(/[-\d.,\s]/g, ""))
+ // But different coordinates (the dumbbell is rotated)
+ expect(p90).not.toBe(p0)
+ })
+
+ test("rotation by 0° gives the same path as no rotation", () => {
+ expect(harmonicPath(1, 0)).toBe(harmonicPath(1))
+ })
+
+ test("circle is invariant under rotation (mode 0)", () => {
+ expect(harmonicPath(0, 0)).toBe(harmonicPath(0, 45))
+ expect(harmonicPath(0, 0)).toBe(harmonicPath(0, 90))
+ })
+})
+
+describe("pulse sequence", () => {
+ test("has PULSE_COUNT entries", () => {
+ expect(PULSE_SEQUENCE).toHaveLength(PULSE_COUNT)
+ })
+
+ test("uses modes 1–6 only (never circle as a pulse shape)", () => {
+ for (const { mode } of PULSE_SEQUENCE) {
+ expect(mode).toBeGreaterThanOrEqual(1)
+ expect(mode).toBeLessThan(MODE_COUNT)
+ }
+ })
+
+ test("skinny shapes (modes 1, 2, 7) are never at 90° or 270° — avoids vertical elongation", () => {
+ for (const { mode, rotation } of PULSE_SEQUENCE) {
+ if (mode === 1 || mode === 2 || mode === 7) {
+ expect(rotation).not.toBe(90)
+ expect(rotation).not.toBe(270)
+ }
+ }
+ })
+
+ test("consecutive shapes have maximum visual contrast (no two identical)", () => {
+ for (let i = 1; i < PULSE_SEQUENCE.length; i++) {
+ const prev = PULSE_SEQUENCE[i - 1]
+ const curr = PULSE_SEQUENCE[i]
+ const same = prev.mode === curr.mode && prev.rotation === curr.rotation
+ expect(same).toBe(false)
+ }
+ })
+
+ test("PULSE_PATHS matches the sequence", () => {
+ expect(PULSE_PATHS).toHaveLength(PULSE_COUNT)
+ for (let i = 0; i < PULSE_COUNT; i++) {
+ const { mode, rotation } = PULSE_SEQUENCE[i]
+ expect(PULSE_PATHS[i]).toBe(harmonicPath(mode, rotation))
+ }
+ })
+})
+
+describe("SMIL keyframes", () => {
+ test("values has PULSE_COUNT*4 + 1 entries (holds + morphs + close)", () => {
+ const count = SMIL.values.split(";").length
+ expect(count).toBe(PULSE_COUNT * 4 + 1)
+ })
+
+ test("keyTimes has same count as values", () => {
+ const valCount = SMIL.values.split(";").length
+ const timeCount = SMIL.keyTimes.split(";").length
+ expect(timeCount).toBe(valCount)
+ })
+
+ test("keyTimes starts at 0 and ends at 1", () => {
+ const times = SMIL.keyTimes.split(";").map(Number)
+ expect(times[0]).toBe(0)
+ expect(times[times.length - 1]).toBe(1)
+ })
+
+ test("keyTimes are monotonically non-decreasing", () => {
+ const times = SMIL.keyTimes.split(";").map(Number)
+ for (let i = 1; i < times.length; i++) {
+ expect(times[i]).toBeGreaterThanOrEqual(times[i - 1])
+ }
+ })
+
+ test("dur matches CYCLE_MS", () => {
+ expect(SMIL.dur).toBe(`${CYCLE_MS}ms`)
+ })
+
+ test("first and last values are both circle donut (seamless loop)", () => {
+ const vals = SMIL.values.split(";")
+ expect(vals[0]).toBe(CIRCLE_DONUT_PATH)
+ expect(vals[vals.length - 1]).toBe(CIRCLE_DONUT_PATH)
+ })
+
+ test("every other pair of values is (circle donut, circle donut) for sphere holds", () => {
+ // Pattern: C,C,S,S,C,C,S,S,...,C
+ // Positions 0,1 are circle (first sphere hold)
+ // Positions 4,5 are circle (second sphere hold)
+ // etc.
+ const vals = SMIL.values.split(";")
+ for (let pulse = 0; pulse < PULSE_COUNT; pulse++) {
+ const base = pulse * 4
+ expect(vals[base]).toBe(CIRCLE_DONUT_PATH)
+ expect(vals[base + 1]).toBe(CIRCLE_DONUT_PATH)
+ }
+ })
+
+ test("shape values match PULSE_DONUT_PATHS at the right positions", () => {
+ const vals = SMIL.values.split(";")
+ for (let pulse = 0; pulse < PULSE_COUNT; pulse++) {
+ const base = pulse * 4
+ // Positions base+2 and base+3 are the shape
+ expect(vals[base + 2]).toBe(PULSE_DONUT_PATHS[pulse])
+ expect(vals[base + 3]).toBe(PULSE_DONUT_PATHS[pulse])
+ }
+ })
+
+ test("all value paths have identical SMIL-compatible structure", () => {
+ const vals = SMIL.values.split(";")
+ const structure = vals[0].replace(/[-\d.,\s]/g, "")
+ for (const v of vals) {
+ expect(v.replace(/[-\d.,\s]/g, "")).toBe(structure)
+ }
+ })
+})
+
+describe("randomPulseSequence + buildSmil", () => {
+ test("randomPulseSequence returns PULSE_COUNT entries matching PULSE_MODES", () => {
+ const seq = randomPulseSequence()
+ expect(seq).toHaveLength(PULSE_MODES.length)
+ for (let i = 0; i < seq.length; i++) {
+ expect(seq[i].mode).toBe(PULSE_MODES[i])
+ }
+ })
+
+ test("skinny modes (1, 2, 7) never get 90° or 270° in random sequences", () => {
+ for (let run = 0; run < 50; run++) {
+ const seq = randomPulseSequence()
+ for (const { mode, rotation } of seq) {
+ if (mode === 1 || mode === 2 || mode === 7) {
+ expect(rotation).not.toBe(90)
+ expect(rotation).not.toBe(270)
+ }
+ }
+ }
+ })
+
+ test("random sequences produce different angles across runs", () => {
+ const seqs = Array.from({ length: 20 }, () => randomPulseSequence())
+ const signatures = seqs.map((s) => s.map((p) => p.rotation).join(","))
+ // With 6–8 angle choices per slot, getting 20 identical signatures is ~impossible
+ const unique = new Set(signatures)
+ expect(unique.size).toBeGreaterThan(1)
+ })
+
+ test("buildSmil produces valid SMIL for a random sequence", () => {
+ const seq = randomPulseSequence()
+ const smil = buildSmil(seq)
+ const vals = smil.values.split(";")
+ const times = smil.keyTimes.split(";").map(Number)
+ // Correct count
+ expect(vals.length).toBe(seq.length * 4 + 1)
+ expect(times.length).toBe(vals.length)
+ // Bounds
+ expect(times[0]).toBe(0)
+ expect(times[times.length - 1]).toBe(1)
+ // Monotonic
+ for (let i = 1; i < times.length; i++) {
+ expect(times[i]).toBeGreaterThanOrEqual(times[i - 1])
+ }
+ // First and last are circle donut
+ expect(vals[0]).toBe(CIRCLE_DONUT_PATH)
+ expect(vals[vals.length - 1]).toBe(CIRCLE_DONUT_PATH)
+ })
+
+ test("all angles are from 45° increment set", () => {
+ const valid = new Set([0, 45, 90, 135, 180, 225, 270, 315])
+ for (let run = 0; run < 20; run++) {
+ for (const { rotation } of randomPulseSequence()) {
+ expect(valid.has(rotation)).toBe(true)
+ }
+ }
+ })
+})
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.ts b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.ts
new file mode 100644
index 00000000..ca75807b
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/harmonic-geometry.ts
@@ -0,0 +1,339 @@
+// packages/ui/src/amicode/harmonic-geometry.ts
+// AMICODE: pure geometry + timing for the spherical-harmonic morphing dot (harmonic-dot.tsx).
+// Mirrors the wave-geometry.ts pattern: DOM-free, unit-tested, module-level precomputation.
+//
+// Rhythm: sphere → harmonic → sphere → harmonic → ... (the sphere is "home base").
+// Each pulse is ~1.2s: sphere-hold (350ms) → morph-out (175ms) → shape-hold (500ms)
+// → morph-back (175ms). Four pulses make one full cycle (~4.8s).
+//
+// All paths share the same command structure (64 points, M + 63 L + Z) so SVG
+// SMIL can interpolate natively between them.
+
+/** CSS size of the morphing dot when in the running state (px). */
+export const HARMONIC_SIZE = 13
+
+/** Number of angular samples per shape — shared across all modes for SMIL compat. */
+export const HARMONIC_SAMPLES = 64
+
+// --- Timing constants (pulse rhythm) ---
+
+/** How long the sphere rests between pulses (ms). */
+export const SPHERE_HOLD_MS = 350
+
+/** Duration of the morph transition sphere↔shape (ms). */
+export const MORPH_MS = 175
+
+/** How long each harmonic shape is held at full excitation (ms). */
+export const SHAPE_HOLD_MS = 500
+
+/** One full pulse: sphere-hold + morph-out + shape-hold + morph-back (ms). */
+export const PULSE_MS = SPHERE_HOLD_MS + MORPH_MS + SHAPE_HOLD_MS + MORPH_MS
+
+/** Number of pulses in one full cycle. */
+export const PULSE_COUNT = 10
+
+/** Total cycle duration (ms). */
+export const CYCLE_MS = PULSE_MS * PULSE_COUNT
+
+// --- Modes ---
+
+/** Number of distinct harmonic modes (circle + 7 shapes). */
+export const MODE_COUNT = 8
+
+/**
+ * Compute the normalized radius [0, 1] for a given mode at angle theta.
+ *
+ * Mode 0: Y_0^0 — circle (constant)
+ * Mode 1: Y_1^0 — dumbbell (cos²θ) — NOT USED in pulse sequence (phallic-adjacent)
+ * Mode 2: Y_2^0 — pinched (|3cos²θ − 1| normalized, with base)
+ * Mode 3: l=2 m=2 — four-lobe clover (|cos(2θ)| with base)
+ * Mode 4: l=3 m=3 — six-lobe rosette (|cos(3θ)| with base)
+ * Mode 5: l=3 m=0 — trefoil (gentle 3-lobe via (1+cos(3θ))/2)
+ * Mode 6: l=4 m=4 — eight-lobe star (|cos(4θ)| with base)
+ * Mode 7: l=4 m=0 — double pinch (|P_4^0(cosθ)| — 4 lobes along axis with 2 waists)
+ *
+ * A base offset (min radius ~0.2–0.3) prevents cusps and keeps shapes "spherical" —
+ * at 13px a cusp would be a single-pixel spike, unreadable.
+ */
+export function harmonicRadius(mode: number, theta: number): number {
+ switch (mode) {
+ case 0:
+ // Perfect circle
+ return 1.0
+ case 1: {
+ // Dumbbell: two lobes (legacy, not in pulse sequence)
+ const cos = Math.cos(theta)
+ return 0.25 + 0.75 * cos * cos
+ }
+ case 2: {
+ // Pinched: |3cos²θ - 1| gives lobes at poles + equatorial bump
+ const cos = Math.cos(theta)
+ const raw = Math.abs(3 * cos * cos - 1) // range [0, 2]
+ return 0.2 + 0.8 * (raw / 2)
+ }
+ case 3: {
+ // Four-lobe clover: |cos(2θ)| gives four symmetric lobes
+ const raw = Math.abs(Math.cos(2 * theta)) // range [0, 1]
+ return 0.2 + 0.8 * raw
+ }
+ case 4: {
+ // Six-lobe rosette: |cos(3θ)| gives six symmetric lobes
+ const raw = Math.abs(Math.cos(3 * theta)) // range [0, 1]
+ return 0.25 + 0.75 * raw
+ }
+ case 5: {
+ // Trefoil: (1 + cos(3θ))/2 gives gentle 3-lobe shape
+ const raw = (1 + Math.cos(3 * theta)) / 2 // range [0, 1]
+ return 0.3 + 0.7 * raw
+ }
+ case 6: {
+ // Eight-lobe star: |cos(4θ)| gives eight fine lobes
+ const raw = Math.abs(Math.cos(4 * theta)) // range [0, 1]
+ return 0.3 + 0.7 * raw
+ }
+ case 7: {
+ // Double pinch: |P_4^0(cosθ)| = |35cos⁴θ − 30cos²θ + 3|/8
+ // Gives 4 lobes along the polar axis with two pinched waists between them
+ const cos = Math.cos(theta)
+ const cos2 = cos * cos
+ const raw = Math.abs(35 * cos2 * cos2 - 30 * cos2 + 3) / 8 // range [0, 1]
+ return 0.2 + 0.8 * raw
+ }
+ default:
+ return 1.0
+ }
+}
+
+/**
+ * Generate a closed SVG path for a harmonic mode, optionally rotated.
+ * The path fits inside a HARMONIC_SIZE × HARMONIC_SIZE viewBox,
+ * centred at (HARMONIC_SIZE/2, HARMONIC_SIZE/2).
+ *
+ * @param mode — which harmonic shape (0=circle, 1=dumbbell, 2=pinched, 3=clover)
+ * @param rotationDeg — rotation angle in degrees (applied as offset to sampling angle)
+ * @param samples — number of angular samples (must be consistent for SMIL)
+ */
+export function harmonicPath(mode: number, rotationDeg: number = 0, samples: number = HARMONIC_SAMPLES): string {
+ const cx = HARMONIC_SIZE / 2
+ const cy = HARMONIC_SIZE / 2
+ // Leave 0.5px margin for anti-aliasing / border
+ const maxR = (HARMONIC_SIZE - 1) / 2
+ const rotationRad = (rotationDeg * Math.PI) / 180
+
+ const round = (n: number) => Math.round(n * 100) / 100
+
+ const parts: string[] = []
+ for (let i = 0; i < samples; i++) {
+ const theta = (i / samples) * 2 * Math.PI
+ // Sample the harmonic at the rotated angle, but plot at the original angle
+ const r = harmonicRadius(mode, theta - rotationRad) * maxR
+ const x = round(cx + r * Math.cos(theta))
+ const y = round(cy + r * Math.sin(theta))
+ parts.push(i === 0 ? `M${x},${y}` : `L${x},${y}`)
+ }
+ parts.push("Z")
+ return parts.join("")
+}
+
+/**
+ * Generate a donut SVG path: outer harmonic shape (CW) + inner circle (CCW).
+ * Used with fill-rule="evenodd" to punch a hole — a single filled path that
+ * renders as a ring, no stroke needed.
+ *
+ * When innerR=0, the inner sub-path collapses to a point at centre (solid shape).
+ * SMIL interpolates between donut paths point-by-point, so the ring smoothly
+ * closes/opens as the outer shape morphs.
+ *
+ * @param mode — which harmonic shape for the outer contour
+ * @param rotationDeg — rotation for the outer contour
+ * @param innerR — radius of the inner hole (0 = no hole = solid)
+ */
+export function harmonicDonutPath(mode: number, rotationDeg: number = 0, innerR: number = INNER_R, samples: number = HARMONIC_SAMPLES): string {
+ const cx = HARMONIC_SIZE / 2
+ const cy = HARMONIC_SIZE / 2
+ const maxR = (HARMONIC_SIZE - 1) / 2
+ const rotationRad = (rotationDeg * Math.PI) / 180
+ const round = (n: number) => Math.round(n * 100) / 100
+
+ // Outer contour — clockwise
+ const parts: string[] = []
+ for (let i = 0; i < samples; i++) {
+ const theta = (i / samples) * 2 * Math.PI
+ const r = harmonicRadius(mode, theta - rotationRad) * maxR
+ const x = round(cx + r * Math.cos(theta))
+ const y = round(cy + r * Math.sin(theta))
+ parts.push(i === 0 ? `M${x},${y}` : `L${x},${y}`)
+ }
+ parts.push("Z")
+
+ // Inner contour — counter-clockwise (punches the hole via evenodd)
+ // When innerR=0, all points collapse to centre = no visible hole.
+ for (let i = 0; i < samples; i++) {
+ const theta = ((samples - i) / samples) * 2 * Math.PI // reversed direction
+ const x = round(cx + innerR * Math.cos(theta))
+ const y = round(cy + innerR * Math.sin(theta))
+ parts.push(i === 0 ? `M${x},${y}` : `L${x},${y}`)
+ }
+ parts.push("Z")
+
+ return parts.join("")
+}
+
+/**
+ * The pulse mode sequence: which harmonic shape appears in each pulse.
+ * Order is fixed for visual contrast; ANGLES are randomized per mount.
+ * 10 pulses using 6 shapes (modes 1–6), no adjacent repeats.
+ */
+export const PULSE_MODES: readonly number[] = [
+ 3, // clover (4 lobes, Y_2^2)
+ 1, // dumbbell (2 lobes, Y_1^0)
+ 4, // rosette-6 (6 lobes, Y_3^3)
+ 7, // double pinch (4 axial, P_4^0)
+ 2, // pinched (2+equator, P_2^0)
+ 6, // star-8 (8 lobes, Y_4^4)
+ 3, // clover
+ 1, // dumbbell
+ 4, // rosette-6
+ 6, // star-8
+]
+
+/**
+ * Allowed rotation angles per mode (degrees, 45° increments).
+ *
+ * In SVG coordinates, theta=0 points RIGHT. The dumbbell's natural shape
+ * (rotation=0°) has lobes at LEFT/RIGHT = horizontal. Rotation=90° makes
+ * it VERTICAL — which looks phallic. Pill-shaped modes (1, 2, 7) are
+ * restricted to horizontal only (0°/180°) so they always read as a
+ * horizontal lozenge, never at an odd diagonal.
+ */
+const ANGLES_ANY = [0, 45, 90, 135, 180, 225, 270, 315] as const
+const ANGLES_HORIZONTAL = [0, 180] as const
+
+function allowedAngles(mode: number): readonly number[] {
+ if (mode === 1 || mode === 2 || mode === 7) return ANGLES_HORIZONTAL
+ return ANGLES_ANY
+}
+
+/**
+ * Generate a random pulse sequence (mode + rotation for each pulse).
+ * Called once per HarmonicDot mount — each streaming turn gets a fresh sequence.
+ */
+export function randomPulseSequence(): ReadonlyArray<{ mode: number; rotation: number }> {
+ const result: Array<{ mode: number; rotation: number }> = []
+ for (let i = 0; i < PULSE_MODES.length; i++) {
+ const mode = PULSE_MODES[i]
+ const angles = allowedAngles(mode)
+ let rotation: number
+ const prev = result[i - 1]
+ do {
+ rotation = angles[Math.floor(Math.random() * angles.length)]
+ } while (prev && prev.mode === mode && prev.rotation === rotation)
+ result.push({ mode, rotation })
+ }
+ return result
+}
+
+/** Inner disc radius that creates the ring hole (px in viewBox units).
+ * maxR is 6, so ring thickness = 6 - INNER_R ≈ 1.5px. */
+export const INNER_R = 4.5
+
+/** Pre-computed circle path (the "home" shape). */
+export const CIRCLE_PATH = harmonicPath(0)
+
+/** Pre-computed donut circle path (the ring — sphere with inner hole). */
+export const CIRCLE_DONUT_PATH = harmonicDonutPath(0, 0, INNER_R)
+
+/**
+ * Build SMIL keyframe attributes for a given pulse sequence.
+ *
+ * Uses donut paths (fill-rule evenodd): the sphere state is a ring (outer circle
+ * + inner hole), harmonic states are solid (inner collapsed to centre). SMIL
+ * interpolates between them point-by-point — the ring smoothly closes as the
+ * shape blooms, reopens when returning to sphere.
+ */
+export function buildSmil(sequence: ReadonlyArray<{ mode: number; rotation: number }>): {
+ values: string
+ keyTimes: string
+ /** Background masking circle radius: INNER_R during sphere, 0 during harmonic. */
+ innerRadius: string
+ dur: string
+} {
+ // Harmonic donut paths with inner hole at r=0 (solid)
+ const solidPaths = sequence.map(({ mode, rotation }) => harmonicDonutPath(mode, rotation, 0))
+ const values: string[] = []
+ const radii: number[] = []
+ const times: number[] = []
+ const total = PULSE_MS * sequence.length
+
+ let t = 0
+ for (let i = 0; i < sequence.length; i++) {
+ // Sphere hold start — ring (full inner hole)
+ values.push(CIRCLE_DONUT_PATH)
+ radii.push(INNER_R)
+ times.push(t / total)
+ t += SPHERE_HOLD_MS
+
+ // Sphere hold end — morph-out begins
+ values.push(CIRCLE_DONUT_PATH)
+ radii.push(INNER_R)
+ times.push(t / total)
+ t += MORPH_MS
+
+ // Shape arrived — solid (inner hole collapsed)
+ values.push(solidPaths[i])
+ radii.push(0)
+ times.push(t / total)
+ t += SHAPE_HOLD_MS
+
+ // Shape hold end — morph-back begins
+ values.push(solidPaths[i])
+ radii.push(0)
+ times.push(t / total)
+ t += MORPH_MS
+ }
+
+ // Final: back to ring
+ values.push(CIRCLE_DONUT_PATH)
+ radii.push(INNER_R)
+ times.push(1)
+
+ return {
+ values: values.join(";"),
+ keyTimes: times.map((v) => Math.round(v * 10000) / 10000).join(";"),
+ innerRadius: radii.join(";"),
+ dur: `${total}ms`,
+ }
+}
+
+// --- Deterministic exports for tests ---
+
+/** A deterministic sequence for testing — uses first allowed angle per mode. */
+export const PULSE_SEQUENCE: ReadonlyArray<{ mode: number; rotation: number }> =
+ PULSE_MODES.map((mode) => ({ mode, rotation: allowedAngles(mode)[0] }))
+
+/** Pre-computed paths for the deterministic test sequence. */
+export const PULSE_PATHS: readonly string[] = PULSE_SEQUENCE.map(
+ ({ mode, rotation }) => harmonicPath(mode, rotation),
+)
+
+/** Pre-computed donut paths (solid, inner r=0) for the deterministic test sequence. */
+export const PULSE_DONUT_PATHS: readonly string[] = PULSE_SEQUENCE.map(
+ ({ mode, rotation }) => harmonicDonutPath(mode, rotation, 0),
+)
+
+/** Pre-computed base paths for all raw modes (no rotation). */
+export const HARMONIC_PATHS: readonly string[] = Array.from(
+ { length: MODE_COUNT },
+ (_, mode) => harmonicPath(mode),
+)
+
+/** Pre-computed SMIL for the deterministic test sequence. */
+export const SMIL = buildSmil(PULSE_SEQUENCE)
+
+/** @deprecated use SMIL.dur or CYCLE_MS */
+export const MORPH_CADENCE_MS = CYCLE_MS
+
+/** @deprecated use SMIL.keyTimes */
+export function smilKeyTimes(): string {
+ return SMIL.keyTimes
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/home-cards.tsx b/packages/app-bundle/overlay/packages/ui/src/amicode/home-cards.tsx
index 23c9355f..9790ca18 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/home-cards.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/home-cards.tsx
@@ -248,9 +248,9 @@ function PrimaryButton(props: { children: JSX.Element; onClick: () => void; slot
// MEET AMICO — static identity + capabilities (the H-bot's home)
// ---------------------------------------------------------------------------
const AMICO_CAN = [
- "run automated experiments from a conversation",
- "verify results independently before trusting them",
- "remember your work and build on prior results",
+ "design pulses from a conversation",
+ "optimize for fidelity, speed, or robustness",
+ "warm-start from your pulse bank",
"tune & calibrate on real hardware",
]
diff --git a/packages/app-bundle/overlay/packages/ui/src/amicode/run-window.tsx b/packages/app-bundle/overlay/packages/ui/src/amicode/run-window.tsx
index 2cacd14d..b0ae61c2 100644
--- a/packages/app-bundle/overlay/packages/ui/src/amicode/run-window.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/amicode/run-window.tsx
@@ -1,6 +1,5 @@
import { For, Show, createEffect, createMemo, onCleanup, onMount } from "solid-js"
import { createStore, reconcile } from "solid-js/store"
-import { AmicoMark } from "./spinner"
import { fetchAmicodeRunSeries, openAmicodeEntity } from "./ui-bridge"
import { heroPaths, objectivePath } from "./run-plot"
import {
@@ -157,12 +156,12 @@ export function RunWindow(props: { run: string; lab?: string }) {
cursor: "pointer",
}}
>
- {/* header: [H] Run · status · iter · metric · elapsed (AMICO wordmark
- dropped — identity lives in the rail; spec-20260712-amico-third-actor) */}
+ {/* header: Run · status · iter · metric · spark · elapsed. No Amico mark:
+ the wordmark went first (identity lives in the rail —
+ spec-20260712-amico-third-actor) and the H-mark followed it on every
+ amicode surface (Kate 2026-08-23). This panel is unmistakably Amico's
+ without a stamp, and the glyph only repeated what "Run" already says. */}
-
-
-
Run
- typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
-
export function ThinkingLine(props: {
/** streamed token count so far; when omitted the tokens chip is hidden */
tokens?: number
/** show the "esc to interrupt" hint — only pass when the mount site wires esc */
interruptible?: boolean
- /** @deprecated no-op — the H-mark was removed (wave+verb is the indicator now); kept for compat */
+ /** @deprecated no-op; kept for call-site compat */
mark?: boolean
class?: string
style?: ComponentProps<"span">["style"]
}) {
- const still = reducedMotion()
const [elapsedMs, setElapsedMs] = createSignal(0)
- // Random start so each turn/mount opens on a different verb; the module-level
- // shuffle already decorrelates reloads, this decorrelates simultaneous mounts.
- const [tick, setTick] = createSignal(Math.floor(Math.random() * SHUFFLED_WORDS.length))
onMount(() => {
const start = Date.now()
const clock = setInterval(() => setElapsedMs(Date.now() - start), TICK_MS)
onCleanup(() => clearInterval(clock))
- if (!still) {
- const words = setInterval(() => setTick((n) => n + 1), WORD_MS)
- onCleanup(() => clearInterval(words))
- }
})
- const word = () => (still ? "Thinking" : shuffledWordAt(tick()))
-
return (
- Amico is thinking…
-
- {/* word first in DOM (baseline — see header); grid places it visually */}
-
- {word()}…
+ Amico is working…
-
{formatElapsed(elapsedMs())}
diff --git a/packages/app-bundle/overlay/packages/ui/src/components/amicode-harmonic-dot.tsx b/packages/app-bundle/overlay/packages/ui/src/components/amicode-harmonic-dot.tsx
new file mode 100644
index 00000000..d3ddcc11
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/components/amicode-harmonic-dot.tsx
@@ -0,0 +1,4 @@
+// AMICODE: re-export shim (same wildcard-export pattern as amicode-thinking.tsx).
+// Logic lives in ../amicode/harmonic-geometry.ts and ../amicode/harmonic-dot.tsx.
+export { HarmonicDot } from "../amicode/harmonic-dot"
+export { HARMONIC_SIZE, randomPulseSequence, buildSmil } from "../amicode/harmonic-geometry"
diff --git a/packages/app-bundle/overlay/packages/ui/src/components/amicode-thinking.tsx b/packages/app-bundle/overlay/packages/ui/src/components/amicode-thinking.tsx
index cdc0b2f6..c2e8ca3c 100644
--- a/packages/app-bundle/overlay/packages/ui/src/components/amicode-thinking.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/components/amicode-thinking.tsx
@@ -1,4 +1,4 @@
// AMICODE: re-export shim (same wildcard-export pattern as amicode-card.tsx).
// Logic lives in ../amicode/thinking.ts and ../amicode/thinking-line.tsx.
-export { turnTokens } from "../amicode/thinking"
+export { formatElapsed, formatTokens, turnTokens } from "../amicode/thinking"
export { ThinkingLine } from "../amicode/thinking-line"
diff --git a/packages/app-bundle/overlay/packages/ui/src/components/icon.tsx b/packages/app-bundle/overlay/packages/ui/src/components/icon.tsx
index a8b7b61a..7fad71ff 100644
--- a/packages/app-bundle/overlay/packages/ui/src/components/icon.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/components/icon.tsx
@@ -3,6 +3,8 @@ import { onMount, splitProps, type ComponentProps } from "solid-js"
const icons = {
// AMICODE entity glyphs (Kate 2026-07-24): drawn to match the family's line
// aesthetic (20×20, currentColor). target → System, activity → Pulse in the rail.
+ home: ``,
+ "context-ring": ``,
target: ``,
activity: ``,
pulse: ``,
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/ar.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/ar.ts
new file mode 100644
index 00000000..c00cf7e7
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/ar.ts
@@ -0,0 +1,194 @@
+export const dict = {
+ "ui.sessionReview.title": "تغييرات الجلسة",
+ "ui.sessionReview.title.git": "تغييرات Git",
+ "ui.sessionReview.title.branch": "تغييرات الفرع",
+ "ui.sessionReview.title.lastTurn": "تغييرات آخر دور",
+ "ui.sessionReview.diffStyle.unified": "موحد",
+ "ui.sessionReview.diffStyle.split": "منقسم",
+ "ui.sessionReview.openFile": "فتح ملف",
+ "ui.sessionReview.selection.line": "سطر {{line}}",
+ "ui.sessionReview.selection.lines": "الأسطر {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "توسيع الكل",
+ "ui.sessionReview.collapseAll": "طي الكل",
+ "ui.sessionReview.change.added": "مضاف",
+ "ui.sessionReview.change.removed": "محذوف",
+ "ui.sessionReview.change.modified": "معدل",
+ "ui.sessionReview.image.loading": "جار التحميل...",
+ "ui.sessionReview.image.placeholder": "صورة",
+ "ui.sessionReview.largeDiff.title": "Diff كبير جدا لعرضه",
+ "ui.sessionReview.largeDiff.meta": "الحد: {{limit}} سطرًا متغيرًا. الحالي: {{current}} سطرًا متغيرًا.",
+ "ui.sessionReview.largeDiff.renderAnyway": "اعرض على أي حال",
+ "ui.sessionReviewV2.expandMode": "توسيع الفروقات أو طيها",
+ "ui.sessionReviewV2.filterFiles": "تصفية الملفات",
+ "ui.sessionReviewV2.toggleSidebar": "تبديل شجرة الملفات",
+ "ui.sessionReviewV2.showAllLines": "إظهار جميع الأسطر",
+ "ui.sessionReviewV2.hideNonDiffLines": "إخفاء الأسطر خارج الفروقات",
+ "ui.sessionReviewV2.unifiedDiff": "فروقات موحدة",
+ "ui.sessionReviewV2.splitDiff": "فروقات منقسمة",
+ "ui.sessionReviewV2.previousFile": "الملف السابق",
+ "ui.sessionReviewV2.nextFile": "الملف التالي",
+ "ui.sessionReviewV2.diffView": "عرض الفروقات",
+ "ui.sessionReviewV2.empty.noGit.title": "لا توجد تغييرات متتبعة",
+ "ui.sessionReviewV2.empty.noGit.description": "تتبع التغييرات في هذا المشروع وراجعها وتراجع عنها",
+ "ui.sessionReviewV2.empty.noGit.action": "إنشاء مستودع Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "جارٍ إنشاء مستودع Git...",
+ "ui.sessionReviewV2.empty.changes.title": "لا توجد تغييرات في الملفات بعد",
+ "ui.sessionReviewV2.empty.changes.description": "ستظهر تغييرات المشروع هنا",
+ "ui.fileMedia.kind.image": "صورة",
+ "ui.fileMedia.kind.audio": "صوت",
+ "ui.fileMedia.state.removed": "تمت إزالة {{kind}}",
+ "ui.fileMedia.state.loading": "جاري تحميل {{kind}}...",
+ "ui.fileMedia.state.error": "خطأ في تحميل {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} غير متوفر",
+ "ui.fileMedia.binary.title": "ملف ثنائي",
+ "ui.fileMedia.binary.description.path": "{{path}} عبارة عن ملف ثنائي ولا يمكن عرضه.",
+ "ui.fileMedia.binary.description.default": "هذا ملف ثنائي ولا يمكن عرضه.",
+
+ "ui.lineComment.label.prefix": "تعليق على ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "جارٍ التعليق على ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "أضف تعليقًا",
+ "ui.lineComment.submit": "تعليق",
+ "ui.lineComment.cancel": "إلغاء",
+
+ "ui.sessionTurn.steps.show": "إظهار الخطوات",
+ "ui.sessionTurn.steps.hide": "إخفاء الخطوات",
+ "ui.sessionTurn.summary.response": "استجابة",
+ "ui.sessionTurn.diff.showMore": "إظهار المزيد من التغييرات ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "ملف معدل: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "الملفات المعدلة: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "إظهار الكل",
+ "ui.sessionTurn.diffs.showLess": "إظهار أقل",
+ "ui.sessionTurn.diffs.more": "ملفات إضافية: {{count}}",
+
+ "ui.sessionTurn.retry.retrying": "إعادة المحاولة",
+ "ui.sessionTurn.retry.inSeconds": "خلال {{seconds}} ثواني",
+ "ui.sessionTurn.retry.attempt": "المحاولة رقم {{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - المحاولة رقم {{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini مزدحم حاليا",
+ "ui.sessionTurn.error.freeUsageExceeded": "تم تجاوز حد الاستخدام المجاني",
+ "ui.sessionTurn.error.addCredits": "إضافة رصيد",
+
+ "dialog.usageExceeded.freeTier.title": "تم الوصول إلى الحد المجاني",
+ "dialog.usageExceeded.freeTier.description":
+ "اشترك في OpenCode Go للحصول على وصول موثوق إلى أفضل النماذج مفتوحة المصدر، ابتداءً من $5/شهر.",
+ "dialog.usageExceeded.freeTier.actionLabel": "اشترك",
+ "dialog.usageExceeded.accountRateLimit.title": "تم الوصول إلى حد Go",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "تم الوصول إلى حد الاستخدام. لمتابعة استخدام هذا النموذج الآن، قم بتفعيل الاستخدام من رصيدك المتاح",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "فتح الإعدادات",
+
+ "ui.sessionTurn.status.delegating": "تفويض العمل",
+ "ui.sessionTurn.status.planning": "تخطيط الخطوات التالية",
+ "ui.sessionTurn.status.gatheringContext": "استكشاف",
+ "ui.sessionTurn.status.gatheredContext": "تم الاستكشاف",
+ "ui.sessionTurn.status.searchingCodebase": "البحث في قاعدة التعليمات البرمجية",
+ "ui.sessionTurn.status.searchingWeb": "البحث في الويب",
+ "ui.sessionTurn.status.makingEdits": "إجراء تعديلات",
+ "ui.sessionTurn.status.runningCommands": "تشغيل الأوامر",
+ "ui.sessionTurn.status.thinking": "تفكير",
+ "ui.sessionTurn.status.thinkingWithTopic": "تفكير - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "جمع الأفكار",
+ "ui.sessionTurn.status.consideringNextSteps": "النظر في الخطوات التالية",
+
+ "ui.messagePart.questions.dismissed": "تم رفض الأسئلة",
+ "ui.messagePart.compaction": "تم ضغط الجلسة",
+ "ui.messagePart.context.read.one": "{{count}} قراءة",
+ "ui.messagePart.context.read.other": "{{count}} قراءات",
+ "ui.messagePart.context.search.one": "{{count}} بحث",
+ "ui.messagePart.context.search.other": "{{count}} عمليات بحث",
+ "ui.messagePart.context.list.one": "{{count}} قائمة",
+ "ui.messagePart.context.list.other": "{{count}} قوائم",
+ "ui.messagePart.diagnostic.error": "خطأ",
+ "ui.messagePart.title.edit": "تحرير",
+ "ui.messagePart.title.write": "كتابة",
+ "ui.messagePart.option.typeOwnAnswer": "اكتب إجابتك الخاصة",
+ "ui.messagePart.review.title": "مراجعة إجاباتك",
+
+ "ui.list.loading": "جارٍ التحميل",
+ "ui.list.empty": "لا توجد نتائج",
+ "ui.list.clearFilter": "مسح عامل التصفية",
+ "ui.list.emptyWithFilter.prefix": "لا توجد نتائج لـ",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "رسالة جديدة",
+
+ "ui.textField.copyToClipboard": "نسخ إلى الحافظة",
+ "ui.textField.copyLink": "نسخ الرابط",
+ "ui.textField.copied": "تم النسخ",
+
+ "ui.imagePreview.alt": "معاينة الصورة",
+ "ui.scrollView.ariaLabel": "محتوى قابل للتمرير",
+
+ "ui.tool.read": "قراءة",
+ "ui.tool.loaded": "تم التحميل",
+ "ui.tool.list": "قائمة",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "جلب الويب",
+ "ui.tool.websearch": "بحث الويب",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "تصحيح",
+ "ui.tool.todos": "المهام",
+ "ui.tool.todos.read": "قراءة المهام",
+ "ui.tool.questions": "أسئلة",
+ "ui.tool.agent": "وكيل {{type}}",
+ "ui.tool.agent.default": "وكيل",
+
+ "ui.common.file.one": "ملف",
+ "ui.common.file.other": "ملفات",
+ "ui.common.question.one": "سؤال",
+ "ui.common.question.other": "أسئلة",
+
+ "ui.common.add": "إضافة",
+ "ui.common.back": "رجوع",
+ "ui.common.cancel": "إلغاء",
+ "ui.common.confirm": "تأكيد",
+ "ui.common.dismiss": "رفض",
+ "ui.common.close": "إغلاق",
+ "ui.common.next": "التالي",
+ "ui.common.submit": "إرسال",
+ "ui.common.showMore": "عرض المزيد",
+
+ "ui.permission.deny": "رفض",
+ "ui.permission.allowAlways": "السماح دائمًا",
+ "ui.permission.allowOnce": "السماح مرة واحدة",
+
+ "ui.message.expand": "توسيع الرسالة",
+ "ui.message.collapse": "طي الرسالة",
+ "ui.message.copy": "نسخ",
+ "ui.message.copyMessage": "نسخ الرسالة",
+ "ui.message.forkMessage": "تشعب إلى جلسة جديدة",
+ "ui.message.revertMessage": "إعادة التعيين إلى هذه النقطة",
+ "ui.message.copyResponse": "نسخ الرد",
+ "ui.message.copied": "تم النسخ!",
+ "ui.message.interrupted": "تمت المقاطعة",
+ "ui.message.queued": "في الانتظار",
+ "ui.message.attachment.alt": "مرفق",
+
+ "ui.patch.action.deleted": "محذوف",
+ "ui.patch.action.created": "تم الإنشاء",
+ "ui.patch.action.moved": "منقول",
+ "ui.patch.action.patched": "مصحح",
+
+ "ui.question.subtitle.answered": "{{count}} أجيب",
+ "ui.question.answer.none": "(لا توجد إجابة)",
+ "ui.question.review.notAnswered": "(لم يتم الرد)",
+ "ui.question.multiHint": "حدد كل ما ينطبق",
+ "ui.question.singleHint": "حدد إجابة واحدة",
+ "ui.question.custom.placeholder": "اكتب إجابتك...",
+
+ "ui.fileSearch.placeholder": "بحث",
+ "ui.fileSearch.previousMatch": "المطابقة السابقة",
+ "ui.fileSearch.nextMatch": "المطابقة التالية",
+ "ui.fileSearch.close": "إغلاق البحث",
+ "ui.tool.task": "مهمة",
+ "ui.tool.skill": "مهارة",
+ "ui.basicTool.called": "تم استدعاء `{{tool}}`",
+ "ui.toolErrorCard.failed": "فشل",
+ "ui.toolErrorCard.copyError": "نسخ الخطأ",
+ "ui.message.duration.seconds": "{{count}}ث",
+ "ui.message.duration.minutesSeconds": "{{minutes}}د {{seconds}}ث",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/br.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/br.ts
new file mode 100644
index 00000000..cb3069e0
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/br.ts
@@ -0,0 +1,194 @@
+export const dict = {
+ "ui.sessionReview.title": "Alterações da sessão",
+ "ui.sessionReview.title.git": "Alterações do Git",
+ "ui.sessionReview.title.branch": "Alterações da branch",
+ "ui.sessionReview.title.lastTurn": "Alterações do último turno",
+ "ui.sessionReview.diffStyle.unified": "Unificado",
+ "ui.sessionReview.diffStyle.split": "Dividido",
+ "ui.sessionReview.openFile": "Abrir arquivo",
+ "ui.sessionReview.selection.line": "linha {{line}}",
+ "ui.sessionReview.selection.lines": "linhas {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Expandir tudo",
+ "ui.sessionReview.collapseAll": "Recolher tudo",
+ "ui.sessionReview.change.added": "Adicionado",
+ "ui.sessionReview.change.removed": "Removido",
+ "ui.sessionReview.change.modified": "Modificado",
+ "ui.sessionReview.image.loading": "Carregando...",
+ "ui.sessionReview.image.placeholder": "Imagem",
+ "ui.sessionReview.largeDiff.title": "Diff grande demais para renderizar",
+ "ui.sessionReview.largeDiff.meta": "Limite: {{limit}} linhas alteradas. Atual: {{current}} linhas alteradas.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Renderizar mesmo assim",
+ "ui.sessionReviewV2.expandMode": "Expandir ou recolher diff",
+ "ui.sessionReviewV2.filterFiles": "Filtrar arquivos",
+ "ui.sessionReviewV2.toggleSidebar": "Alternar árvore de arquivos",
+ "ui.sessionReviewV2.showAllLines": "Mostrar todas as linhas",
+ "ui.sessionReviewV2.hideNonDiffLines": "Ocultar linhas fora do diff",
+ "ui.sessionReviewV2.unifiedDiff": "Diff unificado",
+ "ui.sessionReviewV2.splitDiff": "Diff dividido",
+ "ui.sessionReviewV2.previousFile": "Arquivo anterior",
+ "ui.sessionReviewV2.nextFile": "Próximo arquivo",
+ "ui.sessionReviewV2.diffView": "Visualização do diff",
+ "ui.sessionReviewV2.empty.noGit.title": "Nenhuma alteração rastreada",
+ "ui.sessionReviewV2.empty.noGit.description": "Rastreie, revise e desfaça alterações neste projeto",
+ "ui.sessionReviewV2.empty.noGit.action": "Criar repositório Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Criando repositório Git...",
+ "ui.sessionReviewV2.empty.changes.title": "Nenhuma alteração em arquivos ainda",
+ "ui.sessionReviewV2.empty.changes.description": "As alterações do projeto aparecerão aqui",
+ "ui.fileMedia.kind.image": "imagem",
+ "ui.fileMedia.kind.audio": "áudio",
+ "ui.fileMedia.state.removed": "Removido: {{kind}}",
+ "ui.fileMedia.state.loading": "Carregando {{kind}}...",
+ "ui.fileMedia.state.error": "Erro ao carregar {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} indisponível",
+ "ui.fileMedia.binary.title": "Arquivo binário",
+ "ui.fileMedia.binary.description.path": "Não é possível exibir {{path}} porque é um arquivo binário.",
+ "ui.fileMedia.binary.description.default": "Não é possível exibir o arquivo porque ele é binário.",
+
+ "ui.lineComment.label.prefix": "Comentar em ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Comentando em ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Adicionar comentário",
+ "ui.lineComment.submit": "Comentar",
+ "ui.lineComment.cancel": "Cancelar",
+
+ "ui.sessionTurn.steps.show": "Mostrar passos",
+ "ui.sessionTurn.steps.hide": "Ocultar passos",
+ "ui.sessionTurn.summary.response": "Resposta",
+ "ui.sessionTurn.diff.showMore": "Mostrar mais alterações ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Arquivo alterado: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Arquivos alterados: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Mostrar tudo",
+ "ui.sessionTurn.diffs.showLess": "Mostrar menos",
+ "ui.sessionTurn.diffs.more": "+{{count}} a mais",
+
+ "ui.sessionTurn.retry.retrying": "tentando novamente",
+ "ui.sessionTurn.retry.inSeconds": "em {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "tentativa #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - tentativa #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini está muito sobrecarregado agora",
+ "ui.sessionTurn.error.freeUsageExceeded": "Limite de uso gratuito excedido",
+ "ui.sessionTurn.error.addCredits": "Adicionar créditos",
+
+ "dialog.usageExceeded.freeTier.title": "Limite gratuito atingido",
+ "dialog.usageExceeded.freeTier.description":
+ "Assine o OpenCode Go para ter acesso confiável aos melhores modelos open-source, a partir de $5/mês.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Assinar",
+ "dialog.usageExceeded.accountRateLimit.title": "Limite do Go atingido",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Limite de uso atingido. Para continuar usando este modelo agora, ative o uso a partir do seu saldo disponível",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Abrir configurações",
+
+ "ui.sessionTurn.status.delegating": "Delegando trabalho",
+ "ui.sessionTurn.status.planning": "Planejando próximos passos",
+ "ui.sessionTurn.status.gatheringContext": "Explorando",
+ "ui.sessionTurn.status.gatheredContext": "Explorado",
+ "ui.sessionTurn.status.searchingCodebase": "Pesquisando no código",
+ "ui.sessionTurn.status.searchingWeb": "Pesquisando na web",
+ "ui.sessionTurn.status.makingEdits": "Fazendo edições",
+ "ui.sessionTurn.status.runningCommands": "Executando comandos",
+ "ui.sessionTurn.status.thinking": "Pensando",
+ "ui.sessionTurn.status.thinkingWithTopic": "Pensando - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Organizando pensamentos",
+ "ui.sessionTurn.status.consideringNextSteps": "Considerando próximos passos",
+
+ "ui.messagePart.questions.dismissed": "Perguntas descartadas",
+ "ui.messagePart.compaction": "Sessão compactada",
+ "ui.messagePart.context.read.one": "{{count}} leitura",
+ "ui.messagePart.context.read.other": "{{count}} leituras",
+ "ui.messagePart.context.search.one": "{{count}} pesquisa",
+ "ui.messagePart.context.search.other": "{{count}} pesquisas",
+ "ui.messagePart.context.list.one": "{{count}} lista",
+ "ui.messagePart.context.list.other": "{{count}} listas",
+ "ui.messagePart.diagnostic.error": "Erro",
+ "ui.messagePart.title.edit": "Editar",
+ "ui.messagePart.title.write": "Escrever",
+ "ui.messagePart.option.typeOwnAnswer": "Digite sua própria resposta",
+ "ui.messagePart.review.title": "Revise suas respostas",
+
+ "ui.list.loading": "Carregando",
+ "ui.list.empty": "Nenhum resultado",
+ "ui.list.clearFilter": "Limpar filtro",
+ "ui.list.emptyWithFilter.prefix": "Nenhum resultado para",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Nova mensagem",
+
+ "ui.textField.copyToClipboard": "Copiar para área de transferência",
+ "ui.textField.copyLink": "Copiar link",
+ "ui.textField.copied": "Copiado",
+
+ "ui.imagePreview.alt": "Visualização de imagem",
+ "ui.scrollView.ariaLabel": "conteúdo rolável",
+
+ "ui.tool.read": "Ler",
+ "ui.tool.loaded": "Carregado",
+ "ui.tool.list": "Listar",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Buscar Web",
+ "ui.tool.websearch": "Pesquisa na Web",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Tarefas",
+ "ui.tool.todos.read": "Ler tarefas",
+ "ui.tool.questions": "Perguntas",
+ "ui.tool.agent": "Agente {{type}}",
+ "ui.tool.agent.default": "Agente",
+
+ "ui.common.file.one": "arquivo",
+ "ui.common.file.other": "arquivos",
+ "ui.common.question.one": "pergunta",
+ "ui.common.question.other": "perguntas",
+
+ "ui.common.add": "Adicionar",
+ "ui.common.back": "Voltar",
+ "ui.common.cancel": "Cancelar",
+ "ui.common.confirm": "Confirmar",
+ "ui.common.dismiss": "Descartar",
+ "ui.common.close": "Fechar",
+ "ui.common.next": "Próximo",
+ "ui.common.submit": "Enviar",
+ "ui.common.showMore": "Mostrar mais",
+
+ "ui.permission.deny": "Negar",
+ "ui.permission.allowAlways": "Permitir sempre",
+ "ui.permission.allowOnce": "Permitir uma vez",
+
+ "ui.message.expand": "Expandir mensagem",
+ "ui.message.collapse": "Recolher mensagem",
+ "ui.message.copy": "Copiar",
+ "ui.message.copyMessage": "Copiar mensagem",
+ "ui.message.forkMessage": "Bifurcar para nova sessão",
+ "ui.message.revertMessage": "Redefinir para este ponto",
+ "ui.message.copyResponse": "Copiar resposta",
+ "ui.message.copied": "Copiado!",
+ "ui.message.interrupted": "Interrompido",
+ "ui.message.queued": "Na fila",
+ "ui.message.attachment.alt": "anexo",
+
+ "ui.patch.action.deleted": "Excluído",
+ "ui.patch.action.created": "Criado",
+ "ui.patch.action.moved": "Movido",
+ "ui.patch.action.patched": "Patch aplicado",
+
+ "ui.question.subtitle.answered": "{{count}} respondidas",
+ "ui.question.answer.none": "(sem resposta)",
+ "ui.question.review.notAnswered": "(não respondida)",
+ "ui.question.multiHint": "Selecione todas que se aplicam",
+ "ui.question.singleHint": "Selecione uma resposta",
+ "ui.question.custom.placeholder": "Digite sua resposta...",
+
+ "ui.fileSearch.placeholder": "Localizar",
+ "ui.fileSearch.previousMatch": "Ocorrência anterior",
+ "ui.fileSearch.nextMatch": "Próxima ocorrência",
+ "ui.fileSearch.close": "Fechar busca",
+ "ui.tool.task": "Tarefa",
+ "ui.tool.skill": "Habilidade",
+ "ui.basicTool.called": "Chamou `{{tool}}`",
+ "ui.toolErrorCard.failed": "Falhou",
+ "ui.toolErrorCard.copyError": "Copiar erro",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/bs.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/bs.ts
new file mode 100644
index 00000000..888834b1
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/bs.ts
@@ -0,0 +1,198 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+ "ui.sessionReview.title": "Promjene sesije",
+ "ui.sessionReview.title.git": "Git promjene",
+ "ui.sessionReview.title.branch": "Promjene na grani",
+ "ui.sessionReview.title.lastTurn": "Promjene u posljednjem potezu",
+ "ui.sessionReview.diffStyle.unified": "Ujedinjeno",
+ "ui.sessionReview.diffStyle.split": "Podijeljeno",
+ "ui.sessionReview.openFile": "Otvori fajl",
+ "ui.sessionReview.selection.line": "linija {{line}}",
+ "ui.sessionReview.selection.lines": "linije {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Proširi sve",
+ "ui.sessionReview.collapseAll": "Sažmi sve",
+ "ui.sessionReview.change.added": "Dodano",
+ "ui.sessionReview.change.removed": "Uklonjeno",
+ "ui.sessionReview.change.modified": "Izmijenjeno",
+ "ui.sessionReview.image.loading": "Učitavanje...",
+ "ui.sessionReview.image.placeholder": "Slika",
+ "ui.sessionReview.largeDiff.title": "Diff je prevelik za prikaz",
+ "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} izmijenjenih linija. Trenutno: {{current}} izmijenjenih linija.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Prikaži svejedno",
+ "ui.sessionReviewV2.expandMode": "Proširi ili sažmi diff",
+ "ui.sessionReviewV2.filterFiles": "Filtriraj datoteke",
+ "ui.sessionReviewV2.toggleSidebar": "Prikaži/sakrij stablo datoteka",
+ "ui.sessionReviewV2.showAllLines": "Prikaži sve linije",
+ "ui.sessionReviewV2.hideNonDiffLines": "Sakrij linije bez izmjena",
+ "ui.sessionReviewV2.unifiedDiff": "Ujedinjeni diff",
+ "ui.sessionReviewV2.splitDiff": "Podijeljeni diff",
+ "ui.sessionReviewV2.previousFile": "Prethodna datoteka",
+ "ui.sessionReviewV2.nextFile": "Sljedeća datoteka",
+ "ui.sessionReviewV2.diffView": "Prikaz diff-a",
+ "ui.sessionReviewV2.empty.noGit.title": "Nema praćenih promjena",
+ "ui.sessionReviewV2.empty.noGit.description": "Prati, pregledaj i poništi promjene u ovom projektu",
+ "ui.sessionReviewV2.empty.noGit.action": "Kreiraj Git repozitorij",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Kreiranje Git repozitorija...",
+ "ui.sessionReviewV2.empty.changes.title": "Još nema izmjena u datotekama",
+ "ui.sessionReviewV2.empty.changes.description": "Promjene projekta će se prikazati ovdje",
+ "ui.fileMedia.kind.image": "slika",
+ "ui.fileMedia.kind.audio": "audio",
+ "ui.fileMedia.state.removed": "Uklonjeno: {{kind}}",
+ "ui.fileMedia.state.loading": "Učitavanje: {{kind}}...",
+ "ui.fileMedia.state.error": "Greška pri učitavanju: {{kind}}",
+ "ui.fileMedia.state.unavailable": "Nedostupno: {{kind}}",
+ "ui.fileMedia.binary.title": "Binarni fajl",
+ "ui.fileMedia.binary.description.path": "{{path}} se ne može prikazati jer je binarni fajl.",
+ "ui.fileMedia.binary.description.default": "Ovaj fajl se ne može prikazati jer je binarni.",
+
+ "ui.lineComment.label.prefix": "Komentar na ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Komentarišeš ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Dodaj komentar",
+ "ui.lineComment.submit": "Komentariši",
+ "ui.lineComment.cancel": "Otkaži",
+
+ "ui.sessionTurn.steps.show": "Prikaži korake",
+ "ui.sessionTurn.steps.hide": "Sakrij korake",
+ "ui.sessionTurn.summary.response": "Odgovor",
+ "ui.sessionTurn.diff.showMore": "Prikaži još izmjena ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Izmijenjena datoteka: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Izmijenjene datoteke: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Prikaži sve",
+ "ui.sessionTurn.diffs.showLess": "Prikaži manje",
+ "ui.sessionTurn.diffs.more": "+ još {{count}}",
+
+ "ui.sessionTurn.retry.retrying": "ponovni pokušaj",
+ "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "pokušaj #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - pokušaj #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini je trenutno preopterećen",
+ "ui.sessionTurn.error.freeUsageExceeded": "Besplatna upotreba premašena",
+ "ui.sessionTurn.error.addCredits": "Dodaj kredite",
+
+ "dialog.usageExceeded.freeTier.title": "Dostignut besplatan limit",
+ "dialog.usageExceeded.freeTier.description":
+ "Pretplatite se na OpenCode Go za pouzdan pristup najboljim open-source modelima, počevši od $5/mjesec.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Pretplati se",
+ "dialog.usageExceeded.accountRateLimit.title": "Dostignut Go limit",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Dostignut je limit korištenja. Da nastavite koristiti ovaj model sada, omogućite korištenje iz vašeg dostupnog stanja",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Otvori postavke",
+
+ "ui.sessionTurn.status.delegating": "Delegiranje posla",
+ "ui.sessionTurn.status.planning": "Planiranje sljedećih koraka",
+ "ui.sessionTurn.status.gatheringContext": "Istraživanje",
+ "ui.sessionTurn.status.gatheredContext": "Istraženo",
+ "ui.sessionTurn.status.searchingCodebase": "Pretraživanje baze koda",
+ "ui.sessionTurn.status.searchingWeb": "Pretraživanje weba",
+ "ui.sessionTurn.status.makingEdits": "Pravljenje izmjena",
+ "ui.sessionTurn.status.runningCommands": "Pokretanje komandi",
+ "ui.sessionTurn.status.thinking": "Razmišljanje",
+ "ui.sessionTurn.status.thinkingWithTopic": "Razmišljanje - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Sređivanje misli",
+ "ui.sessionTurn.status.consideringNextSteps": "Razmatranje sljedećih koraka",
+
+ "ui.messagePart.questions.dismissed": "Pitanja odbačena",
+ "ui.messagePart.compaction": "Sesija sažeta",
+ "ui.messagePart.context.read.one": "{{count}} čitanje",
+ "ui.messagePart.context.read.other": "{{count}} čitanja",
+ "ui.messagePart.context.search.one": "{{count}} pretraga",
+ "ui.messagePart.context.search.other": "{{count}} pretrage",
+ "ui.messagePart.context.list.one": "{{count}} lista",
+ "ui.messagePart.context.list.other": "{{count}} liste",
+ "ui.messagePart.diagnostic.error": "Greška",
+ "ui.messagePart.title.edit": "Uredi",
+ "ui.messagePart.title.write": "Napiši",
+ "ui.messagePart.option.typeOwnAnswer": "Unesi svoj odgovor",
+ "ui.messagePart.review.title": "Pregledaj svoje odgovore",
+
+ "ui.list.loading": "Učitavanje",
+ "ui.list.empty": "Nema rezultata",
+ "ui.list.clearFilter": "Očisti filter",
+ "ui.list.emptyWithFilter.prefix": "Nema rezultata za",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Nova poruka",
+
+ "ui.textField.copyToClipboard": "Kopiraj u međuspremnik",
+ "ui.textField.copyLink": "Kopiraj link",
+ "ui.textField.copied": "Kopirano",
+
+ "ui.imagePreview.alt": "Pregled slike",
+ "ui.scrollView.ariaLabel": "sadržaj za pomjeranje",
+
+ "ui.tool.read": "Čitanje",
+ "ui.tool.loaded": "Učitano",
+ "ui.tool.list": "Listanje",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Web preuzimanje",
+ "ui.tool.websearch": "Pretraga weba",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Lista zadataka",
+ "ui.tool.todos.read": "Čitanje liste zadataka",
+ "ui.tool.questions": "Pitanja",
+ "ui.tool.agent": "{{type}} agent",
+ "ui.tool.agent.default": "agent",
+
+ "ui.common.file.one": "datoteka",
+ "ui.common.file.other": "datoteke",
+ "ui.common.question.one": "pitanje",
+ "ui.common.question.other": "pitanja",
+
+ "ui.common.add": "Dodaj",
+ "ui.common.back": "Nazad",
+ "ui.common.cancel": "Otkaži",
+ "ui.common.confirm": "Potvrdi",
+ "ui.common.dismiss": "Odbaci",
+ "ui.common.close": "Zatvori",
+ "ui.common.next": "Dalje",
+ "ui.common.submit": "Pošalji",
+ "ui.common.showMore": "Prikaži više",
+
+ "ui.permission.deny": "Zabrani",
+ "ui.permission.allowAlways": "Uvijek dozvoli",
+ "ui.permission.allowOnce": "Dozvoli jednom",
+
+ "ui.message.expand": "Proširi poruku",
+ "ui.message.collapse": "Sažmi poruku",
+ "ui.message.copy": "Kopiraj",
+ "ui.message.copyMessage": "Kopiraj poruku",
+ "ui.message.forkMessage": "Forkaj u novu sesiju",
+ "ui.message.revertMessage": "Resetuj na ovu tačku",
+ "ui.message.copyResponse": "Kopiraj odgovor",
+ "ui.message.copied": "Kopirano!",
+ "ui.message.interrupted": "Prekinuto",
+ "ui.message.queued": "U redu",
+ "ui.message.attachment.alt": "prilog",
+
+ "ui.patch.action.deleted": "Obrisano",
+ "ui.patch.action.created": "Kreirano",
+ "ui.patch.action.moved": "Premješteno",
+ "ui.patch.action.patched": "Primijenjeno",
+
+ "ui.question.subtitle.answered": "{{count}} odgovoreno",
+ "ui.question.answer.none": "(nema odgovora)",
+ "ui.question.review.notAnswered": "(nije odgovoreno)",
+ "ui.question.multiHint": "Odaberi sve što važi",
+ "ui.question.singleHint": "Odaberi jedan odgovor",
+ "ui.question.custom.placeholder": "Unesi svoj odgovor...",
+
+ "ui.fileSearch.placeholder": "Pronađi",
+ "ui.fileSearch.previousMatch": "Prethodno",
+ "ui.fileSearch.nextMatch": "Sljedeće",
+ "ui.fileSearch.close": "Zatvori pretragu",
+ "ui.tool.task": "Zadatak",
+ "ui.tool.skill": "Vještina",
+ "ui.basicTool.called": "Pozvan `{{tool}}`",
+ "ui.toolErrorCard.failed": "Neuspješno",
+ "ui.toolErrorCard.copyError": "Kopiraj grešku",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/da.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/da.ts
new file mode 100644
index 00000000..39540243
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/da.ts
@@ -0,0 +1,193 @@
+export const dict = {
+ "ui.sessionReview.title": "Sessionsændringer",
+ "ui.sessionReview.title.git": "Git-ændringer",
+ "ui.sessionReview.title.branch": "Grenændringer",
+ "ui.sessionReview.title.lastTurn": "Ændringer fra sidste tur",
+ "ui.sessionReview.diffStyle.unified": "Samlet",
+ "ui.sessionReview.diffStyle.split": "Opdelt",
+ "ui.sessionReview.openFile": "Åbn fil",
+ "ui.sessionReview.selection.line": "linje {{line}}",
+ "ui.sessionReview.selection.lines": "linjer {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Udvid alle",
+ "ui.sessionReview.collapseAll": "Skjul alle",
+
+ "ui.sessionReview.change.added": "Tilføjet",
+ "ui.sessionReview.change.removed": "Fjernet",
+ "ui.sessionReview.change.modified": "Ændret",
+ "ui.sessionReview.image.loading": "Indlæser...",
+ "ui.sessionReview.image.placeholder": "Billede",
+ "ui.sessionReview.largeDiff.title": "Diff er for stor til at blive vist",
+ "ui.sessionReview.largeDiff.meta": "Grænse: {{limit}} ændrede linjer. Nuværende: {{current}} ændrede linjer.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Vis alligevel",
+ "ui.sessionReviewV2.expandMode": "Udvid eller skjul diff",
+ "ui.sessionReviewV2.filterFiles": "Filtrer filer",
+ "ui.sessionReviewV2.toggleSidebar": "Skift filtræ",
+ "ui.sessionReviewV2.showAllLines": "Vis alle linjer",
+ "ui.sessionReviewV2.hideNonDiffLines": "Skjul linjer uden ændringer",
+ "ui.sessionReviewV2.unifiedDiff": "Samlet diff",
+ "ui.sessionReviewV2.splitDiff": "Opdelt diff",
+ "ui.sessionReviewV2.previousFile": "Forrige fil",
+ "ui.sessionReviewV2.nextFile": "Næste fil",
+ "ui.sessionReviewV2.diffView": "Diffvisning",
+ "ui.sessionReviewV2.empty.noGit.title": "Ingen sporede ændringer",
+ "ui.sessionReviewV2.empty.noGit.description": "Spor, gennemgå og fortryd ændringer i dette projekt",
+ "ui.sessionReviewV2.empty.noGit.action": "Opret et Git-repository",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Opretter Git-repository...",
+ "ui.sessionReviewV2.empty.changes.title": "Ingen filændringer endnu",
+ "ui.sessionReviewV2.empty.changes.description": "Projektændringer vises her",
+ "ui.fileMedia.kind.image": "billede",
+ "ui.fileMedia.kind.audio": "lyd",
+ "ui.fileMedia.state.removed": "Fjernet: {{kind}}",
+ "ui.fileMedia.state.loading": "Indlæser {{kind}}...",
+ "ui.fileMedia.state.error": "Fejl ved indlæsning: {{kind}}",
+ "ui.fileMedia.state.unavailable": "Utilgængelig: {{kind}}",
+ "ui.fileMedia.binary.title": "Binær fil",
+ "ui.fileMedia.binary.description.path": "{{path}} kan ikke vises, fordi det er en binær fil.",
+ "ui.fileMedia.binary.description.default": "Denne fil kan ikke vises, fordi det er en binær fil.",
+ "ui.lineComment.label.prefix": "Kommenter på ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Kommenterer på ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Tilføj kommentar",
+ "ui.lineComment.submit": "Kommenter",
+ "ui.lineComment.cancel": "Annuller",
+ "ui.sessionTurn.steps.show": "Vis trin",
+ "ui.sessionTurn.steps.hide": "Skjul trin",
+ "ui.sessionTurn.summary.response": "Svar",
+ "ui.sessionTurn.diff.showMore": "Vis flere ændringer ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Ændret fil: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Ændrede filer: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Vis alle",
+ "ui.sessionTurn.diffs.showLess": "Vis færre",
+ "ui.sessionTurn.diffs.more": "+{{count}} mere",
+
+ "ui.sessionTurn.retry.retrying": "prøver igen",
+ "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "forsøg #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - forsøg #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini er meget overbelastet lige nu",
+ "ui.sessionTurn.error.freeUsageExceeded": "Gratis forbrug overskredet",
+ "ui.sessionTurn.error.addCredits": "Tilføj kreditter",
+
+ "dialog.usageExceeded.freeTier.title": "Gratis grænse nået",
+ "dialog.usageExceeded.freeTier.description":
+ "Abonnér på OpenCode Go for pålidelig adgang til de bedste open source-modeller, fra $5/måned.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Abonnér",
+ "dialog.usageExceeded.accountRateLimit.title": "Go-grænse nået",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Forbrugsgrænse nået. For at fortsætte med at bruge denne model nu, aktivér forbrug fra din tilgængelige saldo",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Åbn indstillinger",
+
+ "ui.sessionTurn.status.delegating": "Delegerer arbejde",
+ "ui.sessionTurn.status.planning": "Planlægger næste trin",
+ "ui.sessionTurn.status.gatheringContext": "Udforsker",
+ "ui.sessionTurn.status.gatheredContext": "Udforsket",
+ "ui.sessionTurn.status.searchingCodebase": "Søger i koden",
+ "ui.sessionTurn.status.searchingWeb": "Søger på nettet",
+ "ui.sessionTurn.status.makingEdits": "Laver ændringer",
+ "ui.sessionTurn.status.runningCommands": "Kører kommandoer",
+ "ui.sessionTurn.status.thinking": "Tænker",
+ "ui.sessionTurn.status.thinkingWithTopic": "Tænker - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Samler tanker",
+ "ui.sessionTurn.status.consideringNextSteps": "Overvejer næste skridt",
+
+ "ui.messagePart.questions.dismissed": "Spørgsmål afvist",
+ "ui.messagePart.compaction": "Session komprimeret",
+ "ui.messagePart.context.read.one": "{{count}} læsning",
+ "ui.messagePart.context.read.other": "{{count}} læsninger",
+ "ui.messagePart.context.search.one": "{{count}} søgning",
+ "ui.messagePart.context.search.other": "{{count}} søgninger",
+ "ui.messagePart.context.list.one": "{{count}} liste",
+ "ui.messagePart.context.list.other": "{{count}} lister",
+ "ui.messagePart.diagnostic.error": "Fejl",
+ "ui.messagePart.title.edit": "Rediger",
+ "ui.messagePart.title.write": "Skriv",
+ "ui.messagePart.option.typeOwnAnswer": "Skriv dit eget svar",
+ "ui.messagePart.review.title": "Gennemgå dine svar",
+
+ "ui.list.loading": "Indlæser",
+ "ui.list.empty": "Ingen resultater",
+ "ui.list.clearFilter": "Ryd filter",
+ "ui.list.emptyWithFilter.prefix": "Ingen resultater for",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Ny besked",
+
+ "ui.textField.copyToClipboard": "Kopier til udklipsholder",
+ "ui.textField.copyLink": "Kopier link",
+ "ui.textField.copied": "Kopieret",
+
+ "ui.imagePreview.alt": "Billedforhåndsvisning",
+ "ui.scrollView.ariaLabel": "rulbart indhold",
+
+ "ui.tool.read": "Læs",
+ "ui.tool.loaded": "Indlæst",
+ "ui.tool.list": "Liste",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webhentning",
+ "ui.tool.websearch": "Websøgning",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Opgaver",
+ "ui.tool.todos.read": "Læs opgaver",
+ "ui.tool.questions": "Spørgsmål",
+ "ui.tool.agent": "{{type}} Agent",
+ "ui.tool.agent.default": "Agent",
+
+ "ui.common.file.one": "fil",
+ "ui.common.file.other": "filer",
+ "ui.common.question.one": "spørgsmål",
+ "ui.common.question.other": "spørgsmål",
+
+ "ui.common.add": "Tilføj",
+ "ui.common.back": "Tilbage",
+ "ui.common.cancel": "Annuller",
+ "ui.common.confirm": "Bekræft",
+ "ui.common.dismiss": "Afvis",
+ "ui.common.close": "Luk",
+ "ui.common.next": "Næste",
+ "ui.common.submit": "Indsend",
+ "ui.common.showMore": "Vis mere",
+
+ "ui.permission.deny": "Afvis",
+ "ui.permission.allowAlways": "Tillad altid",
+ "ui.permission.allowOnce": "Tillad én gang",
+
+ "ui.message.expand": "Udvid besked",
+ "ui.message.collapse": "Skjul besked",
+ "ui.message.copy": "Kopier",
+ "ui.message.copyMessage": "Kopier besked",
+ "ui.message.forkMessage": "Forgren til ny session",
+ "ui.message.revertMessage": "Nulstil til dette punkt",
+ "ui.message.copyResponse": "Kopier svar",
+ "ui.message.copied": "Kopieret!",
+ "ui.message.interrupted": "Afbrudt",
+ "ui.message.queued": "I kø",
+ "ui.message.attachment.alt": "vedhæftning",
+
+ "ui.patch.action.deleted": "Slettet",
+ "ui.patch.action.created": "Oprettet",
+ "ui.patch.action.moved": "Flyttet",
+ "ui.patch.action.patched": "Patchet",
+
+ "ui.question.subtitle.answered": "{{count}} besvaret",
+ "ui.question.answer.none": "(intet svar)",
+ "ui.question.review.notAnswered": "(ikke besvaret)",
+ "ui.question.multiHint": "Vælg alle der gælder",
+ "ui.question.singleHint": "Vælg ét svar",
+ "ui.question.custom.placeholder": "Skriv dit svar...",
+
+ "ui.fileSearch.placeholder": "Find",
+ "ui.fileSearch.previousMatch": "Forrige match",
+ "ui.fileSearch.nextMatch": "Næste match",
+ "ui.fileSearch.close": "Luk søgning",
+ "ui.tool.task": "Opgave",
+ "ui.tool.skill": "Færdighed",
+ "ui.basicTool.called": "Kaldte `{{tool}}`",
+ "ui.toolErrorCard.failed": "Fejlede",
+ "ui.toolErrorCard.copyError": "Kopier fejl",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/de.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/de.ts
new file mode 100644
index 00000000..68a1e050
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/de.ts
@@ -0,0 +1,200 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+ "ui.sessionReview.title": "Sitzungsänderungen",
+ "ui.sessionReview.title.git": "Git-Änderungen",
+ "ui.sessionReview.title.branch": "Branch-Änderungen",
+ "ui.sessionReview.title.lastTurn": "Änderungen der letzten Runde",
+ "ui.sessionReview.diffStyle.unified": "Vereinheitlicht",
+ "ui.sessionReview.diffStyle.split": "Geteilt",
+ "ui.sessionReview.openFile": "Datei öffnen",
+ "ui.sessionReview.selection.line": "Zeile {{line}}",
+ "ui.sessionReview.selection.lines": "Zeilen {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Alle erweitern",
+ "ui.sessionReview.collapseAll": "Alle reduzieren",
+
+ "ui.sessionReview.change.added": "Hinzugefügt",
+ "ui.sessionReview.change.removed": "Entfernt",
+ "ui.sessionReview.change.modified": "Geändert",
+ "ui.sessionReview.image.loading": "Wird geladen...",
+ "ui.sessionReview.image.placeholder": "Bild",
+ "ui.sessionReview.largeDiff.title": "Diff zu groß zum Rendern",
+ "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} geänderte Zeilen. Aktuell: {{current}} geänderte Zeilen.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Trotzdem rendern",
+ "ui.sessionReviewV2.expandMode": "Diff ein- oder ausklappen",
+ "ui.sessionReviewV2.filterFiles": "Dateien filtern",
+ "ui.sessionReviewV2.toggleSidebar": "Dateibaum umschalten",
+ "ui.sessionReviewV2.showAllLines": "Alle Zeilen anzeigen",
+ "ui.sessionReviewV2.hideNonDiffLines": "Zeilen außerhalb des Diffs ausblenden",
+ "ui.sessionReviewV2.unifiedDiff": "Vereinheitlichter Diff",
+ "ui.sessionReviewV2.splitDiff": "Geteilter Diff",
+ "ui.sessionReviewV2.previousFile": "Vorherige Datei",
+ "ui.sessionReviewV2.nextFile": "Nächste Datei",
+ "ui.sessionReviewV2.diffView": "Diff-Ansicht",
+ "ui.sessionReviewV2.empty.noGit.title": "Keine verfolgten Änderungen",
+ "ui.sessionReviewV2.empty.noGit.description":
+ "Änderungen in diesem Projekt verfolgen, überprüfen und rückgängig machen",
+ "ui.sessionReviewV2.empty.noGit.action": "Git-Repository erstellen",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Git-Repository wird erstellt...",
+ "ui.sessionReviewV2.empty.changes.title": "Noch keine Dateiänderungen",
+ "ui.sessionReviewV2.empty.changes.description": "Projektänderungen werden hier angezeigt",
+ "ui.fileMedia.kind.image": "bild",
+ "ui.fileMedia.kind.audio": "audio",
+ "ui.fileMedia.state.removed": "{{kind}} entfernt",
+ "ui.fileMedia.state.loading": "{{kind}} wird geladen",
+ "ui.fileMedia.state.error": "Fehler bei {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} nicht verfügbar",
+ "ui.fileMedia.binary.title": "Binärdatei",
+ "ui.fileMedia.binary.description.path":
+ "{{path}} kann nicht angezeigt werden, da es sich um eine Binärdatei handelt.",
+ "ui.fileMedia.binary.description.default":
+ "Diese Datei kann nicht angezeigt werden, da es sich um eine Binärdatei handelt.",
+ "ui.lineComment.label.prefix": "Kommentar zu ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Kommentiere ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Kommentar hinzufügen",
+ "ui.lineComment.submit": "Kommentieren",
+ "ui.lineComment.cancel": "Abbrechen",
+ "ui.sessionTurn.steps.show": "Schritte anzeigen",
+ "ui.sessionTurn.steps.hide": "Schritte ausblenden",
+ "ui.sessionTurn.summary.response": "Antwort",
+ "ui.sessionTurn.diff.showMore": "Weitere Änderungen anzeigen ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Geänderte Datei: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Geänderte Dateien: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Alle anzeigen",
+ "ui.sessionTurn.diffs.showLess": "Weniger anzeigen",
+ "ui.sessionTurn.diffs.more": "+{{count}} weitere",
+
+ "ui.sessionTurn.retry.retrying": "erneuter Versuch",
+ "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "Versuch #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - Versuch #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini ist gerade sehr überlastet",
+ "ui.sessionTurn.error.freeUsageExceeded": "Kostenloses Nutzungslimit überschritten",
+ "ui.sessionTurn.error.addCredits": "Guthaben aufladen",
+
+ "dialog.usageExceeded.freeTier.title": "Kostenloses Limit erreicht",
+ "dialog.usageExceeded.freeTier.description":
+ "Abonniere OpenCode Go für zuverlässigen Zugriff auf die besten Open-Source-Modelle, ab $5/Monat.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Abonnieren",
+ "dialog.usageExceeded.accountRateLimit.title": "Go-Limit erreicht",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Nutzungslimit erreicht. Um dieses Modell jetzt weiter zu nutzen, aktiviere die Nutzung über dein verfügbares Guthaben",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Einstellungen öffnen",
+
+ "ui.sessionTurn.status.delegating": "Arbeit delegieren",
+ "ui.sessionTurn.status.planning": "Nächste Schritte planen",
+ "ui.sessionTurn.status.gatheringContext": "Erkunden",
+ "ui.sessionTurn.status.gatheredContext": "Erkundet",
+ "ui.sessionTurn.status.searchingCodebase": "Codebasis durchsuchen",
+ "ui.sessionTurn.status.searchingWeb": "Web durchsuchen",
+ "ui.sessionTurn.status.makingEdits": "Änderungen vornehmen",
+ "ui.sessionTurn.status.runningCommands": "Befehle ausführen",
+ "ui.sessionTurn.status.thinking": "Denken",
+ "ui.sessionTurn.status.thinkingWithTopic": "Denken - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Gedanken sammeln",
+ "ui.sessionTurn.status.consideringNextSteps": "Nächste Schritte erwägen",
+
+ "ui.messagePart.questions.dismissed": "Fragen verworfen",
+ "ui.messagePart.compaction": "Sitzung komprimiert",
+ "ui.messagePart.context.read.one": "{{count}} Lesevorgang",
+ "ui.messagePart.context.read.other": "{{count}} Lesevorgänge",
+ "ui.messagePart.context.search.one": "{{count}} Suche",
+ "ui.messagePart.context.search.other": "{{count}} Suchen",
+ "ui.messagePart.context.list.one": "{{count}} Liste",
+ "ui.messagePart.context.list.other": "{{count}} Listen",
+ "ui.messagePart.diagnostic.error": "Fehler",
+ "ui.messagePart.title.edit": "Bearbeiten",
+ "ui.messagePart.title.write": "Schreiben",
+ "ui.messagePart.option.typeOwnAnswer": "Eigene Antwort eingeben",
+ "ui.messagePart.review.title": "Antworten überprüfen",
+
+ "ui.list.loading": "Laden",
+ "ui.list.empty": "Keine Ergebnisse",
+ "ui.list.clearFilter": "Filter löschen",
+ "ui.list.emptyWithFilter.prefix": "Keine Ergebnisse für",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Neue Nachricht",
+
+ "ui.textField.copyToClipboard": "In die Zwischenablage kopieren",
+ "ui.textField.copyLink": "Link kopieren",
+ "ui.textField.copied": "Kopiert",
+
+ "ui.imagePreview.alt": "Bildvorschau",
+ "ui.scrollView.ariaLabel": "scrollbarer Inhalt",
+
+ "ui.tool.read": "Lesen",
+ "ui.tool.loaded": "Geladen",
+ "ui.tool.list": "Auflisten",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webabruf",
+ "ui.tool.websearch": "Websuche",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Aufgaben",
+ "ui.tool.todos.read": "Aufgaben lesen",
+ "ui.tool.questions": "Fragen",
+ "ui.tool.agent": "{{type}} Agent",
+ "ui.tool.agent.default": "Agent",
+
+ "ui.common.file.one": "Datei",
+ "ui.common.file.other": "Dateien",
+ "ui.common.question.one": "Frage",
+ "ui.common.question.other": "Fragen",
+
+ "ui.common.add": "Hinzufügen",
+ "ui.common.back": "Zurück",
+ "ui.common.cancel": "Abbrechen",
+ "ui.common.confirm": "Bestätigen",
+ "ui.common.dismiss": "Verwerfen",
+ "ui.common.close": "Schließen",
+ "ui.common.next": "Weiter",
+ "ui.common.submit": "Absenden",
+ "ui.common.showMore": "Mehr anzeigen",
+
+ "ui.permission.deny": "Verweigern",
+ "ui.permission.allowAlways": "Immer erlauben",
+ "ui.permission.allowOnce": "Einmal erlauben",
+
+ "ui.message.expand": "Nachricht erweitern",
+ "ui.message.collapse": "Nachricht reduzieren",
+ "ui.message.copy": "Kopieren",
+ "ui.message.copyMessage": "Nachricht kopieren",
+ "ui.message.forkMessage": "In neue Sitzung abzweigen",
+ "ui.message.revertMessage": "Auf diesen Punkt zurücksetzen",
+ "ui.message.copyResponse": "Antwort kopieren",
+ "ui.message.copied": "Kopiert!",
+ "ui.message.interrupted": "Unterbrochen",
+ "ui.message.queued": "In Warteschlange",
+ "ui.message.attachment.alt": "Anhang",
+
+ "ui.patch.action.deleted": "Gelöscht",
+ "ui.patch.action.created": "Erstellt",
+ "ui.patch.action.moved": "Verschoben",
+ "ui.patch.action.patched": "Gepatched",
+
+ "ui.question.subtitle.answered": "{{count}} beantwortet",
+ "ui.question.answer.none": "(keine Antwort)",
+ "ui.question.review.notAnswered": "(nicht beantwortet)",
+ "ui.question.multiHint": "Alle zutreffenden auswählen",
+ "ui.question.singleHint": "Eine Antwort auswählen",
+ "ui.question.custom.placeholder": "Geben Sie Ihre Antwort ein...",
+
+ "ui.fileSearch.placeholder": "Suchen",
+ "ui.fileSearch.previousMatch": "Vorheriges Ergebnis",
+ "ui.fileSearch.nextMatch": "Nächstes Ergebnis",
+ "ui.fileSearch.close": "Suche schließen",
+ "ui.tool.task": "Aufgabe",
+ "ui.tool.skill": "Fähigkeit",
+ "ui.basicTool.called": "`{{tool}}` aufgerufen",
+ "ui.toolErrorCard.failed": "Fehlgeschlagen",
+ "ui.toolErrorCard.copyError": "Fehler kopieren",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/en.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/en.ts
index c492953e..fbbfa2fc 100644
--- a/packages/app-bundle/overlay/packages/ui/src/i18n/en.ts
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/en.ts
@@ -175,6 +175,7 @@ export const dict: Record = {
"ui.message.forkMessage": "Fork to new session",
"ui.message.revertMessage": "Revert message",
"ui.message.copyResponse": "Copy response",
+ "ui.message.copyTrace": "Copy trace",
"ui.message.copied": "Copied",
"ui.message.duration.seconds": "{{count}}s",
"ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/es.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/es.ts
new file mode 100644
index 00000000..2ba67a7d
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/es.ts
@@ -0,0 +1,194 @@
+export const dict = {
+ "ui.sessionReview.title": "Cambios de la sesión",
+ "ui.sessionReview.title.git": "Cambios de Git",
+ "ui.sessionReview.title.branch": "Cambios de la rama",
+ "ui.sessionReview.title.lastTurn": "Cambios del último turno",
+ "ui.sessionReview.diffStyle.unified": "Unificado",
+ "ui.sessionReview.diffStyle.split": "Dividido",
+ "ui.sessionReview.openFile": "Abrir archivo",
+ "ui.sessionReview.selection.line": "línea {{line}}",
+ "ui.sessionReview.selection.lines": "líneas {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Expandir todo",
+ "ui.sessionReview.collapseAll": "Colapsar todo",
+ "ui.sessionReview.change.added": "Añadido",
+ "ui.sessionReview.change.removed": "Eliminado",
+ "ui.sessionReview.change.modified": "Modificado",
+ "ui.sessionReview.image.loading": "Cargando...",
+ "ui.sessionReview.image.placeholder": "Imagen",
+ "ui.sessionReview.largeDiff.title": "Diff demasiado grande para renderizar",
+ "ui.sessionReview.largeDiff.meta": "Límite: {{limit}} líneas modificadas. Actual: {{current}} líneas modificadas.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Renderizar de todos modos",
+ "ui.sessionReviewV2.expandMode": "Expandir o colapsar diff",
+ "ui.sessionReviewV2.filterFiles": "Filtrar archivos",
+ "ui.sessionReviewV2.toggleSidebar": "Alternar árbol de archivos",
+ "ui.sessionReviewV2.showAllLines": "Mostrar todas las líneas",
+ "ui.sessionReviewV2.hideNonDiffLines": "Ocultar líneas sin cambios",
+ "ui.sessionReviewV2.unifiedDiff": "Diff unificado",
+ "ui.sessionReviewV2.splitDiff": "Diff dividido",
+ "ui.sessionReviewV2.previousFile": "Archivo anterior",
+ "ui.sessionReviewV2.nextFile": "Siguiente archivo",
+ "ui.sessionReviewV2.diffView": "Vista de diff",
+ "ui.sessionReviewV2.empty.noGit.title": "No hay cambios rastreados",
+ "ui.sessionReviewV2.empty.noGit.description": "Rastrea, revisa y deshaz cambios en este proyecto",
+ "ui.sessionReviewV2.empty.noGit.action": "Crear repositorio Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Creando repositorio Git...",
+ "ui.sessionReviewV2.empty.changes.title": "Aún no hay cambios en los archivos",
+ "ui.sessionReviewV2.empty.changes.description": "Los cambios del proyecto aparecerán aquí",
+ "ui.fileMedia.kind.image": "imagen",
+ "ui.fileMedia.kind.audio": "audio",
+ "ui.fileMedia.state.removed": "Archivo de {{kind}} eliminado",
+ "ui.fileMedia.state.loading": "Cargando archivo de {{kind}}",
+ "ui.fileMedia.state.error": "Error en el archivo de {{kind}}",
+ "ui.fileMedia.state.unavailable": "Archivo de {{kind}} no disponible",
+ "ui.fileMedia.binary.title": "Archivo binario",
+ "ui.fileMedia.binary.description.path": "No se puede mostrar {{path}} porque es un archivo binario.",
+ "ui.fileMedia.binary.description.default": "No se puede mostrar este archivo porque es un archivo binario.",
+
+ "ui.lineComment.label.prefix": "Comentar en ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Comentando en ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Añadir comentario",
+ "ui.lineComment.submit": "Comentar",
+ "ui.lineComment.cancel": "Cancelar",
+
+ "ui.sessionTurn.steps.show": "Mostrar pasos",
+ "ui.sessionTurn.steps.hide": "Ocultar pasos",
+ "ui.sessionTurn.summary.response": "Respuesta",
+ "ui.sessionTurn.diff.showMore": "Mostrar más cambios ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Archivo modificado: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Archivos modificados: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Mostrar todos",
+ "ui.sessionTurn.diffs.showLess": "Mostrar menos",
+ "ui.sessionTurn.diffs.more": "+{{count}} más",
+
+ "ui.sessionTurn.retry.retrying": "reintentando",
+ "ui.sessionTurn.retry.inSeconds": "en {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "intento #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - intento #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini está demasiado saturado",
+ "ui.sessionTurn.error.freeUsageExceeded": "Límite de uso gratuito excedido",
+ "ui.sessionTurn.error.addCredits": "Añadir créditos",
+
+ "dialog.usageExceeded.freeTier.title": "Límite gratuito alcanzado",
+ "dialog.usageExceeded.freeTier.description":
+ "Suscríbete a OpenCode Go para acceso fiable a los mejores modelos de código abierto, desde $5/mes.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Suscribirse",
+ "dialog.usageExceeded.accountRateLimit.title": "Límite de Go alcanzado",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Límite de uso alcanzado. Para seguir usando este modelo ahora, habilita el uso desde tu saldo disponible",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Abrir configuración",
+
+ "ui.sessionTurn.status.delegating": "Delegando trabajo",
+ "ui.sessionTurn.status.planning": "Planificando siguientes pasos",
+ "ui.sessionTurn.status.gatheringContext": "Explorando",
+ "ui.sessionTurn.status.gatheredContext": "Explorado",
+ "ui.sessionTurn.status.searchingCodebase": "Buscando en la base de código",
+ "ui.sessionTurn.status.searchingWeb": "Buscando en la web",
+ "ui.sessionTurn.status.makingEdits": "Realizando ediciones",
+ "ui.sessionTurn.status.runningCommands": "Ejecutando comandos",
+ "ui.sessionTurn.status.thinking": "Pensando",
+ "ui.sessionTurn.status.thinkingWithTopic": "Pensando - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Recopilando pensamientos",
+ "ui.sessionTurn.status.consideringNextSteps": "Considerando siguientes pasos",
+
+ "ui.messagePart.questions.dismissed": "Preguntas descartadas",
+ "ui.messagePart.compaction": "Sesión compactada",
+ "ui.messagePart.context.read.one": "{{count}} lectura",
+ "ui.messagePart.context.read.other": "{{count}} lecturas",
+ "ui.messagePart.context.search.one": "{{count}} búsqueda",
+ "ui.messagePart.context.search.other": "{{count}} búsquedas",
+ "ui.messagePart.context.list.one": "{{count}} lista",
+ "ui.messagePart.context.list.other": "{{count}} listas",
+ "ui.messagePart.diagnostic.error": "Error",
+ "ui.messagePart.title.edit": "Editar",
+ "ui.messagePart.title.write": "Escribir",
+ "ui.messagePart.option.typeOwnAnswer": "Escribe tu propia respuesta",
+ "ui.messagePart.review.title": "Revisa tus respuestas",
+
+ "ui.list.loading": "Cargando",
+ "ui.list.empty": "Sin resultados",
+ "ui.list.clearFilter": "Borrar filtro",
+ "ui.list.emptyWithFilter.prefix": "Sin resultados para",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Nuevo mensaje",
+
+ "ui.textField.copyToClipboard": "Copiar al portapapeles",
+ "ui.textField.copyLink": "Copiar enlace",
+ "ui.textField.copied": "Copiado",
+
+ "ui.imagePreview.alt": "Vista previa de imagen",
+ "ui.scrollView.ariaLabel": "contenido desplazable",
+
+ "ui.tool.read": "Leer",
+ "ui.tool.loaded": "Cargado",
+ "ui.tool.list": "Listar",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "Búsqueda web",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Parche",
+ "ui.tool.todos": "Tareas",
+ "ui.tool.todos.read": "Leer tareas",
+ "ui.tool.questions": "Preguntas",
+ "ui.tool.agent": "Agente {{type}}",
+ "ui.tool.agent.default": "Agente",
+
+ "ui.common.file.one": "archivo",
+ "ui.common.file.other": "archivos",
+ "ui.common.question.one": "pregunta",
+ "ui.common.question.other": "preguntas",
+
+ "ui.common.add": "Añadir",
+ "ui.common.back": "Atrás",
+ "ui.common.cancel": "Cancelar",
+ "ui.common.confirm": "Confirmar",
+ "ui.common.dismiss": "Descartar",
+ "ui.common.close": "Cerrar",
+ "ui.common.next": "Siguiente",
+ "ui.common.submit": "Enviar",
+ "ui.common.showMore": "Mostrar más",
+
+ "ui.permission.deny": "Denegar",
+ "ui.permission.allowAlways": "Permitir siempre",
+ "ui.permission.allowOnce": "Permitir una vez",
+
+ "ui.message.expand": "Expandir mensaje",
+ "ui.message.collapse": "Colapsar mensaje",
+ "ui.message.copy": "Copiar",
+ "ui.message.copyMessage": "Copiar mensaje",
+ "ui.message.forkMessage": "Bifurcar a nueva sesión",
+ "ui.message.revertMessage": "Restablecer a este punto",
+ "ui.message.copyResponse": "Copiar respuesta",
+ "ui.message.copied": "¡Copiado!",
+ "ui.message.interrupted": "Interrumpido",
+ "ui.message.queued": "En cola",
+ "ui.message.attachment.alt": "adjunto",
+
+ "ui.patch.action.deleted": "Eliminado",
+ "ui.patch.action.created": "Creado",
+ "ui.patch.action.moved": "Movido",
+ "ui.patch.action.patched": "Parcheado",
+
+ "ui.question.subtitle.answered": "{{count}} respondidas",
+ "ui.question.answer.none": "(sin respuesta)",
+ "ui.question.review.notAnswered": "(no respondida)",
+ "ui.question.multiHint": "Selecciona todas las que correspondan",
+ "ui.question.singleHint": "Selecciona una respuesta",
+ "ui.question.custom.placeholder": "Escribe tu respuesta...",
+
+ "ui.fileSearch.placeholder": "Buscar",
+ "ui.fileSearch.previousMatch": "Anterior",
+ "ui.fileSearch.nextMatch": "Siguiente",
+ "ui.fileSearch.close": "Cerrar búsqueda",
+ "ui.tool.task": "Tarea",
+ "ui.tool.skill": "Habilidad",
+ "ui.basicTool.called": "Llamado `{{tool}}`",
+ "ui.toolErrorCard.failed": "Falló",
+ "ui.toolErrorCard.copyError": "Copiar error",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/fr.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/fr.ts
new file mode 100644
index 00000000..44a8ad13
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/fr.ts
@@ -0,0 +1,194 @@
+export const dict = {
+ "ui.sessionReview.title": "Modifications de la session",
+ "ui.sessionReview.title.git": "Modifications Git",
+ "ui.sessionReview.title.branch": "Modifications de la branche",
+ "ui.sessionReview.title.lastTurn": "Modifications du dernier tour",
+ "ui.sessionReview.diffStyle.unified": "Unifié",
+ "ui.sessionReview.diffStyle.split": "Divisé",
+ "ui.sessionReview.openFile": "Ouvrir le fichier",
+ "ui.sessionReview.selection.line": "ligne {{line}}",
+ "ui.sessionReview.selection.lines": "lignes {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Tout développer",
+ "ui.sessionReview.collapseAll": "Tout réduire",
+ "ui.sessionReview.change.added": "Ajouté",
+ "ui.sessionReview.change.removed": "Supprimé",
+ "ui.sessionReview.change.modified": "Modifié",
+ "ui.sessionReview.image.loading": "Chargement...",
+ "ui.sessionReview.image.placeholder": "Image",
+ "ui.sessionReview.largeDiff.title": "Diff trop volumineux pour être affiché",
+ "ui.sessionReview.largeDiff.meta": "Limite : {{limit}} lignes modifiées. Actuel : {{current}} lignes modifiées.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Afficher quand même",
+ "ui.sessionReviewV2.expandMode": "Développer ou réduire le diff",
+ "ui.sessionReviewV2.filterFiles": "Filtrer les fichiers",
+ "ui.sessionReviewV2.toggleSidebar": "Afficher ou masquer l'arborescence des fichiers",
+ "ui.sessionReviewV2.showAllLines": "Afficher toutes les lignes",
+ "ui.sessionReviewV2.hideNonDiffLines": "Masquer les lignes hors diff",
+ "ui.sessionReviewV2.unifiedDiff": "Diff unifié",
+ "ui.sessionReviewV2.splitDiff": "Diff côte à côte",
+ "ui.sessionReviewV2.previousFile": "Fichier précédent",
+ "ui.sessionReviewV2.nextFile": "Fichier suivant",
+ "ui.sessionReviewV2.diffView": "Vue du diff",
+ "ui.sessionReviewV2.empty.noGit.title": "Aucune modification suivie",
+ "ui.sessionReviewV2.empty.noGit.description": "Suivre, examiner et annuler les modifications dans ce projet",
+ "ui.sessionReviewV2.empty.noGit.action": "Créer un dépôt Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Création du dépôt Git...",
+ "ui.sessionReviewV2.empty.changes.title": "Aucune modification de fichier pour l'instant",
+ "ui.sessionReviewV2.empty.changes.description": "Les modifications du projet apparaîtront ici",
+ "ui.fileMedia.kind.image": "image",
+ "ui.fileMedia.kind.audio": "audio",
+ "ui.fileMedia.state.removed": "Fichier {{kind}} supprimé",
+ "ui.fileMedia.state.loading": "Chargement du fichier {{kind}}",
+ "ui.fileMedia.state.error": "Erreur avec le fichier {{kind}}",
+ "ui.fileMedia.state.unavailable": "Fichier {{kind}} indisponible",
+ "ui.fileMedia.binary.title": "Fichier binaire",
+ "ui.fileMedia.binary.description.path": "Impossible d'afficher {{path}} car il s'agit d'un fichier binaire.",
+ "ui.fileMedia.binary.description.default": "Impossible d'afficher ce fichier car il s'agit d'un fichier binaire.",
+
+ "ui.lineComment.label.prefix": "Commenter sur ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Commentaire sur ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Ajouter un commentaire",
+ "ui.lineComment.submit": "Commenter",
+ "ui.lineComment.cancel": "Annuler",
+
+ "ui.sessionTurn.steps.show": "Afficher les étapes",
+ "ui.sessionTurn.steps.hide": "Masquer les étapes",
+ "ui.sessionTurn.summary.response": "Réponse",
+ "ui.sessionTurn.diff.showMore": "Afficher plus de modifications ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Fichier modifié : {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Fichiers modifiés : {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Tout afficher",
+ "ui.sessionTurn.diffs.showLess": "Afficher moins",
+ "ui.sessionTurn.diffs.more": "+{{count}} de plus",
+
+ "ui.sessionTurn.retry.retrying": "nouvelle tentative",
+ "ui.sessionTurn.retry.inSeconds": "dans {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "tentative n°{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - tentative n°{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini est en surchauffe",
+ "ui.sessionTurn.error.freeUsageExceeded": "Limite d'utilisation gratuite dépassée",
+ "ui.sessionTurn.error.addCredits": "Ajouter des crédits",
+
+ "dialog.usageExceeded.freeTier.title": "Limite gratuite atteinte",
+ "dialog.usageExceeded.freeTier.description":
+ "Abonnez-vous à OpenCode Go pour un accès fiable aux meilleurs modèles open source, à partir de $5/mois.",
+ "dialog.usageExceeded.freeTier.actionLabel": "S'abonner",
+ "dialog.usageExceeded.accountRateLimit.title": "Limite Go atteinte",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Limite d'utilisation atteinte. Pour continuer à utiliser ce modèle maintenant, activez l'utilisation depuis votre solde disponible",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Ouvrir les paramètres",
+
+ "ui.sessionTurn.status.delegating": "Délégation du travail",
+ "ui.sessionTurn.status.planning": "Planification des prochaines étapes",
+ "ui.sessionTurn.status.gatheringContext": "Exploration",
+ "ui.sessionTurn.status.gatheredContext": "Exploré",
+ "ui.sessionTurn.status.searchingCodebase": "Recherche dans la base de code",
+ "ui.sessionTurn.status.searchingWeb": "Recherche sur le web",
+ "ui.sessionTurn.status.makingEdits": "Application des modifications",
+ "ui.sessionTurn.status.runningCommands": "Exécution des commandes",
+ "ui.sessionTurn.status.thinking": "Réflexion",
+ "ui.sessionTurn.status.thinkingWithTopic": "Réflexion - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Rassemblement des idées",
+ "ui.sessionTurn.status.consideringNextSteps": "Examen des prochaines étapes",
+
+ "ui.messagePart.questions.dismissed": "Questions ignorées",
+ "ui.messagePart.compaction": "Session compactée",
+ "ui.messagePart.context.read.one": "{{count}} lecture",
+ "ui.messagePart.context.read.other": "{{count}} lectures",
+ "ui.messagePart.context.search.one": "{{count}} recherche",
+ "ui.messagePart.context.search.other": "{{count}} recherches",
+ "ui.messagePart.context.list.one": "{{count}} liste",
+ "ui.messagePart.context.list.other": "{{count}} listes",
+ "ui.messagePart.diagnostic.error": "Erreur",
+ "ui.messagePart.title.edit": "Modifier",
+ "ui.messagePart.title.write": "Écrire",
+ "ui.messagePart.option.typeOwnAnswer": "Tapez votre propre réponse",
+ "ui.messagePart.review.title": "Passez en revue vos réponses",
+
+ "ui.list.loading": "Chargement",
+ "ui.list.empty": "Aucun résultat",
+ "ui.list.clearFilter": "Effacer le filtre",
+ "ui.list.emptyWithFilter.prefix": "Aucun résultat pour",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Nouveau message",
+
+ "ui.textField.copyToClipboard": "Copier dans le presse-papiers",
+ "ui.textField.copyLink": "Copier le lien",
+ "ui.textField.copied": "Copié",
+
+ "ui.imagePreview.alt": "Aperçu de l'image",
+ "ui.scrollView.ariaLabel": "contenu défilable",
+
+ "ui.tool.read": "Lire",
+ "ui.tool.loaded": "Chargé",
+ "ui.tool.list": "Lister",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "Recherche Web",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Tâches",
+ "ui.tool.todos.read": "Lire les tâches",
+ "ui.tool.questions": "Questions",
+ "ui.tool.agent": "Agent {{type}}",
+ "ui.tool.agent.default": "Agent",
+
+ "ui.common.file.one": "fichier",
+ "ui.common.file.other": "fichiers",
+ "ui.common.question.one": "question",
+ "ui.common.question.other": "questions",
+
+ "ui.common.add": "Ajouter",
+ "ui.common.back": "Retour",
+ "ui.common.cancel": "Annuler",
+ "ui.common.confirm": "Confirmer",
+ "ui.common.dismiss": "Ignorer",
+ "ui.common.close": "Fermer",
+ "ui.common.next": "Suivant",
+ "ui.common.submit": "Soumettre",
+ "ui.common.showMore": "Afficher plus",
+
+ "ui.permission.deny": "Refuser",
+ "ui.permission.allowAlways": "Toujours autoriser",
+ "ui.permission.allowOnce": "Autoriser une fois",
+
+ "ui.message.expand": "Développer le message",
+ "ui.message.collapse": "Réduire le message",
+ "ui.message.copy": "Copier",
+ "ui.message.copyMessage": "Copier le message",
+ "ui.message.forkMessage": "Bifurquer vers une nouvelle session",
+ "ui.message.revertMessage": "Réinitialiser à ce point",
+ "ui.message.copyResponse": "Copier la réponse",
+ "ui.message.copied": "Copié !",
+ "ui.message.interrupted": "Interrompu",
+ "ui.message.queued": "En file",
+ "ui.message.attachment.alt": "pièce jointe",
+
+ "ui.patch.action.deleted": "Supprimé",
+ "ui.patch.action.created": "Créé",
+ "ui.patch.action.moved": "Déplacé",
+ "ui.patch.action.patched": "Corrigé",
+
+ "ui.question.subtitle.answered": "{{count}} répondu(s)",
+ "ui.question.answer.none": "(pas de réponse)",
+ "ui.question.review.notAnswered": "(non répondu)",
+ "ui.question.multiHint": "Sélectionnez tout ce qui s'applique",
+ "ui.question.singleHint": "Sélectionnez une réponse",
+ "ui.question.custom.placeholder": "Tapez votre réponse...",
+
+ "ui.fileSearch.placeholder": "Rechercher",
+ "ui.fileSearch.previousMatch": "Précédent",
+ "ui.fileSearch.nextMatch": "Suivant",
+ "ui.fileSearch.close": "Fermer la recherche",
+ "ui.tool.task": "Tâche",
+ "ui.tool.skill": "Compétence",
+ "ui.basicTool.called": "Appelé `{{tool}}`",
+ "ui.toolErrorCard.failed": "Échoué",
+ "ui.toolErrorCard.copyError": "Copier l'erreur",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/ja.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/ja.ts
new file mode 100644
index 00000000..f7a895bb
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/ja.ts
@@ -0,0 +1,193 @@
+export const dict = {
+ "ui.sessionReview.title": "セッションの変更",
+ "ui.sessionReview.title.git": "Gitの変更",
+ "ui.sessionReview.title.branch": "ブランチの変更",
+ "ui.sessionReview.title.lastTurn": "前回ターンの変更",
+ "ui.sessionReview.diffStyle.unified": "統合差分",
+ "ui.sessionReview.diffStyle.split": "分割差分",
+ "ui.sessionReview.openFile": "ファイルを開く",
+ "ui.sessionReview.selection.line": "{{line}} 行目",
+ "ui.sessionReview.selection.lines": "{{start}}-{{end}} 行目",
+ "ui.sessionReview.expandAll": "すべて展開",
+ "ui.sessionReview.collapseAll": "すべて折りたたむ",
+
+ "ui.sessionReview.change.added": "追加",
+ "ui.sessionReview.change.removed": "削除",
+ "ui.sessionReview.change.modified": "変更",
+ "ui.sessionReview.image.loading": "読み込み中...",
+ "ui.sessionReview.image.placeholder": "画像",
+ "ui.sessionReview.largeDiff.title": "差分が大きすぎて表示できません",
+ "ui.sessionReview.largeDiff.meta": "上限: {{limit}} 変更行。現在: {{current}} 変更行。",
+ "ui.sessionReview.largeDiff.renderAnyway": "それでも表示する",
+ "ui.sessionReviewV2.expandMode": "差分を展開または折りたたむ",
+ "ui.sessionReviewV2.filterFiles": "ファイルを絞り込む",
+ "ui.sessionReviewV2.toggleSidebar": "ファイルツリーを切り替える",
+ "ui.sessionReviewV2.showAllLines": "すべての行を表示",
+ "ui.sessionReviewV2.hideNonDiffLines": "差分以外の行を非表示",
+ "ui.sessionReviewV2.unifiedDiff": "統合差分",
+ "ui.sessionReviewV2.splitDiff": "分割差分",
+ "ui.sessionReviewV2.previousFile": "前のファイル",
+ "ui.sessionReviewV2.nextFile": "次のファイル",
+ "ui.sessionReviewV2.diffView": "差分ビュー",
+ "ui.sessionReviewV2.empty.noGit.title": "追跡中の変更はありません",
+ "ui.sessionReviewV2.empty.noGit.description": "このプロジェクトの変更を追跡、レビュー、取り消しできます",
+ "ui.sessionReviewV2.empty.noGit.action": "Gitリポジトリを作成",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Gitリポジトリを作成中...",
+ "ui.sessionReviewV2.empty.changes.title": "ファイルの変更はまだありません",
+ "ui.sessionReviewV2.empty.changes.description": "プロジェクトの変更がここに表示されます",
+ "ui.fileMedia.kind.image": "画像",
+ "ui.fileMedia.kind.audio": "音声",
+ "ui.fileMedia.state.removed": "{{kind}}は削除されました",
+ "ui.fileMedia.state.loading": "{{kind}}を読み込んでいます...",
+ "ui.fileMedia.state.error": "{{kind}}の読み込みに失敗しました",
+ "ui.fileMedia.state.unavailable": "{{kind}}は表示できません",
+ "ui.fileMedia.binary.title": "バイナリファイル",
+ "ui.fileMedia.binary.description.path": "{{path}} はバイナリファイルのため表示できません。",
+ "ui.fileMedia.binary.description.default": "このファイルはバイナリファイルのため表示できません。",
+ "ui.lineComment.label.prefix": "",
+ "ui.lineComment.label.suffix": "へのコメント",
+ "ui.lineComment.editorLabel.prefix": "",
+ "ui.lineComment.editorLabel.suffix": "へのコメントを作成中",
+ "ui.lineComment.placeholder": "コメントを追加",
+ "ui.lineComment.submit": "コメント",
+ "ui.lineComment.cancel": "キャンセル",
+ "ui.sessionTurn.steps.show": "ステップを表示",
+ "ui.sessionTurn.steps.hide": "ステップを隠す",
+ "ui.sessionTurn.summary.response": "応答",
+ "ui.sessionTurn.diff.showMore": "さらに変更を表示 ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "変更済みファイル: {{count}}件",
+ "ui.sessionTurn.diffs.changed.other": "変更済みファイル: {{count}}件",
+ "ui.sessionTurn.diffs.showAll": "すべて表示",
+ "ui.sessionTurn.diffs.showLess": "一部のみ表示",
+ "ui.sessionTurn.diffs.more": "+他{{count}}件",
+
+ "ui.sessionTurn.retry.retrying": "再試行中",
+ "ui.sessionTurn.retry.inSeconds": "{{seconds}}秒後",
+ "ui.sessionTurn.retry.attempt": "{{attempt}}回目",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - {{attempt}}回目",
+ "ui.sessionTurn.retry.geminiHot": "gemini が混雑しています",
+ "ui.sessionTurn.error.freeUsageExceeded": "無料使用制限に達しました",
+ "ui.sessionTurn.error.addCredits": "クレジットを追加",
+
+ "dialog.usageExceeded.freeTier.title": "無料制限に達しました",
+ "dialog.usageExceeded.freeTier.description":
+ "OpenCode Go にサブスクライブして、最高のオープンソースモデルに安定してアクセスできます。月額 $5 から。",
+ "dialog.usageExceeded.freeTier.actionLabel": "サブスクライブ",
+ "dialog.usageExceeded.accountRateLimit.title": "Go の制限に達しました",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "使用制限に達しました。今すぐこのモデルを使い続けるには、利用可能な残高からの使用を有効にしてください",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "設定を開く",
+
+ "ui.sessionTurn.status.delegating": "作業を委任中",
+ "ui.sessionTurn.status.planning": "次のステップを計画中",
+ "ui.sessionTurn.status.gatheringContext": "探索中",
+ "ui.sessionTurn.status.gatheredContext": "探索済み",
+ "ui.sessionTurn.status.searchingCodebase": "コードベースを検索中",
+ "ui.sessionTurn.status.searchingWeb": "ウェブを検索中",
+ "ui.sessionTurn.status.makingEdits": "編集を実行中",
+ "ui.sessionTurn.status.runningCommands": "コマンドを実行中",
+ "ui.sessionTurn.status.thinking": "思考中",
+ "ui.sessionTurn.status.thinkingWithTopic": "思考中 - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "考えをまとめています",
+ "ui.sessionTurn.status.consideringNextSteps": "次のステップを検討中",
+
+ "ui.messagePart.questions.dismissed": "質問をスキップしました",
+ "ui.messagePart.compaction": "セッションを圧縮しました",
+ "ui.messagePart.context.read.one": "{{count}} 件の読み取り",
+ "ui.messagePart.context.read.other": "{{count}} 件の読み取り",
+ "ui.messagePart.context.search.one": "{{count}} 件の検索",
+ "ui.messagePart.context.search.other": "{{count}} 件の検索",
+ "ui.messagePart.context.list.one": "{{count}} 件のリスト",
+ "ui.messagePart.context.list.other": "{{count}} 件のリスト",
+ "ui.messagePart.diagnostic.error": "エラー",
+ "ui.messagePart.title.edit": "編集",
+ "ui.messagePart.title.write": "作成",
+ "ui.messagePart.option.typeOwnAnswer": "自分の回答を入力",
+ "ui.messagePart.review.title": "回答を確認",
+
+ "ui.list.loading": "読み込み中",
+ "ui.list.empty": "結果なし",
+ "ui.list.clearFilter": "フィルターをクリア",
+ "ui.list.emptyWithFilter.prefix": "次の検索結果はありません: ",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "新しいメッセージ",
+
+ "ui.textField.copyToClipboard": "クリップボードにコピー",
+ "ui.textField.copyLink": "リンクをコピー",
+ "ui.textField.copied": "コピーしました",
+
+ "ui.imagePreview.alt": "画像プレビュー",
+ "ui.scrollView.ariaLabel": "スクロール可能なコンテンツ",
+
+ "ui.tool.read": "読み込み",
+ "ui.tool.loaded": "読み込み済み",
+ "ui.tool.list": "リスト",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "Web検索",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Todo",
+ "ui.tool.todos.read": "Todo読み込み",
+ "ui.tool.questions": "質問",
+ "ui.tool.agent": "{{type}}エージェント",
+ "ui.tool.agent.default": "エージェント",
+
+ "ui.common.file.one": "ファイル",
+ "ui.common.file.other": "ファイル",
+ "ui.common.question.one": "質問",
+ "ui.common.question.other": "質問",
+
+ "ui.common.add": "追加",
+ "ui.common.back": "戻る",
+ "ui.common.cancel": "キャンセル",
+ "ui.common.confirm": "確認",
+ "ui.common.dismiss": "閉じる",
+ "ui.common.close": "閉じる",
+ "ui.common.next": "次へ",
+ "ui.common.submit": "送信",
+ "ui.common.showMore": "さらに表示",
+
+ "ui.permission.deny": "拒否",
+ "ui.permission.allowAlways": "常に許可",
+ "ui.permission.allowOnce": "今回のみ許可",
+
+ "ui.message.expand": "メッセージを展開",
+ "ui.message.collapse": "メッセージを折りたたむ",
+ "ui.message.copy": "コピー",
+ "ui.message.copyMessage": "メッセージをコピー",
+ "ui.message.forkMessage": "新しいセッションにフォーク",
+ "ui.message.revertMessage": "この時点までリセット",
+ "ui.message.copyResponse": "応答をコピー",
+ "ui.message.copied": "コピーしました!",
+ "ui.message.interrupted": "中断",
+ "ui.message.queued": "待機中",
+ "ui.message.attachment.alt": "添付ファイル",
+
+ "ui.patch.action.deleted": "削除済み",
+ "ui.patch.action.created": "作成済み",
+ "ui.patch.action.moved": "移動済み",
+ "ui.patch.action.patched": "パッチ適用済み",
+
+ "ui.question.subtitle.answered": "{{count}}件回答済み",
+ "ui.question.answer.none": "(回答なし)",
+ "ui.question.review.notAnswered": "(未回答)",
+ "ui.question.multiHint": "該当するものをすべて選択",
+ "ui.question.singleHint": "1 つ選択",
+ "ui.question.custom.placeholder": "回答を入力...",
+
+ "ui.fileSearch.placeholder": "検索",
+ "ui.fileSearch.previousMatch": "前の一致",
+ "ui.fileSearch.nextMatch": "次の一致",
+ "ui.fileSearch.close": "検索を閉じる",
+ "ui.tool.task": "タスク",
+ "ui.tool.skill": "スキル",
+ "ui.basicTool.called": "`{{tool}}` を呼び出しました",
+ "ui.toolErrorCard.failed": "失敗",
+ "ui.toolErrorCard.copyError": "エラーをコピー",
+ "ui.message.duration.seconds": "{{count}}秒",
+ "ui.message.duration.minutesSeconds": "{{minutes}}分 {{seconds}}秒",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/ko.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/ko.ts
new file mode 100644
index 00000000..b10fe560
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/ko.ts
@@ -0,0 +1,195 @@
+export const dict = {
+ "ui.sessionReview.title": "세션 변경 사항",
+ "ui.sessionReview.title.lastTurn": "마지막 턴 변경 사항",
+ "ui.sessionReview.diffStyle.unified": "통합 보기",
+ "ui.sessionReview.diffStyle.split": "분할 보기",
+ "ui.sessionReview.openFile": "파일 열기",
+ "ui.sessionReview.selection.line": "{{line}}번 줄",
+ "ui.sessionReview.selection.lines": "{{start}}-{{end}}번 줄",
+ "ui.sessionReview.expandAll": "모두 펼치기",
+ "ui.sessionReview.collapseAll": "모두 접기",
+ "ui.sessionReview.change.added": "추가됨",
+ "ui.sessionReview.change.removed": "삭제됨",
+ "ui.sessionReview.change.modified": "수정됨",
+ "ui.sessionReview.image.loading": "로딩 중...",
+ "ui.sessionReview.image.placeholder": "이미지",
+ "ui.sessionReview.largeDiff.title": "차이가 너무 커서 렌더링할 수 없습니다",
+ "ui.sessionReview.largeDiff.meta": "제한: {{limit}} 변경 줄. 현재: {{current}} 변경 줄.",
+ "ui.sessionReview.largeDiff.renderAnyway": "그래도 렌더링",
+ "ui.fileMedia.kind.image": "이미지",
+ "ui.fileMedia.kind.audio": "오디오",
+ "ui.fileMedia.state.removed": "{{kind}} 제거됨",
+ "ui.fileMedia.state.loading": "{{kind}} 로드 중...",
+ "ui.fileMedia.state.error": "{{kind}} 로드 오류",
+ "ui.fileMedia.state.unavailable": "{{kind}} 사용 불가",
+ "ui.fileMedia.binary.title": "바이너리 파일",
+ "ui.fileMedia.binary.description.path": "{{path}}은(는) 바이너리 파일이므로 표시할 수 없습니다.",
+ "ui.fileMedia.binary.description.default": "바이너리 파일이므로 표시할 수 없습니다.",
+
+ "ui.lineComment.label.prefix": "",
+ "ui.lineComment.label.suffix": "에 댓글 달기",
+ "ui.lineComment.editorLabel.prefix": "",
+ "ui.lineComment.editorLabel.suffix": "에 댓글 작성 중",
+ "ui.lineComment.placeholder": "댓글 추가",
+ "ui.lineComment.submit": "댓글",
+
+ "ui.sessionTurn.steps.show": "단계 표시",
+ "ui.sessionTurn.steps.hide": "단계 숨기기",
+ "ui.sessionTurn.summary.response": "응답",
+ "ui.sessionTurn.diff.showMore": "변경 사항 더 보기 ({{count}})",
+
+ "ui.sessionTurn.retry.retrying": "재시도 중",
+ "ui.sessionTurn.retry.inSeconds": "{{seconds}}초 후",
+ "ui.sessionTurn.retry.attempt": "{{attempt}}번째",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - {{attempt}}번째",
+ "ui.sessionTurn.retry.geminiHot": "gemini가 현재 과부하 상태입니다",
+ "ui.sessionTurn.error.freeUsageExceeded": "무료 사용량 초과",
+ "ui.sessionTurn.error.addCredits": "크레딧 추가",
+
+ "dialog.usageExceeded.freeTier.title": "무료 한도에 도달했습니다",
+ "dialog.usageExceeded.freeTier.description":
+ "OpenCode Go를 구독하여 최고의 오픈 소스 모델에 안정적으로 액세스하세요. 월 $5부터 시작합니다.",
+ "dialog.usageExceeded.freeTier.actionLabel": "구독",
+ "dialog.usageExceeded.accountRateLimit.title": "Go 한도에 도달했습니다",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "사용량 한도에 도달했습니다. 지금 이 모델을 계속 사용하려면 사용 가능한 잔액에서 사용을 활성화하세요",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "설정 열기",
+
+ "ui.sessionTurn.status.delegating": "작업 위임 중",
+ "ui.sessionTurn.status.planning": "다음 단계 계획 중",
+ "ui.sessionTurn.status.gatheringContext": "탐색 중",
+ "ui.sessionTurn.status.gatheredContext": "탐색됨",
+ "ui.sessionTurn.status.searchingCodebase": "코드베이스 검색 중",
+ "ui.sessionTurn.status.searchingWeb": "웹 검색 중",
+ "ui.sessionTurn.status.makingEdits": "편집 수행 중",
+ "ui.sessionTurn.status.runningCommands": "명령어 실행 중",
+ "ui.sessionTurn.status.thinking": "생각 중",
+ "ui.sessionTurn.status.thinkingWithTopic": "생각 중 - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "생각 정리 중",
+ "ui.sessionTurn.status.consideringNextSteps": "다음 단계 고려 중",
+
+ "ui.messagePart.questions.dismissed": "질문 무시됨",
+ "ui.messagePart.compaction": "세션 압축됨",
+ "ui.messagePart.context.read.one": "{{count}}개 읽음",
+ "ui.messagePart.context.read.other": "{{count}}개 읽음",
+ "ui.messagePart.context.search.one": "{{count}}개 검색",
+ "ui.messagePart.context.search.other": "{{count}}개 검색",
+ "ui.messagePart.context.list.one": "{{count}}개 목록",
+ "ui.messagePart.context.list.other": "{{count}}개 목록",
+ "ui.messagePart.diagnostic.error": "오류",
+ "ui.messagePart.title.edit": "편집",
+ "ui.messagePart.title.write": "작성",
+ "ui.messagePart.option.typeOwnAnswer": "직접 답변 입력",
+ "ui.messagePart.review.title": "답변 검토",
+
+ "ui.list.loading": "로딩 중",
+ "ui.list.empty": "결과 없음",
+ "ui.list.clearFilter": "필터 지우기",
+ "ui.list.emptyWithFilter.prefix": "다음에 대한 결과 없음: ",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "새 메시지",
+
+ "ui.textField.copyToClipboard": "클립보드에 복사",
+ "ui.textField.copyLink": "링크 복사",
+ "ui.textField.copied": "복사됨",
+
+ "ui.imagePreview.alt": "이미지 미리보기",
+ "ui.scrollView.ariaLabel": "스크롤 가능한 콘텐츠",
+
+ "ui.tool.read": "읽기",
+ "ui.tool.loaded": "로드됨",
+ "ui.tool.list": "목록",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "웹 가져오기",
+ "ui.tool.websearch": "웹 검색",
+ "ui.tool.shell": "셸",
+ "ui.tool.patch": "패치",
+ "ui.tool.todos": "할 일",
+ "ui.tool.todos.read": "할 일 읽기",
+ "ui.tool.questions": "질문",
+ "ui.tool.agent": "{{type}} 에이전트",
+ "ui.tool.agent.default": "에이전트",
+
+ "ui.common.file.one": "파일",
+ "ui.common.file.other": "파일",
+ "ui.common.question.one": "질문",
+ "ui.common.question.other": "질문",
+
+ "ui.common.add": "추가",
+ "ui.common.back": "뒤로",
+ "ui.common.cancel": "취소",
+ "ui.common.confirm": "확인",
+ "ui.common.dismiss": "닫기",
+ "ui.common.close": "닫기",
+ "ui.common.next": "다음",
+ "ui.common.submit": "제출",
+ "ui.common.showMore": "더 보기",
+
+ "ui.permission.deny": "거부",
+ "ui.permission.allowAlways": "항상 허용",
+ "ui.permission.allowOnce": "한 번만 허용",
+
+ "ui.message.expand": "메시지 펼치기",
+ "ui.message.collapse": "메시지 접기",
+ "ui.message.copy": "복사",
+ "ui.message.copyMessage": "메시지 복사",
+ "ui.message.forkMessage": "새 세션으로 분기",
+ "ui.message.revertMessage": "이 시점으로 초기화",
+ "ui.message.copyResponse": "응답 복사",
+ "ui.message.copied": "복사됨!",
+ "ui.message.interrupted": "중단됨",
+ "ui.message.queued": "대기 중",
+ "ui.message.attachment.alt": "첨부 파일",
+
+ "ui.patch.action.deleted": "삭제됨",
+ "ui.patch.action.created": "생성됨",
+ "ui.patch.action.moved": "이동됨",
+ "ui.patch.action.patched": "패치됨",
+
+ "ui.question.subtitle.answered": "{{count}}개 답변됨",
+ "ui.question.answer.none": "(답변 없음)",
+ "ui.question.review.notAnswered": "(답변되지 않음)",
+ "ui.question.multiHint": "해당하는 항목 모두 선택",
+ "ui.question.singleHint": "하나의 답변을 선택",
+ "ui.question.custom.placeholder": "답변 입력...",
+
+ "ui.fileSearch.placeholder": "찾기",
+ "ui.fileSearch.previousMatch": "이전 항목",
+ "ui.fileSearch.nextMatch": "다음 항목",
+ "ui.fileSearch.close": "검색 닫기",
+ "ui.tool.task": "작업",
+ "ui.tool.skill": "스킬",
+ "ui.basicTool.called": "`{{tool}}` 호출됨",
+ "ui.toolErrorCard.failed": "실패",
+ "ui.toolErrorCard.copyError": "오류 복사",
+ "ui.message.duration.seconds": "{{count}}초",
+ "ui.message.duration.minutesSeconds": "{{minutes}}분 {{seconds}}초",
+
+ "ui.sessionReview.title.git": "Git 변경 사항",
+ "ui.sessionReview.title.branch": "브랜치 변경 사항",
+ "ui.sessionReviewV2.expandMode": "diff 펼치기 또는 접기",
+ "ui.sessionReviewV2.filterFiles": "파일 필터링",
+ "ui.sessionReviewV2.toggleSidebar": "파일 트리 토글",
+ "ui.sessionReviewV2.showAllLines": "모든 줄 표시",
+ "ui.sessionReviewV2.hideNonDiffLines": "변경되지 않은 줄 숨기기",
+ "ui.sessionReviewV2.unifiedDiff": "통합 diff",
+ "ui.sessionReviewV2.splitDiff": "분할 diff",
+ "ui.sessionReviewV2.previousFile": "이전 파일",
+ "ui.sessionReviewV2.nextFile": "다음 파일",
+ "ui.sessionReviewV2.diffView": "diff 보기",
+ "ui.sessionReviewV2.empty.noGit.title": "추적 중인 변경 사항 없음",
+ "ui.sessionReviewV2.empty.noGit.description": "이 프로젝트의 변경 사항을 추적, 검토 및 실행 취소",
+ "ui.sessionReviewV2.empty.noGit.action": "Git 저장소 생성",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Git 저장소 생성 중...",
+ "ui.sessionReviewV2.empty.changes.title": "아직 파일 변경 사항 없음",
+ "ui.sessionReviewV2.empty.changes.description": "프로젝트 변경 사항이 여기에 표시됩니다",
+ "ui.lineComment.cancel": "취소",
+ "ui.sessionTurn.diffs.changed.one": "변경된 파일: {{count}}개",
+ "ui.sessionTurn.diffs.changed.other": "변경된 파일: {{count}}개",
+ "ui.sessionTurn.diffs.showAll": "모두 표시",
+ "ui.sessionTurn.diffs.showLess": "간략히 표시",
+ "ui.sessionTurn.diffs.more": "+{{count}}개 더 보기",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/no.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/no.ts
new file mode 100644
index 00000000..ae0d85ff
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/no.ts
@@ -0,0 +1,198 @@
+import { dict as en } from "./en"
+type Keys = keyof typeof en
+
+export const dict: Record = {
+ "ui.sessionReview.title": "Sesjonsendringer",
+ "ui.sessionReview.title.lastTurn": "Endringer i siste tur",
+ "ui.sessionReview.diffStyle.unified": "Samlet",
+ "ui.sessionReview.diffStyle.split": "Delt",
+ "ui.sessionReview.openFile": "Åpne fil",
+ "ui.sessionReview.selection.line": "linje {{line}}",
+ "ui.sessionReview.selection.lines": "linjer {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Utvid alle",
+ "ui.sessionReview.collapseAll": "Fold sammen alle",
+ "ui.sessionReview.change.added": "Lagt til",
+ "ui.sessionReview.change.removed": "Fjernet",
+ "ui.sessionReview.change.modified": "Endret",
+ "ui.sessionReview.image.loading": "Laster...",
+ "ui.sessionReview.image.placeholder": "Bilde",
+ "ui.sessionReview.largeDiff.title": "Diff er for stor til å gjengi",
+ "ui.sessionReview.largeDiff.meta": "Grense: {{limit}} endrede linjer. Nåværende: {{current}} endrede linjer.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Gjengi likevel",
+ "ui.fileMedia.kind.image": "bilde",
+ "ui.fileMedia.kind.audio": "lyd",
+ "ui.fileMedia.state.removed": "Fjernet: {{kind}}",
+ "ui.fileMedia.state.loading": "Laster inn {{kind}}...",
+ "ui.fileMedia.state.error": "Feil ved innlasting: {{kind}}",
+ "ui.fileMedia.state.unavailable": "Ikke tilgjengelig: {{kind}}",
+ "ui.fileMedia.binary.title": "Binærfil",
+ "ui.fileMedia.binary.description.path": "{{path}} kan ikke vises fordi det er en binærfil.",
+ "ui.fileMedia.binary.description.default": "Denne filen kan ikke vises fordi det er en binærfil.",
+
+ "ui.lineComment.label.prefix": "Kommenter på ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Kommenterer på ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Legg til kommentar",
+ "ui.lineComment.submit": "Kommenter",
+
+ "ui.sessionTurn.steps.show": "Vis trinn",
+ "ui.sessionTurn.steps.hide": "Skjul trinn",
+ "ui.sessionTurn.summary.response": "Svar",
+ "ui.sessionTurn.diff.showMore": "Vis flere endringer ({{count}})",
+
+ "ui.sessionTurn.retry.retrying": "Prøver igjen",
+ "ui.sessionTurn.retry.inSeconds": "om {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "forsøk #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - forsøk #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini er veldig overbelastet nå",
+ "ui.sessionTurn.error.freeUsageExceeded": "Gratis bruk overskredet",
+ "ui.sessionTurn.error.addCredits": "Legg til kreditt",
+
+ "dialog.usageExceeded.freeTier.title": "Gratis grense nådd",
+ "dialog.usageExceeded.freeTier.description":
+ "Abonner på OpenCode Go for pålitelig tilgang til de beste åpen kildekode-modellene, fra $5/måned.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Abonner",
+ "dialog.usageExceeded.accountRateLimit.title": "Go-grense nådd",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Bruksgrense nådd. For å fortsette å bruke denne modellen nå, aktiver bruk fra din tilgjengelige saldo",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Åpne innstillinger",
+
+ "ui.sessionTurn.status.delegating": "Delegerer arbeid",
+ "ui.sessionTurn.status.planning": "Planlegger neste trinn",
+ "ui.sessionTurn.status.gatheringContext": "Utforsker",
+ "ui.sessionTurn.status.gatheredContext": "Utforsket",
+ "ui.sessionTurn.status.searchingCodebase": "Søker i kodebasen",
+ "ui.sessionTurn.status.searchingWeb": "Søker på nettet",
+ "ui.sessionTurn.status.makingEdits": "Gjør endringer",
+ "ui.sessionTurn.status.runningCommands": "Kjører kommandoer",
+ "ui.sessionTurn.status.thinking": "Tenker",
+ "ui.sessionTurn.status.thinkingWithTopic": "Tenker - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Samler tanker",
+ "ui.sessionTurn.status.consideringNextSteps": "Vurderer neste trinn",
+
+ "ui.messagePart.questions.dismissed": "Spørsmål avvist",
+ "ui.messagePart.compaction": "Økt komprimert",
+ "ui.messagePart.context.read.one": "{{count}} lest",
+ "ui.messagePart.context.read.other": "{{count}} lest",
+ "ui.messagePart.context.search.one": "{{count}} søk",
+ "ui.messagePart.context.search.other": "{{count}} søk",
+ "ui.messagePart.context.list.one": "{{count}} liste",
+ "ui.messagePart.context.list.other": "{{count}} lister",
+ "ui.messagePart.diagnostic.error": "Feil",
+ "ui.messagePart.title.edit": "Rediger",
+ "ui.messagePart.title.write": "Skriv",
+ "ui.messagePart.option.typeOwnAnswer": "Skriv ditt eget svar",
+ "ui.messagePart.review.title": "Gjennomgå svarene dine",
+
+ "ui.list.loading": "Laster",
+ "ui.list.empty": "Ingen resultater",
+ "ui.list.clearFilter": "Tøm filter",
+ "ui.list.emptyWithFilter.prefix": "Ingen resultater for",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Ny melding",
+
+ "ui.textField.copyToClipboard": "Kopier til utklippstavlen",
+ "ui.textField.copyLink": "Kopier lenke",
+ "ui.textField.copied": "Kopiert",
+
+ "ui.imagePreview.alt": "Bildeforhåndsvisning",
+ "ui.scrollView.ariaLabel": "rullbart innhold",
+
+ "ui.tool.read": "Les",
+ "ui.tool.loaded": "Lastet",
+ "ui.tool.list": "Liste",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webhenting",
+ "ui.tool.websearch": "Nettsøk",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Gjøremål",
+ "ui.tool.todos.read": "Les gjøremål",
+ "ui.tool.questions": "Spørsmål",
+ "ui.tool.agent": "{{type}}-agent",
+ "ui.tool.agent.default": "Agent",
+
+ "ui.common.file.one": "fil",
+ "ui.common.file.other": "filer",
+ "ui.common.question.one": "spørsmål",
+ "ui.common.question.other": "spørsmål",
+
+ "ui.common.add": "Legg til",
+ "ui.common.back": "Tilbake",
+ "ui.common.cancel": "Avbryt",
+ "ui.common.confirm": "Bekreft",
+ "ui.common.dismiss": "Avvis",
+ "ui.common.close": "Lukk",
+ "ui.common.next": "Neste",
+ "ui.common.submit": "Send inn",
+ "ui.common.showMore": "Vis mer",
+
+ "ui.permission.deny": "Avslå",
+ "ui.permission.allowAlways": "Tillat alltid",
+ "ui.permission.allowOnce": "Tillat én gang",
+
+ "ui.message.expand": "Utvid melding",
+ "ui.message.collapse": "Skjul melding",
+ "ui.message.copy": "Kopier",
+ "ui.message.copyMessage": "Kopier melding",
+ "ui.message.forkMessage": "Forgren til ny sesjon",
+ "ui.message.revertMessage": "Tilbakestill til dette punktet",
+ "ui.message.copyResponse": "Kopier svar",
+ "ui.message.copied": "Kopiert!",
+ "ui.message.interrupted": "Avbrutt",
+ "ui.message.queued": "I kø",
+ "ui.message.attachment.alt": "vedlegg",
+
+ "ui.patch.action.deleted": "Slettet",
+ "ui.patch.action.created": "Opprettet",
+ "ui.patch.action.moved": "Flyttet",
+ "ui.patch.action.patched": "Oppdatert",
+
+ "ui.question.subtitle.answered": "{{count}} besvart",
+ "ui.question.answer.none": "(ingen svar)",
+ "ui.question.review.notAnswered": "(ikke besvart)",
+ "ui.question.multiHint": "Velg alle som gjelder",
+ "ui.question.singleHint": "Velg ett svar",
+ "ui.question.custom.placeholder": "Skriv svaret ditt...",
+
+ "ui.fileSearch.placeholder": "Finn",
+ "ui.fileSearch.previousMatch": "Forrige treff",
+ "ui.fileSearch.nextMatch": "Neste treff",
+ "ui.fileSearch.close": "Lukk søk",
+ "ui.tool.task": "Oppgave",
+ "ui.tool.skill": "Ferdighet",
+ "ui.basicTool.called": "Kalte `{{tool}}`",
+ "ui.toolErrorCard.failed": "Mislyktes",
+ "ui.toolErrorCard.copyError": "Kopier feil",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+
+ "ui.sessionReview.title.git": "Git-endringer",
+ "ui.sessionReview.title.branch": "Grenendringer",
+ "ui.sessionReviewV2.expandMode": "Utvid eller fold sammen diff",
+ "ui.sessionReviewV2.filterFiles": "Filtrer filer",
+ "ui.sessionReviewV2.toggleSidebar": "Vis eller skjul filtreet",
+ "ui.sessionReviewV2.showAllLines": "Vis alle linjer",
+ "ui.sessionReviewV2.hideNonDiffLines": "Skjul uendrede linjer",
+ "ui.sessionReviewV2.unifiedDiff": "Samlet diff",
+ "ui.sessionReviewV2.splitDiff": "Delt diff",
+ "ui.sessionReviewV2.previousFile": "Forrige fil",
+ "ui.sessionReviewV2.nextFile": "Neste fil",
+ "ui.sessionReviewV2.diffView": "Diffvisning",
+ "ui.sessionReviewV2.empty.noGit.title": "Ingen sporede endringer",
+ "ui.sessionReviewV2.empty.noGit.description": "Spor, gjennomgå og angre endringer i dette prosjektet",
+ "ui.sessionReviewV2.empty.noGit.action": "Opprett et Git-depot",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Oppretter Git-depot...",
+ "ui.sessionReviewV2.empty.changes.title": "Ingen filendringer ennå",
+ "ui.sessionReviewV2.empty.changes.description": "Prosjektendringer vises her",
+ "ui.lineComment.cancel": "Avbryt",
+ "ui.sessionTurn.diffs.changed.one": "Endret fil: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Endrede filer: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Vis alle",
+ "ui.sessionTurn.diffs.showLess": "Vis færre",
+ "ui.sessionTurn.diffs.more": "+{{count}} til",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/pl.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/pl.ts
new file mode 100644
index 00000000..a4de5714
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/pl.ts
@@ -0,0 +1,193 @@
+export const dict = {
+ "ui.sessionReview.title": "Zmiany w sesji",
+ "ui.sessionReview.title.git": "Zmiany Git",
+ "ui.sessionReview.title.branch": "Zmiany w gałęzi",
+ "ui.sessionReview.title.lastTurn": "Zmiany z ostatniej tury",
+ "ui.sessionReview.diffStyle.unified": "Ujednolicony",
+ "ui.sessionReview.diffStyle.split": "Podzielony",
+ "ui.sessionReview.openFile": "Otwórz plik",
+ "ui.sessionReview.selection.line": "linia {{line}}",
+ "ui.sessionReview.selection.lines": "linie {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Rozwiń wszystko",
+ "ui.sessionReview.collapseAll": "Zwiń wszystko",
+
+ "ui.sessionReview.change.added": "Dodano",
+ "ui.sessionReview.change.removed": "Usunięto",
+ "ui.sessionReview.change.modified": "Zmodyfikowano",
+ "ui.sessionReview.image.loading": "Ładowanie...",
+ "ui.sessionReview.image.placeholder": "Obraz",
+ "ui.sessionReview.largeDiff.title": "Diff jest zbyt duży, aby go wyrenderować",
+ "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} zmienionych linii. Obecnie: {{current}} zmienionych linii.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Renderuj mimo to",
+ "ui.sessionReviewV2.expandMode": "Rozwiń lub zwiń diff",
+ "ui.sessionReviewV2.filterFiles": "Filtruj pliki",
+ "ui.sessionReviewV2.toggleSidebar": "Przełącz drzewo plików",
+ "ui.sessionReviewV2.showAllLines": "Pokaż wszystkie linie",
+ "ui.sessionReviewV2.hideNonDiffLines": "Ukryj linie spoza zmian",
+ "ui.sessionReviewV2.unifiedDiff": "Ujednolicony diff",
+ "ui.sessionReviewV2.splitDiff": "Podzielony diff",
+ "ui.sessionReviewV2.previousFile": "Poprzedni plik",
+ "ui.sessionReviewV2.nextFile": "Następny plik",
+ "ui.sessionReviewV2.diffView": "Widok zmian",
+ "ui.sessionReviewV2.empty.noGit.title": "Brak śledzonych zmian",
+ "ui.sessionReviewV2.empty.noGit.description": "Śledź, przeglądaj i cofaj zmiany w tym projekcie",
+ "ui.sessionReviewV2.empty.noGit.action": "Utwórz repozytorium Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Tworzenie repozytorium Git...",
+ "ui.sessionReviewV2.empty.changes.title": "Brak jeszcze zmian w plikach",
+ "ui.sessionReviewV2.empty.changes.description": "Zmiany w projekcie pojawią się tutaj",
+ "ui.fileMedia.kind.image": "obraz",
+ "ui.fileMedia.kind.audio": "dźwięk",
+ "ui.fileMedia.state.removed": "{{kind}} usunięty",
+ "ui.fileMedia.state.loading": "Wczytywanie: {{kind}}...",
+ "ui.fileMedia.state.error": "Błąd wczytywania: {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} niedostępny",
+ "ui.fileMedia.binary.title": "Plik binarny",
+ "ui.fileMedia.binary.description.path": "Nie można wyświetlić pliku {{path}}, ponieważ jest to plik binarny.",
+ "ui.fileMedia.binary.description.default": "Nie można wyświetlić tego pliku, ponieważ jest to plik binarny.",
+ "ui.lineComment.label.prefix": "Komentarz do ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Komentowanie: ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Dodaj komentarz",
+ "ui.lineComment.submit": "Skomentuj",
+ "ui.lineComment.cancel": "Anuluj",
+ "ui.sessionTurn.steps.show": "Pokaż kroki",
+ "ui.sessionTurn.steps.hide": "Ukryj kroki",
+ "ui.sessionTurn.summary.response": "Odpowiedź",
+ "ui.sessionTurn.diff.showMore": "Pokaż więcej zmian ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Zmieniony plik: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Zmienione pliki: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Pokaż wszystkie",
+ "ui.sessionTurn.diffs.showLess": "Pokaż mniej",
+ "ui.sessionTurn.diffs.more": "+{{count}} więcej",
+
+ "ui.sessionTurn.retry.retrying": "ponawianie",
+ "ui.sessionTurn.retry.inSeconds": "za {{seconds}}s",
+ "ui.sessionTurn.retry.attempt": "próba #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - próba #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini jest teraz mocno przeciążony",
+ "ui.sessionTurn.error.freeUsageExceeded": "Przekroczono limit darmowego użytkowania",
+ "ui.sessionTurn.error.addCredits": "Dodaj kredyty",
+
+ "dialog.usageExceeded.freeTier.title": "Osiągnięto limit darmowy",
+ "dialog.usageExceeded.freeTier.description":
+ "Subskrybuj OpenCode Go, aby uzyskać niezawodny dostęp do najlepszych modeli open source, od $5/miesiąc.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Subskrybuj",
+ "dialog.usageExceeded.accountRateLimit.title": "Osiągnięto limit Go",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Osiągnięto limit użycia. Aby kontynuować korzystanie z tego modelu teraz, włącz użycie z dostępnego salda",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Otwórz ustawienia",
+
+ "ui.sessionTurn.status.delegating": "Delegowanie pracy",
+ "ui.sessionTurn.status.planning": "Planowanie kolejnych kroków",
+ "ui.sessionTurn.status.gatheringContext": "Eksplorowanie",
+ "ui.sessionTurn.status.gatheredContext": "Wyeksplorowano",
+ "ui.sessionTurn.status.searchingCodebase": "Przeszukiwanie bazy kodu",
+ "ui.sessionTurn.status.searchingWeb": "Przeszukiwanie sieci",
+ "ui.sessionTurn.status.makingEdits": "Wprowadzanie zmian",
+ "ui.sessionTurn.status.runningCommands": "Uruchamianie poleceń",
+ "ui.sessionTurn.status.thinking": "Myślenie",
+ "ui.sessionTurn.status.thinkingWithTopic": "Myślenie - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Zbieranie myśli",
+ "ui.sessionTurn.status.consideringNextSteps": "Rozważanie kolejnych kroków",
+
+ "ui.messagePart.questions.dismissed": "Pytania odrzucone",
+ "ui.messagePart.compaction": "Sesja skompaktowana",
+ "ui.messagePart.context.read.one": "{{count}} odczyt",
+ "ui.messagePart.context.read.other": "{{count}} odczyty",
+ "ui.messagePart.context.search.one": "{{count}} wyszukiwanie",
+ "ui.messagePart.context.search.other": "{{count}} wyszukiwania",
+ "ui.messagePart.context.list.one": "{{count}} lista",
+ "ui.messagePart.context.list.other": "{{count}} listy",
+ "ui.messagePart.diagnostic.error": "Błąd",
+ "ui.messagePart.title.edit": "Edycja",
+ "ui.messagePart.title.write": "Pisanie",
+ "ui.messagePart.option.typeOwnAnswer": "Wpisz własną odpowiedź",
+ "ui.messagePart.review.title": "Przejrzyj swoje odpowiedzi",
+
+ "ui.list.loading": "Ładowanie",
+ "ui.list.empty": "Brak wyników",
+ "ui.list.clearFilter": "Wyczyść filtr",
+ "ui.list.emptyWithFilter.prefix": "Brak wyników dla",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Nowa wiadomość",
+
+ "ui.textField.copyToClipboard": "Skopiuj do schowka",
+ "ui.textField.copyLink": "Skopiuj link",
+ "ui.textField.copied": "Skopiowano",
+
+ "ui.imagePreview.alt": "Podgląd obrazu",
+ "ui.scrollView.ariaLabel": "treść przewijana",
+
+ "ui.tool.read": "Odczyt",
+ "ui.tool.loaded": "Załadowano",
+ "ui.tool.list": "Lista",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Pobieranie sieciowe",
+ "ui.tool.websearch": "Wyszukiwanie w sieci",
+ "ui.tool.shell": "Terminal",
+ "ui.tool.patch": "Patch",
+ "ui.tool.todos": "Zadania",
+ "ui.tool.todos.read": "Czytaj zadania",
+ "ui.tool.questions": "Pytania",
+ "ui.tool.agent": "Agent {{type}}",
+ "ui.tool.agent.default": "Agent",
+
+ "ui.common.file.one": "plik",
+ "ui.common.file.other": "pliki",
+ "ui.common.question.one": "pytanie",
+ "ui.common.question.other": "pytania",
+
+ "ui.common.add": "Dodaj",
+ "ui.common.back": "Wstecz",
+ "ui.common.cancel": "Anuluj",
+ "ui.common.confirm": "Potwierdź",
+ "ui.common.dismiss": "Odrzuć",
+ "ui.common.close": "Zamknij",
+ "ui.common.next": "Dalej",
+ "ui.common.submit": "Prześlij",
+ "ui.common.showMore": "Pokaż więcej",
+
+ "ui.permission.deny": "Odmów",
+ "ui.permission.allowAlways": "Zezwalaj zawsze",
+ "ui.permission.allowOnce": "Zezwól raz",
+
+ "ui.message.expand": "Rozwiń wiadomość",
+ "ui.message.collapse": "Zwiń wiadomość",
+ "ui.message.copy": "Kopiuj",
+ "ui.message.copyMessage": "Kopiuj wiadomość",
+ "ui.message.forkMessage": "Rozwidlij do nowej sesji",
+ "ui.message.revertMessage": "Zresetuj do tego punktu",
+ "ui.message.copyResponse": "Kopiuj odpowiedź",
+ "ui.message.copied": "Skopiowano!",
+ "ui.message.interrupted": "Przerwano",
+ "ui.message.queued": "W kolejce",
+ "ui.message.attachment.alt": "załącznik",
+
+ "ui.patch.action.deleted": "Usunięto",
+ "ui.patch.action.created": "Utworzono",
+ "ui.patch.action.moved": "Przeniesiono",
+ "ui.patch.action.patched": "Załatano",
+
+ "ui.question.subtitle.answered": "{{count}} odpowiedzi",
+ "ui.question.answer.none": "(brak odpowiedzi)",
+ "ui.question.review.notAnswered": "(bez odpowiedzi)",
+ "ui.question.multiHint": "Zaznacz wszystkie pasujące",
+ "ui.question.singleHint": "Wybierz jedną odpowiedź",
+ "ui.question.custom.placeholder": "Wpisz swoją odpowiedź...",
+
+ "ui.fileSearch.placeholder": "Szukaj",
+ "ui.fileSearch.previousMatch": "Poprzednie",
+ "ui.fileSearch.nextMatch": "Następne",
+ "ui.fileSearch.close": "Zamknij wyszukiwanie",
+ "ui.tool.task": "Zadanie",
+ "ui.tool.skill": "Umiejętność",
+ "ui.basicTool.called": "Wywołano `{{tool}}`",
+ "ui.toolErrorCard.failed": "Błąd",
+ "ui.toolErrorCard.copyError": "Kopiuj błąd",
+ "ui.message.duration.seconds": "{{count}}s",
+ "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/ru.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/ru.ts
new file mode 100644
index 00000000..448c2075
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/ru.ts
@@ -0,0 +1,193 @@
+export const dict = {
+ "ui.sessionReview.title": "Изменения сессии",
+ "ui.sessionReview.title.git": "Изменения Git",
+ "ui.sessionReview.title.branch": "Изменения ветки",
+ "ui.sessionReview.title.lastTurn": "Изменения последнего хода",
+ "ui.sessionReview.diffStyle.unified": "Объединённый",
+ "ui.sessionReview.diffStyle.split": "Разделённый",
+ "ui.sessionReview.openFile": "Открыть файл",
+ "ui.sessionReview.selection.line": "строка {{line}}",
+ "ui.sessionReview.selection.lines": "строки {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Развернуть всё",
+ "ui.sessionReview.collapseAll": "Свернуть всё",
+
+ "ui.sessionReview.change.added": "Добавлено",
+ "ui.sessionReview.change.removed": "Удалено",
+ "ui.sessionReview.change.modified": "Изменено",
+ "ui.sessionReview.image.loading": "Загрузка...",
+ "ui.sessionReview.image.placeholder": "Изображение",
+ "ui.sessionReview.largeDiff.title": "Diff слишком большой для отображения",
+ "ui.sessionReview.largeDiff.meta": "Лимит: {{limit}} изменённых строк. Текущий: {{current}} изменённых строк.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Отобразить всё равно",
+ "ui.sessionReviewV2.expandMode": "Развернуть или свернуть diff",
+ "ui.sessionReviewV2.filterFiles": "Фильтровать файлы",
+ "ui.sessionReviewV2.toggleSidebar": "Переключить дерево файлов",
+ "ui.sessionReviewV2.showAllLines": "Показать все строки",
+ "ui.sessionReviewV2.hideNonDiffLines": "Скрыть строки без изменений",
+ "ui.sessionReviewV2.unifiedDiff": "Объединённый diff",
+ "ui.sessionReviewV2.splitDiff": "Разделённый diff",
+ "ui.sessionReviewV2.previousFile": "Предыдущий файл",
+ "ui.sessionReviewV2.nextFile": "Следующий файл",
+ "ui.sessionReviewV2.diffView": "Просмотр diff",
+ "ui.sessionReviewV2.empty.noGit.title": "Нет отслеживаемых изменений",
+ "ui.sessionReviewV2.empty.noGit.description": "Отслеживайте, просматривайте и отменяйте изменения в этом проекте",
+ "ui.sessionReviewV2.empty.noGit.action": "Создать репозиторий Git",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Создание репозитория Git...",
+ "ui.sessionReviewV2.empty.changes.title": "Изменений в файлах пока нет",
+ "ui.sessionReviewV2.empty.changes.description": "Изменения проекта появятся здесь",
+ "ui.fileMedia.kind.image": "изображение",
+ "ui.fileMedia.kind.audio": "аудио",
+ "ui.fileMedia.state.removed": "{{kind}} удалено",
+ "ui.fileMedia.state.loading": "Загружается {{kind}}...",
+ "ui.fileMedia.state.error": "Не удалось загрузить {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} недоступно",
+ "ui.fileMedia.binary.title": "Бинарный файл",
+ "ui.fileMedia.binary.description.path": "Невозможно отобразить {{path}}, так как это бинарный файл.",
+ "ui.fileMedia.binary.description.default": "Невозможно отобразить этот файл, так как он бинарный.",
+ "ui.lineComment.label.prefix": "Комментарий к ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Комментирование: ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Добавить комментарий",
+ "ui.lineComment.submit": "Комментировать",
+ "ui.lineComment.cancel": "Отмена",
+ "ui.sessionTurn.steps.show": "Показать шаги",
+ "ui.sessionTurn.steps.hide": "Скрыть шаги",
+ "ui.sessionTurn.summary.response": "Ответ",
+ "ui.sessionTurn.diff.showMore": "Показать ещё изменений ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Изменённый файл: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Изменённые файлы: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Показать все",
+ "ui.sessionTurn.diffs.showLess": "Показать меньше",
+ "ui.sessionTurn.diffs.more": "+ ещё {{count}}",
+
+ "ui.sessionTurn.retry.retrying": "повтор",
+ "ui.sessionTurn.retry.inSeconds": "через {{seconds}}с",
+ "ui.sessionTurn.retry.attempt": "попытка №{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - попытка №{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini сейчас перегружен",
+ "ui.sessionTurn.error.freeUsageExceeded": "Лимит бесплатного использования превышен",
+ "ui.sessionTurn.error.addCredits": "Добавить кредиты",
+
+ "dialog.usageExceeded.freeTier.title": "Достигнут бесплатный лимит",
+ "dialog.usageExceeded.freeTier.description":
+ "Подпишитесь на OpenCode Go для надёжного доступа к лучшим моделям с открытым исходным кодом, от $5/месяц.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Подписаться",
+ "dialog.usageExceeded.accountRateLimit.title": "Достигнут лимит Go",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Достигнут лимит использования. Чтобы продолжить использовать эту модель сейчас, включите использование из доступного баланса",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Открыть настройки",
+
+ "ui.sessionTurn.status.delegating": "Делегирование работы",
+ "ui.sessionTurn.status.planning": "Планирование следующих шагов",
+ "ui.sessionTurn.status.gatheringContext": "Исследование",
+ "ui.sessionTurn.status.gatheredContext": "Исследовано",
+ "ui.sessionTurn.status.searchingCodebase": "Поиск в кодовой базе",
+ "ui.sessionTurn.status.searchingWeb": "Поиск в интернете",
+ "ui.sessionTurn.status.makingEdits": "Внесение изменений",
+ "ui.sessionTurn.status.runningCommands": "Выполнение команд",
+ "ui.sessionTurn.status.thinking": "Размышление",
+ "ui.sessionTurn.status.thinkingWithTopic": "Размышление - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Сбор мыслей",
+ "ui.sessionTurn.status.consideringNextSteps": "Рассмотрение следующих шагов",
+
+ "ui.messagePart.questions.dismissed": "Вопросы отклонены",
+ "ui.messagePart.compaction": "Сессия сжата",
+ "ui.messagePart.context.read.one": "{{count}} чтение",
+ "ui.messagePart.context.read.other": "{{count}} чтений",
+ "ui.messagePart.context.search.one": "{{count}} поиск",
+ "ui.messagePart.context.search.other": "{{count}} поисков",
+ "ui.messagePart.context.list.one": "{{count}} список",
+ "ui.messagePart.context.list.other": "{{count}} списков",
+ "ui.messagePart.diagnostic.error": "Ошибка",
+ "ui.messagePart.title.edit": "Редактировать",
+ "ui.messagePart.title.write": "Написать",
+ "ui.messagePart.option.typeOwnAnswer": "Введите свой ответ",
+ "ui.messagePart.review.title": "Проверьте ваши ответы",
+
+ "ui.list.loading": "Загрузка",
+ "ui.list.empty": "Нет результатов",
+ "ui.list.clearFilter": "Очистить фильтр",
+ "ui.list.emptyWithFilter.prefix": "Нет результатов для",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Новое сообщение",
+
+ "ui.textField.copyToClipboard": "Копировать в буфер обмена",
+ "ui.textField.copyLink": "Копировать ссылку",
+ "ui.textField.copied": "Скопировано",
+
+ "ui.imagePreview.alt": "Предпросмотр изображения",
+ "ui.scrollView.ariaLabel": "прокручиваемый контент",
+
+ "ui.tool.read": "Чтение",
+ "ui.tool.loaded": "Загружено",
+ "ui.tool.list": "Список",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "Веб-поиск",
+ "ui.tool.shell": "Оболочка",
+ "ui.tool.patch": "Патч",
+ "ui.tool.todos": "Задачи",
+ "ui.tool.todos.read": "Читать задачи",
+ "ui.tool.questions": "Вопросы",
+ "ui.tool.agent": "Агент {{type}}",
+ "ui.tool.agent.default": "Агент",
+
+ "ui.common.file.one": "файл",
+ "ui.common.file.other": "файлов",
+ "ui.common.question.one": "вопрос",
+ "ui.common.question.other": "вопросов",
+
+ "ui.common.add": "Добавить",
+ "ui.common.back": "Назад",
+ "ui.common.cancel": "Отмена",
+ "ui.common.confirm": "Подтвердить",
+ "ui.common.dismiss": "Закрыть",
+ "ui.common.close": "Закрыть",
+ "ui.common.next": "Далее",
+ "ui.common.submit": "Отправить",
+ "ui.common.showMore": "Показать ещё",
+
+ "ui.permission.deny": "Запретить",
+ "ui.permission.allowAlways": "Разрешить всегда",
+ "ui.permission.allowOnce": "Разрешить один раз",
+
+ "ui.message.expand": "Развернуть сообщение",
+ "ui.message.collapse": "Свернуть сообщение",
+ "ui.message.copy": "Копировать",
+ "ui.message.copyMessage": "Копировать сообщение",
+ "ui.message.forkMessage": "Ответвить в новую сессию",
+ "ui.message.revertMessage": "Сбросить до этого момента",
+ "ui.message.copyResponse": "Копировать ответ",
+ "ui.message.copied": "Скопировано!",
+ "ui.message.interrupted": "Прервано",
+ "ui.message.queued": "В очереди",
+ "ui.message.attachment.alt": "вложение",
+
+ "ui.patch.action.deleted": "Удалено",
+ "ui.patch.action.created": "Создано",
+ "ui.patch.action.moved": "Перемещено",
+ "ui.patch.action.patched": "Изменено",
+
+ "ui.question.subtitle.answered": "{{count}} отвечено",
+ "ui.question.answer.none": "(нет ответа)",
+ "ui.question.review.notAnswered": "(не отвечено)",
+ "ui.question.multiHint": "Выберите все подходящие",
+ "ui.question.singleHint": "Выберите один ответ",
+ "ui.question.custom.placeholder": "Введите ваш ответ...",
+
+ "ui.fileSearch.placeholder": "Найти",
+ "ui.fileSearch.previousMatch": "Предыдущее",
+ "ui.fileSearch.nextMatch": "Следующее",
+ "ui.fileSearch.close": "Закрыть поиск",
+ "ui.tool.task": "Задача",
+ "ui.tool.skill": "Навык",
+ "ui.basicTool.called": "Вызван `{{tool}}`",
+ "ui.toolErrorCard.failed": "Ошибка",
+ "ui.toolErrorCard.copyError": "Скопировать ошибку",
+ "ui.message.duration.seconds": "{{count}}с",
+ "ui.message.duration.minutesSeconds": "{{minutes}}м {{seconds}}с",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/th.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/th.ts
new file mode 100644
index 00000000..8bece1b5
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/th.ts
@@ -0,0 +1,195 @@
+export const dict = {
+ "ui.sessionReview.title": "การเปลี่ยนแปลงเซสชัน",
+ "ui.sessionReview.title.git": "การเปลี่ยนแปลงใน Git",
+ "ui.sessionReview.title.branch": "การเปลี่ยนแปลงในสาขา",
+ "ui.sessionReview.title.lastTurn": "การเปลี่ยนแปลงของเทิร์นล่าสุด",
+ "ui.sessionReview.diffStyle.unified": "แบบรวม",
+ "ui.sessionReview.diffStyle.split": "แบบแยก",
+ "ui.sessionReview.openFile": "เปิดไฟล์",
+ "ui.sessionReview.selection.line": "บรรทัดที่ {{line}}",
+ "ui.sessionReview.selection.lines": "บรรทัดที่ {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "ขยายทั้งหมด",
+ "ui.sessionReview.collapseAll": "ย่อทั้งหมด",
+ "ui.sessionReview.change.added": "เพิ่ม",
+ "ui.sessionReview.change.removed": "ลบ",
+ "ui.sessionReview.change.modified": "แก้ไข",
+ "ui.sessionReview.image.loading": "กำลังโหลด...",
+ "ui.sessionReview.image.placeholder": "รูปภาพ",
+ "ui.sessionReview.largeDiff.title": "Diff มีขนาดใหญ่เกินไปจนไม่สามารถแสดงผลได้",
+ "ui.sessionReview.largeDiff.meta":
+ "ขีดจำกัด: {{limit}} บรรทัดที่เปลี่ยนแปลง. ปัจจุบัน: {{current}} บรรทัดที่เปลี่ยนแปลง.",
+ "ui.sessionReview.largeDiff.renderAnyway": "แสดงผลต่อไป",
+ "ui.sessionReviewV2.expandMode": "ขยายหรือย่อ diff",
+ "ui.sessionReviewV2.filterFiles": "กรองไฟล์",
+ "ui.sessionReviewV2.toggleSidebar": "สลับต้นไม้ไฟล์",
+ "ui.sessionReviewV2.showAllLines": "แสดงทุกบรรทัด",
+ "ui.sessionReviewV2.hideNonDiffLines": "ซ่อนบรรทัดที่ไม่มี diff",
+ "ui.sessionReviewV2.unifiedDiff": "diff แบบรวม",
+ "ui.sessionReviewV2.splitDiff": "diff แบบแยก",
+ "ui.sessionReviewV2.previousFile": "ไฟล์ก่อนหน้า",
+ "ui.sessionReviewV2.nextFile": "ไฟล์ถัดไป",
+ "ui.sessionReviewV2.diffView": "มุมมอง diff",
+ "ui.sessionReviewV2.empty.noGit.title": "ไม่มีการเปลี่ยนแปลงที่ติดตามอยู่",
+ "ui.sessionReviewV2.empty.noGit.description": "ติดตาม ตรวจสอบ และเลิกทำการเปลี่ยนแปลงในโปรเจกต์นี้",
+ "ui.sessionReviewV2.empty.noGit.action": "สร้าง Git รีโพซิทอรี",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "กำลังสร้าง Git รีโพซิทอรี...",
+ "ui.sessionReviewV2.empty.changes.title": "ยังไม่มีการเปลี่ยนแปลงไฟล์",
+ "ui.sessionReviewV2.empty.changes.description": "การเปลี่ยนแปลงในโปรเจกต์จะแสดงที่นี่",
+ "ui.fileMedia.kind.image": "รูปภาพ",
+ "ui.fileMedia.kind.audio": "เสียง",
+ "ui.fileMedia.state.removed": "ลบ{{kind}}แล้ว",
+ "ui.fileMedia.state.loading": "กำลังโหลด{{kind}}...",
+ "ui.fileMedia.state.error": "เกิดข้อผิดพลาดในการโหลด{{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}}ไม่พร้อมใช้งาน",
+ "ui.fileMedia.binary.title": "ไฟล์ไบนารี",
+ "ui.fileMedia.binary.description.path": "{{path}} เป็นไฟล์ไบนารีและไม่สามารถแสดงผลได้",
+ "ui.fileMedia.binary.description.default": "ไฟล์ไบนารีไม่สามารถแสดงผลได้",
+
+ "ui.lineComment.label.prefix": "แสดงความคิดเห็นบน ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "กำลังแสดงความคิดเห็นบน ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "เพิ่มความคิดเห็น",
+ "ui.lineComment.submit": "แสดงความคิดเห็น",
+ "ui.lineComment.cancel": "ยกเลิก",
+
+ "ui.sessionTurn.steps.show": "แสดงขั้นตอน",
+ "ui.sessionTurn.steps.hide": "ซ่อนขั้นตอน",
+ "ui.sessionTurn.summary.response": "การตอบสนอง",
+ "ui.sessionTurn.diff.showMore": "แสดงการเปลี่ยนแปลงเพิ่มเติม ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "จำนวนไฟล์ที่เปลี่ยนแปลง: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "จำนวนไฟล์ที่เปลี่ยนแปลง: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "แสดงทั้งหมด",
+ "ui.sessionTurn.diffs.showLess": "แสดงน้อยลง",
+ "ui.sessionTurn.diffs.more": "+{{count}} ไฟล์เพิ่มเติม",
+
+ "ui.sessionTurn.retry.retrying": "กำลังลองใหม่",
+ "ui.sessionTurn.retry.inSeconds": "ใน {{seconds}}วิ",
+ "ui.sessionTurn.retry.attempt": "ครั้งที่ {{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - ครั้งที่ {{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini กำลังใช้งานหนาแน่นมาก",
+ "ui.sessionTurn.error.freeUsageExceeded": "เกินขีดจำกัดการใช้งานฟรี",
+ "ui.sessionTurn.error.addCredits": "เพิ่มเครดิต",
+
+ "dialog.usageExceeded.freeTier.title": "ถึงขีดจำกัดฟรีแล้ว",
+ "dialog.usageExceeded.freeTier.description":
+ "สมัครสมาชิก OpenCode Go เพื่อการเข้าถึงโมเดลโอเพนซอร์สที่ดีที่สุดอย่างเชื่อถือได้ เริ่มต้นที่ $5/เดือน",
+ "dialog.usageExceeded.freeTier.actionLabel": "สมัครสมาชิก",
+ "dialog.usageExceeded.accountRateLimit.title": "ถึงขีดจำกัดของ Go แล้ว",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "ถึงขีดจำกัดการใช้งานแล้ว หากต้องการใช้โมเดลนี้ต่อในตอนนี้ ให้เปิดใช้งานจากยอดคงเหลือที่มี",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "เปิดการตั้งค่า",
+
+ "ui.sessionTurn.status.delegating": "มอบหมายงาน",
+ "ui.sessionTurn.status.planning": "วางแผนขั้นตอนถัดไป",
+ "ui.sessionTurn.status.gatheringContext": "กำลังสำรวจ",
+ "ui.sessionTurn.status.gatheredContext": "สำรวจแล้ว",
+ "ui.sessionTurn.status.searchingCodebase": "กำลังค้นหาโค้ดเบส",
+ "ui.sessionTurn.status.searchingWeb": "กำลังค้นหาบนเว็บ",
+ "ui.sessionTurn.status.makingEdits": "กำลังแก้ไข",
+ "ui.sessionTurn.status.runningCommands": "กำลังเรียกใช้คำสั่ง",
+ "ui.sessionTurn.status.thinking": "กำลังคิด",
+ "ui.sessionTurn.status.thinkingWithTopic": "กำลังคิด - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "รวบรวมความคิด",
+ "ui.sessionTurn.status.consideringNextSteps": "พิจารณาขั้นตอนถัดไป",
+
+ "ui.messagePart.questions.dismissed": "ละทิ้งคำถามแล้ว",
+ "ui.messagePart.compaction": "บีบอัดเซสชันแล้ว",
+ "ui.messagePart.context.read.one": "อ่าน {{count}} รายการ",
+ "ui.messagePart.context.read.other": "อ่าน {{count}} รายการ",
+ "ui.messagePart.context.search.one": "ค้นหา {{count}} รายการ",
+ "ui.messagePart.context.search.other": "ค้นหา {{count}} รายการ",
+ "ui.messagePart.context.list.one": "รายการ {{count}} รายการ",
+ "ui.messagePart.context.list.other": "รายการ {{count}} รายการ",
+ "ui.messagePart.diagnostic.error": "ข้อผิดพลาด",
+ "ui.messagePart.title.edit": "แก้ไข",
+ "ui.messagePart.title.write": "เขียน",
+ "ui.messagePart.option.typeOwnAnswer": "พิมพ์คำตอบของคุณเอง",
+ "ui.messagePart.review.title": "ตรวจสอบคำตอบของคุณ",
+
+ "ui.list.loading": "กำลังโหลด",
+ "ui.list.empty": "ไม่มีผลลัพธ์",
+ "ui.list.clearFilter": "ล้างตัวกรอง",
+ "ui.list.emptyWithFilter.prefix": "ไม่มีผลลัพธ์สำหรับ",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "ข้อความใหม่",
+
+ "ui.textField.copyToClipboard": "คัดลอกไปยังคลิปบอร์ด",
+ "ui.textField.copyLink": "คัดลอกลิงก์",
+ "ui.textField.copied": "คัดลอกแล้ว",
+
+ "ui.imagePreview.alt": "ตัวอย่างรูปภาพ",
+ "ui.scrollView.ariaLabel": "เนื้อหาที่เลื่อนได้",
+
+ "ui.tool.read": "อ่าน",
+ "ui.tool.loaded": "โหลดแล้ว",
+ "ui.tool.list": "รายการ",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "ดึงจากเว็บ",
+ "ui.tool.websearch": "ค้นหาเว็บ",
+ "ui.tool.shell": "เชลล์",
+ "ui.tool.patch": "แพตช์",
+ "ui.tool.todos": "รายการงาน",
+ "ui.tool.todos.read": "อ่านรายการงาน",
+ "ui.tool.questions": "คำถาม",
+ "ui.tool.agent": "เอเจนต์ {{type}}",
+ "ui.tool.agent.default": "เอเจนต์",
+
+ "ui.common.file.one": "ไฟล์",
+ "ui.common.file.other": "ไฟล์",
+ "ui.common.question.one": "คำถาม",
+ "ui.common.question.other": "คำถาม",
+
+ "ui.common.add": "เพิ่ม",
+ "ui.common.back": "ย้อนกลับ",
+ "ui.common.cancel": "ยกเลิก",
+ "ui.common.confirm": "ยืนยัน",
+ "ui.common.dismiss": "ปิด",
+ "ui.common.close": "ปิด",
+ "ui.common.next": "ถัดไป",
+ "ui.common.submit": "ส่ง",
+ "ui.common.showMore": "แสดงเพิ่มเติม",
+
+ "ui.permission.deny": "ปฏิเสธ",
+ "ui.permission.allowAlways": "อนุญาตเสมอ",
+ "ui.permission.allowOnce": "อนุญาตครั้งเดียว",
+
+ "ui.message.expand": "ขยายข้อความ",
+ "ui.message.collapse": "ย่อข้อความ",
+ "ui.message.copy": "คัดลอก",
+ "ui.message.copyMessage": "คัดลอกข้อความ",
+ "ui.message.forkMessage": "แตกแขนงไปยังเซสชันใหม่",
+ "ui.message.revertMessage": "รีเซ็ตไปยังจุดนี้",
+ "ui.message.copyResponse": "คัดลอกคำตอบ",
+ "ui.message.copied": "คัดลอกแล้ว!",
+ "ui.message.interrupted": "ถูกขัดจังหวะ",
+ "ui.message.queued": "อยู่ในคิว",
+ "ui.message.attachment.alt": "ไฟล์แนบ",
+
+ "ui.patch.action.deleted": "ลบ",
+ "ui.patch.action.created": "สร้าง",
+ "ui.patch.action.moved": "ย้าย",
+ "ui.patch.action.patched": "แพตช์",
+
+ "ui.question.subtitle.answered": "{{count}} ตอบแล้ว",
+ "ui.question.answer.none": "(ไม่มีคำตอบ)",
+ "ui.question.review.notAnswered": "(ไม่ได้ตอบ)",
+ "ui.question.multiHint": "เลือกทั้งหมดที่ใช้",
+ "ui.question.singleHint": "เลือกหนึ่งคำตอบ",
+ "ui.question.custom.placeholder": "พิมพ์คำตอบของคุณ...",
+
+ "ui.fileSearch.placeholder": "ค้นหา",
+ "ui.fileSearch.previousMatch": "ก่อนหน้า",
+ "ui.fileSearch.nextMatch": "ถัดไป",
+ "ui.fileSearch.close": "ปิดการค้นหา",
+ "ui.tool.task": "งาน",
+ "ui.tool.skill": "ทักษะ",
+ "ui.basicTool.called": "เรียกใช้ `{{tool}}`",
+ "ui.toolErrorCard.failed": "ล้มเหลว",
+ "ui.toolErrorCard.copyError": "คัดลอกข้อผิดพลาด",
+ "ui.message.duration.seconds": "{{count}}วิ",
+ "ui.message.duration.minutesSeconds": "{{minutes}}นาที {{seconds}}วิ",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/tr.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/tr.ts
new file mode 100644
index 00000000..574edbb0
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/tr.ts
@@ -0,0 +1,200 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+ "ui.sessionReview.title": "Oturum değişiklikleri",
+ "ui.sessionReview.title.git": "Git değişiklikleri",
+ "ui.sessionReview.title.branch": "Dal değişiklikleri",
+ "ui.sessionReview.title.lastTurn": "Son tur değişiklikleri",
+ "ui.sessionReview.diffStyle.unified": "Birleşik",
+ "ui.sessionReview.diffStyle.split": "Bölünmüş",
+ "ui.sessionReview.openFile": "Dosyayı aç",
+ "ui.sessionReview.selection.line": "satır {{line}}",
+ "ui.sessionReview.selection.lines": "satırlar {{start}}-{{end}}",
+ "ui.sessionReview.expandAll": "Tümünü genişlet",
+ "ui.sessionReview.collapseAll": "Tümünü daralt",
+
+ "ui.sessionReview.change.added": "Eklendi",
+ "ui.sessionReview.change.removed": "Kaldırıldı",
+ "ui.sessionReview.change.modified": "Değiştirildi",
+ "ui.sessionReview.image.loading": "Yükleniyor...",
+ "ui.sessionReview.image.placeholder": "Görsel",
+ "ui.sessionReview.largeDiff.title": "Fark gösterimi için çok büyük",
+ "ui.sessionReview.largeDiff.meta": "Limit: {{limit}} değişen satır. Mevcut: {{current}} değişen satır.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Yine de göster",
+ "ui.sessionReviewV2.expandMode": "Farkı genişlet veya daralt",
+ "ui.sessionReviewV2.filterFiles": "Dosyaları filtrele",
+ "ui.sessionReviewV2.toggleSidebar": "Dosya ağacını aç/kapat",
+ "ui.sessionReviewV2.showAllLines": "Tüm satırları göster",
+ "ui.sessionReviewV2.hideNonDiffLines": "Fark içermeyen satırları gizle",
+ "ui.sessionReviewV2.unifiedDiff": "Birleşik fark",
+ "ui.sessionReviewV2.splitDiff": "Bölünmüş fark",
+ "ui.sessionReviewV2.previousFile": "Önceki dosya",
+ "ui.sessionReviewV2.nextFile": "Sonraki dosya",
+ "ui.sessionReviewV2.diffView": "Fark görünümü",
+ "ui.sessionReviewV2.empty.noGit.title": "İzlenen değişiklik yok",
+ "ui.sessionReviewV2.empty.noGit.description": "Bu projedeki değişiklikleri takip et, incele ve geri al",
+ "ui.sessionReviewV2.empty.noGit.action": "Git deposu oluştur",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Git deposu oluşturuluyor...",
+ "ui.sessionReviewV2.empty.changes.title": "Henüz dosya değişikliği yok",
+ "ui.sessionReviewV2.empty.changes.description": "Proje değişiklikleri burada görünecek",
+
+ "ui.fileMedia.kind.image": "görsel",
+ "ui.fileMedia.kind.audio": "ses",
+ "ui.fileMedia.state.removed": "{{kind}} dosyası kaldırıldı.",
+ "ui.fileMedia.state.loading": "{{kind}} yükleniyor...",
+ "ui.fileMedia.state.error": "{{kind}} yüklenemedi.",
+ "ui.fileMedia.state.unavailable": "{{kind}} önizlemesi kullanılamıyor.",
+ "ui.fileMedia.binary.title": "İkili dosya",
+ "ui.fileMedia.binary.description.path": "{{path}} ikili dosyadır.",
+ "ui.fileMedia.binary.description.default": "İkili içerik",
+
+ "ui.lineComment.label.prefix": "Yorum: ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Yorum yapılıyor: ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Yorum ekle",
+ "ui.lineComment.submit": "Yorum yap",
+ "ui.lineComment.cancel": "İptal",
+
+ "ui.sessionTurn.steps.show": "Adımları göster",
+ "ui.sessionTurn.steps.hide": "Adımları gizle",
+ "ui.sessionTurn.summary.response": "Yanıt",
+ "ui.sessionTurn.diff.showMore": "Daha fazla değişiklik göster ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Değiştirilen dosya: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Değiştirilen dosyalar: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Tümünü göster",
+ "ui.sessionTurn.diffs.showLess": "Daha az göster",
+ "ui.sessionTurn.diffs.more": "+{{count}} dosya daha",
+
+ "ui.sessionTurn.retry.retrying": "yeniden deneniyor",
+ "ui.sessionTurn.retry.inSeconds": "{{seconds}}sn içinde",
+ "ui.sessionTurn.retry.attempt": "deneme #{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - deneme #{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini şu anda aşırı yoğun",
+ "ui.sessionTurn.error.freeUsageExceeded": "Ücretsiz kullanım aşıldı",
+ "ui.sessionTurn.error.addCredits": "Kredi ekle",
+
+ "dialog.usageExceeded.freeTier.title": "Ücretsiz sınıra ulaşıldı",
+ "dialog.usageExceeded.freeTier.description":
+ "En iyi açık kaynak modellere güvenilir erişim için OpenCode Go'ya abone olun. Aylık $5'tan başlar.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Abone ol",
+ "dialog.usageExceeded.accountRateLimit.title": "Go sınırına ulaşıldı",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Kullanım sınırına ulaşıldı. Bu modeli şimdi kullanmaya devam etmek için mevcut bakiyenizden kullanımı etkinleştirin",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Ayarları aç",
+
+ "ui.sessionTurn.status.delegating": "Görev devrediliyor",
+ "ui.sessionTurn.status.planning": "Sonraki adımlar planlanıyor",
+ "ui.sessionTurn.status.gatheringContext": "Keşfediliyor",
+ "ui.sessionTurn.status.gatheredContext": "Keşfedildi",
+ "ui.sessionTurn.status.searchingCodebase": "Kod tabanı aranıyor",
+ "ui.sessionTurn.status.searchingWeb": "Web aranıyor",
+ "ui.sessionTurn.status.makingEdits": "Düzenlemeler yapılıyor",
+ "ui.sessionTurn.status.runningCommands": "Komutlar çalıştırılıyor",
+ "ui.sessionTurn.status.thinking": "Düşünüyor",
+ "ui.sessionTurn.status.thinkingWithTopic": "Düşünüyor - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Düşünceler toplanıyor",
+ "ui.sessionTurn.status.consideringNextSteps": "Sonraki adımlar değerlendiriliyor",
+
+ "ui.messagePart.questions.dismissed": "Sorular reddedildi",
+ "ui.messagePart.compaction": "Oturum sıkıştırıldı",
+ "ui.messagePart.context.read.one": "{{count}} okuma",
+ "ui.messagePart.context.read.other": "{{count}} okuma",
+ "ui.messagePart.context.search.one": "{{count}} arama",
+ "ui.messagePart.context.search.other": "{{count}} arama",
+ "ui.messagePart.context.list.one": "{{count}} liste",
+ "ui.messagePart.context.list.other": "{{count}} liste",
+ "ui.messagePart.diagnostic.error": "Hata",
+ "ui.messagePart.title.edit": "Düzenle",
+ "ui.messagePart.title.write": "Yaz",
+ "ui.messagePart.option.typeOwnAnswer": "Kendi cevabınızı yazın",
+ "ui.messagePart.review.title": "Cevapları inceleyin",
+
+ "ui.list.loading": "Yükleniyor",
+ "ui.list.empty": "Sonuç bulunamadı",
+ "ui.list.clearFilter": "Filtreyi temizle",
+ "ui.list.emptyWithFilter.prefix": "Sonuç bulunamadı:",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.messageNav.newMessage": "Yeni mesaj",
+
+ "ui.textField.copyToClipboard": "Panoya kopyala",
+ "ui.textField.copyLink": "Bağlantı kopyala",
+ "ui.textField.copied": "Kopyalandı",
+
+ "ui.imagePreview.alt": "Görsel önizleme",
+ "ui.scrollView.ariaLabel": "kaydırılabilir içerik",
+
+ "ui.tool.read": "Oku",
+ "ui.tool.loaded": "Yüklendi",
+ "ui.tool.list": "Listele",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Web getir",
+ "ui.tool.websearch": "Web Araması",
+ "ui.tool.shell": "Kabuk",
+ "ui.tool.patch": "Yama",
+ "ui.tool.todos": "Görevler",
+ "ui.tool.todos.read": "Görevleri oku",
+ "ui.tool.questions": "Sorular",
+ "ui.tool.agent": "{{type}} Ajan",
+ "ui.tool.agent.default": "Ajan",
+
+ "ui.common.file.one": "dosya",
+ "ui.common.file.other": "dosya",
+ "ui.common.question.one": "soru",
+ "ui.common.question.other": "soru",
+
+ "ui.common.add": "Ekle",
+ "ui.common.back": "Geri",
+ "ui.common.cancel": "İptal",
+ "ui.common.confirm": "Onayla",
+ "ui.common.dismiss": "Kapat",
+ "ui.common.close": "Kapat",
+ "ui.common.next": "İleri",
+ "ui.common.submit": "Gönder",
+ "ui.common.showMore": "Daha fazla göster",
+
+ "ui.permission.deny": "Reddet",
+ "ui.permission.allowAlways": "Her zaman izin ver",
+ "ui.permission.allowOnce": "Bir kez izin ver",
+
+ "ui.message.expand": "Mesajı genişlet",
+ "ui.message.collapse": "Mesajı daralt",
+ "ui.message.copy": "Kopyala",
+ "ui.message.copyMessage": "Mesajı kopyala",
+ "ui.message.forkMessage": "Yeni oturuma dallandır",
+ "ui.message.revertMessage": "Bu noktaya sıfırla",
+ "ui.message.copyResponse": "Yanıtı kopyala",
+ "ui.message.copied": "Kopyalandı",
+ "ui.message.interrupted": "Kesildi",
+ "ui.message.queued": "Sırada",
+ "ui.message.attachment.alt": "ek",
+
+ "ui.patch.action.deleted": "Silindi",
+ "ui.patch.action.created": "Oluşturuldu",
+ "ui.patch.action.moved": "Taşındı",
+ "ui.patch.action.patched": "Yamalandı",
+
+ "ui.question.subtitle.answered": "{{count}} cevaplandı",
+ "ui.question.answer.none": "(cevap yok)",
+ "ui.question.review.notAnswered": "(cevaplanmadı)",
+ "ui.question.multiHint": "Geçerli tüm cevapları seçin",
+ "ui.question.singleHint": "Bir cevap seçin",
+ "ui.question.custom.placeholder": "Cevabınızı yazın...",
+
+ "ui.fileSearch.placeholder": "Bul",
+ "ui.fileSearch.previousMatch": "Önceki",
+ "ui.fileSearch.nextMatch": "Sonraki",
+ "ui.fileSearch.close": "Aramayı kapat",
+ "ui.tool.task": "Görev",
+ "ui.tool.skill": "Yetenek",
+ "ui.basicTool.called": "`{{tool}}` çağrıldı",
+ "ui.toolErrorCard.failed": "Başarısız",
+ "ui.toolErrorCard.copyError": "Hatayı kopyala",
+ "ui.message.duration.seconds": "{{count}}sn",
+ "ui.message.duration.minutesSeconds": "{{minutes}}dk {{seconds}}sn",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/uk.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/uk.ts
new file mode 100644
index 00000000..18451f38
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/uk.ts
@@ -0,0 +1,197 @@
+export const dict: Record = {
+ "ui.sessionReview.title": "Зміни сесії",
+ "ui.sessionReview.title.git": "Зміни Git",
+ "ui.sessionReview.title.branch": "Зміни гілки",
+ "ui.sessionReview.title.lastTurn": "Зміни останнього кроку",
+ "ui.sessionReview.diffStyle.unified": "Об'єднаний",
+ "ui.sessionReview.diffStyle.split": "Розділений",
+ "ui.sessionReview.expandAll": "Розгорнути все",
+ "ui.sessionReview.collapseAll": "Згорнути все",
+ "ui.sessionReview.change.added": "Додано",
+ "ui.sessionReview.change.removed": "Видалено",
+ "ui.sessionReview.change.modified": "Змінено",
+ "ui.sessionReview.image.loading": "Завантаження...",
+ "ui.sessionReview.image.placeholder": "Зображення",
+ "ui.sessionReview.largeDiff.title": "Завеликий diff для відображення",
+ "ui.sessionReview.largeDiff.meta": "Ліміт: {{limit}} змінених рядків. Поточно: {{current}} змінених рядків.",
+ "ui.sessionReview.largeDiff.renderAnyway": "Все одно відобразити",
+ "ui.sessionReviewV2.expandMode": "Розгорнути або згорнути diff",
+ "ui.sessionReviewV2.filterFiles": "Фільтрувати файли",
+ "ui.sessionReviewV2.toggleSidebar": "Перемкнути дерево файлів",
+ "ui.sessionReviewV2.showAllLines": "Показати всі рядки",
+ "ui.sessionReviewV2.hideNonDiffLines": "Приховати рядки поза diff",
+ "ui.sessionReviewV2.unifiedDiff": "Об'єднаний diff",
+ "ui.sessionReviewV2.splitDiff": "Розділений diff",
+ "ui.sessionReviewV2.previousFile": "Попередній файл",
+ "ui.sessionReviewV2.nextFile": "Наступний файл",
+ "ui.sessionReviewV2.diffView": "Перегляд diff",
+ "ui.sessionReviewV2.empty.noGit.title": "Немає відстежуваних змін",
+ "ui.sessionReviewV2.empty.noGit.description": "Відстежуйте, переглядайте та скасовуйте зміни в цьому проєкті",
+ "ui.sessionReviewV2.empty.noGit.action": "Створити Git-репозиторій",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "Створення Git-репозиторію...",
+ "ui.sessionReviewV2.empty.changes.title": "Змін у файлах ще немає",
+ "ui.sessionReviewV2.empty.changes.description": "Зміни проєкту з'являться тут",
+
+ "ui.sessionReview.openFile": "Відкрити файл",
+ "ui.sessionReview.selection.line": "рядок {{line}}",
+ "ui.sessionReview.selection.lines": "рядки {{start}}-{{end}}",
+
+ "ui.fileMedia.kind.image": "зображення",
+ "ui.fileMedia.kind.audio": "аудіо",
+ "ui.fileMedia.state.removed": "{{kind}} видалено",
+ "ui.fileMedia.state.loading": "Завантаження {{kind}}...",
+ "ui.fileMedia.state.error": "Не вдалося завантажити {{kind}}",
+ "ui.fileMedia.state.unavailable": "{{kind}} недоступне",
+ "ui.fileMedia.binary.title": "Бінарний файл",
+ "ui.fileMedia.binary.description.path": "Неможливо відобразити {{path}}, оскільки це бінарний файл.",
+ "ui.fileMedia.binary.description.default": "Неможливо відобразити цей файл, оскільки він бінарний.",
+
+ "ui.lineComment.label.prefix": "Коментар до ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "Коментування: ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "Додати коментар",
+ "ui.lineComment.submit": "Коментувати",
+ "ui.lineComment.cancel": "Скасувати",
+
+ "ui.sessionTurn.steps.show": "Показати кроки",
+ "ui.sessionTurn.steps.hide": "Приховати кроки",
+ "ui.sessionTurn.summary.response": "Відповідь",
+ "ui.sessionTurn.diff.showMore": "Показати більше змін ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "Змінений файл: {{count}}",
+ "ui.sessionTurn.diffs.changed.other": "Змінені файли: {{count}}",
+ "ui.sessionTurn.diffs.showAll": "Показати всі",
+ "ui.sessionTurn.diffs.showLess": "Показати менше",
+ "ui.sessionTurn.diffs.more": "+ ще {{count}}",
+
+ "ui.sessionTurn.retry.retrying": "повтор",
+ "ui.sessionTurn.retry.inSeconds": "за {{seconds}}с",
+ "ui.sessionTurn.retry.attempt": "спроба №{{attempt}}",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} — спроба №{{attempt}}",
+ "ui.sessionTurn.retry.geminiHot": "gemini зараз перевантажений",
+ "ui.sessionTurn.error.freeUsageExceeded": "Перевищено ліміт безкоштовного використання",
+ "ui.sessionTurn.error.addCredits": "Додати кредити",
+
+ "dialog.usageExceeded.freeTier.title": "Безкоштовний ліміт вичерпано",
+ "dialog.usageExceeded.freeTier.description":
+ "Підпишіться на OpenCode Go для надійного доступу до найкращих моделей із відкритим кодом від $5 на місяць.",
+ "dialog.usageExceeded.freeTier.actionLabel": "Підписатися",
+ "dialog.usageExceeded.accountRateLimit.title": "Ліміт Go вичерпано",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "Ліміт використання вичерпано. Щоб і надалі користуватися цією моделлю, увімкніть оплату з доступного балансу",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "Відкрити налаштування",
+
+ "ui.sessionTurn.status.delegating": "Делегування роботи",
+ "ui.sessionTurn.status.planning": "Планування наступних кроків",
+ "ui.sessionTurn.status.gatheringContext": "Дослідження",
+ "ui.sessionTurn.status.gatheredContext": "Досліджено",
+ "ui.sessionTurn.status.searchingCodebase": "Пошук у кодовій базі",
+ "ui.sessionTurn.status.searchingWeb": "Пошук в інтернеті",
+ "ui.sessionTurn.status.makingEdits": "Внесення змін",
+ "ui.sessionTurn.status.runningCommands": "Виконання команд",
+ "ui.sessionTurn.status.thinking": "Міркування",
+ "ui.sessionTurn.status.thinkingWithTopic": "Міркування — {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "Збирання думок",
+ "ui.sessionTurn.status.consideringNextSteps": "Розгляд наступних кроків",
+
+ "ui.messagePart.diagnostic.error": "Помилка",
+ "ui.messagePart.title.edit": "Редагувати",
+ "ui.messagePart.title.write": "Написати",
+ "ui.messagePart.option.typeOwnAnswer": "Введіть власну відповідь",
+ "ui.messagePart.review.title": "Перевірте свої відповіді",
+ "ui.messagePart.questions.dismissed": "Питання відхилено",
+ "ui.messagePart.compaction": "Сесію стиснуто",
+ "ui.messagePart.context.read.one": "{{count}} читання",
+ "ui.messagePart.context.read.other": "{{count}} читань",
+ "ui.messagePart.context.search.one": "{{count}} пошук",
+ "ui.messagePart.context.search.other": "{{count}} пошуків",
+ "ui.messagePart.context.list.one": "{{count}} список",
+ "ui.messagePart.context.list.other": "{{count}} списків",
+
+ "ui.list.loading": "Завантаження",
+ "ui.list.empty": "Немає результатів",
+ "ui.list.clearFilter": "Очистити фільтр",
+ "ui.list.emptyWithFilter.prefix": "Немає результатів для",
+ "ui.list.emptyWithFilter.suffix": "",
+
+ "ui.fileSearch.placeholder": "Знайти",
+ "ui.fileSearch.previousMatch": "Попередній збіг",
+ "ui.fileSearch.nextMatch": "Наступний збіг",
+ "ui.fileSearch.close": "Закрити пошук",
+
+ "ui.messageNav.newMessage": "Нове повідомлення",
+
+ "ui.textField.copyToClipboard": "Копіювати в буфер обміну",
+ "ui.textField.copyLink": "Копіювати посилання",
+ "ui.textField.copied": "Скопійовано",
+
+ "ui.imagePreview.alt": "Попередній перегляд зображення",
+ "ui.scrollView.ariaLabel": "контент для прокручування",
+
+ "ui.tool.read": "Читання",
+ "ui.tool.loaded": "Завантажено",
+ "ui.tool.list": "Список",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.task": "Завдання",
+ "ui.tool.webfetch": "Веб-отримання",
+ "ui.tool.websearch": "Веб-пошук",
+ "ui.tool.shell": "Оболонка",
+ "ui.tool.patch": "Патч",
+ "ui.tool.todos": "Завдання",
+ "ui.tool.todos.read": "Читати завдання",
+ "ui.tool.questions": "Питання",
+ "ui.tool.agent": "Агент {{type}}",
+ "ui.tool.agent.default": "Агент",
+ "ui.tool.skill": "Навичка",
+
+ "ui.basicTool.called": "Викликано `{{tool}}`",
+ "ui.toolErrorCard.failed": "Помилка",
+ "ui.toolErrorCard.copyError": "Копіювати помилку",
+
+ "ui.common.file.one": "файл",
+ "ui.common.file.other": "файлів",
+ "ui.common.question.one": "питання",
+ "ui.common.question.other": "питань",
+
+ "ui.common.add": "Додати",
+ "ui.common.back": "Назад",
+ "ui.common.cancel": "Скасувати",
+ "ui.common.confirm": "Підтвердити",
+ "ui.common.dismiss": "Відхилити",
+ "ui.common.close": "Закрити",
+ "ui.common.next": "Далі",
+ "ui.common.submit": "Надіслати",
+ "ui.common.showMore": "Показати більше",
+
+ "ui.permission.deny": "Заборонити",
+ "ui.permission.allowAlways": "Дозволяти завжди",
+ "ui.permission.allowOnce": "Дозволити один раз",
+
+ "ui.message.expand": "Розгорнути повідомлення",
+ "ui.message.collapse": "Згорнути повідомлення",
+ "ui.message.copy": "Копіювати",
+ "ui.message.copyMessage": "Копіювати повідомлення",
+ "ui.message.forkMessage": "Відгалузити в нову сесію",
+ "ui.message.revertMessage": "Скинути до цього моменту",
+ "ui.message.copyResponse": "Копіювати відповідь",
+ "ui.message.copied": "Скопійовано",
+ "ui.message.duration.seconds": "{{count}}с",
+ "ui.message.duration.minutesSeconds": "{{minutes}}хв {{seconds}}с",
+ "ui.message.interrupted": "Перервано",
+ "ui.message.queued": "У черзі",
+ "ui.message.attachment.alt": "вкладення",
+
+ "ui.patch.action.deleted": "Видалено",
+ "ui.patch.action.created": "Створено",
+ "ui.patch.action.moved": "Переміщено",
+ "ui.patch.action.patched": "Пропатчено",
+
+ "ui.question.subtitle.answered": "{{count}} відповідей",
+ "ui.question.answer.none": "(немає відповіді)",
+ "ui.question.review.notAnswered": "(не відповіли)",
+ "ui.question.multiHint": "Виберіть усі відповідні варіанти",
+ "ui.question.singleHint": "Виберіть одну відповідь",
+ "ui.question.custom.placeholder": "Введіть свою відповідь...",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/zh.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/zh.ts
new file mode 100644
index 00000000..7b2b4c9f
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/zh.ts
@@ -0,0 +1,197 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+ "ui.sessionReview.title": "会话变更",
+ "ui.sessionReview.title.git": "Git 变更",
+ "ui.sessionReview.title.branch": "分支变更",
+ "ui.sessionReview.title.lastTurn": "上一轮变更",
+ "ui.sessionReview.diffStyle.unified": "统一",
+ "ui.sessionReview.diffStyle.split": "拆分",
+ "ui.sessionReview.openFile": "打开文件",
+ "ui.sessionReview.selection.line": "第 {{line}} 行",
+ "ui.sessionReview.selection.lines": "第 {{start}}-{{end}} 行",
+ "ui.sessionReview.expandAll": "全部展开",
+ "ui.sessionReview.collapseAll": "全部收起",
+ "ui.sessionReview.change.added": "已添加",
+ "ui.sessionReview.change.removed": "已移除",
+ "ui.sessionReview.change.modified": "已修改",
+ "ui.sessionReview.image.loading": "加载中...",
+ "ui.sessionReview.image.placeholder": "图片",
+ "ui.sessionReview.largeDiff.title": "差异过大,无法渲染",
+ "ui.sessionReview.largeDiff.meta": "限制:{{limit}} 行变更。当前:{{current}} 行变更。",
+ "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染",
+ "ui.sessionReviewV2.expandMode": "展开或折叠差异",
+ "ui.sessionReviewV2.filterFiles": "筛选文件",
+ "ui.sessionReviewV2.toggleSidebar": "切换文件树",
+ "ui.sessionReviewV2.showAllLines": "显示所有行",
+ "ui.sessionReviewV2.hideNonDiffLines": "隐藏非差异行",
+ "ui.sessionReviewV2.unifiedDiff": "统一差异",
+ "ui.sessionReviewV2.splitDiff": "拆分差异",
+ "ui.sessionReviewV2.previousFile": "上一个文件",
+ "ui.sessionReviewV2.nextFile": "下一个文件",
+ "ui.sessionReviewV2.diffView": "差异视图",
+ "ui.sessionReviewV2.empty.noGit.title": "无已跟踪的变更",
+ "ui.sessionReviewV2.empty.noGit.description": "在此项目中跟踪、审查和撤销更改",
+ "ui.sessionReviewV2.empty.noGit.action": "创建 Git 仓库",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "正在创建 Git 仓库...",
+ "ui.sessionReviewV2.empty.changes.title": "尚无文件变更",
+ "ui.sessionReviewV2.empty.changes.description": "项目变更将显示在此处",
+ "ui.fileMedia.kind.image": "图片",
+ "ui.fileMedia.kind.audio": "音频",
+ "ui.fileMedia.state.removed": "{{kind}}已移除",
+ "ui.fileMedia.state.loading": "正在加载{{kind}}...",
+ "ui.fileMedia.state.error": "加载{{kind}}失败",
+ "ui.fileMedia.state.unavailable": "{{kind}}不可预览",
+ "ui.fileMedia.binary.title": "二进制文件",
+ "ui.fileMedia.binary.description.path": "无法显示 {{path}},因为它是二进制文件。",
+ "ui.fileMedia.binary.description.default": "无法显示此文件,因为它是二进制文件。",
+
+ "ui.lineComment.label.prefix": "评论 ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "正在评论 ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "添加评论",
+ "ui.lineComment.submit": "评论",
+ "ui.lineComment.cancel": "取消",
+
+ "ui.sessionTurn.steps.show": "显示步骤",
+ "ui.sessionTurn.steps.hide": "隐藏步骤",
+ "ui.sessionTurn.summary.response": "回复",
+ "ui.sessionTurn.diff.showMore": "显示更多更改({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "已更改文件:{{count}} 个",
+ "ui.sessionTurn.diffs.changed.other": "已更改文件:{{count}} 个",
+ "ui.sessionTurn.diffs.showAll": "全部显示",
+ "ui.sessionTurn.diffs.showLess": "收起",
+ "ui.sessionTurn.diffs.more": "+{{count}} 个文件",
+
+ "ui.sessionTurn.retry.retrying": "重试中",
+ "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒后",
+ "ui.sessionTurn.retry.attempt": "第 {{attempt}} 次",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - 第 {{attempt}} 次",
+ "ui.sessionTurn.retry.geminiHot": "gemini 当前过载",
+ "ui.sessionTurn.error.freeUsageExceeded": "免费使用额度已用完",
+ "ui.sessionTurn.error.addCredits": "添加积分",
+
+ "dialog.usageExceeded.freeTier.title": "免费额度已用完",
+ "dialog.usageExceeded.freeTier.description": "订阅 OpenCode Go,可靠地使用最佳开源模型,每月 $5 起。",
+ "dialog.usageExceeded.freeTier.actionLabel": "订阅",
+ "dialog.usageExceeded.accountRateLimit.title": "Go 额度已用完",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "使用额度已达上限。如需现在继续使用此模型,请从可用余额中启用使用",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "打开设置",
+
+ "ui.sessionTurn.status.delegating": "正在委派工作",
+ "ui.sessionTurn.status.planning": "正在规划下一步",
+ "ui.sessionTurn.status.gatheringContext": "正在探索",
+ "ui.sessionTurn.status.gatheredContext": "已探索",
+ "ui.sessionTurn.status.searchingCodebase": "正在搜索代码库",
+ "ui.sessionTurn.status.searchingWeb": "正在搜索网页",
+ "ui.sessionTurn.status.makingEdits": "正在修改",
+ "ui.sessionTurn.status.runningCommands": "正在运行命令",
+ "ui.sessionTurn.status.thinking": "思考中",
+ "ui.sessionTurn.status.thinkingWithTopic": "思考:{{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "正在整理思路",
+ "ui.sessionTurn.status.consideringNextSteps": "正在考虑下一步",
+
+ "ui.messagePart.questions.dismissed": "问题已忽略",
+ "ui.messagePart.compaction": "会话已压缩",
+ "ui.messagePart.context.read.one": "{{count}} 次读取",
+ "ui.messagePart.context.read.other": "{{count}} 次读取",
+ "ui.messagePart.context.search.one": "{{count}} 次搜索",
+ "ui.messagePart.context.search.other": "{{count}} 次搜索",
+ "ui.messagePart.context.list.one": "{{count}} 个列表",
+ "ui.messagePart.context.list.other": "{{count}} 个列表",
+ "ui.messagePart.diagnostic.error": "错误",
+ "ui.messagePart.title.edit": "编辑",
+ "ui.messagePart.title.write": "写入",
+ "ui.messagePart.option.typeOwnAnswer": "输入自己的答案",
+ "ui.messagePart.review.title": "检查你的答案",
+
+ "ui.list.loading": "加载中",
+ "ui.list.empty": "无结果",
+ "ui.list.clearFilter": "清除筛选",
+ "ui.list.emptyWithFilter.prefix": "没有关于",
+ "ui.list.emptyWithFilter.suffix": "的结果",
+
+ "ui.messageNav.newMessage": "新消息",
+
+ "ui.textField.copyToClipboard": "复制到剪贴板",
+ "ui.textField.copyLink": "复制链接",
+ "ui.textField.copied": "已复制",
+
+ "ui.imagePreview.alt": "图片预览",
+ "ui.scrollView.ariaLabel": "可滚动内容",
+
+ "ui.tool.read": "读取",
+ "ui.tool.loaded": "已加载",
+ "ui.tool.list": "列表",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "网络搜索",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "补丁",
+ "ui.tool.todos": "待办",
+ "ui.tool.todos.read": "读取待办",
+ "ui.tool.questions": "问题",
+ "ui.tool.agent": "{{type}} 智能体",
+ "ui.tool.agent.default": "智能体",
+
+ "ui.common.file.one": "个文件",
+ "ui.common.file.other": "个文件",
+ "ui.common.question.one": "个问题",
+ "ui.common.question.other": "个问题",
+
+ "ui.common.add": "添加",
+ "ui.common.back": "返回",
+ "ui.common.cancel": "取消",
+ "ui.common.confirm": "确认",
+ "ui.common.dismiss": "忽略",
+ "ui.common.close": "关闭",
+ "ui.common.next": "下一步",
+ "ui.common.submit": "提交",
+ "ui.common.showMore": "显示更多",
+
+ "ui.permission.deny": "拒绝",
+ "ui.permission.allowAlways": "始终允许",
+ "ui.permission.allowOnce": "允许一次",
+
+ "ui.message.expand": "展开消息",
+ "ui.message.collapse": "收起消息",
+ "ui.message.copy": "复制",
+ "ui.message.copyMessage": "复制消息",
+ "ui.message.forkMessage": "分叉到新会话",
+ "ui.message.revertMessage": "重置到此点",
+ "ui.message.copyResponse": "复制回复",
+ "ui.message.copied": "已复制!",
+ "ui.message.interrupted": "已中断",
+ "ui.message.queued": "排队中",
+ "ui.message.attachment.alt": "附件",
+
+ "ui.patch.action.deleted": "已删除",
+ "ui.patch.action.created": "已创建",
+ "ui.patch.action.moved": "已移动",
+ "ui.patch.action.patched": "已应用补丁",
+
+ "ui.question.subtitle.answered": "{{count}} 已回答",
+ "ui.question.answer.none": "(无答案)",
+ "ui.question.review.notAnswered": "(未回答)",
+ "ui.question.multiHint": "可多选",
+ "ui.question.singleHint": "选择一个答案",
+ "ui.question.custom.placeholder": "输入你的答案...",
+
+ "ui.fileSearch.placeholder": "查找",
+ "ui.fileSearch.previousMatch": "上一个",
+ "ui.fileSearch.nextMatch": "下一个",
+ "ui.fileSearch.close": "关闭搜索",
+ "ui.tool.task": "任务",
+ "ui.tool.skill": "技能",
+ "ui.basicTool.called": "调用了 `{{tool}}`",
+ "ui.toolErrorCard.failed": "失败",
+ "ui.toolErrorCard.copyError": "复制错误",
+ "ui.message.duration.seconds": "{{count}}秒",
+ "ui.message.duration.minutesSeconds": "{{minutes}}分 {{seconds}}秒",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/i18n/zht.ts b/packages/app-bundle/overlay/packages/ui/src/i18n/zht.ts
new file mode 100644
index 00000000..8b674f96
--- /dev/null
+++ b/packages/app-bundle/overlay/packages/ui/src/i18n/zht.ts
@@ -0,0 +1,197 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+ "ui.sessionReview.title": "工作階段變更",
+ "ui.sessionReview.title.git": "Git 變更",
+ "ui.sessionReview.title.branch": "分支變更",
+ "ui.sessionReview.title.lastTurn": "上一輪變更",
+ "ui.sessionReview.diffStyle.unified": "整合",
+ "ui.sessionReview.diffStyle.split": "拆分",
+ "ui.sessionReview.openFile": "開啟檔案",
+ "ui.sessionReview.selection.line": "第 {{line}} 行",
+ "ui.sessionReview.selection.lines": "第 {{start}}-{{end}} 行",
+ "ui.sessionReview.expandAll": "全部展開",
+ "ui.sessionReview.collapseAll": "全部收合",
+ "ui.sessionReview.change.added": "已新增",
+ "ui.sessionReview.change.removed": "已移除",
+ "ui.sessionReview.change.modified": "已修改",
+ "ui.sessionReview.image.loading": "載入中...",
+ "ui.sessionReview.image.placeholder": "圖片",
+ "ui.sessionReview.largeDiff.title": "差異過大,無法渲染",
+ "ui.sessionReview.largeDiff.meta": "限制:{{limit}} 行變更。目前:{{current}} 行變更。",
+ "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染",
+ "ui.sessionReviewV2.expandMode": "展開或收合差異",
+ "ui.sessionReviewV2.filterFiles": "篩選檔案",
+ "ui.sessionReviewV2.toggleSidebar": "切換檔案樹",
+ "ui.sessionReviewV2.showAllLines": "顯示所有行",
+ "ui.sessionReviewV2.hideNonDiffLines": "隱藏無差異的行",
+ "ui.sessionReviewV2.unifiedDiff": "整合差異",
+ "ui.sessionReviewV2.splitDiff": "拆分差異",
+ "ui.sessionReviewV2.previousFile": "上一個檔案",
+ "ui.sessionReviewV2.nextFile": "下一個檔案",
+ "ui.sessionReviewV2.diffView": "差異檢視",
+ "ui.sessionReviewV2.empty.noGit.title": "沒有追蹤的變更",
+ "ui.sessionReviewV2.empty.noGit.description": "追蹤、檢閱及復原此專案中的變更",
+ "ui.sessionReviewV2.empty.noGit.action": "建立 Git 儲存庫",
+ "ui.sessionReviewV2.empty.noGit.actionLoading": "正在建立 Git 儲存庫...",
+ "ui.sessionReviewV2.empty.changes.title": "尚無檔案變更",
+ "ui.sessionReviewV2.empty.changes.description": "專案變更會顯示在這裡",
+ "ui.fileMedia.kind.image": "圖片",
+ "ui.fileMedia.kind.audio": "音訊",
+ "ui.fileMedia.state.removed": "{{kind}}已移除",
+ "ui.fileMedia.state.loading": "正在載入{{kind}}...",
+ "ui.fileMedia.state.error": "載入{{kind}}失敗",
+ "ui.fileMedia.state.unavailable": "{{kind}}無法預覽",
+ "ui.fileMedia.binary.title": "二進位檔案",
+ "ui.fileMedia.binary.description.path": "無法顯示 {{path}},因為它是二進位檔案。",
+ "ui.fileMedia.binary.description.default": "無法顯示此檔案,因為它是二進位檔案。",
+
+ "ui.lineComment.label.prefix": "評論 ",
+ "ui.lineComment.label.suffix": "",
+ "ui.lineComment.editorLabel.prefix": "正在評論 ",
+ "ui.lineComment.editorLabel.suffix": "",
+ "ui.lineComment.placeholder": "新增評論",
+ "ui.lineComment.submit": "評論",
+ "ui.lineComment.cancel": "取消",
+
+ "ui.sessionTurn.steps.show": "顯示步驟",
+ "ui.sessionTurn.steps.hide": "隱藏步驟",
+ "ui.sessionTurn.summary.response": "回覆",
+ "ui.sessionTurn.diff.showMore": "顯示更多變更 ({{count}})",
+ "ui.sessionTurn.diffs.changed.one": "已變更檔案:{{count}} 個",
+ "ui.sessionTurn.diffs.changed.other": "已變更檔案:{{count}} 個",
+ "ui.sessionTurn.diffs.showAll": "全部顯示",
+ "ui.sessionTurn.diffs.showLess": "顯示較少",
+ "ui.sessionTurn.diffs.more": "+{{count}} 個檔案",
+
+ "ui.sessionTurn.retry.retrying": "重試中",
+ "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒後",
+ "ui.sessionTurn.retry.attempt": "第 {{attempt}} 次",
+ "ui.sessionTurn.retry.attemptLine": "{{line}} - 第 {{attempt}} 次",
+ "ui.sessionTurn.retry.geminiHot": "gemini 目前過載",
+ "ui.sessionTurn.error.freeUsageExceeded": "免費使用額度已用完",
+ "ui.sessionTurn.error.addCredits": "新增點數",
+
+ "dialog.usageExceeded.freeTier.title": "已達免費額度上限",
+ "dialog.usageExceeded.freeTier.description": "訂閱 OpenCode Go,可靠地使用最佳開源模型,每月 $5 起。",
+ "dialog.usageExceeded.freeTier.actionLabel": "訂閱",
+ "dialog.usageExceeded.accountRateLimit.title": "已達 Go 額度上限",
+ "dialog.usageExceeded.accountRateLimit.description":
+ "已達使用額度上限。若要現在繼續使用此模型,請從可用餘額中啟用使用",
+ "dialog.usageExceeded.accountRateLimit.actionLabel": "開啟設定",
+
+ "ui.sessionTurn.status.delegating": "正在委派工作",
+ "ui.sessionTurn.status.planning": "正在規劃下一步",
+ "ui.sessionTurn.status.gatheringContext": "正在探索",
+ "ui.sessionTurn.status.gatheredContext": "已探索",
+ "ui.sessionTurn.status.searchingCodebase": "正在搜尋程式碼庫",
+ "ui.sessionTurn.status.searchingWeb": "正在搜尋網頁",
+ "ui.sessionTurn.status.makingEdits": "正在修改",
+ "ui.sessionTurn.status.runningCommands": "正在執行命令",
+ "ui.sessionTurn.status.thinking": "思考中",
+ "ui.sessionTurn.status.thinkingWithTopic": "思考 - {{topic}}",
+ "ui.sessionTurn.status.gatheringThoughts": "正在整理思緒",
+ "ui.sessionTurn.status.consideringNextSteps": "正在考慮下一步",
+
+ "ui.messagePart.questions.dismissed": "問題已略過",
+ "ui.messagePart.compaction": "工作階段已壓縮",
+ "ui.messagePart.context.read.one": "{{count}} 次讀取",
+ "ui.messagePart.context.read.other": "{{count}} 次讀取",
+ "ui.messagePart.context.search.one": "{{count}} 次搜尋",
+ "ui.messagePart.context.search.other": "{{count}} 次搜尋",
+ "ui.messagePart.context.list.one": "{{count}} 個清單",
+ "ui.messagePart.context.list.other": "{{count}} 個清單",
+ "ui.messagePart.diagnostic.error": "錯誤",
+ "ui.messagePart.title.edit": "編輯",
+ "ui.messagePart.title.write": "寫入",
+ "ui.messagePart.option.typeOwnAnswer": "輸入自己的答案",
+ "ui.messagePart.review.title": "檢查你的答案",
+
+ "ui.list.loading": "載入中",
+ "ui.list.empty": "無結果",
+ "ui.list.clearFilter": "清除篩選",
+ "ui.list.emptyWithFilter.prefix": "沒有關於",
+ "ui.list.emptyWithFilter.suffix": "的結果",
+
+ "ui.messageNav.newMessage": "新訊息",
+
+ "ui.textField.copyToClipboard": "複製到剪貼簿",
+ "ui.textField.copyLink": "複製連結",
+ "ui.textField.copied": "已複製",
+
+ "ui.imagePreview.alt": "圖片預覽",
+ "ui.scrollView.ariaLabel": "可捲動內容",
+
+ "ui.tool.read": "讀取",
+ "ui.tool.loaded": "已載入",
+ "ui.tool.list": "清單",
+ "ui.tool.glob": "Glob",
+ "ui.tool.grep": "Grep",
+ "ui.tool.webfetch": "Webfetch",
+ "ui.tool.websearch": "網頁搜尋",
+ "ui.tool.shell": "Shell",
+ "ui.tool.patch": "修補",
+ "ui.tool.todos": "待辦",
+ "ui.tool.todos.read": "讀取待辦",
+ "ui.tool.questions": "問題",
+ "ui.tool.agent": "{{type}} 代理程式",
+ "ui.tool.agent.default": "代理程式",
+
+ "ui.common.file.one": "個檔案",
+ "ui.common.file.other": "個檔案",
+ "ui.common.question.one": "個問題",
+ "ui.common.question.other": "個問題",
+
+ "ui.common.add": "新增",
+ "ui.common.back": "返回",
+ "ui.common.cancel": "取消",
+ "ui.common.confirm": "確認",
+ "ui.common.dismiss": "忽略",
+ "ui.common.close": "關閉",
+ "ui.common.next": "下一步",
+ "ui.common.submit": "提交",
+ "ui.common.showMore": "顯示更多",
+
+ "ui.permission.deny": "拒絕",
+ "ui.permission.allowAlways": "永遠允許",
+ "ui.permission.allowOnce": "允許一次",
+
+ "ui.message.expand": "展開訊息",
+ "ui.message.collapse": "收合訊息",
+ "ui.message.copy": "複製",
+ "ui.message.copyMessage": "複製訊息",
+ "ui.message.forkMessage": "分支到新工作階段",
+ "ui.message.revertMessage": "重設至此點",
+ "ui.message.copyResponse": "複製回覆",
+ "ui.message.copied": "已複製!",
+ "ui.message.interrupted": "已中斷",
+ "ui.message.queued": "排隊中",
+ "ui.message.attachment.alt": "附件",
+
+ "ui.patch.action.deleted": "已刪除",
+ "ui.patch.action.created": "已建立",
+ "ui.patch.action.moved": "已移動",
+ "ui.patch.action.patched": "已套用修補",
+
+ "ui.question.subtitle.answered": "{{count}} 已回答",
+ "ui.question.answer.none": "(無答案)",
+ "ui.question.review.notAnswered": "(未回答)",
+ "ui.question.multiHint": "可多選",
+ "ui.question.singleHint": "選擇一個答案",
+ "ui.question.custom.placeholder": "輸入你的答案...",
+
+ "ui.fileSearch.placeholder": "搜尋",
+ "ui.fileSearch.previousMatch": "上一個",
+ "ui.fileSearch.nextMatch": "下一個",
+ "ui.fileSearch.close": "關閉搜尋",
+ "ui.tool.task": "任務",
+ "ui.tool.skill": "技能",
+ "ui.basicTool.called": "呼叫了 `{{tool}}`",
+ "ui.toolErrorCard.failed": "失敗",
+ "ui.toolErrorCard.copyError": "複製錯誤",
+ "ui.message.duration.seconds": "{{count}}秒",
+ "ui.message.duration.minutesSeconds": "{{minutes}}分 {{seconds}}秒",
+ "ui.message.copyTrace": "Copy trace",
+}
diff --git a/packages/app-bundle/overlay/packages/ui/src/theme/themes/harmoniqs.json b/packages/app-bundle/overlay/packages/ui/src/theme/themes/harmoniqs.json
index 1b06e62d..83cf32e5 100644
--- a/packages/app-bundle/overlay/packages/ui/src/theme/themes/harmoniqs.json
+++ b/packages/app-bundle/overlay/packages/ui/src/theme/themes/harmoniqs.json
@@ -245,33 +245,33 @@
},
"dark": {
"palette": {
- "neutral": "#0F0F0D",
- "ink": "#EFEDCD",
+ "neutral": "#1f1f1f",
+ "ink": "#f1ece8",
"primary": "#FFE614",
"accent": "#FFE614",
"success": "#4ade80",
"warning": "#F0D600",
"error": "#e88484",
- "info": "#C9C7A6",
+ "info": "#edb2f1",
"interactive": "#FFE614",
"diffAdd": "#4ade80",
"diffDelete": "#e88484"
},
"overrides": {
- "text-strong": "#EFEDCD",
- "text-base": "#C9C7A6",
- "text-weak": "#A9A88C",
- "text-weaker": "#8a8972",
+ "text-strong": "#EDEDED",
+ "text-base": "#A0A0A0",
+ "text-weak": "#707070",
+ "text-weaker": "#505050",
"text-diff-add-base": "var(--v2-state-fg-success)",
"text-diff-delete-base": "var(--v2-state-fg-danger)",
- "border-weak-base": "#EFEDCD38",
- "border-weaker-base": "#EFEDCD1F",
- "icon-base": "#C9C7A6",
- "icon-weak-base": "#8a8972",
- "surface-raised-base": "#171714",
- "surface-raised-base-hover": "#201f1b",
- "surface-base": "#0F0F0D",
- "surface-base-hover": "#EFEDCD0D",
+ "border-weak-base": "#282828",
+ "border-weaker-base": "#232323",
+ "icon-base": "#7E7E7E",
+ "icon-weak-base": "#343434",
+ "surface-raised-base": "#232323",
+ "surface-raised-base-hover": "#282828",
+ "surface-base": "#1C1C1C",
+ "surface-base-hover": "#FFFFFF0D",
"surface-interactive-weak": "#2a2600",
"surface-success-base": "#052e16",
"syntax-comment": "var(--v2-text-text-muted)",
@@ -280,7 +280,7 @@
"syntax-primitive": "var(--v2-pink-400)",
"syntax-property": "var(--v2-orange-400)",
"syntax-type": "var(--v2-purple-400)",
- "syntax-constant": "#C9C7A6",
+ "syntax-constant": "#93e9f6",
"syntax-critical": "var(--v2-red-400)",
"syntax-diff-add": "var(--v2-state-fg-success)",
"syntax-diff-delete": "var(--v2-state-fg-danger)",
@@ -288,19 +288,19 @@
"surface-critical-base": "#2a0c0c"
},
"v2Overrides": {
- "v2-grey-50": "#FFFDF0ff",
- "v2-grey-100": "#EFEDCDff",
- "v2-grey-200": "#E3E0C0ff",
- "v2-grey-300": "#C9C7A6ff",
- "v2-grey-400": "#A9A88Cff",
- "v2-grey-500": "#8a8972ff",
- "v2-grey-600": "#6e6d5aff",
- "v2-grey-700": "#545343ff",
- "v2-grey-800": "#3a3a30ff",
- "v2-grey-900": "#201f1bff",
- "v2-grey-1000": "#171714ff",
- "v2-grey-1100": "#0F0F0Dff",
- "v2-grey-1200": "#000000ff",
+ "v2-grey-50": "#ffffffff",
+ "v2-grey-100": "#fafafaff",
+ "v2-grey-200": "#f2f2f2ff",
+ "v2-grey-300": "#eeeeeeff",
+ "v2-grey-400": "#dbdbdbff",
+ "v2-grey-500": "#aeaeaeff",
+ "v2-grey-600": "#808080ff",
+ "v2-grey-700": "#5c5c5cff",
+ "v2-grey-800": "#3a3a3aff",
+ "v2-grey-900": "#2e2e2eff",
+ "v2-grey-1000": "#242424ff",
+ "v2-grey-1100": "#161616ff",
+ "v2-grey-1200": "#080808ff",
"v2-red-100": "#fde2e2ff",
"v2-red-200": "#f6d5d3ff",
"v2-red-300": "#fca5a5ff",
@@ -407,23 +407,23 @@
"v2-background-bg-contrast": "var(--v2-grey-700)",
"v2-background-bg-button-neutral": "var(--v2-alpha-light-6)",
"v2-background-bg-accent": "#FFE614",
- "v2-text-text-base": "var(--v2-grey-100)",
- "v2-text-text-muted": "var(--v2-grey-300)",
- "v2-text-text-faint": "var(--v2-grey-400)",
+ "v2-text-text-base": "var(--v2-grey-200)",
+ "v2-text-text-muted": "var(--v2-grey-500)",
+ "v2-text-text-faint": "var(--v2-grey-600)",
"v2-text-text-inverse": "var(--v2-grey-1000)",
"v2-text-text-contrast": "var(--v2-grey-100)",
"v2-text-text-accent": "#FFE614",
"v2-text-text-accent-hover": "#F0D600",
"v2-text-text-code-accent": "var(--v2-grey-200)",
- "v2-icon-icon-base": "var(--v2-grey-300)",
- "v2-icon-icon-muted": "var(--v2-grey-400)",
+ "v2-icon-icon-base": "var(--v2-grey-400)",
+ "v2-icon-icon-muted": "var(--v2-grey-600)",
"v2-icon-icon-inverse": "var(--v2-grey-1000)",
"v2-icon-icon-contrast": "var(--v2-grey-200)",
"v2-icon-icon-accent": "#FFE614",
"v2-icon-icon-accent-hover": "#F0D600",
- "v2-border-border-muted": "#EFEDCD1F",
- "v2-border-border-base": "#EFEDCD38",
- "v2-border-border-strong": "#EFEDCD5C",
+ "v2-border-border-muted": "var(--v2-alpha-light-8)",
+ "v2-border-border-base": "var(--v2-alpha-light-10)",
+ "v2-border-border-strong": "var(--v2-alpha-light-20)",
"v2-border-border-inverse": "var(--v2-grey-100)",
"v2-border-border-focus": "var(--v2-blue-500)",
"v2-overlay-simple-overlay-hover": "var(--v2-alpha-light-6)",
diff --git a/packages/app-bundle/overlay/packages/ui/src/v2/components/icon.tsx b/packages/app-bundle/overlay/packages/ui/src/v2/components/icon.tsx
index 6631e549..ffff95f6 100644
--- a/packages/app-bundle/overlay/packages/ui/src/v2/components/icon.tsx
+++ b/packages/app-bundle/overlay/packages/ui/src/v2/components/icon.tsx
@@ -165,6 +165,10 @@ const icons = {
viewBox: "0 0 16 16",
body: ``,
},
+ person: {
+ viewBox: "0 0 16 16",
+ body: ``,
+ },
}
const spriteID = "opencode-v2-icon-sprite"
diff --git a/packages/extension/test/fixtures/amicode/golden.json b/packages/extension/test/fixtures/amicode/golden.json
index 9033df6f..edd164b1 100644
--- a/packages/extension/test/fixtures/amicode/golden.json
+++ b/packages/extension/test/fixtures/amicode/golden.json
@@ -1,12 +1,12 @@
{
- "recordedAt": "2026-08-26T21:57:37.788Z",
+ "recordedAt": "2026-08-29T12:58:52.911Z",
"fork": {
"version": "1.18.10",
- "tag": "v1.18.10-amicode.17"
+ "tag": "v1.18.10-amicode.18"
},
- "sandbox": "/tmp/amicode-fixture-jMqKEG",
- "sandboxReal": "/tmp/amicode-fixture-jMqKEG",
- "seededAt": 1787781455597,
+ "sandbox": "/tmp/amicode-fixture-f5CKEm",
+ "sandboxReal": "/tmp/amicode-fixture-f5CKEm",
+ "seededAt": 1788008331201,
"entries": [
{
"name": "cold read — synthesized identity + stats + remembers",
@@ -75,7 +75,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"name\":\"attachable-demo\",\"kind\":\"personal\",\"path\":\"/tmp/amicode-fixture-jMqKEG/vaults/attachable-demo\"}"
+ "body": "{\"ok\":true,\"name\":\"attachable-demo\",\"kind\":\"personal\",\"path\":\"/tmp/amicode-fixture-f5CKEm/vaults/attachable-demo\"}"
},
{
"name": "vaults — post-attach (cache bust, new mount)",
@@ -189,7 +189,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-jMqKEG/docs/readme.md\",\"mount\":null,\"kind\":\"file\"}"
+ "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-f5CKEm/docs/readme.md\",\"mount\":null,\"kind\":\"file\"}"
},
{
"name": "resolve mount-prefixed (tier 3)",
@@ -200,7 +200,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-jMqKEG/vaults/personal-main/notes/note.md\",\"mount\":\"personal-main\",\"kind\":\"file\"}"
+ "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-f5CKEm/vaults/personal-main/notes/note.md\",\"mount\":\"personal-main\",\"kind\":\"file\"}"
},
{
"name": "resolve relative w/ dir part (tier 4 → project dir)",
@@ -211,7 +211,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-jMqKEG/docs/readme.md\",\"mount\":null,\"kind\":\"file\"}"
+ "body": "{\"ok\":true,\"found\":true,\"path\":\"/tmp/amicode-fixture-f5CKEm/docs/readme.md\",\"mount\":null,\"kind\":\"file\"}"
},
{
"name": "resolve bare typed-prefix — miss (tier 5)",
@@ -244,7 +244,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"active\":\"x-gate-transmon\",\"problems\":[{\"slug\":\"cat-state-cavity\",\"name\":\"Cat State (Cavity)\",\"status\":\"designing\",\"score\":null,\"recorded\":null,\"entity_kinds\":[\"system\"]},{\"slug\":\"t-gate-transmon\",\"name\":\"T Gate (Transmon)\",\"status\":\"solved\",\"score\":null,\"recorded\":null,\"entity_kinds\":[\"system\"]},{\"slug\":\"x-gate-transmon\",\"name\":\"X Gate (Transmon)\",\"status\":\"solved\",\"score\":\"pulse-designer\",\"recorded\":\"2026-08-15\",\"entity_kinds\":[\"formulation\",\"system\"]}],\"error\":null}"
+ "body": "{\"ok\":true,\"active\":\"x-gate-transmon\",\"problems\":[{\"slug\":\"x-gate-transmon\",\"name\":\"X Gate (Transmon)\",\"status\":\"solved\",\"score\":\"pulse-designer\",\"recorded\":\"2026-08-15\",\"entity_kinds\":[\"formulation\",\"system\"]},{\"slug\":\"cat-state-cavity\",\"name\":\"Cat State (Cavity)\",\"status\":\"designing\",\"score\":null,\"recorded\":null,\"entity_kinds\":[\"system\"]},{\"slug\":\"t-gate-transmon\",\"name\":\"T Gate (Transmon)\",\"status\":\"solved\",\"score\":null,\"recorded\":null,\"entity_kinds\":[\"system\"]}],\"error\":null}"
},
{
"name": "problem detail — active slug (score stamped)",
@@ -354,7 +354,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"run\":{\"run_id\":\"r20260810-000000Z-3d4e5f\",\"lab\":\"default\",\"status\":\"solving\",\"iteration\":2,\"fidelity\":null,\"best_f\":0.35,\"last_f\":0.35,\"elapsed_ms\":1461455594,\"series\":[{\"iter\":1,\"f\":0.4},{\"iter\":2,\"f\":0.35}],\"pulse\":{\"iter\":2,\"dt\":0.2,\"values\":[0.01,0.02,0.03,0.04,0.05,0.06]},\"pulse_meta\":{\"drives\":2,\"knots\":3,\"labels\":[\"a_1\",\"a_2\"]},\"tail\":[\"AMICODE_PULSE_META drives=2 knots=3 labels=\\\"a_1\\\",\\\"a_2\\\" bounds=-0.2:0.2,-0.2:0.2\",\"AMICODE_ITER iter=1 f=4.0e-01 inf_pr=1.0e-01 inf_du=5.0e-01\",\"AMICODE_ITER iter=2 f=3.5e-01 inf_pr=1.0e-02 inf_du=5.0e-02\",\"AMICODE_PULSE iter=2 dt=0.2 a=0.01,0.02,0.03;0.04,0.05,0.06\"]},\"error\":null}"
+ "body": "{\"ok\":true,\"run\":{\"run_id\":\"r20260810-000000Z-3d4e5f\",\"lab\":\"default\",\"status\":\"solving\",\"iteration\":2,\"fidelity\":null,\"best_f\":0.35,\"last_f\":0.35,\"elapsed_ms\":1688331200,\"series\":[{\"iter\":1,\"f\":0.4},{\"iter\":2,\"f\":0.35}],\"pulse\":{\"iter\":2,\"dt\":0.2,\"values\":[0.01,0.02,0.03,0.04,0.05,0.06]},\"pulse_meta\":{\"drives\":2,\"knots\":3,\"labels\":[\"a_1\",\"a_2\"]},\"tail\":[\"AMICODE_PULSE_META drives=2 knots=3 labels=\\\"a_1\\\",\\\"a_2\\\" bounds=-0.2:0.2,-0.2:0.2\",\"AMICODE_ITER iter=1 f=4.0e-01 inf_pr=1.0e-01 inf_du=5.0e-01\",\"AMICODE_ITER iter=2 f=3.5e-01 inf_pr=1.0e-02 inf_du=5.0e-02\",\"AMICODE_PULSE iter=2 dt=0.2 a=0.01,0.02,0.03;0.04,0.05,0.06\"]},\"error\":null}"
},
{
"name": "run series — failed (result.toml ≠ finished)",
@@ -376,7 +376,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"run\":{\"run_id\":\"r20260818-000000Z-4h5i6j\",\"lab\":\"default\",\"status\":\"stalled\",\"iteration\":2,\"fidelity\":null,\"best_f\":0.59,\"last_f\":0.59,\"elapsed_ms\":763055595,\"series\":[{\"iter\":1,\"f\":0.6},{\"iter\":2,\"f\":0.59}],\"pulse\":{\"iter\":2,\"dt\":0.2,\"values\":[0.01,0.02,0.03,0.04,0.05,0.06]},\"pulse_meta\":{\"drives\":2,\"knots\":3,\"labels\":[\"a_1\",\"a_2\"]},\"tail\":[\"AMICODE_PULSE_META drives=2 knots=3 labels=\\\"a_1\\\",\\\"a_2\\\" bounds=-0.2:0.2,-0.2:0.2\",\"AMICODE_ITER iter=1 f=6.0e-01 inf_pr=1.0e-01 inf_du=5.0e-01\",\"AMICODE_ITER iter=2 f=5.9e-01 inf_pr=1.0e-02 inf_du=5.0e-02\",\"AMICODE_PULSE iter=2 dt=0.2 a=0.01,0.02,0.03;0.04,0.05,0.06\"]},\"error\":null}"
+ "body": "{\"ok\":true,\"run\":{\"run_id\":\"r20260818-000000Z-4h5i6j\",\"lab\":\"default\",\"status\":\"stalled\",\"iteration\":2,\"fidelity\":null,\"best_f\":0.59,\"last_f\":0.59,\"elapsed_ms\":989931201,\"series\":[{\"iter\":1,\"f\":0.6},{\"iter\":2,\"f\":0.59}],\"pulse\":{\"iter\":2,\"dt\":0.2,\"values\":[0.01,0.02,0.03,0.04,0.05,0.06]},\"pulse_meta\":{\"drives\":2,\"knots\":3,\"labels\":[\"a_1\",\"a_2\"]},\"tail\":[\"AMICODE_PULSE_META drives=2 knots=3 labels=\\\"a_1\\\",\\\"a_2\\\" bounds=-0.2:0.2,-0.2:0.2\",\"AMICODE_ITER iter=1 f=6.0e-01 inf_pr=1.0e-01 inf_du=5.0e-01\",\"AMICODE_ITER iter=2 f=5.9e-01 inf_pr=1.0e-02 inf_du=5.0e-02\",\"AMICODE_PULSE iter=2 dt=0.2 a=0.01,0.02,0.03;0.04,0.05,0.06\"]},\"error\":null}"
},
{
"name": "run series — explicit lab",
@@ -409,7 +409,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"papers\":[{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
+ "body": "{\"ok\":true,\"papers\":[{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
},
{
"name": "library upload — valid PDF (refreshed listing)",
@@ -424,7 +424,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"papers\":[{\"name\":\"new paper.pdf\",\"size\":29,\"added_ms\":1787781457231,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/new paper.pdf\"},{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
+ "body": "{\"ok\":true,\"papers\":[{\"name\":\"new paper.pdf\",\"size\":29,\"added_ms\":1788008332332,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/new paper.pdf\"},{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
},
{
"name": "library upload — bad_filetype refusal",
@@ -464,7 +464,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"papers\":[{\"name\":\"new paper.pdf\",\"size\":29,\"added_ms\":1787781457231,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/new paper.pdf\"},{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-jMqKEG/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
+ "body": "{\"ok\":true,\"papers\":[{\"name\":\"new paper.pdf\",\"size\":29,\"added_ms\":1788008332332,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/new paper.pdf\"},{\"name\":\"piccolo-trajectory-2023.pdf\",\"size\":28,\"added_ms\":1785974400000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/piccolo-trajectory-2023.pdf\"},{\"name\":\"rydberg-blockade-2024.pdf\",\"size\":28,\"added_ms\":1785628800000,\"path\":\"/tmp/amicode-fixture-f5CKEm/.amico/library/rydberg-blockade-2024.pdf\"}],\"error\":null}"
},
{
"name": "widget registry — builtins with content hashes",
@@ -624,7 +624,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"connections\":[{\"id\":\"company-compute\",\"state\":\"connected\",\"validated_at\":\"2026-08-26T21:56:35.595Z\",\"stale\":false,\"identity\":\"aaron\",\"entitlements\":[\"hpc\"],\"icon\":\"\",\"name\":\"Harmoniqs Cloud\"},{\"id\":\"pasqal-cloud\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Pasqal Cloud\"},{\"id\":\"slack\",\"state\":\"connected\",\"validated_at\":\"2026-08-26T21:56:35.595Z\",\"stale\":false,\"identity\":\"aaron@example\",\"icon\":\"\",\"name\":\"Slack\"},{\"id\":\"github\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"GitHub\"},{\"id\":\"linear\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Linear\"},{\"id\":\"google\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"google-drive\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google Drive\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"custom-seed1\",\"state\":\"connected\",\"validated_at\":null,\"stale\":true,\"icon\":\"L\",\"name\":\"Lab QPU\"}],\"error\":null}"
+ "body": "{\"ok\":true,\"connections\":[{\"id\":\"company-compute\",\"state\":\"connected\",\"validated_at\":\"2026-08-29T12:57:51.201Z\",\"stale\":false,\"identity\":\"aaron\",\"entitlements\":[\"hpc\"],\"icon\":\"\",\"name\":\"Harmoniqs Cloud\"},{\"id\":\"pasqal-cloud\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Pasqal Cloud\"},{\"id\":\"slack\",\"state\":\"connected\",\"validated_at\":\"2026-08-29T12:57:51.201Z\",\"stale\":false,\"identity\":\"aaron@example\",\"icon\":\"\",\"name\":\"Slack\"},{\"id\":\"github\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"GitHub\"},{\"id\":\"linear\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Linear\"},{\"id\":\"google\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"google-drive\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google Drive\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"custom-seed1\",\"state\":\"connected\",\"validated_at\":null,\"stale\":true,\"icon\":\"L\",\"name\":\"Lab QPU\"}],\"error\":null}"
},
{
"name": "connections catalog — configured filtered out",
@@ -817,7 +817,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"connections\":[{\"id\":\"company-compute\",\"state\":\"connected\",\"validated_at\":\"2026-08-26T21:56:35.595Z\",\"stale\":false,\"identity\":\"aaron\",\"entitlements\":[\"hpc\"],\"icon\":\"\",\"name\":\"Harmoniqs Cloud\"},{\"id\":\"pasqal-cloud\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Pasqal Cloud\"},{\"id\":\"slack\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Slack\"},{\"id\":\"github\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"GitHub\"},{\"id\":\"linear\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Linear\"},{\"id\":\"google\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"google-drive\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google Drive\",\"auth_methods\":[\"token\",\"browser\"]}],\"error\":null}"
+ "body": "{\"ok\":true,\"connections\":[{\"id\":\"company-compute\",\"state\":\"connected\",\"validated_at\":\"2026-08-29T12:57:51.201Z\",\"stale\":false,\"identity\":\"aaron\",\"entitlements\":[\"hpc\"],\"icon\":\"\",\"name\":\"Harmoniqs Cloud\"},{\"id\":\"pasqal-cloud\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Pasqal Cloud\"},{\"id\":\"slack\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Slack\"},{\"id\":\"github\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"GitHub\"},{\"id\":\"linear\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Linear\"},{\"id\":\"google\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google\",\"auth_methods\":[\"token\",\"browser\"]},{\"id\":\"google-drive\",\"state\":\"needs-key\",\"validated_at\":null,\"stale\":false,\"icon\":\"\",\"name\":\"Google Drive\",\"auth_methods\":[\"token\",\"browser\"]}],\"error\":null}"
},
{
"name": "project create — mkdir (git absent, best-effort)",
@@ -831,7 +831,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"path\":\"/tmp/amicode-fixture-jMqKEG/AmicodeProjects/my-new-project\",\"slug\":\"my-new-project\",\"gitInitialized\":false}"
+ "body": "{\"ok\":true,\"path\":\"/tmp/amicode-fixture-f5CKEm/AmicodeProjects/my-new-project\",\"slug\":\"my-new-project\",\"gitInitialized\":false}"
},
{
"name": "project create — collision",
@@ -885,7 +885,7 @@
"status": 200,
"contentType": "application/json",
"csp": null,
- "body": "{\"ok\":true,\"parentDir\":\"/tmp/amicode-fixture-jMqKEG/AmicodeProjects\",\"projects\":[{\"slug\":\"my-new-project\",\"path\":\"/tmp/amicode-fixture-jMqKEG/AmicodeProjects/my-new-project\"},{\"slug\":\"prior-project\",\"path\":\"/tmp/amicode-fixture-jMqKEG/AmicodeProjects/prior-project\"}]}"
+ "body": "{\"ok\":true,\"parentDir\":\"/tmp/amicode-fixture-f5CKEm/AmicodeProjects\",\"projects\":[{\"slug\":\"my-new-project\",\"path\":\"/tmp/amicode-fixture-f5CKEm/AmicodeProjects/my-new-project\"},{\"slug\":\"prior-project\",\"path\":\"/tmp/amicode-fixture-f5CKEm/AmicodeProjects/prior-project\"}]}"
}
]
}
diff --git a/packages/extension/test/titlebar_dblclick_close.test.ts b/packages/extension/test/titlebar_dblclick_close.test.ts
index 6797166d..61eb04db 100644
--- a/packages/extension/test/titlebar_dblclick_close.test.ts
+++ b/packages/extension/test/titlebar_dblclick_close.test.ts
@@ -3,41 +3,40 @@ import * as fs from "node:fs";
import * as path from "node:path";
/**
- * Regression for harmoniqs/amicode#323 — Double-clicking a session tab does not close it.
- * The tab component should bind onDblClick to the existing close-tab handler (props.onClose / closeTab).
- * Mirrors the e2e expectation in tab-dblclick-close.spec.ts but runs as a fast unit check on source.
+ * Titlebar tab close/rename interactions, pinned at fork pin
+ * v1.18.10-amicode.18.
+ *
+ * amicode#323 ("close tab on double-click") is SUPERSEDED: the fork's .18 tab
+ * UX reworked the interactions deliberately — double-click now opens the
+ * rename flow, middle-click closes, and the × button stays a plain close.
+ * The regression spirit survives: a tab is closable without hunting the ×
+ * (middle-click), and double-click does something useful (rename). Pin the
+ * current contract so the next pin bump that changes it says so loudly.
*/
-describe("titlebar tab — double-click to close (amicode#323)", () => {
+describe("titlebar tab interactions (.18 pin: dblclick renames, middle-click closes)", () => {
const file = path.resolve(
__dirname,
"../../app-bundle/overlay/packages/app/src/components/titlebar-tab-nav.tsx",
);
- it("TabNavItem binds onDblClick to close the tab (not only rename)", () => {
+ it("double-click on the tab title opens the rename flow, not close", () => {
const src = fs.readFileSync(file, "utf8");
- // The outer [data-titlebar-tab] container for session tabs should have an onDblClick that closes.
- // We expect at least two onDblClick bindings: one for rename (title) and one for close (container).
- // Count onDblClick occurrences — before fix there is exactly 1 (title rename), after fix 2+ (container close).
- const dblClickCount = (src.match(/onDblClick/g) ?? []).length;
- expect(dblClickCount).toBeGreaterThanOrEqual(2);
-
- // The close binding should be on the tab container ([data-titlebar-tab]) and call the close handler.
- // Look for a pattern like onDblClick={...onClose or ...closeTab}
- const hasCloseDblClick =
- /data-titlebar-tab[\s\S]*?onDblClick\s*=\s*\{[^}]*closeTab/i.test(src) ||
- /data-titlebar-tab[\s\S]*?onDblClick\s*=\s*\{[^}]*onClose/i.test(src) ||
- /onDblClick\s*=\s*\{[^}]*props\.onClose/i.test(src);
- expect(hasCloseDblClick).toBe(true);
+ expect(/onDblClick\s*=\s*\{\s*openRename\s*\}/.test(src)).toBe(true);
});
- it("DraftTabItem also binds onDblClick to close", () => {
+ it("middle-click closes the tab in both components (onAuxClick → closeTab)", () => {
const src = fs.readFileSync(file, "utf8");
- // DraftTabItem is the second component in the file — ensure it also has a close double-click.
- // Split at 'export function DraftTabItem' and check second half.
const parts = src.split("export function DraftTabItem");
expect(parts.length).toBe(2);
- const draftSrc = parts[1];
- const hasDraftClose = /onDblClick/i.test(draftSrc) && /onClose|closeTab/i.test(draftSrc);
- expect(hasDraftClose).toBe(true);
+ for (const section of parts) {
+ expect(/onAuxClick\s*=\s*\{/.test(section)).toBe(true);
+ expect(/MIDDLE_MOUSE_BUTTON/.test(section)).toBe(true);
+ expect(/closeTab\(/.test(section)).toBe(true);
+ }
+ });
+
+ it("the close handler is still wired to a plain click (the × button path)", () => {
+ const src = fs.readFileSync(file, "utf8");
+ expect(/onClick\s*=\s*\{\s*closeTab\s*\}/.test(src)).toBe(true);
});
-});
+});
\ No newline at end of file
diff --git a/packages/extension/test/vault_click_render.test.ts b/packages/extension/test/vault_click_render.test.ts
index 0c378849..7eb05f94 100644
--- a/packages/extension/test/vault_click_render.test.ts
+++ b/packages/extension/test/vault_click_render.test.ts
@@ -17,9 +17,15 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"
import { join } from "node:path"
import { tmpdir } from "node:os"
import { vaultFileBody } from "../src/amicode_service/vault_browser"
-// the pure client modules, by overlay path (no runtime deps of their own)
-import { vaultRefFromPath, vaultNodeLocked } from "../../app-bundle/overlay/packages/ui/src/amicode/context-tree-data"
-import { effectiveMount } from "../../app-bundle/overlay/packages/app/src/components/vault-browser-model"
+// the pure client modules, by overlay path (no runtime deps of their own).
+// NOTE (fork pin v1.18.10-amicode.18): the .16 helpers `vaultNodeLocked` and
+// `effectiveMount` no longer exist — the lock decision became the injected
+// `opts.vaultLocked(mount)` callback in context-tree-data (covered by the
+// fork's own context-tree-data.test.ts), and the deep-link mount choice was
+// inlined into vault-browser.tsx's `mount` memo (chosen ?? mounts[0], with
+// membership validation). The extension pins the surviving seam: path →
+// vault ref, and the drawer's fetch rendering markdown.
+import { vaultRefFromPath } from "../../app-bundle/overlay/packages/ui/src/amicode/context-tree-data"
const NOTE_PATH = "/Users/aaron/.amico/vaults/armonia-aaron-trowbridge/amicode/memory/MEMORY.md"
@@ -47,29 +53,6 @@ describe("knowledge-graph note click → rendered markdown (amicode#447)", () =>
})
})
- test("the note node is NOT locked on the standard dir≠name layout", () => {
- // pre-fix this was locked: the browsable map keys by marker name, the
- // node carries the directory identity, map.has() missed → fail-closed
- expect(vaultNodeLocked({ mounts: WIRE_MOUNTS, vaultDir: "armonia-aaron-trowbridge" })).toBe(false)
- })
-
- test("a genuinely non-browsable mount stays locked through either identity", () => {
- expect(vaultNodeLocked({ mounts: WIRE_MOUNTS, vaultDir: "armonissima" })).toBe(true)
- expect(vaultNodeLocked({ mounts: WIRE_MOUNTS, vaultDir: "unknown-vault" })).toBe(true)
- })
-
- test("no wire data never locks (the fetch failed — clicks may try)", () => {
- expect(vaultNodeLocked({ mounts: undefined, vaultDir: "armonia-aaron-trowbridge" })).toBe(false)
- })
-
- test("the drawer asks for the deep-link mount verbatim, not mounts[0]", () => {
- // pre-fix the unlisted chosen mount was swapped for the first listed one —
- // correct only while personal happens to sort first
- expect(effectiveMount("armonia-aaron-trowbridge", WIRE_MOUNTS)).toBe("armonia-aaron-trowbridge")
- expect(effectiveMount(undefined, WIRE_MOUNTS)).toBe("aaron")
- expect(effectiveMount(undefined, [])).toBeUndefined()
- })
-
test("the drawer's fetch with that payload returns the markdown that renders", () => {
const root = fixtureRoot()
try {