@bleedingdev/modern-js-create 3.4.0-ultramodern.8 → 3.5.0-ultramodern.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 +25 -23
- package/dist/cjs/index.cjs +37 -4
- package/dist/cjs/locale/en.cjs +12 -2
- package/dist/cjs/locale/zh.cjs +12 -2
- package/dist/cjs/ultramodern-tooling/commands.cjs +185 -0
- package/dist/cjs/ultramodern-tooling/config.cjs +172 -0
- package/dist/cjs/ultramodern-workspace/add-vertical.cjs +87 -75
- package/dist/cjs/ultramodern-workspace/{effect-api.cjs → api.cjs} +207 -208
- package/dist/cjs/ultramodern-workspace/bridge-config.cjs +327 -0
- package/dist/cjs/ultramodern-workspace/codesmith.cjs +1 -0
- package/dist/cjs/ultramodern-workspace/contracts.cjs +127 -657
- package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
- package/dist/cjs/ultramodern-workspace/descriptors.cjs +25 -25
- package/dist/cjs/ultramodern-workspace/fs-io.cjs +117 -0
- package/dist/cjs/ultramodern-workspace/generation-result.cjs +5 -5
- package/dist/cjs/ultramodern-workspace/index.cjs +4 -0
- package/dist/cjs/ultramodern-workspace/mf-validation.cjs +571 -0
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +33 -18
- package/dist/cjs/ultramodern-workspace/overlays.cjs +2 -2
- package/dist/cjs/ultramodern-workspace/package-json.cjs +57 -41
- package/dist/cjs/ultramodern-workspace/policy.cjs +4 -4
- package/dist/cjs/ultramodern-workspace/public-api.cjs +4 -0
- package/dist/cjs/ultramodern-workspace/public-surface.cjs +2 -2
- package/dist/cjs/ultramodern-workspace/versions.cjs +5 -0
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +119 -50
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +62 -21
- package/dist/esm/index.js +37 -4
- package/dist/esm/locale/en.js +12 -2
- package/dist/esm/locale/zh.js +12 -2
- package/dist/esm/ultramodern-tooling/commands.js +132 -0
- package/dist/esm/ultramodern-tooling/config.js +120 -0
- package/dist/esm/ultramodern-workspace/add-vertical.js +88 -79
- package/dist/esm/ultramodern-workspace/{effect-api.js → api.js} +146 -147
- package/dist/esm/ultramodern-workspace/bridge-config.js +270 -0
- package/dist/esm/ultramodern-workspace/codesmith.js +1 -0
- package/dist/esm/ultramodern-workspace/contracts.js +129 -611
- package/dist/esm/ultramodern-workspace/demo-components.js +13 -13
- package/dist/esm/ultramodern-workspace/descriptors.js +11 -11
- package/dist/esm/ultramodern-workspace/fs-io.js +116 -2
- package/dist/esm/ultramodern-workspace/generation-result.js +6 -6
- package/dist/esm/ultramodern-workspace/index.js +1 -0
- package/dist/esm/ultramodern-workspace/mf-validation.js +516 -0
- package/dist/esm/ultramodern-workspace/module-federation.js +34 -19
- package/dist/esm/ultramodern-workspace/overlays.js +2 -2
- package/dist/esm/ultramodern-workspace/package-json.js +56 -40
- package/dist/esm/ultramodern-workspace/policy.js +5 -5
- package/dist/esm/ultramodern-workspace/public-api.js +1 -0
- package/dist/esm/ultramodern-workspace/public-surface.js +2 -2
- package/dist/esm/ultramodern-workspace/versions.js +3 -1
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +107 -34
- package/dist/esm/ultramodern-workspace/write-workspace.js +64 -26
- package/dist/esm-node/index.js +37 -4
- package/dist/esm-node/locale/en.js +12 -2
- package/dist/esm-node/locale/zh.js +12 -2
- package/dist/esm-node/ultramodern-tooling/commands.js +133 -0
- package/dist/esm-node/ultramodern-tooling/config.js +121 -0
- package/dist/esm-node/ultramodern-workspace/add-vertical.js +88 -79
- package/dist/esm-node/ultramodern-workspace/{effect-api.js → api.js} +146 -147
- package/dist/esm-node/ultramodern-workspace/bridge-config.js +271 -0
- package/dist/esm-node/ultramodern-workspace/codesmith.js +1 -0
- package/dist/esm-node/ultramodern-workspace/contracts.js +129 -611
- package/dist/esm-node/ultramodern-workspace/demo-components.js +13 -13
- package/dist/esm-node/ultramodern-workspace/descriptors.js +11 -11
- package/dist/esm-node/ultramodern-workspace/fs-io.js +116 -2
- package/dist/esm-node/ultramodern-workspace/generation-result.js +6 -6
- package/dist/esm-node/ultramodern-workspace/index.js +1 -0
- package/dist/esm-node/ultramodern-workspace/mf-validation.js +517 -0
- package/dist/esm-node/ultramodern-workspace/module-federation.js +34 -19
- package/dist/esm-node/ultramodern-workspace/overlays.js +2 -2
- package/dist/esm-node/ultramodern-workspace/package-json.js +56 -40
- package/dist/esm-node/ultramodern-workspace/policy.js +5 -5
- package/dist/esm-node/ultramodern-workspace/public-api.js +1 -0
- package/dist/esm-node/ultramodern-workspace/public-surface.js +2 -2
- package/dist/esm-node/ultramodern-workspace/versions.js +3 -1
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +107 -34
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +64 -26
- package/dist/types/locale/en.d.ts +10 -0
- package/dist/types/locale/index.d.ts +20 -0
- package/dist/types/locale/zh.d.ts +10 -0
- package/dist/types/ultramodern-tooling/commands.d.ts +1 -0
- package/dist/types/ultramodern-tooling/config.d.ts +43 -0
- package/dist/types/ultramodern-workspace/add-vertical.d.ts +5 -2
- package/dist/types/ultramodern-workspace/api.d.ts +73 -0
- package/dist/types/ultramodern-workspace/bridge-config.d.ts +64 -0
- package/dist/types/ultramodern-workspace/codesmith.d.ts +1 -0
- package/dist/types/ultramodern-workspace/contracts.d.ts +2 -17
- package/dist/types/ultramodern-workspace/descriptors.d.ts +10 -10
- package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -0
- package/dist/types/ultramodern-workspace/index.d.ts +2 -0
- package/dist/types/ultramodern-workspace/mf-validation.d.ts +27 -0
- package/dist/types/ultramodern-workspace/package-json.d.ts +5 -4
- package/dist/types/ultramodern-workspace/public-api.d.ts +2 -0
- package/dist/types/ultramodern-workspace/types.d.ts +9 -7
- package/dist/types/ultramodern-workspace/versions.d.ts +2 -0
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +2 -7
- package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -2
- package/package.json +5 -3
- package/template-workspace/{.agents → .codex}/skills-lock.json +12 -12
- package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +2 -0
- package/template-workspace/.gitignore.handlebars +3 -0
- package/template-workspace/AGENTS.md.handlebars +11 -5
- package/template-workspace/README.md.handlebars +15 -12
- package/template-workspace/oxfmt.config.ts +1 -0
- package/template-workspace/oxlint.config.ts +1 -0
- package/template-workspace/patches/@tanstack__router-core@1.171.13.patch +51 -0
- package/template-workspace/pnpm-workspace.yaml.handlebars +4 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +77 -67
- package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +51 -8
- package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +344 -0
- package/templates/workspace-scripts/{check-ultramodern-i18n-boundaries.mjs → check-ultramodern-i18n-boundaries.mts} +1 -1
- package/templates/workspace-scripts/generate-public-surface-assets.mjs +246 -9
- package/templates/workspace-scripts/proof-cloudflare-version.mjs +277 -9
- package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +35 -10
- package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +165 -2
- package/templates/workspace-scripts/ultramodern-typecheck.mjs +4 -2
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +840 -84
- package/dist/types/ultramodern-workspace/effect-api.d.ts +0 -73
- /package/template-workspace/{.agents → .codex}/rstackjs-agent-skills-LICENSE +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsbuild-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/command-map.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/common-analysis-patterns.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rslib-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rslib-modern-package/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/bottlenecks.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/tracing-guide.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/scripts/analyze_trace.js +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rstest-best-practices/SKILL.md +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UltraModern Agent Contract
|
|
2
2
|
|
|
3
3
|
This workspace is generated as an agent-ready UltraModern.js SuperApp shell.
|
|
4
|
-
|
|
4
|
+
Codex should treat the files under `.codex/skills` as local project
|
|
5
5
|
instructions, not optional reading.
|
|
6
6
|
|
|
7
7
|
## Quality Gates
|
|
@@ -19,7 +19,7 @@ baseline; do not reintroduce Corepack or older pnpm aliases.
|
|
|
19
19
|
- `pnpm check` is a local convenience aggregate for the primitive gates.
|
|
20
20
|
- Generated CI runs primitive gates as separate matrix jobs instead of calling `pnpm check`.
|
|
21
21
|
- Generated Codex stop hooks and subagent-stop hooks run `pnpm format && pnpm lint:fix && pnpm check`.
|
|
22
|
-
- `postinstall` formats the generated tree and installs `lefthook`. It never
|
|
22
|
+
- `postinstall` formats the generated tree, installs/updates pinned Codex skills, and installs `lefthook`. It never installs system packages. Clone-backed public skills are attempted by default; offline clone failures are advisory. Reference repos remain an explicit `pnpm agents:refs:install` step. Generated `lefthook.yml` runs separate format and lint-fix commands on pre-commit; pre-push runs read-only primitive gates in parallel.
|
|
23
23
|
|
|
24
24
|
## Localized Routes
|
|
25
25
|
|
|
@@ -48,7 +48,13 @@ Use these skills when the task touches the matching subsystem:
|
|
|
48
48
|
- `rstest-best-practices`: Rstest configuration, test writing, mocking, snapshots, coverage, and CI test behavior.
|
|
49
49
|
- `mf`: Module Federation docs, Modern.js integration, DTS/type checks, shared dependency checks, runtime errors, and observability troubleshooting.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Skill bodies are lockfile-pinned in `.codex/skills-lock.json` and installed
|
|
52
|
+
into the repo-owned `.codex/skills` directory by default. The installer updates
|
|
53
|
+
only pinned skill directories and preserves unrelated user skills already
|
|
54
|
+
present under `.codex/skills`. Set `ULTRAMODERN_SKIP_CODEX_SKILLS=1` or
|
|
55
|
+
`ULTRAMODERN_CODEX_SKILLS=0` to opt out during install. `pnpm skills:check` is
|
|
56
|
+
advisory when local skill bodies are missing so offline CI can still run the
|
|
57
|
+
normal gate.
|
|
52
58
|
|
|
53
59
|
## Private Skills
|
|
54
60
|
|
|
@@ -58,7 +64,7 @@ ScriptedAlchemy/TechsioCZ skills are private and are cloned only when the curren
|
|
|
58
64
|
pnpm skills:install
|
|
59
65
|
```
|
|
60
66
|
|
|
61
|
-
The installer copies only the pinned private skills from `.
|
|
67
|
+
The installer copies only the pinned private skills from `.codex/skills-lock.json`: `plan-graph`, `dag`, `subagent-graph`, `helm`, and `debugger-mode`.
|
|
62
68
|
|
|
63
69
|
## Agent Reference Repositories
|
|
64
70
|
|
|
@@ -85,4 +91,4 @@ Agents may read files under `repos/` to understand upstream patterns, APIs, and
|
|
|
85
91
|
|
|
86
92
|
## Skill Provenance
|
|
87
93
|
|
|
88
|
-
The
|
|
94
|
+
The Rstack skills, public Module Federation skill, and private TechsioCZ skill set are pinned in `.codex/skills-lock.json`. Do not update, remove, or replace them casually. If a skill needs updating, update the lock file and run the affected primitive gate plus `pnpm check`.
|
|
@@ -80,11 +80,14 @@ UltraModern.js source lookup using squashed git subtrees) are an explicit
|
|
|
80
80
|
opt-in step: run `pnpm agents:refs:install` when you want them. `pnpm install`
|
|
81
81
|
never clones repositories.
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
Codex skill bodies are lockfile-pinned in `.codex/skills-lock.json` and
|
|
84
|
+
repo-owned under `.codex/skills`. `pnpm install` runs the bootstrap by default:
|
|
85
|
+
vendored pinned skills are copied locally, clone-backed public skills are
|
|
86
|
+
fetched when network access is available, and offline clone failures remain
|
|
87
|
+
advisory. Existing unrelated `.codex/skills/*` directories are preserved. Set
|
|
88
|
+
`ULTRAMODERN_SKIP_CODEX_SKILLS=1` or `ULTRAMODERN_CODEX_SKILLS=0` to opt out.
|
|
89
|
+
`pnpm skills:check` is advisory when local skill bodies are missing so offline
|
|
90
|
+
CI can still run the normal gate.
|
|
88
91
|
|
|
89
92
|
The topology and ownership metadata are generated under `topology/`. The
|
|
90
93
|
workspace also ships `.github/workflows/ultramodern-workspace-gates.yml` and
|
|
@@ -93,12 +96,12 @@ actions, frozen installs, StepSecurity audit-mode runner hardening, dependency
|
|
|
93
96
|
dashboard review, one-day release age, grouped updates, and manual approval for
|
|
94
97
|
major upgrades.
|
|
95
98
|
|
|
96
|
-
Package source
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
Package source provenance is recorded in `.modernjs/ultramodern.json`. The
|
|
100
|
+
default strategy keeps UltraModern.js runtime and tooling packages on
|
|
101
|
+
`workspace:*` for monorepo development. To create a workspace that can install
|
|
102
|
+
those packages outside the monorepo, generate with
|
|
103
|
+
`--ultramodern-package-source install`; generated shared packages still use
|
|
104
|
+
`workspace:*` because they are part of this workspace.
|
|
102
105
|
|
|
103
106
|
## Public URL Environment Variables
|
|
104
107
|
|
|
@@ -151,7 +154,7 @@ pnpm cloudflare:proof -- --require-public-urls
|
|
|
151
154
|
| Package cohort mismatch | Regenerate with one package source strategy, run `mise install`, then rerun `pnpm install` from the activated shell. | Generated workspace package source metadata |
|
|
152
155
|
| Install failure | Check the active Node/pnpm from `mise install`; rerun `pnpm install` after the shell sees the pinned versions. | Toolchain setup |
|
|
153
156
|
| Build failure | Run the matching primitive gate (`pnpm lint`, `pnpm typecheck`, `pnpm i18n:boundaries`, `pnpm contract:check`) before `pnpm build`; fix the owning failure first. | Owning package or generated contract |
|
|
154
|
-
| Missing public URL | Set the env key
|
|
157
|
+
| Missing public URL | Set the app public URL env key recorded in `.modernjs/ultramodern.json`, for example `ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP`. | Deployment operator |
|
|
155
158
|
| Cloudflare credentials | Confirm Wrangler credentials before `pnpm cloudflare:deploy`; local checks do not prove live Worker access. | Deployment operator |
|
|
156
159
|
| Asset or CSS 404 | Rebuild with `pnpm build` or `pnpm cloudflare:deploy` and inspect emitted Modern/Rspack asset paths instead of hardcoding CSS URLs. | Framework/runtime asset pipeline |
|
|
157
160
|
| Federation manifest failure | Run the shell and vertical build scripts, then check each deployed `/mf-manifest.json` URL used by the shell. | Module Federation owner |
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
diff --git a/dist/cjs/load-matches.cjs b/dist/cjs/load-matches.cjs
|
|
2
|
+
index c09976a80c2c112b7dac6f941e643c81eeaf8d52..ec5156d89e9c5924a9ec0c19aad79711124f9ff4 100644
|
|
3
|
+
--- a/dist/cjs/load-matches.cjs
|
|
4
|
+
+++ b/dist/cjs/load-matches.cjs
|
|
5
|
+
@@ -442,0 +443 @@
|
|
6
|
+
+ if (!match) return;
|
|
7
|
+
@@ -472,0 +474 @@
|
|
8
|
+
+ if (!match) return inner.matches[index];
|
|
9
|
+
@@ -487,0 +490 @@
|
|
10
|
+
+ if (!match) return inner.matches[index];
|
|
11
|
+
@@ -503 +506 @@
|
|
12
|
+
- return inner.router.getMatch(matchId);
|
|
13
|
+
+ return inner.router.getMatch(matchId) ?? inner.matches[index];
|
|
14
|
+
diff --git a/dist/esm/load-matches.js b/dist/esm/load-matches.js
|
|
15
|
+
index bcea2e0d88d037a01b93bf36dd6e643f98028e83..57484bf2825dab47030a1d4f905b9fb2e6067310 100644
|
|
16
|
+
--- a/dist/esm/load-matches.js
|
|
17
|
+
+++ b/dist/esm/load-matches.js
|
|
18
|
+
@@ -442,0 +443 @@
|
|
19
|
+
+ if (!match) return;
|
|
20
|
+
@@ -472,0 +474 @@
|
|
21
|
+
+ if (!match) return inner.matches[index];
|
|
22
|
+
@@ -487,0 +490 @@
|
|
23
|
+
+ if (!match) return inner.matches[index];
|
|
24
|
+
@@ -503 +506 @@
|
|
25
|
+
- return inner.router.getMatch(matchId);
|
|
26
|
+
+ return inner.router.getMatch(matchId) ?? inner.matches[index];
|
|
27
|
+
diff --git a/src/load-matches.ts b/src/load-matches.ts
|
|
28
|
+
index f901a0c97ddf0618dd83229ac260277b46e2676d..76674e01e89ac2cbaba4d776c2be3bf0e3fdb432 100644
|
|
29
|
+
--- a/src/load-matches.ts
|
|
30
|
+
+++ b/src/load-matches.ts
|
|
31
|
+
@@ -838 +838,4 @@
|
|
32
|
+
- const match = inner.router.getMatch(matchId)!
|
|
33
|
+
+ const match = inner.router.getMatch(matchId)
|
|
34
|
+
+ if (!match) {
|
|
35
|
+
+ return
|
|
36
|
+
+ }
|
|
37
|
+
@@ -906 +909,4 @@
|
|
38
|
+
- const match = inner.router.getMatch(matchId)!
|
|
39
|
+
+ const match = inner.router.getMatch(matchId)
|
|
40
|
+
+ if (!match) {
|
|
41
|
+
+ return inner.matches[index]!
|
|
42
|
+
+ }
|
|
43
|
+
@@ -936 +942,4 @@
|
|
44
|
+
- const match = inner.router.getMatch(matchId)!
|
|
45
|
+
+ const match = inner.router.getMatch(matchId)
|
|
46
|
+
+ if (!match) {
|
|
47
|
+
+ return inner.matches[index]!
|
|
48
|
+
+ }
|
|
49
|
+
@@ -955 +964 @@
|
|
50
|
+
- return inner.router.getMatch(matchId)!
|
|
51
|
+
+ return inner.router.getMatch(matchId) ?? inner.matches[index]!
|
|
@@ -41,6 +41,7 @@ peerDependencyRules:
|
|
|
41
41
|
|
|
42
42
|
overrides:
|
|
43
43
|
'@tanstack/react-router': {{tanstackRouterVersion}}
|
|
44
|
+
'@tanstack/router-core': {{tanstackRouterCoreVersion}}
|
|
44
45
|
node-fetch: '{{nodeFetchVersion}}'
|
|
45
46
|
|
|
46
47
|
allowBuilds:
|
|
@@ -51,3 +52,6 @@ allowBuilds:
|
|
|
51
52
|
msgpackr-extract: true
|
|
52
53
|
sharp: true
|
|
53
54
|
workerd: true
|
|
55
|
+
|
|
56
|
+
patchedDependencies:
|
|
57
|
+
'@tanstack/router-core@{{tanstackRouterCoreVersion}}': patches/@tanstack__router-core@{{tanstackRouterCoreVersion}}.patch
|
|
@@ -2,19 +2,22 @@ import { execFileSync } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
|
|
6
7
|
const root = process.cwd();
|
|
7
|
-
const
|
|
8
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const templateWorkspaceDir = path.resolve(scriptDir, '..');
|
|
10
|
+
const vendoredSkillsDir = path.join(templateWorkspaceDir, '.codex/skills');
|
|
11
|
+
const lockPath = path.join(root, '.codex/skills-lock.json');
|
|
8
12
|
const checkOnly = process.argv.includes('--check');
|
|
9
|
-
const force = process.argv.includes('--force');
|
|
10
13
|
const postinstall = process.argv.includes('--postinstall');
|
|
11
14
|
const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
|
|
12
15
|
const falsy = value => /^(0|false|no|off)$/i.test(String(value ?? ''));
|
|
13
16
|
const skipRequested =
|
|
14
|
-
truthy(process.env.
|
|
15
|
-
falsy(process.env.
|
|
17
|
+
truthy(process.env.ULTRAMODERN_SKIP_CODEX_SKILLS) ||
|
|
18
|
+
falsy(process.env.ULTRAMODERN_CODEX_SKILLS);
|
|
16
19
|
const cloneTimeoutMs = Number.parseInt(
|
|
17
|
-
process.env.
|
|
20
|
+
process.env.ULTRAMODERN_CODEX_SKILLS_CLONE_TIMEOUT_MS ?? '60000',
|
|
18
21
|
10,
|
|
19
22
|
);
|
|
20
23
|
|
|
@@ -60,7 +63,7 @@ const requireGit = () => {
|
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
throw new Error(
|
|
63
|
-
'Git is required to install
|
|
66
|
+
'Git is required to install clone-backed Codex skills. Install git yourself (for example "brew install git" or "sudo apt-get install git") and run pnpm skills:install again. This script never installs system packages on your behalf.',
|
|
64
67
|
);
|
|
65
68
|
};
|
|
66
69
|
|
|
@@ -172,31 +175,42 @@ const resolveSkillDir = (sourceRoot, skillName) => {
|
|
|
172
175
|
};
|
|
173
176
|
|
|
174
177
|
if (!fs.existsSync(lockPath)) {
|
|
175
|
-
console.error('Missing .
|
|
178
|
+
console.error('Missing .codex/skills-lock.json');
|
|
176
179
|
process.exit(1);
|
|
177
180
|
}
|
|
178
181
|
|
|
179
182
|
const lock = readJson(lockPath);
|
|
180
|
-
const installDir = path.join(root, lock.installDir ?? '.
|
|
183
|
+
const installDir = path.join(root, lock.installDir ?? '.codex/skills');
|
|
181
184
|
const sources = lock.sources ?? [];
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
);
|
|
185
|
+
const vendoredSources = sources.filter(source => source.install === 'vendored');
|
|
186
|
+
const cloneSources = sources.filter(source => source.install === 'clone');
|
|
185
187
|
const optionalCloneSources = sources.filter(
|
|
186
188
|
source => source.install === 'clone-if-authorized',
|
|
187
189
|
);
|
|
188
|
-
const
|
|
189
|
-
[...
|
|
190
|
-
(source.baseline ?? []).map(skill => skill.name),
|
|
190
|
+
const explicitSourceSkillNames = new Set(
|
|
191
|
+
[...vendoredSources, ...cloneSources, ...optionalCloneSources].flatMap(
|
|
192
|
+
source => (source.baseline ?? []).map(skill => skill.name),
|
|
191
193
|
),
|
|
192
194
|
);
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
const skillsForSource = source =>
|
|
196
|
+
source.baseline ??
|
|
197
|
+
(source.install === 'vendored'
|
|
198
|
+
? (lock.baseline ?? []).filter(
|
|
199
|
+
skill => !explicitSourceSkillNames.has(skill.name),
|
|
200
|
+
)
|
|
201
|
+
: []);
|
|
202
|
+
const lockedSkillNames = (lock.baseline ?? []).map(skill => skill.name);
|
|
203
|
+
const installedSkillNames = () =>
|
|
204
|
+
lockedSkillNames.filter(skillName =>
|
|
205
|
+
fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
206
|
+
);
|
|
207
|
+
const missingSkillNames = () =>
|
|
208
|
+
lockedSkillNames.filter(
|
|
209
|
+
skillName => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
210
|
+
);
|
|
197
211
|
|
|
198
212
|
if (skipRequested) {
|
|
199
|
-
const reason = '
|
|
213
|
+
const reason = 'Codex skills bootstrap skipped by environment';
|
|
200
214
|
if (checkOnly) {
|
|
201
215
|
console.log(reason);
|
|
202
216
|
process.exit(0);
|
|
@@ -207,80 +221,76 @@ if (skipRequested) {
|
|
|
207
221
|
}
|
|
208
222
|
|
|
209
223
|
if (checkOnly) {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
skillName => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
214
|
-
);
|
|
215
|
-
const missingCloneInstalled = [
|
|
216
|
-
...requiredCloneSources,
|
|
217
|
-
...optionalCloneSources,
|
|
218
|
-
].flatMap(source =>
|
|
219
|
-
(source.baseline ?? [])
|
|
220
|
-
.map(skill => skill.name)
|
|
221
|
-
.filter(
|
|
222
|
-
skillName =>
|
|
223
|
-
!fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
224
|
-
),
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
if (missingVendored.length > 0) {
|
|
228
|
-
console.error(
|
|
229
|
-
`Required agent skills not installed: ${missingVendored.join(', ')}. Run pnpm skills:install.`,
|
|
230
|
-
);
|
|
231
|
-
process.exit(1);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (missingCloneInstalled.length > 0) {
|
|
224
|
+
const missing = missingSkillNames();
|
|
225
|
+
const installed = installedSkillNames();
|
|
226
|
+
if (missing.length > 0) {
|
|
235
227
|
console.log(
|
|
236
|
-
`Advisory:
|
|
228
|
+
`Advisory: pinned Codex skills are not installed: ${missing.join(', ')}. This is expected in offline postinstall runs and fresh check-only CI; run pnpm skills:install when you need local skill bodies.`,
|
|
237
229
|
);
|
|
238
230
|
} else {
|
|
239
|
-
console.log('All pinned
|
|
231
|
+
console.log('All pinned Codex skills are installed.');
|
|
232
|
+
}
|
|
233
|
+
if (installed.length > 0) {
|
|
234
|
+
console.log(`Installed Codex skills: ${installed.join(', ')}.`);
|
|
240
235
|
}
|
|
241
236
|
process.exit(0);
|
|
242
237
|
}
|
|
243
238
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
|
|
239
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
240
|
+
|
|
241
|
+
const installSkillFromDir = (sourceSkillDir, skillName) => {
|
|
242
|
+
const targetSkillDir = path.join(installDir, skillName);
|
|
243
|
+
if (path.resolve(sourceSkillDir) === path.resolve(targetSkillDir)) {
|
|
244
|
+
console.log(`Pinned Codex skill ${skillName} is already present`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (fs.existsSync(targetSkillDir)) {
|
|
248
|
+
removeTree(targetSkillDir);
|
|
249
|
+
}
|
|
250
|
+
fs.mkdirSync(path.dirname(targetSkillDir), { recursive: true });
|
|
251
|
+
fs.cpSync(sourceSkillDir, targetSkillDir, { recursive: true });
|
|
252
|
+
console.log(`Installed Codex skill ${skillName}`);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
for (const source of vendoredSources) {
|
|
256
|
+
for (const skill of skillsForSource(source)) {
|
|
257
|
+
const sourceSkillDir = resolveSkillDir(vendoredSkillsDir, skill.name);
|
|
258
|
+
if (!sourceSkillDir) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Vendored Codex skill ${skill.name} not found in ${vendoredSkillsDir}`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
installSkillFromDir(sourceSkillDir, skill.name);
|
|
264
|
+
}
|
|
250
265
|
}
|
|
251
266
|
|
|
252
|
-
|
|
253
|
-
|
|
267
|
+
const cloneInstallSources = postinstall
|
|
268
|
+
? cloneSources
|
|
269
|
+
: [...cloneSources, ...optionalCloneSources];
|
|
254
270
|
|
|
255
|
-
for (const source of
|
|
271
|
+
for (const source of cloneInstallSources) {
|
|
256
272
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ultramodern-skills-'));
|
|
257
273
|
try {
|
|
258
274
|
try {
|
|
275
|
+
requireGit();
|
|
259
276
|
cloneSource(source, tempDir);
|
|
260
277
|
} catch (error) {
|
|
261
278
|
if (source.install === 'clone-if-authorized' || postinstall) {
|
|
262
|
-
console.warn(
|
|
279
|
+
console.warn(
|
|
280
|
+
`Advisory: unable to install Codex skills from ${source.repository}; ${error.message}. Offline postinstall may continue. Run pnpm skills:install later when network access is available.`,
|
|
281
|
+
);
|
|
263
282
|
continue;
|
|
264
283
|
}
|
|
265
284
|
throw error;
|
|
266
285
|
}
|
|
267
|
-
for (const skill of source
|
|
286
|
+
for (const skill of skillsForSource(source)) {
|
|
268
287
|
const sourceSkillDir = resolveSkillDir(tempDir, skill.name);
|
|
269
288
|
if (!sourceSkillDir) {
|
|
270
289
|
throw new Error(
|
|
271
290
|
`Skill ${skill.name} not found in ${source.repository}`,
|
|
272
291
|
);
|
|
273
292
|
}
|
|
274
|
-
|
|
275
|
-
if (fs.existsSync(targetSkillDir)) {
|
|
276
|
-
if (!force) {
|
|
277
|
-
console.log(`Skipping existing ${skill.name}`);
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
removeTree(targetSkillDir);
|
|
281
|
-
}
|
|
282
|
-
fs.cpSync(sourceSkillDir, targetSkillDir, { recursive: true });
|
|
283
|
-
console.log(`Installed ${skill.name}`);
|
|
293
|
+
installSkillFromDir(sourceSkillDir, skill.name);
|
|
284
294
|
}
|
|
285
295
|
} finally {
|
|
286
296
|
removeTree(tempDir);
|
|
@@ -2,19 +2,62 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
const root = process.cwd();
|
|
5
|
-
const
|
|
6
|
-
root,
|
|
7
|
-
'.modernjs/ultramodern-generated-contract.json',
|
|
8
|
-
);
|
|
9
|
-
const generatedContract = fs.existsSync(generatedContractPath)
|
|
10
|
-
? JSON.parse(fs.readFileSync(generatedContractPath, 'utf-8'))
|
|
11
|
-
: undefined;
|
|
5
|
+
const compactConfigPath = path.join(root, '.modernjs/ultramodern.json');
|
|
12
6
|
const defaultAppDirs = {{defaultAppDirsJson}};
|
|
13
7
|
|
|
8
|
+
function readJson(filePath) {
|
|
9
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeRelativePath(value) {
|
|
13
|
+
return String(value ?? '').replace(/\\/gu, '/').replace(/^\.\/+/u, '');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readGeneratedContractView() {
|
|
17
|
+
if (fs.existsSync(compactConfigPath)) {
|
|
18
|
+
const compactConfig = readJson(compactConfigPath);
|
|
19
|
+
return {
|
|
20
|
+
sourcePath: compactConfigPath,
|
|
21
|
+
apps: Array.isArray(compactConfig.topology?.apps)
|
|
22
|
+
? compactConfig.topology.apps.map(app => {
|
|
23
|
+
const moduleFederation =
|
|
24
|
+
app.moduleFederation && typeof app.moduleFederation === 'object'
|
|
25
|
+
? app.moduleFederation
|
|
26
|
+
: {};
|
|
27
|
+
return {
|
|
28
|
+
id: String(app.id),
|
|
29
|
+
path:
|
|
30
|
+
typeof app.path === 'string'
|
|
31
|
+
? normalizeRelativePath(app.path)
|
|
32
|
+
: '.',
|
|
33
|
+
moduleFederation: {
|
|
34
|
+
exposes: Array.isArray(moduleFederation.exposes)
|
|
35
|
+
? moduleFederation.exposes.filter(
|
|
36
|
+
expose => typeof expose === 'string',
|
|
37
|
+
)
|
|
38
|
+
: [],
|
|
39
|
+
dts: {
|
|
40
|
+
compilerInstance:
|
|
41
|
+
moduleFederation.dts?.compilerInstance ?? 'tsgo',
|
|
42
|
+
tsConfigPath:
|
|
43
|
+
moduleFederation.dts?.tsConfigPath ??
|
|
44
|
+
'./tsconfig.mf-types.json',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
})
|
|
49
|
+
: [],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
throw new Error('Missing UltraModern config. Expected .modernjs/ultramodern.json.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const generatedContract = readGeneratedContractView();
|
|
56
|
+
|
|
14
57
|
const args = process.argv.slice(2);
|
|
15
58
|
if (args.includes('--help') || args.includes('-h')) {
|
|
16
59
|
process.stdout.write(`Usage:
|
|
17
|
-
node scripts/assert-mf-types.
|
|
60
|
+
node scripts/assert-mf-types.mts [app-dir...]
|
|
18
61
|
|
|
19
62
|
Checks that every Module Federation remote with exposed modules emitted a non-empty dist/@mf-types.zip archive and uses the workspace TypeScript compiler.
|
|
20
63
|
`);
|