@zhuoyuezs/ml-platform 0.1.12 → 0.1.14

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/checksums.json CHANGED
@@ -7,18 +7,18 @@
7
7
  },
8
8
  {
9
9
  "path": "runtime/business-client/package-lock.json",
10
- "sha256": "sha256:cfd3633238713a21444bd4d1810e7ee2c48557157f9817be9b0e7c59a4dc46b3",
10
+ "sha256": "sha256:ce726848e97416159f1fe8141082f67927405b45de8367e35c3da30cb0e8a639",
11
11
  "size_bytes": 381
12
12
  },
13
13
  {
14
14
  "path": "runtime/business-client/package.json",
15
- "sha256": "sha256:e6bd1fd8a9cf49366a97f10e03b368c448d33f48df38f036a96c2979f1a2ec1b",
15
+ "sha256": "sha256:c275cc028d7f1e0257d1354ed2df082f879a6c79d17e73d65ae2e21b80dee33d",
16
16
  "size_bytes": 501
17
17
  },
18
18
  {
19
19
  "path": "runtime/business-client/src/catalog.js",
20
- "sha256": "sha256:5625abc155779d827850de475db104995feadea6b64d56419e3665005669225f",
21
- "size_bytes": 54291
20
+ "sha256": "sha256:6c8f800574fda6ccc4e6176d9d607d4408df2e88c8e9c33289701dd7699b50ca",
21
+ "size_bytes": 56017
22
22
  },
23
23
  {
24
24
  "path": "runtime/business-client/src/cli.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "ML 数据平台 business CLI 与 Agent Skills 管理工具",
5
5
  "bin": {
6
6
  "ml-platform": "scripts/main.js"
package/release.json CHANGED
@@ -13,8 +13,8 @@
13
13
  "entrypoint": "src/cli.js",
14
14
  "name": "ml-platform",
15
15
  "path": "runtime/business-client",
16
- "sha256": "sha256:0c928cad92c70c10b00d58a8bd9bd95f0bf88ac2f876c7967c67c5b17bfbfa2c",
17
- "version": "0.7.2"
16
+ "sha256": "sha256:b7c1b24987c680dc1b13bbcf49dc61c4856e9843a06499f78ed5bbd6ac10c0f5",
17
+ "version": "0.7.4"
18
18
  },
19
19
  "policy_sha256": "sha256:02fbde0134696b78c0c365d6e0b76c9814227208da5b2b3d4e5dbd82dc4a3606",
20
20
  "public_schema_versions": [
@@ -25,7 +25,7 @@
25
25
  "ml_data_platform.feature_set/v1",
26
26
  "ml_data_platform.dataset_manifest/v1"
27
27
  ],
28
- "release_version": "0.1.12",
28
+ "release_version": "0.1.14",
29
29
  "runtime_requirements": {
30
30
  "node": ">=18",
31
31
  "os": [
@@ -37,16 +37,16 @@
37
37
  "skills": {
38
38
  "feature-management": {
39
39
  "path": "skills/feature-management",
40
- "requires_cli": ">=0.7.2 <0.8.0",
41
- "revision": "0.1.12",
40
+ "requires_cli": ">=0.7.4 <0.8.0",
41
+ "revision": "0.1.14",
42
42
  "sha256": "sha256:182b6f2df4fe58c946e482dfaf416c7d5b78c6fde9c8c8d7293103246618cb4e"
43
43
  },
44
44
  "model-lifecycle-management": {
45
45
  "path": "skills/model-lifecycle-management",
46
- "requires_cli": ">=0.7.2 <0.8.0",
47
- "revision": "0.1.12",
46
+ "requires_cli": ">=0.7.4 <0.8.0",
47
+ "revision": "0.1.14",
48
48
  "sha256": "sha256:61ba17f955b36d1c2e8329a10454d040ee7eca5afdb90ff0914d3f85b6e2d203"
49
49
  }
50
50
  },
51
- "source_commit": "0246c26b396ce551fed3a9c8d4341a2230765025"
51
+ "source_commit": "9175c96d8475003b17c5e0c4c3df4f8cf8614c0f"
52
52
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform-business-client",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@zhuoyuezs/ml-platform-business-client",
9
- "version": "0.7.2",
9
+ "version": "0.7.4",
10
10
  "license": "UNLICENSED",
11
11
  "bin": {
12
12
  "ml-platform": "src/cli.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhuoyuezs/ml-platform-business-client",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "private": true,
5
5
  "description": "JavaScript implementation of the ML Platform business client",
6
6
  "bin": {
@@ -167,7 +167,22 @@ function loadCatalog(directory) {
167
167
  }
168
168
 
169
169
  async function fetchAll(client, endpoint, params = {}) { const rows = []; for (let offset = 0; ; offset += 500) { const response = await client.get(endpoint, { ...params, limit: 500, offset }); if (Array.isArray(response)) return response; const page = response.items; if (!Array.isArray(page)) throw new Error(`${endpoint} returned an invalid list response`); rows.push(...page); if (response.total == null || rows.length >= response.total || page.length < 500) return rows; } }
170
- async function snapshot(client, targetProject) { const scope = { project: targetProject ?? "default" }; const [parameters, operators, features, featureSets, datasets] = await Promise.all([fetchAll(client, "/parameters", scope), fetchAll(client, "/operators", scope), fetchAll(client, "/features", scope), fetchAll(client, "/feature-sets", scope), fetchAll(client, "/datasets", { ...scope, include_deleted: true })]); return { parameters: new Map(parameters.map((x) => [key(x), x])), operators: new Map(operators.map((x) => [key(normalizeRegistryOperator(x)), normalizeRegistryOperator(x)])), features: new Map(features.map((x) => [key(normalizeFeature(x)), normalizeFeature(x)])), feature_sets: new Map(featureSets.map((x) => [key(normalizeFeatureSet(x)), normalizeFeatureSet(x)])), datasets: new Map(datasets.filter((x) => !x.deleted_at).map((x) => [datasetKey(normalizeRegistryDataset(x)), normalizeRegistryDataset(x)])) }; }
170
+ async function snapshot(client, targetProject) { const scope = { project: targetProject ?? "default" }; const [parameters, operators, features, featureSets, datasets] = await Promise.all([fetchAll(client, "/parameters", scope), fetchAll(client, "/operators", scope), fetchAll(client, "/features", scope), fetchAll(client, "/feature-sets", scope), fetchAll(client, "/datasets", { ...scope, include_deleted: true })]); return { parameters: new Map(parameters.map((x) => [key(x), x])), operators: new Map(operators.map((x) => [key(x), x])), features: new Map(features.map((x) => [key(x), x])), feature_sets: new Map(featureSets.map((x) => [key(x), x])), datasets: new Map(datasets.filter((x) => !x.deleted_at).map((x) => [datasetKey(x), x])) }; }
171
+
172
+ async function hydrate(client, current, assets, endpoint, normalizer, keyFn = key, seen = new Set()) { for (const asset of assets) { const assetKey = keyFn(asset); if (current.has(assetKey) && !seen.has(assetKey)) { current.set(assetKey, normalizer(await client.get(endpoint(asset)))); seen.add(assetKey); } } }
173
+ async function hydrateCatalog(client, catalog, current) {
174
+ const hydrated = { parameters: new Set(), operators: new Set(), features: new Set(), feature_sets: new Set(), datasets: new Set() };
175
+ const resource = (prefix) => (asset) => `/${prefix}/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.name)}/${encodeURIComponent(asset.version)}`;
176
+ await hydrate(client, current.parameters, catalog.parameters, resource("parameters"), normalizeParameter, key, hydrated.parameters);
177
+ const operatorRefs = catalog.features.map((asset) => ({ project: asset.project, name: asset.operator, version: asset.operator_version }));
178
+ await hydrate(client, current.operators, [...catalog.operators.map((item) => item.spec), ...operatorRefs], resource("operators"), normalizeOperator, key, hydrated.operators);
179
+ const featureSetRefs = catalog.datasets.map((asset) => ({ project: asset.project, ...asset.feature_set }));
180
+ await hydrate(client, current.feature_sets, [...catalog.feature_sets, ...featureSetRefs], resource("feature-sets"), normalizeFeatureSet, key, hydrated.feature_sets);
181
+ await hydrate(client, current.datasets, catalog.datasets, (asset) => `/datasets/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.dataset_id)}/${encodeURIComponent(asset.dataset_version)}`, normalizeDataset, datasetKey, hydrated.datasets);
182
+ const declaredFeatureSets = new Map(catalog.feature_sets.map((asset) => [key(asset), asset]));
183
+ const featureRefs = catalog.datasets.flatMap((asset) => (declaredFeatureSets.get(referenceKey(asset.feature_set)) ?? current.feature_sets.get(referenceKey(asset.feature_set)) ?? { features: [] }).features.map((feature) => ({ project: asset.project, ...feature })));
184
+ await hydrate(client, current.features, [...catalog.features, ...featureRefs], resource("features"), normalizeFeature, key, hydrated.features);
185
+ }
171
186
 
172
187
  function requiresPackage(spec) { return ["custom_python", "feature", "spark_udf"].includes(spec.type) && spec.code_artifact == null && !String(spec.package_uri ?? "").startsWith("pythonpath://"); }
173
188
  function validateCatalog(catalog, current) {
@@ -198,8 +213,7 @@ function assertImmutable(label, assetKey, candidate, existing) { if (existing &&
198
213
  function sha256File(file) { return `sha256:${crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex")}`; }
199
214
 
200
215
  async function applyCatalog(catalog, client, dryRun, targetProject) {
201
- validateCatalogProject(catalog, targetProject); const current = await snapshot(client, targetProject); validateCatalog(catalog, current); const groups = { parameters: catalog.parameters.length, operators: catalog.operators.length, features: catalog.features.length, feature_sets: catalog.feature_sets.length, datasets: catalog.datasets.length }; const summary = Object.fromEntries(Object.entries(groups).map(([name, count]) => [name, { declared: count, planned: 0, applied: 0, unchanged: 0 }]));
202
- for (const asset of catalog.parameters) { const assetKey = key(asset); if (current.parameters.has(assetKey)) current.parameters.set(assetKey, normalizeParameter(await client.get(`/parameters/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.name)}/${encodeURIComponent(asset.version)}`))); }
216
+ validateCatalogProject(catalog, targetProject); const current = await snapshot(client, targetProject); await hydrateCatalog(client, catalog, current); validateCatalog(catalog, current); const groups = { parameters: catalog.parameters.length, operators: catalog.operators.length, features: catalog.features.length, feature_sets: catalog.feature_sets.length, datasets: catalog.datasets.length }; const summary = Object.fromEntries(Object.entries(groups).map(([name, count]) => [name, { declared: count, planned: 0, applied: 0, unchanged: 0 }]));
203
217
  for (const asset of catalog.parameters) assertImmutable("parameter", key(asset), asset, current.parameters.get(key(asset)));
204
218
  for (const item of catalog.operators) { const existing = current.operators.get(key(item.spec)); if (!existing) continue; let candidate = item.spec; if (item.package_path) { if (existing.code_hash !== sha256File(item.package_path) || !existing.code_artifact) throw new Error(`operator version is immutable: ${key(item.spec)}; publish a new version`); candidate = normalizeOperator({ ...item.spec, code_hash: existing.code_artifact.sha256, package_uri: existing.code_artifact.uri, code_artifact: existing.code_artifact }); } assertImmutable("operator", key(item.spec), candidate, existing); }
205
219
  const plain = async (assets, existing, label, endpoint, keyFn = key, params) => { for (const asset of assets) { const assetKey = keyFn(asset); assertImmutable(label, assetKey, asset, existing.get(assetKey)); if (existing.has(assetKey)) summary[label].unchanged += 1; else if (dryRun) summary[label].planned += 1; else { await client.post(endpoint, asset, params); summary[label].applied += 1; } } };