@omega.js/desktop 0.53.0 → 0.54.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +38 -38
  2. package/dist/cli-run.js +4 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/commands/cdp/client.js +1 -1
  5. package/dist/commands/cdp.js +1 -1
  6. package/dist/commands/clean.js +2 -3
  7. package/dist/commands/dev.js +25 -0
  8. package/dist/commands/lib/ensure-target.js +12 -17
  9. package/dist/commands/lib/migrate.js +17 -0
  10. package/dist/commands/logs.js +1 -1
  11. package/dist/commands/release.js +1 -1
  12. package/dist/commands/test.js +4 -4
  13. package/dist/commands/update.js +5 -4
  14. package/dist/defaults/.github/workflows/build.yml +18 -18
  15. package/dist/defaults/_.gitignore +0 -2
  16. package/dist/defaults/_mas/README.md +3 -3
  17. package/dist/defaults/config/certs/README.md +1 -1
  18. package/dist/defaults/config/omega.json5 +36 -36
  19. package/dist/defaults/docs/README.md +3 -3
  20. package/dist/defaults/gulpfile.js +1 -1
  21. package/dist/defaults/hooks/build/post.js +1 -1
  22. package/dist/defaults/hooks/build/pre.js +1 -1
  23. package/dist/defaults/hooks/notarize/post.js +2 -2
  24. package/dist/defaults/hooks/release/post.js +1 -1
  25. package/dist/defaults/hooks/release/pre.js +1 -1
  26. package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
  27. package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
  28. package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
  29. package/dist/defaults/src/integrations/context-menu/index.js +11 -11
  30. package/dist/defaults/src/integrations/menu/index.js +5 -5
  31. package/dist/defaults/src/integrations/tray/index.js +9 -9
  32. package/dist/defaults/src/main.js +2 -2
  33. package/dist/defaults/src/preload.js +1 -1
  34. package/dist/defaults/test/README.md +3 -3
  35. package/dist/defaults/test/_init.js +1 -1
  36. package/dist/gulp/tasks/audit.js +5 -8
  37. package/dist/lib/restart-manager/index.js +1 -1
  38. package/dist/lib/restart-manager/install.js +1 -1
  39. package/dist/lib/restart-manager/protocol.js +1 -1
  40. package/dist/main.js +4 -3
  41. package/dist/preload.js +1 -1
  42. package/dist/test/suites/build/audit.test.js +20 -7
  43. package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
  44. package/dist/test/suites/build/cli.test.js +28 -0
  45. package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
  46. package/dist/test/suites/build/defaults-scaffold.test.js +19 -5
  47. package/dist/test/suites/build/deploy-direct.test.js +7 -5
  48. package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
  49. package/dist/test/suites/build/deploy-hook.test.js +4 -2
  50. package/dist/test/suites/build/dev-verb.test.js +67 -0
  51. package/dist/test/suites/build/ensure-target.test.js +11 -3
  52. package/dist/test/suites/build/merge-line-files.test.js +6 -6
  53. package/dist/test/suites/build/migrate.test.js +29 -0
  54. package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
  55. package/dist/test/suites/build/runner-env-write.test.js +73 -0
  56. package/dist/test/suites/build/runner.test.js +9 -8
  57. package/dist/test/suites/build/setup-scripts.test.js +27 -0
  58. package/dist/test/suites/build/validate-config.test.js +13 -2
  59. package/dist/test/suites/build/verb-logs.test.js +20 -0
  60. package/dist/test/suites/renderer/window-desktop-surface.test.js +1 -1
  61. package/dist/utils/build-pipeline.js +4 -4
  62. package/dist/utils/runner-env.js +13 -28
  63. package/dist/vendor/config/company.js +46 -14
  64. package/dist/vendor/config/defaults.js +30 -7
  65. package/dist/vendor/config/edit.js +25 -3
  66. package/dist/vendor/config/env-delivery.js +1 -1
  67. package/dist/vendor/config/env-schema.js +3 -6
  68. package/dist/vendor/config/env.js +34 -22
  69. package/dist/vendor/config/index.js +13 -17
  70. package/dist/vendor/config/load.js +15 -7
  71. package/dist/vendor/config/repo.js +10 -27
  72. package/dist/vendor/config/schema-client.js +64 -0
  73. package/dist/vendor/config/schema-cloud.js +38 -0
  74. package/dist/vendor/config/schema-manager.js +118 -0
  75. package/dist/vendor/config/schema-overrides.js +68 -0
  76. package/dist/vendor/config/schema.js +99 -152
  77. package/dist/vendor/config/validate.js +97 -77
  78. package/dist/vendor/devkit/agents-md.js +233 -0
  79. package/dist/vendor/devkit/attach-log-file.js +15 -1
  80. package/dist/vendor/devkit/ci-workflows.js +30 -30
  81. package/dist/vendor/devkit/cli-router.js +13 -7
  82. package/dist/vendor/devkit/defaults-engine.js +9 -43
  83. package/dist/vendor/devkit/deploy-snapshot.js +44 -9
  84. package/dist/vendor/devkit/env-lines.js +183 -0
  85. package/dist/vendor/devkit/local.js +62 -10
  86. package/dist/vendor/devkit/lockfile.js +32 -13
  87. package/dist/vendor/devkit/logger.js +7 -2
  88. package/dist/vendor/devkit/merge-line-files.js +219 -176
  89. package/dist/vendor/devkit/omega-bin.js +208 -111
  90. package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
  91. package/dist/vendor/devkit/preludes/index.js +1 -0
  92. package/dist/vendor/devkit/target-picker.js +45 -0
  93. package/dist/vendor/devkit/test/dashed-files.js +37 -0
  94. package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
  95. package/dist/vendor/devkit/update.js +15 -15
  96. package/dist/vendor/devkit/verb-scripts.js +40 -0
  97. package/dist/vendor/devkit/verbs.js +170 -0
  98. package/package.json +18 -24
  99. package/dist/commands/install.js +0 -37
  100. package/dist/defaults/AGENTS.md +0 -119
  101. package/dist/defaults/CLAUDE.md +0 -1
  102. package/dist/vendor/config/env-retired.js +0 -137
  103. package/dist/vendor/config/retired-keys.js +0 -635
  104. package/docs/analytics.md +0 -140
  105. package/docs/app-state.md +0 -92
  106. package/docs/audit.md +0 -69
  107. package/docs/auth.md +0 -284
  108. package/docs/auto-updater.md +0 -243
  109. package/docs/boot-sequence.md +0 -44
  110. package/docs/build-system.md +0 -169
  111. package/docs/cdp-debugging.md +0 -169
  112. package/docs/common-mistakes.md +0 -21
  113. package/docs/config-schema.md +0 -120
  114. package/docs/context-menu.md +0 -112
  115. package/docs/context.md +0 -81
  116. package/docs/css.md +0 -84
  117. package/docs/deep-link.md +0 -186
  118. package/docs/environment-detection.md +0 -112
  119. package/docs/fontawesome.md +0 -109
  120. package/docs/hooks.md +0 -89
  121. package/docs/icons.md +0 -79
  122. package/docs/index.md +0 -328
  123. package/docs/installer-options.md +0 -165
  124. package/docs/ipc.md +0 -61
  125. package/docs/lib-modules.md +0 -53
  126. package/docs/logging.md +0 -227
  127. package/docs/menu.md +0 -160
  128. package/docs/releasing.md +0 -239
  129. package/docs/remote-config.md +0 -118
  130. package/docs/remote-scripts.md +0 -144
  131. package/docs/restart-manager.md +0 -144
  132. package/docs/runner.md +0 -290
  133. package/docs/sentry.md +0 -97
  134. package/docs/shared/agent-docs.md +0 -89
  135. package/docs/shared/analytics.md +0 -612
  136. package/docs/shared/brands.md +0 -57
  137. package/docs/shared/breaking-changes.md +0 -917
  138. package/docs/shared/config.md +0 -1948
  139. package/docs/shared/deploys.md +0 -341
  140. package/docs/shared/icons.md +0 -219
  141. package/docs/shared/local-dev.md +0 -167
  142. package/docs/shared/logging.md +0 -205
  143. package/docs/shared/monitoring.md +0 -167
  144. package/docs/shared/publishing.md +0 -187
  145. package/docs/shared/rulings.md +0 -34
  146. package/docs/shared/testing.md +0 -147
  147. package/docs/shared/theming.md +0 -629
  148. package/docs/shared/translation.md +0 -342
  149. package/docs/shared/updates.md +0 -61
  150. package/docs/signing.md +0 -293
  151. package/docs/startup.md +0 -142
  152. package/docs/storage.md +0 -59
  153. package/docs/templating.md +0 -101
  154. package/docs/test-boot-layer.md +0 -157
  155. package/docs/test-framework.md +0 -362
  156. package/docs/themes.md +0 -149
  157. package/docs/tooltips.md +0 -99
  158. package/docs/tray.md +0 -164
  159. package/docs/usage.md +0 -58
  160. package/docs/verts.md +0 -62
  161. package/docs/windows.md +0 -149
@@ -1,342 +0,0 @@
1
- # Translation
2
-
3
- AI translation for OMEGA consumers — one engine, config-driven, with a
4
- **committed** per-string cache. Shipped cp96 (Ian directive 2026-07-11),
5
- replacing both legacy systems: UJM's OpenAI-only gulp task with the
6
- `cache-uj-translation` GitHub-branch cache, and BXM's Claude-only task with a
7
- gitignored `.cache/` (which re-translated everything on any change and on
8
- every fresh clone).
9
-
10
- ## Config (shared `translation` section of omega.json5)
11
-
12
- ```json5
13
- translation: {
14
- enabled: true, // optional master switch (default true)
15
- default: 'en', // source language (default 'en')
16
- languages: ['es', 'fr'],// target codes — EMPTY/ABSENT = translation off
17
- providers: { claude: {} },// the engine is a KEY (#425): claude | chatgpt. Absent block = claude
18
- model: null, // optional override for the chosen engine (claude → 'sonnet' alias, chatgpt → 'gpt-5.4-nano')
19
- include: ['**', '!blog/**'], // web only: globs over BRAND page routes, `!` negates; this is the framework default, a brand list replaces it (#858; the framework's own default pages are excluded on their own, #605)
20
- }
21
- ```
22
-
23
- Shared section (typically brand-level; `SHARED_SECTIONS` includes it, so
24
- every target inherits it through the merge chain). Language codes
25
- validate against the SSOT in `@omega.js/devkit/translate` (`LANGUAGE_NAMES`,
26
- ~32 codes) — an unknown code is a hard config error naming the supported set.
27
- The same SSOT carries `LANGUAGE_LOCALES` + `ogLocale(code)`, the one code →
28
- Open Graph `language_TERRITORY` map (`es` → `es_ES`).
29
-
30
- ## Providers
31
-
32
- | Provider | Rides | Credentials |
33
- |----------|-------|-------------|
34
- | `claude` (default) | the locally-installed Claude Code via `@anthropic-ai/claude-agent-sdk` | **none** — local auth |
35
- | `chatgpt` | OpenAI Responses API (native fetch) | `OPENAI_API_KEY` via the .env cascade |
36
-
37
- The claude provider runs **hermetic** sessions: `settingSources: []` (no user
38
- CLAUDE.md/hooks — they pollute mechanical output; a stop-hook reply actually
39
- leaked into a canary before this was locked down), a custom translator system
40
- prompt instead of the CLI persona, and NO `maxTurns` cap (a plain reply
41
- already counts as the final turn — `maxTurns: 1` reports `error_max_turns`
42
- even though the text arrived).
43
-
44
- **Enabling translation on web means installing the SDK (#37).** `@omega.js/web`
45
- does NOT ship `@anthropic-ai/claude-agent-sdk`: translation is opt-in and the
46
- SDK is heavy, so a web brand that turns it on installs it in the target itself
47
- (`npm install @anthropic-ai/claude-agent-sdk`); `@omega.js/extension` still
48
- declares it. The SDK is lazy-required at the first claude call, so a brand
49
- without translation never pays for it, and a brand that enabled translation
50
- without the SDK gets a hard error naming the package and that install command,
51
- never a silent skip. The `chatgpt` provider needs no SDK at all (native fetch
52
- plus `OPENAI_API_KEY`).
53
-
54
- **The manage cycle provisions it (#168).** Nobody types that install in a
55
- managed brand: the manager's workspace service reconciles it like every other
56
- brand file. A web app whose RESOLVED config translates with the `claude`
57
- provider gets `@anthropic-ai/claude-agent-sdk` written into its package.json
58
- `dependencies` (at the range `@omega.js/web` declares as its optional peer,
59
- read from the installed web package), followed by one `npm install` at the
60
- brand root. Converge-to-config, so: already declared (in `dependencies` or
61
- `devDependencies`) = zero-mutation no-op that never overwrites a
62
- consumer-chosen spec, `--dry-run` plans without writing, translation off or
63
- provider `chatgpt` leaves the target untouched, and turning translation back OFF
64
- never REMOVES the dep (uninstalling on a config flip is riskier than leaving
65
- it). Only web targets are provisioned, since backend and extension declare the
66
- SDK as a real dependency of the framework. The loud error above stays the backstop
67
- for hand-managed brands (`packages/manager/src/services/workspace/ensure/translation-sdk.js`,
68
- pinned by `packages/manager/test/workspace-translation-sdk.test.js`).
69
-
70
- ## Engine protocol (`@omega.js/devkit/translate`)
71
-
72
- `translateStrings({ strings, language, languageName, brand, extraRules, send })`
73
- → positionally-aligned translations:
74
-
75
- - **JSON array in → same-length JSON array out**, batches of 25.
76
- - **Batches fly concurrently**, `CONCURRENCY` wide (the constant at the top of
77
- `packages/devkit/src/translate/engine.js`, currently 5 —
78
- [#604](https://github.com/Omega-JS-Stack/omega/issues/604)). A batch is one
79
- model call and the model's latency dominates it, so a serial pass paid that
80
- latency once per 25 strings and one language took minutes it never needed.
81
- Results are stitched back in BATCH order, never completion order, and
82
- everything below still happens per batch, unchanged. Raise it only as far as
83
- the providers' rate limits allow.
84
- - **Duplicates are deduped before batching** ([#529](https://github.com/Omega-JS-Stack/omega/issues/529)):
85
- a page sends its title and description once per meta tag (`<title>`,
86
- `og:title`, `twitter:title`), so the same string used to ride a batch three
87
- times over — three times the AI spend, and adjacent twins are what a model
88
- merges. Each unique string is translated ONCE and the translation is fanned
89
- back to every occurrence. Occurrences key on the exact source string,
90
- whitespace included, so a batch is 25 UNIQUE strings.
91
- - The `OMEGA-TRANSLATION-CONTROL` sentinel is appended to EVERY batch and must
92
- return unchanged at its exact position — alignment proof per batch.
93
- - Validation failures (parse, length, sentinel) retry up to 2× then throw.
94
- - An ALIGNMENT failure (length or sentinel) that survives the retries splits the
95
- batch in half and re-asks each half, down to one string
96
- ([#523](https://github.com/Omega-JS-Stack/omega/issues/523)): a model that
97
- merges a pair of strings does it every time, so retrying the same array can
98
- only fail the same way — the playground's ship-the-docs page came back
99
- 25-for-26 on all six attempts, in both languages, and shipped untranslated.
100
- A single string that still will not come back whole throws, and the caller
101
- ships that page-language pair untranslated (never half-translated).
102
- - Original leading/trailing whitespace is re-applied to every translation.
103
- - Rules baked into the system prompt: preserve HTML/URLs/placeholders
104
- (`$1`, `{name}`, `{{ value }}`), never translate the brand name.
105
-
106
- ## The committed cache (`<app>/translations/`)
107
-
108
- `translations/{lang}/{namespace}.json` maps `sha256(source)[:12]` → translated
109
- string. Committed to git — that's the whole point:
110
-
111
- - **Incremental**: editing one source string changes one hash → exactly one
112
- re-translation. Everything else is a cache hit (zero provider calls).
113
- - **Survives clones/CI**: a warm cache builds a fully-translated site with NO
114
- AI credentials (kills the BXM parked finding where fresh clones burned live
115
- Claude calls). No AI key is delivered to CI by default
116
- ([#819](https://github.com/Omega-JS-Stack/omega/issues/819), Ian 2026-09-13):
117
- translation runs on the developer's machine and a runner reads the committed
118
- cache, which is why `OPENAI_API_KEY` is an `env` delivery on every target that
119
- names it and no workflow carries a line for it
120
- ([#905](https://github.com/Omega-JS-Stack/omega/issues/905) owns the one
121
- system, cloud translation included).
122
- - **Human-overridable**: hand-edit a translation VALUE in the cache file and
123
- it sticks for as long as the source is unchanged (the value is the
124
- translation; the key only changes when the SOURCE changes).
125
- - Maps are pruned to the current source set on save — no stale entries.
126
-
127
- `@omega.js/web` ships a second cache in exactly this shape for its OWN default
128
- pages, inside the package ([below](#framework-shipped-default-page-translations-621)).
129
-
130
- ## Web (`@omega.js/web`)
131
-
132
- `omega build` translates everything by default (Ian's #24 final call): warm
133
- strings come from the committed cache instantly, cold strings translate live
134
- through the provider — a build ships the COMPLETE translated site whenever
135
- the provider delivers, and a warm cache means zero provider calls. A provider
136
- FAILURE ships that page-language pair UNTRANSLATED, warning loudly with the page
137
- and the language (the build still exits 0): no half-translated copy ever ships
138
- behind full language chrome.
139
- `omega build --cached-only` ships cold page-language pairs UNTRANSLATED instead
140
- (the warning lists them) for provider-free builds; `omega translate` fills them.
141
- An untranslated pair still lands the SOURCE page at its translated path
142
- (`dist/{lang}/...`, `{lang}.html` for the home) with its links rewritten into
143
- the language, because every produced copy links there and a missing file is a
144
- dead link that fails `omega test`'s link check and ships with `omega deploy`
145
- ([#953](https://github.com/Omega-JS-Stack/omega/issues/953)). It is never
146
- ADVERTISED: its `<html lang dir>` and `og:locale` name the source language its
147
- text is in, its canonical and `og:url` stay the source page's (it duplicates
148
- that page), no hreflang alternate names it (on it or on the original), and the
149
- sitemap does not list it.
150
- `omega translate` still runs the live pass standalone against an existing
151
- dist/ and exits 1 on failures. `OMEGA_TRANSLATE_ONLY=<route>` limits any of
152
- these to one page (canary/debug).
153
-
154
- Per page × language: text nodes/`<title>`/meta/attribute copy translate
155
- (cache-first), then the copy lands at `dist/{lang}/...` with `<html lang dir>`
156
- (RTL-aware), canonical + `og:url` + `og:locale` localized, internal links
157
- rewritten to `/{lang}/...`, and hreflang + `og:locale:alternate` tags
158
- stitched into BOTH the copy and the original — naming only the languages
159
- actually PRODUCED for that page (a pair left untranslated, cold or failed, is never
160
- advertised, on the copies as on the originals), so hreflang never lies.
161
- `og:locale` carries Open Graph's `language_TERRITORY` form (`en_US`,
162
- `es_ES`) from the devkit language SSOT's locale map — on translated copies
163
- and on the source pages the head include renders. Cache namespace:
164
- `pages/{route}` (`pages/home` for `/`).
165
-
166
- On a site served under a base path ([#355](https://github.com/Omega-JS-Stack/omega/issues/355)),
167
- link rewriting composes **prefix, then language**: the pass reads the mount
168
- point off the `<html data-omega-path-prefix>` stamp the build wrote (so
169
- `omega translate` standalone sees it too), takes the route from underneath it,
170
- and mounts the language segment after it — `/workkit/es/pricing`, never
171
- `/es/workkit/pricing` ([#359](https://github.com/Omega-JS-Stack/omega/issues/359)).
172
- Exclusions are matched on that same underneath-the-prefix route. ABSOLUTE URLs
173
- (canonical, `og:url`, hreflang alternates, the sitemap entries) are built from
174
- `brand.url`, which for a mounted site already carries the path — nothing
175
- prefixes them twice.
176
-
177
- Never sent to the PROVIDER, and the framework owns the list
178
- ([#605](https://github.com/Omega-JS-Stack/omega/issues/605)): every one of its
179
- OWN default pages whose layout says it is plumbing rather than marketing copy —
180
- the auth flows, the `/app` shell, the account/payment/portal screens, the legal
181
- boilerplate, `404`, and the redirect stubs (`/login`, `/account`, `/cancel`, …).
182
- Those pages still get their `/{lang}/` copies — from the translations PACKAGED
183
- with `@omega.js/web`, at no cost to the brand (next section).
184
- The list is DERIVED from the packaged defaults tree
185
- (`packages/web/defaults/pages/**`, read by `src/translate/default-routes.js`),
186
- never typed out, so a default page that moves or arrives cannot drift out of it,
187
- and each excluded route guards its subtree too. On top of that: socials
188
- redirects (config `socials` keys), the `admin`/`test`/`team`/`updates` folders,
189
- every known language-code folder.
190
-
191
- **Which of the BRAND's own pages are translated is `translation.include`**
192
- ([#858](https://github.com/Omega-JS-Stack/omega/issues/858), Ian 2026-09-13,
193
- the same-name ruling): a list of route GLOBS read like a `.gitignore`, where
194
- `!` negates and the LAST pattern that matches a route decides it. A route no
195
- pattern matches is not translated, so an empty list translates nothing. A
196
- folder pattern covers the folder itself as well as its contents, so
197
- `!blog/**` takes `/blog` out along with every post under it. The framework
198
- default lives in the DEFAULTS layer of the merge chain (the schema's own
199
- `default:`, resolution-only so no brand file carries a copy of it):
200
-
201
- ```json5
202
- translation: { include: ['**', '!blog/**'] } // the default: the whole site except the blog
203
- ```
204
-
205
- A brand list **REPLACES** it outright rather than adding to it (arrays replace
206
- at every level of the merge chain), so a brand that writes `['docs/**']` gets
207
- docs and nothing else. It is for the brand's own pages only: the framework's
208
- derived exclusions above are not in its hands, and a brand that names `signin`
209
- or `account` is naming something already skipped.
210
-
211
- **A page overrides the list for itself**, under the same key name one level
212
- down: `translation: { include: true }` in its frontmatter translates a page the
213
- list left out, `false` takes one out that the list would have covered. The
214
- build stamps that answer on `<html data-omega-translate>` (the seam #355's base
215
- path already uses), because the pass runs post-build over `dist/` and
216
- `omega translate` runs with no build in reach. `include` is the only key a page
217
- may write under a bare `translation:`; anything else is a config section
218
- restated bare and fails the build.
219
-
220
- **`translation.exclude` is RETIRED** with it. There is no dual-read: a config
221
- still carrying it fails validation naming its replacement, and
222
- `omega migrate` at the brand root CONVERTS the list (`exclude: ['docs']`
223
- becomes `include: ['**', '!docs']`, which keeps translating exactly what the
224
- brand was translating before) and deletes the old key in the same run.
225
-
226
- Element opt-out: `data-omega-no-translate`, unchanged. Collector fixes vs UJM:
227
- `aria-describedby`/`aria-labelledby` are NOT collected (ID refs), `value`
228
- only on button-type inputs (hidden-input tokens stay intact).
229
-
230
- ### Framework-shipped default-page translations ([#621](https://github.com/Omega-JS-Stack/omega/issues/621))
231
-
232
- The default pages above render the SAME chrome on every brand, so the framework
233
- translates them ONCE and ships the result: `packages/web/translations/{lang}/pages/{route}.json`,
234
- the identical `{lang}/{namespace}.json` shape as a consumer's own cache (same
235
- loader, same `sha256(source)[:12]` keys, same prune-on-save, hand-fixable the
236
- same way), committed to the package and published under `files`.
237
-
238
- The keys are brand-NEUTRAL. The generator renders with a fixture brand and
239
- replaces every occurrence of it with the sentinel `__OMEGA_BRAND__` before
240
- hashing; the read-through replaces the CONSUMER's `brand.name` with the same
241
- token before the lookup and puts it back on the way out, so "Sign in to MiniCo"
242
- and "Sign in to Acme" are one packaged entry (`src/translate/packaged-defaults.js`).
243
-
244
- Consumer side, on every pass — `omega build`, `--cached-only`, `omega translate`
245
- alike, since it never touches a provider:
246
-
247
- - Each default route gets its `dist/{lang}/…` copy with the same localized
248
- chrome, hreflang and sitemap entry as any other page. Link rewriting is the
249
- same pass too, which means links OUT to brand pages gain the language segment
250
- while links between two default routes (signin → signup) do not — those routes
251
- are excluded from rewriting, and that is unchanged from #605.
252
- - A string the package does not carry (copy the brand overrode, a page the
253
- framework has not regenerated for) stays in the source language and is
254
- COUNTED — one log line per route names the miss count. Never guessed at.
255
- - A brand whose NAME is a word the chrome itself uses ("Sign") still gets every
256
- string that does not interpolate the brand — the lookup falls back to the raw
257
- key when the sentinel-normalized one misses. The strings that DO interpolate
258
- it (`Sign in to Sign`) miss, and stay in the source language.
259
- - A route the package carries nothing for gets NO copy, so hreflang keeps
260
- telling the truth. That is how the legal boilerplate stays one language:
261
- `terms`/`privacy`/`cookies` are deliberately not generated.
262
- - A configured language the package does not ship is one log line for the whole
263
- run, not an error — those routes stay in the source language.
264
- - A brand's `translation.include` list never touches the framework's default
265
- pages: it scopes the brand's OWN pages, and the framework's chrome is
266
- translated once, on the framework side.
267
-
268
- **Shipped set: `es`, `fa`.** Regenerating, or extending the set, is one command
269
- in `packages/web` (the ONLY place the framework's own pages ever reach a
270
- provider):
271
-
272
- ```bash
273
- npm run translate:defaults # the shipped set
274
- npm run translate:defaults -- --languages es,fa,de # …plus a new one
275
- ```
276
-
277
- It renders the defaults tree through the real production build against a
278
- throwaway consumer (no brand repo involved), harvests with the same collector
279
- the pass uses, translates ONLY the strings the packaged cache is missing —
280
- across all routes at once, so the header/footer chrome every default page
281
- repeats is paid for exactly once — and writes the files back. Idempotent: a
282
- re-run costs nothing, adding a language costs only that language. A provider
283
- failure, or a translation that dropped the sentinel, STOPS the run and writes
284
- nothing.
285
-
286
- `dist/sitemap.xml` (emitted by the build in the source language only) is
287
- rewritten afterwards so it tells the same story: every PRODUCED copy joins it
288
- as its own `<url>`, and each entry of a translated set — source and copies
289
- alike — carries the full `xhtml:link rel="alternate"` list (`x-default` at the
290
- source language) plus the source entry's `lastmod`/`changefreq`/`priority`.
291
- Entries stay in loc byte order. The language-prefixed entries are owned by that
292
- pass: each run drops them all and re-emits only what it produced, so an
293
- untranslated pair (cold or failed) is listed nowhere.
294
-
295
- The visitor-facing **language switcher** is the footer dropup in the shared
296
- base footer include (`_includes/frontend/sections/footer.html`, the base layer
297
- every theme inherits). It renders CLIENT-SIDE from the page's own
298
- `link[rel="alternate"][hreflang]` tags — the produced-only SSOT above — so the
299
- menu can never offer a copy that was not written: `core/js/core/language-switcher.js`
300
- drops `x-default`, labels each row with its native name (`Intl.DisplayNames` in
301
- that language's own locale, upper-cased code as the fallback), marks
302
- `documentElement.lang` as current, and leaves the mount empty and hidden when
303
- fewer than two languages exist. Selecting a language is a plain link to that
304
- alternate's href — never a redirect or a negotiation.
305
-
306
- Not here yet: no default homepage exists in the D8 set, so brand sites
307
- translate their own `index` when they add one.
308
-
309
- ## Extension (`@omega.js/extension`)
310
-
311
- Build-mode gulp `translate` task (setup/dev builds only deploy):
312
-
313
- - **messages**: per-KEY incremental — unique `message` values without a cache
314
- entry translate (CWS limits ride the prompt as extra rules; violations warn
315
- with the file path to shorten). `dist/_locales/{lang}/messages.json` is
316
- COMPOSED from the EN source + cache (English fallback per missing key, so
317
- the file is always complete; developer `description` fields stay English).
318
- - **description**: whole-document per language →
319
- `translations/{lang}/description.md`, first line
320
- `<!-- omega:source <hash> -->` (stripped on read; source edit →
321
- re-translate). The package task ships them as store assets
322
- (`packaged/assets/description/{lang}.md`).
323
-
324
- Languages/provider come from resolved config — the old hardcoded 16-language
325
- list in `gulp/config/locales.js` is gone (only the CWS `limits` remain there).
326
-
327
- ## Testing
328
-
329
- - devkit `test/translate.test.js` — engine protocol, providers, cache,
330
- language SSOT, settings reader (fake `send`).
331
- - web `test/translate.test.js` — handcrafted dist through the real pipeline:
332
- copies/chrome/links/exclusions/alternates/cache/override/only-filter, the
333
- produced-languages-only alternates, and the untranslated-copy fallback
334
- (cold and failed pairs land unadvertised, no language link dangles).
335
- - web `test/language-switcher.test.js` — the switcher's DOM read (x-default
336
- dropped, duplicates collapsed, current marked, escaping) and the built footer
337
- mount in classy and newsflash.
338
- - extension `build/translate.test.js` — compose + description marker glue.
339
- - Live canary (cp96, local Claude): omega-brand `/about` → es (102 strings,
340
- rerun 0 calls) and the extension's 4 messages (2 unique) + 2,703-char
341
- description → es, both idempotent; artifacts committed under each target's
342
- `translations/`.
@@ -1,61 +0,0 @@
1
- # Dependency updates (`omega update`)
2
-
3
- One shared implementation (`@omega.js/devkit/update`) behind every framework's `omega update` verb (aliases: `outdated`, `out` — npu's muscle memory), thin wiring in web/desktop/extension (router commands), backend (colon-style command class), and the manager (brand-root fan-out). Semantics mirror Ian's `npu out` (node-power-user): report first, apply deliberately, and never trust a brand-new release.
4
-
5
- ## The report (default — no flags)
6
-
7
- For each dependency of the target's `package.json` (prod + dev, grouped):
8
-
9
- | Column | Meaning |
10
- |---|---|
11
- | Current | the base version in `package.json` (`^1.2.3` → `1.2.3`) |
12
- | Installed | the physical `node_modules` copy (nearest, climbing — npm hoists in brand monorepos) |
13
- | Wanted | highest published version satisfying the range (npm-outdated semantics) |
14
- | Latest | the registry `dist-tags.latest` |
15
- | Bump | `patch` / `minor` / `major` — Current → Latest classification |
16
- | Released | Latest's publish date + age in days |
17
- | Status | `QUARANTINED` when Latest is younger than `--min-age` days (default **7**) and not already installed |
18
-
19
- Only rows needing attention print; a fully-current tree reports one line. Rows sort prod-first.
20
-
21
- **Quarantine (supply-chain caution, npu's `--min-age` semantics):** a release published < 7 days ago may be a compromised publish — it is flagged and **excluded from `--apply`**. `--min-age N` changes the window; `--min-age 0` or `--force-fresh` disables it. Unpublished packages (the pre-publish `@omega.js/*` set) report `not on the registry (unpublished?)` instead of a version row.
22
-
23
- **`file:`/`link:`/git specs are SKIPPED** with a dim note — they have no registry story. In the local era every brand's `@omega.js/*` dep is a `file:` spec, so the verb never touches the linked frameworks.
24
-
25
- ## Applying (`--apply`)
26
-
27
- - Default tier is **non-breaking**: each dep rides to its highest same-major version (npu's minor tier) — quarantined targets are held and listed.
28
- - **Majors are never auto-applied**: breaking jumps are listed as held; `--apply --major` opts in explicitly.
29
- - Installs run through **`npu install`** when npu is on the machine (Socket supply-chain firewall); otherwise plain `npm install` with a loud warning. Dev deps install with `--save-dev` in their own pass.
30
-
31
- ## The @omega.js family is pinned, and `omega update` is its ONE mover ([#794](https://github.com/Omega-JS-Stack/omega/issues/794))
32
-
33
- Every `@omega.js/*` spec the manager writes into a brand is an EXACT pin, never a
34
- caret: `"@omega.js/manager": "0.50.0"` at the brand root, `"@omega.js/<framework>":
35
- "0.50.0"` in each target, all at the manager's own version (the family ships
36
- lockstep — [publishing.md](publishing.md)). A caret would let one target float
37
- ahead alone on somebody's `npm update`, which is how a brand ends up serving two
38
- copies of `@omega.js/client` and validating one omega.json5 with two validators.
39
-
40
- Pinned, the only thing that moves a brand is `omega update --apply` at the brand
41
- ROOT (a bare run reports and installs nothing), and it moves every target — and
42
- the root's own manager pin — together. `--apply` installs an `@omega.js/*` dep with
43
- `--save-exact`, in its own command per dep group, so the mover never un-pins
44
- what it just moved (npm's default save-prefix would write `^<version>` back);
45
- every other dependency keeps npm's default prefix, because the pin is the
46
- FAMILY's rule and not a rule for the whole tree.
47
-
48
- The manager's boot check enforces the other half: a brand whose installed
49
- versions have drifted is refused before any service or dev leg runs
50
- ([../manager/brand.md](../manager/brand.md)). The local era is untouched — a
51
- `file:` spec has no registry story, so the verb skips it and the boot check
52
- exempts it. `omega i live` (the publish-day flip back off `file:` specs) writes
53
- the same exact pin ([local-dev.md](local-dev.md) § API surface).
54
-
55
- ## Brand root
56
-
57
- `omega update` at a brand root (manager) fans out over the brand's targets, cp251's deploy fan-out shape: same target discovery, same `--target=<name>[,<name>]` picker ([#780](https://github.com/Omega-JS-Stack/omega/issues/780)), every other flag forwarded verbatim, each target answering through its own framework's `update` verb. Unlike deploy, targets are **independent**: one failing target never blocks the rest (any failure still exits 1). The brand-root shell `package.json` rides the walk as its LAST leg ([#794](https://github.com/Omega-JS-Stack/omega/issues/794)), scoped to the one `@omega.js/*` dependency it carries (`@omega.js/manager`) and run in-process through the same devkit implementation (there is no framework bin at the root to spawn; it would dispatch straight back into this command). A brand's own root tooling is never touched, and a picked run (`--target=`) skips the root, because the picker names targets. Without that leg a manager-behind brand could never heal itself: the boot check would refuse every verb, and the fix it names would move every target except the one that was wrong.
58
-
59
- ## Testing
60
-
61
- Registry lookups, the clock, npu detection, and exec are all injectable — the devkit suite (`packages/devkit/test/update.test.js`) runs entirely offline against fixture packuments with a frozen clock; the manager fan-out test spawns fake framework bins; framework structure tests pin the wiring. The live path is the thin defaults (native `fetch` of the full packument — the abbreviated form carries no publish times).