@omega.js/desktop 0.52.0 → 0.54.0
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.
- package/README.md +53 -48
- package/dist/assets/css/core/_initialize.scss +1 -1
- package/dist/assets/js/core/app-shell.js +14 -15
- package/dist/assets/themes/_template/_theme.js +6 -6
- package/dist/assets/themes/base/_includes/global/sections/account.html +4 -4
- package/dist/assets/themes/base/_includes/global/sections/app-sidebar.html +5 -5
- package/dist/assets/themes/base/_layouts/frontend/pages/account/index.html +3 -3
- package/dist/assets/themes/base/_layouts/frontend/pages/alternatives/index.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/blog/tags/tag.html +1 -1
- package/dist/assets/themes/base/_layouts/frontend/pages/payment/confirmation.html +1 -1
- package/dist/assets/themes/base/_sections/marketing/newsletter-cta/section.js +2 -3
- package/dist/assets/themes/base/_sections/verts/unit/section.html +1 -1
- package/dist/assets/themes/base/_sections/verts/unit/section.js +3 -4
- package/dist/assets/themes/base/_theme.js +4 -3
- package/dist/assets/themes/bootstrap/_theme.js +2 -2
- package/dist/assets/themes/bootstrap/overrides/_links.scss +1 -1
- package/dist/assets/themes/classy/_theme.js +8 -6
- package/dist/assets/themes/classy/css/marketing/_sections.scss +1 -2
- package/dist/assets/themes/classy/js/hero-demo-form.js +3 -2
- package/dist/assets/themes/neobrutalism/_theme.js +5 -5
- package/dist/assets/themes/neobrutalism/js/pages/test/libraries/layers/index.js +1 -1
- package/dist/assets/themes/newsflash/_theme.js +6 -6
- package/dist/assets/themes/newsflash/js/pages/test/libraries/layers/index.js +1 -1
- package/dist/build.js +87 -111
- package/dist/cli-run.js +4 -1
- package/dist/cli.js +3 -3
- package/dist/commands/build.js +2 -2
- package/dist/commands/cdp/capture.js +2 -2
- package/dist/commands/cdp/client.js +1 -1
- package/dist/commands/cdp/quit.js +2 -2
- package/dist/commands/cdp/relaunch.js +2 -2
- package/dist/commands/cdp/theme.js +1 -1
- package/dist/commands/cdp.js +1 -1
- package/dist/commands/clean.js +4 -5
- package/dist/commands/deploy.js +4 -4
- package/dist/commands/dev.js +25 -0
- package/dist/commands/finalize-release.js +4 -4
- package/dist/commands/launch.js +2 -2
- package/dist/commands/lib/deploy-precheck.js +3 -3
- package/dist/commands/lib/ensure-target.js +18 -23
- package/dist/commands/lib/migrate.js +17 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/package.js +2 -2
- package/dist/commands/publish.js +2 -2
- package/dist/commands/release.js +4 -4
- package/dist/commands/runner.js +11 -11
- package/dist/commands/sign-windows.js +5 -5
- package/dist/commands/test.js +8 -8
- package/dist/commands/update.js +7 -6
- package/dist/commands/validate-certs.js +4 -4
- package/dist/commands/version.js +3 -3
- package/dist/defaults/.github/workflows/build.yml +18 -18
- package/dist/defaults/_.gitignore +0 -2
- package/dist/defaults/_mas/README.md +3 -3
- package/dist/defaults/config/certs/README.md +1 -1
- package/dist/defaults/config/omega.json5 +43 -43
- package/dist/defaults/docs/README.md +3 -3
- package/dist/defaults/gulpfile.js +1 -1
- package/dist/defaults/hooks/build/post.js +2 -2
- package/dist/defaults/hooks/build/pre.js +2 -2
- package/dist/defaults/hooks/deploy/pre.js +1 -1
- package/dist/defaults/hooks/notarize/post.js +2 -2
- package/dist/defaults/hooks/release/post.js +2 -2
- package/dist/defaults/hooks/release/pre.js +2 -2
- package/dist/defaults/src/assets/js/components/about/index.js +3 -5
- package/dist/defaults/src/assets/js/components/main/index.js +3 -5
- package/dist/defaults/src/assets/js/components/settings/index.js +3 -5
- package/dist/defaults/src/assets/scss/pages/about.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/main.scss +1 -1
- package/dist/defaults/src/assets/scss/pages/settings.scss +1 -1
- package/dist/defaults/src/integrations/context-menu/index.js +13 -13
- package/dist/defaults/src/integrations/menu/index.js +8 -8
- package/dist/defaults/src/integrations/tray/index.js +12 -12
- package/dist/defaults/src/main.js +5 -7
- package/dist/defaults/src/preload.js +4 -6
- package/dist/defaults/test/README.md +5 -5
- package/dist/defaults/test/_init.js +1 -1
- package/dist/gulp/main.js +9 -10
- package/dist/gulp/tasks/audit.js +11 -14
- package/dist/gulp/tasks/build-config.js +8 -8
- package/dist/gulp/tasks/bundle.js +16 -16
- package/dist/gulp/tasks/defaults.js +3 -3
- package/dist/gulp/tasks/distribute.js +2 -2
- package/dist/gulp/tasks/html.js +9 -9
- package/dist/gulp/tasks/package-quick.js +3 -3
- package/dist/gulp/tasks/package.js +3 -3
- package/dist/gulp/tasks/release.js +3 -3
- package/dist/gulp/tasks/sass.js +6 -6
- package/dist/gulp/tasks/serve.js +4 -4
- package/dist/hooks/notarize-artifacts.js +1 -1
- package/dist/hooks/notarize.js +1 -1
- package/dist/index.js +5 -8
- package/dist/lib/_environment-mixin.js +50 -0
- package/dist/lib/_lifecycle-mixin.js +45 -0
- package/dist/lib/analytics.js +33 -35
- package/dist/lib/app-state.js +14 -14
- package/dist/lib/auth-flow.js +18 -18
- package/dist/lib/auth-persistence.js +12 -12
- package/dist/lib/auth.js +421 -0
- package/dist/lib/auto-updater.js +49 -49
- package/dist/lib/context-menu.js +13 -13
- package/dist/lib/context.js +19 -19
- package/dist/lib/deep-link.js +34 -34
- package/dist/lib/fontawesome.js +5 -5
- package/dist/lib/ipc.js +4 -4
- package/dist/lib/menu.js +25 -25
- package/dist/lib/protocol.js +5 -5
- package/dist/lib/remote-config.js +22 -22
- package/dist/lib/remote-scripts.js +21 -21
- package/dist/lib/restart-manager/index.js +29 -29
- package/dist/lib/restart-manager/install.js +1 -1
- package/dist/lib/restart-manager/protocol.js +1 -1
- package/dist/lib/sign-helpers/exec-with-limit.js +1 -1
- package/dist/lib/sign-helpers/sign-events.js +1 -1
- package/dist/lib/startup.js +18 -13
- package/dist/lib/storage.js +10 -10
- package/dist/lib/templating.js +16 -16
- package/dist/lib/theme.js +10 -10
- package/dist/lib/tray.js +27 -27
- package/dist/lib/usage.js +11 -11
- package/dist/lib/window-manager.js +26 -26
- package/dist/main.js +399 -483
- package/dist/preload.js +236 -176
- package/dist/renderer.js +417 -391
- package/dist/test/fixtures/consumer-app/config/omega.json5 +1 -1
- package/dist/test/fixtures/consumer-app/src/assets/js/components/main/index.js +8 -11
- package/dist/test/fixtures/consumer-app/src/main.js +5 -7
- package/dist/test/fixtures/consumer-app/src/preload.js +2 -2
- package/dist/test/harness/boot-entry.js +22 -20
- package/dist/test/harness/main-entry.js +31 -30
- package/dist/test/harness/renderer-entry.js +5 -5
- package/dist/test/harness/renderer-preload.js +137 -141
- package/dist/test/index.js +10 -10
- package/dist/test/runner.js +2 -2
- package/dist/test/runners/boot.js +7 -6
- package/dist/test/runners/electron.js +3 -2
- package/dist/test/runners/render-event.js +2 -2
- package/dist/test/suites/boot/consumer-app-boots.test.js +57 -26
- package/dist/test/suites/boot/restart-manager.test.js +2 -2
- package/dist/test/suites/boot/storage-bundled.test.js +5 -5
- package/dist/test/suites/boot/theme.test.js +13 -13
- package/dist/test/suites/build/audit.test.js +21 -8
- package/dist/test/suites/build/auth-persistence-resolve.test.js +6 -6
- package/dist/test/suites/build/boot-fixture.test.js +2 -2
- package/dist/test/suites/build/boot-runner-timeout.test.js +6 -5
- package/dist/test/suites/build/brand-scss.test.js +1 -1
- package/dist/test/suites/build/build-json-bake.test.js +1 -1
- package/dist/test/suites/build/build-workflow-jobs.test.js +2 -2
- package/dist/test/suites/build/cli.test.js +30 -2
- package/dist/test/suites/build/config-schema.test.js +5 -5
- package/dist/test/suites/build/defaults-em-dash.test.js +22 -0
- package/dist/test/suites/build/defaults-scaffold.test.js +21 -7
- package/dist/test/suites/build/deploy-direct.test.js +7 -5
- package/dist/test/suites/build/deploy-dispatch.test.js +2 -1
- package/dist/test/suites/build/deploy-hook.test.js +7 -5
- package/dist/test/suites/build/dev-verb.test.js +67 -0
- package/dist/test/suites/build/ensure-target.test.js +13 -5
- package/dist/test/suites/build/env-delivery.test.js +2 -2
- package/dist/test/suites/build/esm-only-dependency.test.js +2 -2
- package/dist/test/suites/build/exports.test.js +9 -8
- package/dist/test/suites/build/get-config.test.js +4 -4
- package/dist/test/suites/build/manifest-deps.test.js +1 -1
- package/dist/test/suites/build/merge-line-files.test.js +7 -7
- package/dist/test/suites/build/migrate.test.js +29 -0
- package/dist/test/suites/build/omega-shell.test.js +34 -2
- package/dist/test/suites/build/omega.test.js +350 -0
- package/dist/test/suites/build/project-scripts-deps.test.js +6 -10
- package/dist/test/suites/build/renderer-auth-bridge.test.js +211 -78
- package/dist/test/suites/build/runner-env-write.test.js +73 -0
- package/dist/test/suites/build/runner.test.js +11 -10
- package/dist/test/suites/build/sentry.test.js +2 -2
- package/dist/test/suites/build/setup-scripts.test.js +27 -0
- package/dist/test/suites/build/sign-windows-e2e.test.js +2 -2
- package/dist/test/suites/build/templating.test.js +3 -3
- package/dist/test/suites/build/test-stealth.test.js +7 -9
- package/dist/test/suites/build/url-helpers.test.js +55 -56
- package/dist/test/suites/build/validate-config.test.js +15 -4
- package/dist/test/suites/build/verb-logs.test.js +20 -0
- package/dist/test/suites/build/wave5-pins.test.js +2 -2
- package/dist/test/suites/main/analytics.test.js +59 -59
- package/dist/test/suites/main/app-state.test.js +66 -66
- package/dist/test/suites/main/auth-flow.test.js +41 -41
- package/dist/test/suites/main/auth-persistence.test.js +54 -43
- package/dist/test/suites/main/{client-bridge.integration.test.js → auth.integration.test.js} +10 -9
- package/dist/test/suites/main/auth.test.js +336 -0
- package/dist/test/suites/main/auto-updater.test.js +134 -134
- package/dist/test/suites/main/boot-sequence.test.js +37 -49
- package/dist/test/suites/main/context-menu.test.js +51 -50
- package/dist/test/suites/main/context.test.js +25 -25
- package/dist/test/suites/main/deep-link.test.js +74 -74
- package/dist/test/suites/main/fontawesome.test.js +27 -27
- package/dist/test/suites/main/ipc.test.js +35 -35
- package/dist/test/suites/main/menu.test.js +101 -100
- package/dist/test/suites/main/protocol.test.js +19 -19
- package/dist/test/suites/main/remote-config.test.js +63 -63
- package/dist/test/suites/main/remote-scripts.test.js +103 -103
- package/dist/test/suites/main/request.test.js +71 -0
- package/dist/test/suites/main/restart-manager.test.js +33 -33
- package/dist/test/suites/main/startup-paths-and-ua.test.js +4 -4
- package/dist/test/suites/main/startup.test.js +26 -26
- package/dist/test/suites/main/stealth-window.test.js +1 -1
- package/dist/test/suites/main/storage.test.js +25 -25
- package/dist/test/suites/main/theme.test.js +34 -34
- package/dist/test/suites/main/tray.test.js +79 -79
- package/dist/test/suites/main/url-helpers.test.js +133 -133
- package/dist/test/suites/main/usage.test.js +25 -25
- package/dist/test/suites/main/window-bounds.test.js +27 -27
- package/dist/test/suites/main/window-manager.test.js +44 -44
- package/dist/test/suites/renderer/analytics-bridge.test.js +5 -5
- package/dist/test/suites/renderer/cross-context-helpers.test.js +37 -31
- package/dist/test/suites/renderer/round-trip.test.js +3 -3
- package/dist/test/suites/renderer/tooltips.test.js +15 -15
- package/dist/test/suites/renderer/{window-em-surface.test.js → window-desktop-surface.test.js} +28 -8
- package/dist/test/utils/extended-mode-warning.js +1 -1
- package/dist/utils/boot-harness.js +56 -0
- package/dist/utils/build-pipeline.js +4 -4
- package/dist/utils/mode-helpers.js +2 -15
- package/dist/utils/runner-env.js +13 -28
- package/dist/utils/ship-keys.js +3 -3
- package/dist/utils/signing-status.js +51 -0
- package/dist/utils/test-events.js +7 -0
- package/dist/utils/test-stealth.js +6 -6
- package/dist/utils/url-helpers.js +52 -42
- package/dist/utils/user-agent.js +44 -0
- package/dist/vendor/account/engine.js +3 -3
- package/dist/vendor/account/index.js +14 -45
- package/dist/vendor/account/resolve-account.js +44 -0
- package/dist/vendor/account/schema.js +1 -1
- package/dist/vendor/account/user.js +99 -0
- package/dist/vendor/config/client-config.js +1 -1
- package/dist/vendor/config/company.js +46 -14
- package/dist/vendor/config/defaults.js +30 -7
- package/dist/vendor/config/edit.js +25 -3
- package/dist/vendor/config/env-delivery.js +1 -1
- package/dist/vendor/config/env-schema.js +3 -6
- package/dist/vendor/config/env.js +34 -22
- package/dist/vendor/config/environment.js +11 -30
- package/dist/vendor/config/index.js +21 -28
- package/dist/vendor/config/load.js +16 -9
- package/dist/vendor/config/platforms.js +1 -1
- package/dist/vendor/config/repo.js +10 -27
- package/dist/vendor/config/schema-client.js +64 -0
- package/dist/vendor/config/schema-cloud.js +38 -0
- package/dist/vendor/config/schema-manager.js +118 -0
- package/dist/vendor/config/schema-overrides.js +68 -0
- package/dist/vendor/config/schema.js +104 -160
- package/dist/vendor/config/site-global.js +2 -3
- package/dist/vendor/config/validate.js +97 -78
- package/dist/vendor/config/winback.js +1 -1
- package/dist/vendor/devkit/actions-secrets.js +1 -1
- package/dist/vendor/devkit/agents-md.js +233 -0
- package/dist/vendor/devkit/attach-log-file.js +16 -2
- package/dist/vendor/devkit/build-json.js +1 -1
- package/dist/vendor/devkit/ci-workflows.js +30 -30
- package/dist/vendor/devkit/cli-router.js +16 -11
- package/dist/vendor/devkit/defaults-engine.js +15 -51
- package/dist/vendor/devkit/deploy-snapshot.js +44 -9
- package/dist/vendor/devkit/env-lines.js +183 -0
- package/dist/vendor/devkit/local.js +64 -10
- package/dist/vendor/devkit/lockfile.js +32 -13
- package/dist/vendor/devkit/logger.js +7 -2
- package/dist/vendor/devkit/merge-line-files.js +219 -177
- package/dist/vendor/devkit/omega-bin.js +208 -111
- package/dist/vendor/devkit/preludes/docs-sync.js +52 -0
- package/dist/vendor/devkit/preludes/index.js +1 -0
- package/dist/vendor/devkit/target-picker.js +45 -0
- package/dist/vendor/devkit/test/dashed-files.js +37 -0
- package/dist/vendor/devkit/test/run-verb-under-tee.js +71 -0
- package/dist/vendor/devkit/test/runner-core.js +6 -6
- package/dist/vendor/devkit/update.js +15 -15
- package/dist/vendor/devkit/verb-scripts.js +40 -0
- package/dist/vendor/devkit/verbs.js +170 -0
- package/dist/vendor/monitoring/env.js +2 -2
- package/dist/vendor/monitoring/index.js +1 -1
- package/dist/vendor/monitoring/main.js +1 -1
- package/dist/vendor/monitoring/preload.js +1 -1
- package/dist/vendor/monitoring/renderer.js +1 -1
- package/package.json +19 -26
- package/dist/commands/install.js +0 -37
- package/dist/defaults/AGENTS.md +0 -110
- package/dist/defaults/CLAUDE.md +0 -1
- package/dist/lib/client-bridge.js +0 -374
- package/dist/lib/logger.js +0 -4
- package/dist/test/suites/build/manager.test.js +0 -213
- package/dist/test/suites/main/client-bridge.test.js +0 -262
- package/dist/vendor/config/env-retired.js +0 -137
- package/dist/vendor/config/retired-keys.js +0 -635
- package/docs/analytics.md +0 -140
- package/docs/app-state.md +0 -92
- package/docs/audit.md +0 -69
- package/docs/auto-updater.md +0 -243
- package/docs/boot-sequence.md +0 -39
- package/docs/build-system.md +0 -169
- package/docs/cdp-debugging.md +0 -169
- package/docs/client-bridge.md +0 -269
- package/docs/common-mistakes.md +0 -21
- package/docs/config-schema.md +0 -120
- package/docs/context-menu.md +0 -112
- package/docs/context.md +0 -81
- package/docs/css.md +0 -90
- package/docs/deep-link.md +0 -186
- package/docs/environment-detection.md +0 -112
- package/docs/fontawesome.md +0 -107
- package/docs/hooks.md +0 -89
- package/docs/icons.md +0 -79
- package/docs/index.md +0 -317
- package/docs/installer-options.md +0 -165
- package/docs/ipc.md +0 -61
- package/docs/lib-modules.md +0 -53
- package/docs/logging.md +0 -229
- package/docs/menu.md +0 -160
- package/docs/releasing.md +0 -239
- package/docs/remote-config.md +0 -118
- package/docs/remote-scripts.md +0 -144
- package/docs/restart-manager.md +0 -144
- package/docs/runner.md +0 -290
- package/docs/sentry.md +0 -97
- package/docs/shared/agent-docs.md +0 -89
- package/docs/shared/analytics.md +0 -612
- package/docs/shared/brands.md +0 -57
- package/docs/shared/breaking-changes.md +0 -851
- package/docs/shared/config.md +0 -1952
- package/docs/shared/deploys.md +0 -341
- package/docs/shared/icons.md +0 -219
- package/docs/shared/local-dev.md +0 -167
- package/docs/shared/logging.md +0 -205
- package/docs/shared/monitoring.md +0 -167
- package/docs/shared/publishing.md +0 -187
- package/docs/shared/rulings.md +0 -34
- package/docs/shared/testing.md +0 -147
- package/docs/shared/theming.md +0 -629
- package/docs/shared/translation.md +0 -333
- package/docs/shared/updates.md +0 -61
- package/docs/signing.md +0 -293
- package/docs/startup.md +0 -142
- package/docs/storage.md +0 -59
- package/docs/templating.md +0 -101
- package/docs/test-boot-layer.md +0 -157
- package/docs/test-framework.md +0 -362
- package/docs/themes.md +0 -149
- package/docs/tooltips.md +0 -99
- package/docs/tray.md +0 -164
- package/docs/usage.md +0 -58
- package/docs/verts.md +0 -62
- package/docs/windows.md +0 -149
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* `site.*` global, so existing template references port verbatim to the new
|
|
4
4
|
* SSG (plan §2: toSiteGlobal()).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* somiibo: config-owned keys referenced in templates are the resolved
|
|
6
|
+
* Config-owned keys referenced in templates are the resolved
|
|
8
7
|
* config's own shape, so this is an identity mapping plus: machinery keys
|
|
9
8
|
* stripped (`targets`, `enabled`), `url` derived (explicit url, else
|
|
10
9
|
* brand.url), `baseurl` defaulted. ENGINE-owned keys (posts, pages, data,
|
|
@@ -24,7 +23,7 @@
|
|
|
24
23
|
* ([#610](https://github.com/Omega-JS-Stack/omega/issues/610)): the
|
|
25
24
|
* `/download` page, the `/extension` page and the shortlink generator all
|
|
26
25
|
* read `site.targets.desktop.releasesUrl` and
|
|
27
|
-
* `site.targets.extension.listings` directly. The
|
|
26
|
+
* `site.targets.extension.listings` directly. The hand-written
|
|
28
27
|
* `download`/`extension` page maps — and the derivation that filled them —
|
|
29
28
|
* are gone; the validator refuses a config still carrying either key.
|
|
30
29
|
*
|
|
@@ -1,40 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Schema-driven validation for resolved omega.json5 configs.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - SHARED_SCHEMA always runs; TARGET_SCHEMAS[options.target] adds that
|
|
12
|
-
* target's refinements against the same resolved top-level namespace
|
|
13
|
-
* - `targets` sanity (#886): every key is a target NAME, so it must be a
|
|
14
|
-
* dir-safe slug, and every entry must be an object declaring a `type` the
|
|
15
|
-
* framework list knows (an ARRAY is the retired multi-instance form, whose
|
|
16
|
-
* replacement is a sibling key; >1 backend target is a WARNING)
|
|
17
|
-
* - the `repo` block (#883): one `provider` from REPO_PROVIDERS, and an `org`
|
|
18
|
-
* that is a real non-empty string whenever the block is there, because the
|
|
19
|
-
* org is the owner of every repo the brand's names derive under
|
|
20
|
-
* - `hosting` (#883) is a WEB target's key: a non-web target carrying it says
|
|
21
|
-
* something nothing serves, and its provider comes from HOSTING_PROVIDERS
|
|
22
|
-
* - `cloud.config.authDomain`, when set, must be the brand's OWN host (the
|
|
23
|
-
* resolved target url, else brand.url): a firebaseapp.com value or a
|
|
24
|
-
* mismatch is an error, and demo-* (emulator-only) projects are exempt
|
|
25
|
-
* - retired keys are always errors (see retired-keys.js) — a name that was
|
|
26
|
-
* renamed outright reads as nothing at all, so it fails loudly instead of
|
|
27
|
-
* losing its settings silently
|
|
28
|
-
* - secret-shaped keys are always errors (see secrets.js) — loadConfig
|
|
29
|
-
* additionally hard-fails on them before any merge happens
|
|
30
|
-
* - keys the schema does not declare are WARNINGS (#636): the walker only
|
|
31
|
-
* ever visits declared paths, so a typo — or a live path nobody declared —
|
|
32
|
-
* used to pass in silence
|
|
2
|
+
* Schema-driven validation for resolved omega.json5 configs. runSchema walks
|
|
3
|
+
* the rules (required/type/match/enum/itemEnum, the value checks only on a
|
|
4
|
+
* PRESENT value; schema.js has the rule format). validateConfig() adds the
|
|
5
|
+
* target's refinements, the `targets` sanity (each key a dir-safe NAME, each
|
|
6
|
+
* entry a known `type`), the `repo` block and web-only `hosting`, the brand's
|
|
7
|
+
* own authDomain, the price and feature shapes, and secret-shaped keys. The
|
|
8
|
+
* schema is STRICT: a path no rule declares is an error, one line per path,
|
|
9
|
+
* naming `omega migrate`. The validator knows only the present shape; the
|
|
10
|
+
* migrate verb is the one code that knows an old name.
|
|
33
11
|
*/
|
|
34
12
|
|
|
35
|
-
const { TARGETS, SHARED_SCHEMA, TARGET_SCHEMAS } = require('./schema.js');
|
|
13
|
+
const { TARGETS, SHARED_SCHEMA, TARGET_SCHEMAS, isCustomTargetEntry } = require('./schema.js');
|
|
36
14
|
const { findSecretKeys } = require('./secrets.js');
|
|
37
|
-
const {
|
|
15
|
+
const { CLIENT_FACT_KEYS } = require('./client-config.js');
|
|
16
|
+
const { RESOLVED_COMPANY_KEYS } = require('./company.js');
|
|
38
17
|
const { isPlainObject } = require('./merge.js');
|
|
39
18
|
const { TARGET_NAME_PATTERN, TARGET_TYPES } = require('./targets.js');
|
|
40
19
|
const { REPO_PROVIDERS, HOSTING_PROVIDERS } = require('./repo.js');
|
|
@@ -44,6 +23,14 @@ const { isCountedFeature } = require('../account/features.js');
|
|
|
44
23
|
// Firebase's own default authDomain shape: a third-party host by definition
|
|
45
24
|
const FIREBASE_AUTH_DOMAIN = /\.firebaseapp\.com$/;
|
|
46
25
|
|
|
26
|
+
// The company facts the loader fills: a staged compose output carries them on
|
|
27
|
+
// purpose, and the loader refuses a TYPED one in a brand or company file.
|
|
28
|
+
const RESOLVED_PATHS = RESOLVED_COMPANY_KEYS.map((key) => `company.${key}`);
|
|
29
|
+
|
|
30
|
+
// The build facts a surface bakes AFTER the load: declared only for
|
|
31
|
+
// `decorated: true`, the re-validation of a baked config (a desktop boot).
|
|
32
|
+
const BUILD_FACT_PATHS = CLIENT_FACT_KEYS;
|
|
33
|
+
|
|
47
34
|
/**
|
|
48
35
|
* Read a dotted path out of a config object — the path resolver the schema
|
|
49
36
|
* walk and the env presence checker (env-rules.js) share.
|
|
@@ -420,24 +407,23 @@ function validateFeatures(config) {
|
|
|
420
407
|
}
|
|
421
408
|
|
|
422
409
|
/**
|
|
423
|
-
* The LEAF paths of a
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* The `targets` subtree is skipped whole: those keys belong to a framework or,
|
|
432
|
-
* for a custom target (#603), to the brand — the targets-sanity check above is
|
|
433
|
-
* what polices that namespace.
|
|
434
|
-
*
|
|
435
|
-
* @param {object} config - The resolved config object.
|
|
410
|
+
* The LEAF paths of a config the schema does not declare. A rule declares its
|
|
411
|
+
* own path; an `object`/`array` rule opens its whole subtree only when no rule
|
|
412
|
+
* is declared beneath it (or it says `open: true`), so a section with typed
|
|
413
|
+
* keys stays closed. An empty object/array (or a `false` off switch) is a leaf,
|
|
414
|
+
* declared when the schema declares anything below it. `targets` is skipped
|
|
415
|
+
* whole: each target's own load judges its entry.
|
|
416
|
+
* @param {object} config - The config object.
|
|
436
417
|
* @param {object[]} schema - Rule array in the schema.js entry format.
|
|
418
|
+
* @param {string[]} [written] - Paths framework code wrote onto a decorated config, each open.
|
|
437
419
|
* @returns {string[]} Undeclared leaf paths, in config order.
|
|
438
420
|
*/
|
|
439
|
-
function findUndeclaredPaths(config, schema) {
|
|
440
|
-
const
|
|
421
|
+
function findUndeclaredPaths(config, schema, written = []) {
|
|
422
|
+
const paths = [...schema.map((rule) => rule.path), ...written];
|
|
423
|
+
const open = schema
|
|
424
|
+
.filter((rule) => /\b(object|array)\b/.test(rule.type || '') && (rule.open || !paths.some((other) => other.startsWith(`${rule.path}.`))))
|
|
425
|
+
.map((rule) => rule.path)
|
|
426
|
+
.concat(written);
|
|
441
427
|
const found = [];
|
|
442
428
|
|
|
443
429
|
const walk = (value, path) => {
|
|
@@ -445,9 +431,10 @@ function findUndeclaredPaths(config, schema) {
|
|
|
445
431
|
Object.keys(value).forEach((key) => walk(value[key], `${path}.${key}`));
|
|
446
432
|
return;
|
|
447
433
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
434
|
+
const declared = paths.includes(path)
|
|
435
|
+
|| open.some((rule) => path.startsWith(`${rule}.`))
|
|
436
|
+
|| paths.some((rule) => rule.startsWith(`${path}.`));
|
|
437
|
+
if (!declared) found.push(path);
|
|
451
438
|
};
|
|
452
439
|
|
|
453
440
|
Object.keys(isPlainObject(config) ? config : {})
|
|
@@ -457,25 +444,69 @@ function findUndeclaredPaths(config, schema) {
|
|
|
457
444
|
return found;
|
|
458
445
|
}
|
|
459
446
|
|
|
447
|
+
/**
|
|
448
|
+
* The rules a target's resolved config answers to: shared + its refinements.
|
|
449
|
+
* @param {string} [target] - Canonical target name; omitted = shared only.
|
|
450
|
+
* @returns {object[]}
|
|
451
|
+
*/
|
|
452
|
+
function schemaFor(target) {
|
|
453
|
+
if (target && !TARGETS.includes(target)) {
|
|
454
|
+
throw new Error(`Unknown target "${target}": must be one of [${TARGETS.join(', ')}]`);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return target ? [...SHARED_SCHEMA, ...TARGET_SCHEMAS[target]] : SHARED_SCHEMA;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* The paths a config carries that no rule declares, for one target's view:
|
|
462
|
+
* what the strict check fails, for a caller (a converter) that drops them.
|
|
463
|
+
* @param {object} config - A resolved config (a target's keys at the top level).
|
|
464
|
+
* @param {object} [options]
|
|
465
|
+
* @param {string} [options.target]
|
|
466
|
+
* @returns {string[]} Undeclared leaf paths, in config order.
|
|
467
|
+
*/
|
|
468
|
+
function undeclaredPaths(config, options) {
|
|
469
|
+
return findUndeclaredPaths(config, schemaFor((options || {}).target), RESOLVED_PATHS);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Every path of an AUTHORED config (one omega.json5 as written) the strict
|
|
474
|
+
* schema refuses: the whole file, `targets` left to its targets, then each
|
|
475
|
+
* framework target entry the way its own load sees it (hoisted to the top
|
|
476
|
+
* level). A target's OWN file names its type, since its top level is that
|
|
477
|
+
* target's layer. A custom target's keys are its own; an unknown type is the
|
|
478
|
+
* targets check's to report.
|
|
479
|
+
* @param {object} config - One file's parsed config.
|
|
480
|
+
* @param {object} [options]
|
|
481
|
+
* @param {string} [options.target] - The type whose own file this is.
|
|
482
|
+
* @returns {string[]} Dotted paths as the file spells them.
|
|
483
|
+
*/
|
|
484
|
+
function undeclaredAuthoredPaths(config, options) {
|
|
485
|
+
const found = undeclaredPaths(config, { target: (options || {}).target });
|
|
486
|
+
const targets = isPlainObject(config) && isPlainObject(config.targets) ? config.targets : {};
|
|
487
|
+
|
|
488
|
+
for (const [name, entry] of Object.entries(targets)) {
|
|
489
|
+
if (!isPlainObject(entry) || isCustomTargetEntry(entry) || !TARGETS.includes(entry.type)) continue;
|
|
490
|
+
found.push(...undeclaredPaths(entry, { target: entry.type }).map((dotted) => `targets.${name}.${dotted}`));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return found;
|
|
494
|
+
}
|
|
495
|
+
|
|
460
496
|
/**
|
|
461
497
|
* Validate a resolved config: shared schema + optional target refinements +
|
|
462
498
|
* targets-key sanity + secret-shaped-key detection.
|
|
463
499
|
* @param {object} config - The resolved config object.
|
|
464
500
|
* @param {object} [options]
|
|
465
501
|
* @param {string} [options.target] - Canonical target name; adds TARGET_SCHEMAS[target].
|
|
502
|
+
* @param {boolean} [options.decorated] - The config already carries a build's
|
|
503
|
+
* facts (a baked config, validated again at boot).
|
|
466
504
|
* @returns {{ errors: string[], warnings: string[] }}
|
|
467
505
|
*/
|
|
468
506
|
function validateConfig(config, options) {
|
|
469
507
|
options = options || {};
|
|
470
508
|
|
|
471
|
-
|
|
472
|
-
throw new Error(`Unknown target "${options.target}" — must be one of [${TARGETS.join(', ')}]`);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const schema = options.target
|
|
476
|
-
? [...SHARED_SCHEMA, ...TARGET_SCHEMAS[options.target]]
|
|
477
|
-
: SHARED_SCHEMA;
|
|
478
|
-
|
|
509
|
+
const schema = schemaFor(options.target);
|
|
479
510
|
const errors = runSchema(config, schema);
|
|
480
511
|
const warnings = [];
|
|
481
512
|
|
|
@@ -574,25 +605,13 @@ function validateConfig(config, options) {
|
|
|
574
605
|
// ─── the features catalog and the values products name (#647) ──────────
|
|
575
606
|
validateFeatures(config).forEach((error) => errors.push(error));
|
|
576
607
|
|
|
577
|
-
// ───
|
|
578
|
-
// A
|
|
579
|
-
//
|
|
580
|
-
|
|
581
|
-
const undeclared = findUndeclaredPaths(config, schema);
|
|
582
|
-
if (undeclared.length > 0) {
|
|
583
|
-
warnings.push(
|
|
584
|
-
'config carries keys the schema does not declare — nothing reads them, so a typo looks exactly like a '
|
|
585
|
-
+ `feature. Remove them, or give each one a rule in @omega.js/config's schema.js `
|
|
586
|
-
+ `(docs/shared/config.md → Validation): ${undeclared.join(', ')}`,
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// ─── retired keys (#142) ───────────────────────────────────────────────
|
|
591
|
-
findRetiredKeys(config).forEach(({ path, replacement, why }) => {
|
|
608
|
+
// ─── the schema is strict ──────────────────────────────────────────────
|
|
609
|
+
// A key nothing declares is a key nothing reads: a typo or a legacy shape.
|
|
610
|
+
// One line per path, so a brand sees every key it has to move or delete.
|
|
611
|
+
findUndeclaredPaths(config, schema, options.decorated ? [...RESOLVED_PATHS, ...BUILD_FACT_PATHS] : RESOLVED_PATHS).forEach((path) => {
|
|
592
612
|
errors.push(
|
|
593
|
-
`config.${path} is
|
|
594
|
-
+ `
|
|
595
|
-
+ `(docs/shared/config.md → "Migration — legacy configs")`,
|
|
613
|
+
`config.${path} is not a key the schema declares. Remove it, or if it is a legacy key run `
|
|
614
|
+
+ '`npx omega migrate` at the brand root (report) and `--execute` to convert (docs/shared/config.md → Validation)',
|
|
596
615
|
);
|
|
597
616
|
});
|
|
598
617
|
|
|
@@ -611,4 +630,4 @@ function formatErrors(errors) {
|
|
|
611
630
|
return errors.map((e, i) => ` ${i + 1}. ${e}`).join('\n');
|
|
612
631
|
}
|
|
613
632
|
|
|
614
|
-
module.exports = { validateConfig, runSchema, formatErrors, getPath, resolvedBrandHost };
|
|
633
|
+
module.exports = { validateConfig, undeclaredPaths, undeclaredAuthoredPaths, runSchema, formatErrors, getPath, resolvedBrandHost };
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* nothing at all still makes one: 50% off the next cycle, one cycle only.
|
|
10
10
|
*
|
|
11
11
|
* That default lives HERE and nowhere else. The backend's apply route resolves
|
|
12
|
-
* `
|
|
12
|
+
* `omega.config.payment` through this function, and the web build bakes the
|
|
13
13
|
* SAME call into the client blob it emits — so the dialog the customer reads and
|
|
14
14
|
* the coupon the provider creates can never disagree about the number.
|
|
15
15
|
*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* repo secrets: hand it a repo (`owner/name`) and a key → value map, it sets
|
|
6
6
|
* each one. The transport is the `gh` CLI (`gh secret set KEY --repo o/n`,
|
|
7
7
|
* which encrypts locally with the repo's public key before sending) — there is
|
|
8
|
-
* NO libsodium/REST fallback here
|
|
8
|
+
* NO libsodium/REST fallback here: without a usable `gh` this
|
|
9
9
|
* FAILS LOUDLY with install/auth instructions rather than growing a crypto
|
|
10
10
|
* dependency to do what the CLI already does.
|
|
11
11
|
*
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE builder of a project-root AGENTS.md, a brand root and a framework
|
|
3
|
+
* used alone alike, written through the one marker engine: the Default section
|
|
4
|
+
* imports the installed manager's AGENTS.md (which imports the omega map from
|
|
5
|
+
* the docs the manager ships), the Custom section holds the project's own
|
|
6
|
+
* notes, verbatim. Every older shape converges once, its notes kept under
|
|
7
|
+
* Custom. A brand target carries none: its brand root is the doc home.
|
|
8
|
+
*/
|
|
9
|
+
const { join } = require('node:path');
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
const jetpack = require('fs-jetpack');
|
|
12
|
+
const { mergeLineBasedFiles, hasSectionMarkers, getCustomSection, isShipped, sectionMarkers, DEFAULT_MARKER } = require('./merge-line-files');
|
|
13
|
+
|
|
14
|
+
const FILE_NAME = 'AGENTS.md';
|
|
15
|
+
const GUIDE_SUBPATH = 'node_modules/@omega.js/manager/AGENTS.md';
|
|
16
|
+
const IMPORT_LINE = `@${GUIDE_SUBPATH}`;
|
|
17
|
+
// The retired scope-level link: an import of it is healed away and the link
|
|
18
|
+
// itself removed.
|
|
19
|
+
const RETIRED_SUBPATH = 'node_modules/@omega.js/AGENTS.md';
|
|
20
|
+
|
|
21
|
+
const SCOPE_PREFIXES = ['', '../', '../../', '../../../'];
|
|
22
|
+
|
|
23
|
+
// The skeleton heading earlier builders wrote under the import.
|
|
24
|
+
const NOTES_HEADING = /^# .+: (project|brand) notes$/;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Is this line an import of the manager's AGENTS.md or the retired scope link
|
|
28
|
+
* (any relative depth)?
|
|
29
|
+
*
|
|
30
|
+
* @param {string} line - A single file line
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
function isImportLine(line) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
return trimmed.startsWith('@') && (trimmed.endsWith(GUIDE_SUBPATH) || trimmed.endsWith(RETIRED_SUBPATH));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The @omega.js scope directory serving this project: its own node_modules
|
|
40
|
+
* normally, an ancestor's when hoisted (npm workspaces). Only a scope holding
|
|
41
|
+
* the manager counts: an empty dir from a partial install would leave the
|
|
42
|
+
* import dangling while the real scope sits a level up.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} root - Absolute project root
|
|
45
|
+
* @returns {{prefix: string, scopeDir: string}|null}
|
|
46
|
+
*/
|
|
47
|
+
function findScope(root) {
|
|
48
|
+
for (const prefix of SCOPE_PREFIXES) {
|
|
49
|
+
const scopeDir = join(root, prefix, 'node_modules', '@omega.js');
|
|
50
|
+
if (jetpack.exists(join(scopeDir, 'manager')) === 'dir') {
|
|
51
|
+
return { prefix, scopeDir };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the import line for THIS project: the depth that reaches the scope
|
|
59
|
+
* holding the manager. Falls back to the canonical project-local path when
|
|
60
|
+
* the manager is not installed, so the line still names where the docs live.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} root - Absolute project root
|
|
63
|
+
* @returns {string} - The `@<relative path>` import line
|
|
64
|
+
*/
|
|
65
|
+
function resolveImportLine(root) {
|
|
66
|
+
const scope = findScope(root);
|
|
67
|
+
return scope ? `@${scope.prefix}${GUIDE_SUBPATH}` : IMPORT_LINE;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Remove the retired `node_modules/@omega.js/AGENTS.md` link (or a stale file
|
|
72
|
+
* in its place) from the scope serving this brand.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} brandRoot - Absolute brand monorepo root
|
|
75
|
+
* @param {{ dryRun?: boolean }} [options] - dryRun: the same verdict, nothing removed
|
|
76
|
+
* @returns {'removed'|'absent'} - What happened
|
|
77
|
+
*/
|
|
78
|
+
function removeRetiredLink(brandRoot, { dryRun = false } = {}) {
|
|
79
|
+
const scope = findScope(brandRoot);
|
|
80
|
+
const link = scope && join(scope.scopeDir, 'AGENTS.md');
|
|
81
|
+
if (!link || !fs.lstatSync(link, { throwIfNoEntry: false })) {
|
|
82
|
+
return 'absent';
|
|
83
|
+
}
|
|
84
|
+
if (!dryRun) {
|
|
85
|
+
fs.rmSync(link, { force: true });
|
|
86
|
+
}
|
|
87
|
+
return 'removed';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Render a fresh project-root AGENTS.md: the import under the Default marker,
|
|
92
|
+
* then the Custom marker and nothing below it.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} [importLine] - The resolved import line
|
|
95
|
+
* @returns {string} - Full file content
|
|
96
|
+
*/
|
|
97
|
+
function renderAgentsMd(importLine = IMPORT_LINE) {
|
|
98
|
+
const { defaultMarker, customMarker } = sectionMarkers(FILE_NAME);
|
|
99
|
+
return `${defaultMarker}\n${importLine}\n\n${customMarker}\n`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Is this the retired per-framework template? It OPENS with the `#` Default
|
|
104
|
+
* marker; a file that merely quotes the markers in its notes is not one.
|
|
105
|
+
*
|
|
106
|
+
* @param {string} content - The AGENTS.md content
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
function isRetiredTemplate(content) {
|
|
110
|
+
return content.split('\n')[0].trim() === DEFAULT_MARKER && hasSectionMarkers(content);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The notes a consumer wrote in an AGENTS.md of any shape, trimmed: the Custom
|
|
115
|
+
* section of a marked or retired-template file, else the whole file, minus
|
|
116
|
+
* every line a framework wrote (the import, the skeleton heading, shipped
|
|
117
|
+
* boilerplate).
|
|
118
|
+
*
|
|
119
|
+
* @param {string} content - The AGENTS.md content
|
|
120
|
+
* @returns {string} - '' when the file holds nothing the framework did not write
|
|
121
|
+
*/
|
|
122
|
+
function consumerNotes(content) {
|
|
123
|
+
const source = hasSectionMarkers(content, FILE_NAME)
|
|
124
|
+
? getCustomSection(content, FILE_NAME)
|
|
125
|
+
: isRetiredTemplate(content) ? getCustomSection(content) : content;
|
|
126
|
+
return source.split('\n')
|
|
127
|
+
.filter((line) => !isImportLine(line) && !NOTES_HEADING.test(line.trim()) && !isShipped(line, FILE_NAME))
|
|
128
|
+
.join('\n')
|
|
129
|
+
.trim();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Ensure the project-root AGENTS.md is the marked shape with the resolved
|
|
134
|
+
* import. A marked file goes through the engine (the Default section healed,
|
|
135
|
+
* the Custom section verbatim); any other shape converges, its notes landing
|
|
136
|
+
* under Custom in order.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} root - Absolute project root
|
|
139
|
+
* @param {{ dryRun?: boolean }} [options] - dryRun: the same verdict, nothing written
|
|
140
|
+
* @returns {'present'|'created'|'healed'|'converged'} - What happened
|
|
141
|
+
*/
|
|
142
|
+
function ensureAgentsMd(root, { dryRun = false } = {}) {
|
|
143
|
+
const file = join(root, FILE_NAME);
|
|
144
|
+
const template = renderAgentsMd(resolveImportLine(root));
|
|
145
|
+
const existing = jetpack.read(file);
|
|
146
|
+
|
|
147
|
+
if (existing === undefined) {
|
|
148
|
+
if (!dryRun) jetpack.write(file, template);
|
|
149
|
+
return 'created';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const marked = hasSectionMarkers(existing, FILE_NAME);
|
|
153
|
+
const next = mergeLineBasedFiles(marked ? existing : consumerNotes(existing), template, FILE_NAME);
|
|
154
|
+
if (next === existing) {
|
|
155
|
+
return 'present';
|
|
156
|
+
}
|
|
157
|
+
if (!dryRun) jetpack.write(file, next);
|
|
158
|
+
return marked ? 'healed' : 'converged';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Keep a brand target free of any AGENTS.md: the brand root is its doc home. A
|
|
163
|
+
* copy holding nothing the consumer wrote is removed; one with notes stays.
|
|
164
|
+
*
|
|
165
|
+
* @param {string} targetDir - Absolute brand target root
|
|
166
|
+
* @returns {'absent'|'removed'|'kept'} - What happened
|
|
167
|
+
*/
|
|
168
|
+
function retireAgentsMd(targetDir) {
|
|
169
|
+
const file = join(targetDir, 'AGENTS.md');
|
|
170
|
+
const existing = jetpack.read(file);
|
|
171
|
+
|
|
172
|
+
if (existing === undefined) {
|
|
173
|
+
return 'absent';
|
|
174
|
+
}
|
|
175
|
+
if (consumerNotes(existing)) {
|
|
176
|
+
return 'kept';
|
|
177
|
+
}
|
|
178
|
+
jetpack.remove(file);
|
|
179
|
+
return 'removed';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* A framework scaffold's AGENTS.md step, recorded into the defaults engine's
|
|
184
|
+
* result and logged the way the engine logs: a standalone project root gets
|
|
185
|
+
* the builder's file; a brand target gets none.
|
|
186
|
+
*
|
|
187
|
+
* @param {object} options
|
|
188
|
+
* @param {string} options.outputDir - Absolute project or target root
|
|
189
|
+
* @param {boolean} options.standalone - True when no brand root sits above it
|
|
190
|
+
* @param {{written: string[], merged: string[], skipped: string[], removed: string[]}} options.result - The engine result to record into
|
|
191
|
+
* @param {object} [options.logger] - `{ log, warn }` (defaults to console)
|
|
192
|
+
*/
|
|
193
|
+
function scaffoldAgentsMd({ outputDir, standalone, result, logger = console }) {
|
|
194
|
+
if (!standalone) {
|
|
195
|
+
const verdict = retireAgentsMd(outputDir);
|
|
196
|
+
if (verdict === 'removed') {
|
|
197
|
+
result.removed.push('AGENTS.md');
|
|
198
|
+
logger.warn('Retired AGENTS.md: a brand target carries none, the brand root AGENTS.md is the one doc home');
|
|
199
|
+
} else if (verdict === 'kept') {
|
|
200
|
+
result.skipped.push('AGENTS.md');
|
|
201
|
+
logger.warn('Kept AGENTS.md: it carries consumer content. A brand target carries no AGENTS.md: move those notes under the Custom marker of the brand root AGENTS.md, then delete the file');
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const verdict = ensureAgentsMd(outputDir);
|
|
207
|
+
if (verdict === 'created') {
|
|
208
|
+
result.written.push('AGENTS.md');
|
|
209
|
+
logger.log('Scaffolded → AGENTS.md');
|
|
210
|
+
} else if (verdict === 'healed') {
|
|
211
|
+
result.merged.push('AGENTS.md');
|
|
212
|
+
logger.log('Healed → AGENTS.md: the Default section imports the manager, your Custom section kept');
|
|
213
|
+
} else if (verdict === 'converged') {
|
|
214
|
+
result.merged.push('AGENTS.md');
|
|
215
|
+
logger.warn('Converged AGENTS.md to the marker sections: the manager import under Default, your notes under Custom');
|
|
216
|
+
} else {
|
|
217
|
+
result.skipped.push('AGENTS.md');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
module.exports = {
|
|
222
|
+
GUIDE_SUBPATH,
|
|
223
|
+
IMPORT_LINE,
|
|
224
|
+
RETIRED_SUBPATH,
|
|
225
|
+
isImportLine,
|
|
226
|
+
findScope,
|
|
227
|
+
resolveImportLine,
|
|
228
|
+
removeRetiredLink,
|
|
229
|
+
renderAgentsMd,
|
|
230
|
+
ensureAgentsMd,
|
|
231
|
+
retireAgentsMd,
|
|
232
|
+
scaffoldAgentsMd,
|
|
233
|
+
};
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
// Two attaches on ONE tee stack the same way: a second attach of a DIFFERENT path pushes a
|
|
26
26
|
// layer on top of the first instead of replacing it, so a verb that runs another verb in
|
|
27
27
|
// process (`omega test` running `omega deploy`) keeps teeing both files. Detach order is
|
|
28
|
-
// LIFO, and the module-level `detach()` pops the newest layer.
|
|
28
|
+
// LIFO, and the module-level `detach()` pops the newest layer. A harness that runs a verb
|
|
29
|
+
// takes `mark()` first and calls the restore it returns after, never a blind `detach()`.
|
|
29
30
|
//
|
|
30
31
|
// Skipped in CI: a runner has its own log capture and wants no logs/ left in the workspace.
|
|
31
32
|
// `attachInCI: true` opts out of that skip, for a sink whose file is the POINT rather than
|
|
@@ -142,8 +143,20 @@ function createTee() {
|
|
|
142
143
|
return detach;
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
// A harness around a verb restores to the mark instead of popping blind: a run can
|
|
147
|
+
// push one layer, several, or none, and only what it pushed comes off, newest first.
|
|
148
|
+
function mark() {
|
|
149
|
+
const kept = layers.slice();
|
|
150
|
+
return function restore() {
|
|
151
|
+
for (const layer of layers.slice().reverse()) {
|
|
152
|
+
if (!kept.includes(layer)) { layer.detach(); }
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
145
157
|
return {
|
|
146
158
|
attach,
|
|
159
|
+
mark,
|
|
147
160
|
detach: () => {
|
|
148
161
|
const newest = layers[layers.length - 1];
|
|
149
162
|
if (newest) { newest.detach(); }
|
|
@@ -161,7 +174,7 @@ function createTee() {
|
|
|
161
174
|
// The roll is what the tee has no need for: a child that stays up for days (a
|
|
162
175
|
// Firebase emulator) has to be truncatable MID-RUN, so a sibling process asks
|
|
163
176
|
// for a fresh log by touching `resetPath` and the poll below honors it within
|
|
164
|
-
// `pollMs`.
|
|
177
|
+
// `pollMs`. The backend's emulator and serve commands share it.
|
|
165
178
|
//
|
|
166
179
|
// Writes go to an open fd synchronously, for the same reason the tee's do: the
|
|
167
180
|
// lines describing a crash are the ones a buffered stream drops.
|
|
@@ -265,6 +278,7 @@ function attachLogFile(filePath, options) {
|
|
|
265
278
|
|
|
266
279
|
module.exports = attachLogFile;
|
|
267
280
|
module.exports.detach = singleton.detach;
|
|
281
|
+
module.exports.mark = singleton.mark;
|
|
268
282
|
module.exports.stripAnsi = stripAnsi;
|
|
269
283
|
module.exports.createTee = createTee;
|
|
270
284
|
module.exports.createChildLog = createChildLog;
|
|
@@ -23,7 +23,7 @@ const { clientConfig } = require('../config/index.js');
|
|
|
23
23
|
// ([#894](https://github.com/Omega-JS-Stack/omega/issues/894)): the build's
|
|
24
24
|
// verdict (`environment`), whether it was a BUILD rather than a dev/watch run,
|
|
25
25
|
// and whether it publishes. A surface's own extra verdicts (desktop's
|
|
26
|
-
// `server`) stay inside that surface's
|
|
26
|
+
// `server`) stay inside that surface's Omega instance and never reach the artifact.
|
|
27
27
|
const MODE_KEYS = ['environment', 'build', 'publish'];
|
|
28
28
|
|
|
29
29
|
/**
|