@neocompose/cli 0.61.1 → 0.61.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.61.2] - 2026-09-30
4
+
5
+ - Delete hidden collection entry members when their owning class or collection declaration is removed or changed to a scalar, while preserving entries still used by surviving declarations.
6
+
3
7
  ## [0.61.1] - 2026-09-30
4
8
 
5
9
  - Resolve and emit lookup dialogue group collections as `Class.Member` and `Reference(root.Assets.Member)`, including lists created in the same push. Existing raw-ID references remain readable.
package/dist/neo.mjs CHANGED
@@ -49838,6 +49838,40 @@ function descendantClassIdsInChildIndex(classId, childrenByClassId) {
49838
49838
  }
49839
49839
  return result;
49840
49840
  }
49841
+ function addDependentMemberIds(memberIds, members) {
49842
+ const childIdsByParentId = /* @__PURE__ */ new Map();
49843
+ const entryIdByOwnerId = /* @__PURE__ */ new Map();
49844
+ const remainingOwnersByEntryId = /* @__PURE__ */ new Map();
49845
+ for (const member of members) {
49846
+ if (member.extendsMemberId) {
49847
+ const children = childIdsByParentId.get(member.extendsMemberId);
49848
+ if (children === void 0) {
49849
+ childIdsByParentId.set(member.extendsMemberId, [member.id]);
49850
+ } else children.push(member.id);
49851
+ }
49852
+ if (member.entryMemberId) {
49853
+ entryIdByOwnerId.set(member.id, member.entryMemberId);
49854
+ remainingOwnersByEntryId.set(
49855
+ member.entryMemberId,
49856
+ (remainingOwnersByEntryId.get(member.entryMemberId) ?? 0) + 1
49857
+ );
49858
+ }
49859
+ }
49860
+ const pending = [...memberIds];
49861
+ function include(memberId) {
49862
+ if (memberIds.has(memberId)) return;
49863
+ memberIds.add(memberId);
49864
+ pending.push(memberId);
49865
+ }
49866
+ for (let id2 = pending.pop(); id2 !== void 0; id2 = pending.pop()) {
49867
+ for (const childId of childIdsByParentId.get(id2) ?? []) include(childId);
49868
+ const entryId = entryIdByOwnerId.get(id2);
49869
+ if (entryId === void 0) continue;
49870
+ const remainingOwners = remainingOwnersByEntryId.get(entryId) - 1;
49871
+ remainingOwnersByEntryId.set(entryId, remainingOwners);
49872
+ if (remainingOwners === 0) include(entryId);
49873
+ }
49874
+ }
49841
49875
  var UnresolvedMemberInheritanceError, NO_CLASSES, NO_MEMBERS, instanceSurfaceMemo, storedInstanceMemo, readOnlyMemberMemo, staticMemberMemo;
49842
49876
  var init_inheritance = __esm({
49843
49877
  "../src/models/classes/inheritance.ts"() {
@@ -122263,6 +122297,61 @@ function recordUpsertChange(args) {
122263
122297
  casBaseHash: inConflictState ? args.base.conflictServerHash : args.base.contentHash
122264
122298
  };
122265
122299
  }
122300
+ function recordDeleteChange(base, file) {
122301
+ return {
122302
+ kind: "delete",
122303
+ recordKind: base.recordKind,
122304
+ recordId: base.recordId,
122305
+ file,
122306
+ baseData: base.data,
122307
+ baseContentHash: base.contentHash,
122308
+ casBaseHash: base.conflictServerHash ?? base.contentHash
122309
+ };
122310
+ }
122311
+ function appendCollectionEntryDeletes(workspace, reconstructed3, changes) {
122312
+ const releasedOwnerIds = /* @__PURE__ */ new Set();
122313
+ for (const change of changes) {
122314
+ if (change.recordKind !== "member") continue;
122315
+ if (change.kind === "delete") {
122316
+ releasedOwnerIds.add(change.recordId);
122317
+ continue;
122318
+ }
122319
+ const base = workspace.state.records[recordStateKey("member", change.recordId)];
122320
+ if (base === void 0) continue;
122321
+ const data = effectiveRecordData(base);
122322
+ if (isObjectRecord2(data) && typeof data.entryMemberId === "string" && data.entryMemberId !== change.nextData?.entryMemberId)
122323
+ releasedOwnerIds.add(change.recordId);
122324
+ }
122325
+ if (releasedOwnerIds.size === 0) return;
122326
+ const members = /* @__PURE__ */ new Map();
122327
+ function setOwnership(id2, data) {
122328
+ if (!isObjectRecord2(data)) return;
122329
+ const entryMemberId = data.entryMemberId;
122330
+ members.set(id2, {
122331
+ id: id2,
122332
+ // Reconstructed entries survive, including entries moved to a new owner.
122333
+ ...typeof entryMemberId === "string" && !reconstructed3.has(recordStateKey("member", entryMemberId)) ? { entryMemberId } : {}
122334
+ });
122335
+ }
122336
+ for (const record6 of Object.values(workspace.state.records)) {
122337
+ if (record6.recordKind === "member" && record6.conflictServerHash !== null)
122338
+ setOwnership(record6.recordId, effectiveRecordData(record6));
122339
+ }
122340
+ for (const record6 of reconstructed3.values()) {
122341
+ if (record6.recordKind === "member" && !releasedOwnerIds.has(record6.recordId))
122342
+ setOwnership(record6.recordId, record6.fullData);
122343
+ }
122344
+ const dependentIds = new Set(releasedOwnerIds);
122345
+ addDependentMemberIds(dependentIds, members.values());
122346
+ for (const id2 of dependentIds) {
122347
+ if (releasedOwnerIds.has(id2)) continue;
122348
+ const key = recordStateKey("member", id2);
122349
+ if (reconstructed3.has(key)) continue;
122350
+ const base = workspace.state.records[key];
122351
+ if (base === void 0 || base.conflictServerHash === null) continue;
122352
+ changes.push(recordDeleteChange(base, base.file ?? null));
122353
+ }
122354
+ }
122266
122355
  function listVirtualProjectSourceFilesV4(files) {
122267
122356
  const selected = files.filter((file) => {
122268
122357
  const kind = neoProjectSourceKind(file.path);
@@ -122790,16 +122879,9 @@ function computeWorkspaceStatus(workspace, options) {
122790
122879
  if (recordState.recordKind === "value") {
122791
122880
  deletedValueIds.add(recordState.recordId);
122792
122881
  }
122793
- changes.push({
122794
- kind: "delete",
122795
- recordKind: recordState.recordKind,
122796
- recordId: recordState.recordId,
122797
- file: recordFile,
122798
- baseData: recordState.data,
122799
- baseContentHash: recordState.contentHash,
122800
- casBaseHash: recordState.conflictServerHash !== void 0 ? recordState.conflictServerHash : recordState.contentHash
122801
- });
122882
+ changes.push(recordDeleteChange(recordState, recordFile));
122802
122883
  }
122884
+ appendCollectionEntryDeletes(workspace, reconstructed3, changes);
122803
122885
  const sourceTextByUri = new Map(
122804
122886
  sourceEntries.map((entry) => [entry.relPath, entry.source])
122805
122887
  );
@@ -124115,6 +124197,7 @@ var init_workspace_status_core = __esm({
124115
124197
  init_materialized_construction_cache();
124116
124198
  init_project_version_whole_graph_validation();
124117
124199
  init_value_base_desync();
124200
+ init_inheritance();
124118
124201
  ANIMATION_DOCUMENT_RECORD_KINDS = [
124119
124202
  ProjectRecordKind.Project,
124120
124203
  ProjectRecordKind.Class,
@@ -145620,7 +145703,7 @@ var init_registry2 = __esm({
145620
145703
  "../packages/manifest/schema-contract/registry.mjs"() {
145621
145704
  "use strict";
145622
145705
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
145623
- cliVersion: "0.61.1",
145706
+ cliVersion: "0.61.2",
145624
145707
  projectFileUploadBatchSize: 32,
145625
145708
  documentRecords: {
145626
145709
  member: {
@@ -154300,7 +154383,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
154300
154383
  async function main() {
154301
154384
  const args = parseArgs(process.argv.slice(2));
154302
154385
  if (args.command === "--version") {
154303
- console.log("0.61.1");
154386
+ console.log("0.61.2");
154304
154387
  return;
154305
154388
  }
154306
154389
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.61.1",
3
+ "version": "0.61.2",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.61.1 -->
12
+ <!-- reviewed-through-cli: 0.61.2 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -110,7 +110,7 @@ wrappers.
110
110
  The marker near the top of `SKILL.md` must exactly match the package version:
111
111
 
112
112
  ```html
113
- <!-- reviewed-through-cli: 0.61.1 -->
113
+ <!-- reviewed-through-cli: 0.61.2 -->
114
114
  ```
115
115
 
116
116
  The quoted version above is checked too, so this instruction cannot go stale
@@ -78,6 +78,12 @@ compilation, schema-commit materialization, seeded structural rows, and
78
78
  whole-graph validation — so a rejection reports before anything is sent. It
79
79
  does not prompt, upload, commit, or rewrite source.
80
80
 
81
+ Removing a class or collection declaration also deletes its hidden collection
82
+ entry members, including nested lists and dictionaries. Replacing a collection
83
+ with a scalar deletes its abandoned entries too. Entries used by surviving
84
+ declarations are retained. Review these derived deletions in `neo status` or
85
+ `neo diff` before pushing.
86
+
81
87
  Dry-run also compares the CLI's derived-edge extractor with the server version
82
88
  saved by the last pull. Run `neo pull` after upgrading the CLI or when an older
83
89
  workspace lacks that metadata. A newer server extractor requires a CLI