@neocompose/cli 0.36.4 → 0.36.6
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,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.36.6] - 2026-08-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Keep normal pull's in-memory overlay of uncommitted static value seeds valid
|
|
8
|
+
for computed-initializer replay. This lets a pull reconcile source that
|
|
9
|
+
still has pending member identities after a successful remote commit without
|
|
10
|
+
requiring a destructive `neo pull --reset`.
|
|
11
|
+
|
|
12
|
+
## [0.36.5] - 2026-08-20
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Recover malformed persisted static members during pull without weakening
|
|
17
|
+
authored schema validation: orphaned rows are queued for deletion and
|
|
18
|
+
structurally owned rows are queued for an `isStatic` correction on the next
|
|
19
|
+
push. Diagnostics now identify the member id, name, and inferred owner kind.
|
|
20
|
+
|
|
3
21
|
## [0.36.4] - 2026-08-19
|
|
4
22
|
|
|
5
23
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -39618,9 +39618,11 @@ function assertStaticMemberInvariants(manifest) {
|
|
|
39618
39618
|
const path = `$.members[${memberIndex}]`;
|
|
39619
39619
|
const owner = requireRecord(member.owner, `${path}.owner`);
|
|
39620
39620
|
if (owner.kind !== "classMember") {
|
|
39621
|
+
const memberName = typeof member.name === "string" ? member.name : "(unnamed)";
|
|
39622
|
+
const ownerKind = typeof owner.kind === "string" ? owner.kind : "unknown";
|
|
39621
39623
|
invalid(
|
|
39622
39624
|
`${path}.owner`,
|
|
39623
|
-
|
|
39625
|
+
`static member ${JSON.stringify(memberName)} (${memberId}) has owner kind ${JSON.stringify(ownerKind)}; expected exactly one direct Class owner.`
|
|
39624
39626
|
);
|
|
39625
39627
|
}
|
|
39626
39628
|
const ownerClassId = nonEmptyString(owner.classId, `${path}.owner.classId`);
|
|
@@ -41593,6 +41595,18 @@ function documentsToProjectSchemaManifest(records2, optionsOrContext = {}) {
|
|
|
41593
41595
|
records2,
|
|
41594
41596
|
options.sourceContext ?? DEFAULT_DOCUMENT_TO_MANIFEST_CONTEXT
|
|
41595
41597
|
);
|
|
41598
|
+
let projectionContext = context;
|
|
41599
|
+
let recoveredMemberRecords;
|
|
41600
|
+
if (options.onInvalidStaticMemberOwnership !== void 0) {
|
|
41601
|
+
const normalizedMembers = new Map(context.normalizedMembers);
|
|
41602
|
+
recoveredMemberRecords = recoverInvalidStaticMemberOwnership(
|
|
41603
|
+
context.recordsByKind.get("member") ?? [],
|
|
41604
|
+
context,
|
|
41605
|
+
normalizedMembers,
|
|
41606
|
+
options.onInvalidStaticMemberOwnership
|
|
41607
|
+
);
|
|
41608
|
+
projectionContext = { ...context, normalizedMembers };
|
|
41609
|
+
}
|
|
41596
41610
|
const collections = {
|
|
41597
41611
|
classes: [],
|
|
41598
41612
|
constructors: [],
|
|
@@ -41608,7 +41622,8 @@ function documentsToProjectSchemaManifest(records2, optionsOrContext = {}) {
|
|
|
41608
41622
|
internalRecordRelations: []
|
|
41609
41623
|
};
|
|
41610
41624
|
for (const adapter of SCHEMA_RECORD_ADAPTERS) {
|
|
41611
|
-
const
|
|
41625
|
+
const rawAdapterRecords = context.recordsByKind.get(adapter.recordKind) ?? [];
|
|
41626
|
+
const adapterRecords = adapter.recordKind === "member" && recoveredMemberRecords !== void 0 ? recoveredMemberRecords : rawAdapterRecords;
|
|
41612
41627
|
if (adapter.cardinality === "one") {
|
|
41613
41628
|
if (adapterRecords.length !== 1) {
|
|
41614
41629
|
throw new Error(
|
|
@@ -41617,12 +41632,12 @@ function documentsToProjectSchemaManifest(records2, optionsOrContext = {}) {
|
|
|
41617
41632
|
}
|
|
41618
41633
|
collections[adapter.manifestCollection] = adapter.fromDocument(
|
|
41619
41634
|
adapterRecords[0],
|
|
41620
|
-
|
|
41635
|
+
projectionContext
|
|
41621
41636
|
);
|
|
41622
41637
|
continue;
|
|
41623
41638
|
}
|
|
41624
41639
|
collections[adapter.manifestCollection] = adapterRecords.map(
|
|
41625
|
-
(record3) => adapter.fromDocument(record3,
|
|
41640
|
+
(record3) => adapter.fromDocument(record3, projectionContext)
|
|
41626
41641
|
);
|
|
41627
41642
|
}
|
|
41628
41643
|
return parseProjectSchemaManifest({
|
|
@@ -41632,6 +41647,50 @@ function documentsToProjectSchemaManifest(records2, optionsOrContext = {}) {
|
|
|
41632
41647
|
...collections
|
|
41633
41648
|
});
|
|
41634
41649
|
}
|
|
41650
|
+
function recoverInvalidStaticMemberOwnership(records2, context, normalizedMembers, onRecovery) {
|
|
41651
|
+
const recovered = [];
|
|
41652
|
+
for (const record3 of records2) {
|
|
41653
|
+
const member = context.normalizedMembers.get(record3.recordId);
|
|
41654
|
+
if (member?.isStatic !== true) {
|
|
41655
|
+
recovered.push(record3);
|
|
41656
|
+
continue;
|
|
41657
|
+
}
|
|
41658
|
+
const owner = context.memberOwners.get(record3.recordId) ?? {
|
|
41659
|
+
kind: "loose"
|
|
41660
|
+
};
|
|
41661
|
+
if (owner.kind === "classMember") {
|
|
41662
|
+
recovered.push(record3);
|
|
41663
|
+
continue;
|
|
41664
|
+
}
|
|
41665
|
+
const ownerKind = typeof owner.kind === "string" ? owner.kind : "unknown";
|
|
41666
|
+
const memberName = typeof member.name === "string" ? member.name : record3.recordId;
|
|
41667
|
+
if (ownerKind === "loose") {
|
|
41668
|
+
normalizedMembers.delete(record3.recordId);
|
|
41669
|
+
onRecovery({
|
|
41670
|
+
memberId: record3.recordId,
|
|
41671
|
+
memberName,
|
|
41672
|
+
ownerKind,
|
|
41673
|
+
action: "delete"
|
|
41674
|
+
});
|
|
41675
|
+
continue;
|
|
41676
|
+
}
|
|
41677
|
+
onRecovery({
|
|
41678
|
+
memberId: record3.recordId,
|
|
41679
|
+
memberName,
|
|
41680
|
+
ownerKind,
|
|
41681
|
+
action: "demote"
|
|
41682
|
+
});
|
|
41683
|
+
normalizedMembers.set(record3.recordId, {
|
|
41684
|
+
...member,
|
|
41685
|
+
isStatic: false
|
|
41686
|
+
});
|
|
41687
|
+
recovered.push({
|
|
41688
|
+
...record3,
|
|
41689
|
+
data: { ...record3.data, isStatic: false }
|
|
41690
|
+
});
|
|
41691
|
+
}
|
|
41692
|
+
return recovered;
|
|
41693
|
+
}
|
|
41635
41694
|
function projectSchemaManifestToDocuments(manifestInput, context) {
|
|
41636
41695
|
const manifest = parseProjectSchemaManifest(manifestInput);
|
|
41637
41696
|
const emissionContext = {
|
|
@@ -80398,6 +80457,19 @@ var init_root_source = __esm({
|
|
|
80398
80457
|
}
|
|
80399
80458
|
});
|
|
80400
80459
|
|
|
80460
|
+
// src/project-source/static-member-ownership-recovery.ts
|
|
80461
|
+
function staticMemberOwnershipRecoveryMessage(recovery) {
|
|
80462
|
+
const identity2 = `${JSON.stringify(recovery.memberName)} (${recovery.memberId})`;
|
|
80463
|
+
return recovery.action === "delete" ? `Recovered malformed static member ${identity2}: it has no Class declaration, so no source was emitted and the next push will delete the orphaned record.` : `Recovered malformed static member ${identity2}: it is owned as ${recovery.ownerKind}, so source projected it as instance metadata and the next push will correct isStatic.`;
|
|
80464
|
+
}
|
|
80465
|
+
var STATIC_MEMBER_OWNERSHIP_RECOVERY_SOURCE;
|
|
80466
|
+
var init_static_member_ownership_recovery = __esm({
|
|
80467
|
+
"src/project-source/static-member-ownership-recovery.ts"() {
|
|
80468
|
+
"use strict";
|
|
80469
|
+
STATIC_MEMBER_OWNERSHIP_RECOVERY_SOURCE = "<project>";
|
|
80470
|
+
}
|
|
80471
|
+
});
|
|
80472
|
+
|
|
80401
80473
|
// ../src/models/animation/animation-clips.ts
|
|
80402
80474
|
function isWorldAnimationStructuralMember(memberId, members) {
|
|
80403
80475
|
const membersById = new Map(members.map((member) => [member.id, member]));
|
|
@@ -95029,7 +95101,13 @@ function computeWorkspaceStatus(workspace, options) {
|
|
|
95029
95101
|
};
|
|
95030
95102
|
}
|
|
95031
95103
|
const baseDocuments = schemaBaseDocuments(workspace);
|
|
95032
|
-
const
|
|
95104
|
+
const staticMemberOwnershipRecoveries = [];
|
|
95105
|
+
const baseManifest = baseDocuments.length === 0 ? void 0 : documentsToProjectSchemaManifest(baseDocuments, {
|
|
95106
|
+
onInvalidStaticMemberOwnership: (recovery) => staticMemberOwnershipRecoveries.push(recovery)
|
|
95107
|
+
});
|
|
95108
|
+
const orphanedStaticMemberKeys = new Set(
|
|
95109
|
+
staticMemberOwnershipRecoveries.filter((recovery) => recovery.action === "delete").map((recovery) => recordStateKey("member", recovery.memberId))
|
|
95110
|
+
);
|
|
95033
95111
|
let manifest;
|
|
95034
95112
|
let authoredValueSeeds = /* @__PURE__ */ new Map();
|
|
95035
95113
|
let staticMemberValueIds = /* @__PURE__ */ new Map();
|
|
@@ -95455,11 +95533,12 @@ function computeWorkspaceStatus(workspace, options) {
|
|
|
95455
95533
|
}
|
|
95456
95534
|
const deletedValueIds = /* @__PURE__ */ new Set();
|
|
95457
95535
|
for (const [key, recordState] of Object.entries(workspace.state.records)) {
|
|
95458
|
-
|
|
95536
|
+
const recordFile = recordState.file ?? (orphanedStaticMemberKeys.has(key) ? STATIC_MEMBER_OWNERSHIP_RECOVERY_SOURCE : void 0);
|
|
95537
|
+
if (recordFile === void 0) continue;
|
|
95459
95538
|
if (reconstructed3.has(key)) continue;
|
|
95460
95539
|
const fileStillBroken = parseErrors.some(
|
|
95461
|
-
(error) => error.file ===
|
|
95462
|
-
) || conflictedFiles.includes(
|
|
95540
|
+
(error) => error.file === recordFile && isBlockingSchemaSourceError(error)
|
|
95541
|
+
) || conflictedFiles.includes(recordFile);
|
|
95463
95542
|
if (fileStillBroken) continue;
|
|
95464
95543
|
if (recordState.recordKind === "value") {
|
|
95465
95544
|
deletedValueIds.add(recordState.recordId);
|
|
@@ -95468,7 +95547,7 @@ function computeWorkspaceStatus(workspace, options) {
|
|
|
95468
95547
|
kind: "delete",
|
|
95469
95548
|
recordKind: recordState.recordKind,
|
|
95470
95549
|
recordId: recordState.recordId,
|
|
95471
|
-
file:
|
|
95550
|
+
file: recordFile,
|
|
95472
95551
|
baseData: recordState.data,
|
|
95473
95552
|
baseContentHash: recordState.contentHash,
|
|
95474
95553
|
casBaseHash: recordState.conflictServerHash !== void 0 ? recordState.conflictServerHash : recordState.contentHash
|
|
@@ -96274,6 +96353,7 @@ var init_workspace_status_core = __esm({
|
|
|
96274
96353
|
init_value_sources();
|
|
96275
96354
|
init_lower_variants();
|
|
96276
96355
|
init_root_source();
|
|
96356
|
+
init_static_member_ownership_recovery();
|
|
96277
96357
|
init_root_value_paths();
|
|
96278
96358
|
init_project_documents();
|
|
96279
96359
|
init_animation_clips();
|
|
@@ -104152,7 +104232,10 @@ function emitProjectDocumentFilesV4(records2) {
|
|
|
104152
104232
|
data: record3.data
|
|
104153
104233
|
});
|
|
104154
104234
|
}
|
|
104155
|
-
const
|
|
104235
|
+
const staticMemberOwnershipRecoveries = [];
|
|
104236
|
+
const manifest = documentsToProjectSchemaManifest(schemaRecords, {
|
|
104237
|
+
onInvalidStaticMemberOwnership: (recovery) => staticMemberOwnershipRecoveries.push(recovery)
|
|
104238
|
+
});
|
|
104156
104239
|
const staticValues = emitStaticValueSourcesV4(records2, manifest);
|
|
104157
104240
|
const memberDefaults = emitMemberDefaultSourcesV4(records2, manifest);
|
|
104158
104241
|
const variantValues = emitVariantValueSourcesV4(records2, manifest);
|
|
@@ -104225,6 +104308,13 @@ function emitProjectDocumentFilesV4(records2) {
|
|
|
104225
104308
|
]) {
|
|
104226
104309
|
for (const key of file.recordKeys) recordFiles.set(key, file.path);
|
|
104227
104310
|
}
|
|
104311
|
+
for (const recovery of staticMemberOwnershipRecoveries) {
|
|
104312
|
+
if (recovery.action !== "delete") continue;
|
|
104313
|
+
recordFiles.set(
|
|
104314
|
+
`member:${recovery.memberId}`,
|
|
104315
|
+
STATIC_MEMBER_OWNERSHIP_RECOVERY_SOURCE
|
|
104316
|
+
);
|
|
104317
|
+
}
|
|
104228
104318
|
const analysis = compileNeoProjectSources(
|
|
104229
104319
|
files.map((file) => {
|
|
104230
104320
|
const kind = neoProjectSourceKind(file.path);
|
|
@@ -104252,7 +104342,8 @@ ${errors.map(
|
|
|
104252
104342
|
recordFiles,
|
|
104253
104343
|
analysis,
|
|
104254
104344
|
materializedConstructors,
|
|
104255
|
-
formAlternates: source.formAlternates
|
|
104345
|
+
formAlternates: source.formAlternates,
|
|
104346
|
+
staticMemberOwnershipRecoveries
|
|
104256
104347
|
};
|
|
104257
104348
|
}
|
|
104258
104349
|
function relationEndpointExpressions(records2) {
|
|
@@ -104305,6 +104396,7 @@ var init_project_documents = __esm({
|
|
|
104305
104396
|
init_root_value_paths();
|
|
104306
104397
|
init_source_diagnostics();
|
|
104307
104398
|
init_source_format();
|
|
104399
|
+
init_static_member_ownership_recovery();
|
|
104308
104400
|
PROJECT_SOURCE_ANALYSIS_V4_CACHE_PATH = ".neo/project-source-analysis-v4.json";
|
|
104309
104401
|
SCHEMA_RECORD_KINDS2 = /* @__PURE__ */ new Set([
|
|
104310
104402
|
"class",
|
|
@@ -105968,7 +106060,8 @@ function resetWorkspaceToProjectSourcesV4(workspace, document, options = {}) {
|
|
|
105968
106060
|
return {
|
|
105969
106061
|
written: emitted.files.length,
|
|
105970
106062
|
removed,
|
|
105971
|
-
fileCount: emitted.files.length
|
|
106063
|
+
fileCount: emitted.files.length,
|
|
106064
|
+
staticMemberOwnershipRecoveries: emitted.staticMemberOwnershipRecoveries
|
|
105972
106065
|
};
|
|
105973
106066
|
}
|
|
105974
106067
|
function preserveManagedSpecs(root) {
|
|
@@ -106393,25 +106486,25 @@ var init_project_file_pull = __esm({
|
|
|
106393
106486
|
});
|
|
106394
106487
|
|
|
106395
106488
|
// src/project-source/static-value-seed-records.ts
|
|
106396
|
-
function staticValueSeedEmitRecords(status, present) {
|
|
106489
|
+
function staticValueSeedEmitRecords(status, present, projectId) {
|
|
106397
106490
|
const records2 = /* @__PURE__ */ new Map();
|
|
106398
106491
|
if (status === null) return records2;
|
|
106399
106492
|
for (const [memberId, seed] of status.authoredValueSeeds) {
|
|
106400
106493
|
const rootId = seed.valueId ?? memberValueIdFromRecord(status, memberId);
|
|
106401
106494
|
if (rootId !== null) {
|
|
106402
|
-
addSeedRecord(records2, present, {
|
|
106495
|
+
addSeedRecord(records2, present, projectId, {
|
|
106403
106496
|
id: rootId,
|
|
106404
106497
|
memberId,
|
|
106405
106498
|
...seed.init === void 0 ? { value: seed.value, classId: seed.classId } : { init: seed.init }
|
|
106406
106499
|
});
|
|
106407
106500
|
}
|
|
106408
106501
|
for (const row of seed.values ?? []) {
|
|
106409
|
-
addSeedRecord(records2, present, { ...row });
|
|
106502
|
+
addSeedRecord(records2, present, projectId, { ...row });
|
|
106410
106503
|
}
|
|
106411
106504
|
}
|
|
106412
106505
|
return records2;
|
|
106413
106506
|
}
|
|
106414
|
-
function addSeedRecord(records2, present, data) {
|
|
106507
|
+
function addSeedRecord(records2, present, projectId, data) {
|
|
106415
106508
|
const key = `value:${data.id}`;
|
|
106416
106509
|
if (present.has(key)) return;
|
|
106417
106510
|
if (records2.has(key)) return;
|
|
@@ -106421,7 +106514,18 @@ function addSeedRecord(records2, present, data) {
|
|
|
106421
106514
|
// A seed has no committed content, so it has no server hash to carry.
|
|
106422
106515
|
contentHash: "",
|
|
106423
106516
|
deleted: false,
|
|
106424
|
-
|
|
106517
|
+
// These records exist only in normal pull's in-memory local projection,
|
|
106518
|
+
// but the value emitter deliberately validates the entire graph before it
|
|
106519
|
+
// replays any computed initializer. Give the seed the same envelope as a
|
|
106520
|
+
// persisted value row so an unrelated replay does not reject a valid
|
|
106521
|
+
// locally-authored static initializer. The overlay is never written to
|
|
106522
|
+
// workspace state or sent to the server.
|
|
106523
|
+
data: {
|
|
106524
|
+
...data,
|
|
106525
|
+
projectId,
|
|
106526
|
+
createdAt: 0,
|
|
106527
|
+
updatedAt: 0
|
|
106528
|
+
}
|
|
106425
106529
|
});
|
|
106426
106530
|
}
|
|
106427
106531
|
function memberValueIdFromRecord(status, memberId) {
|
|
@@ -106690,6 +106794,9 @@ async function runResetPull(workspace) {
|
|
|
106690
106794
|
const reset = resetWorkspaceToProjectSourcesV4(workspace, document, {
|
|
106691
106795
|
regenerateSourceNames: true
|
|
106692
106796
|
});
|
|
106797
|
+
for (const recovery of reset.staticMemberOwnershipRecoveries ?? []) {
|
|
106798
|
+
warn(staticMemberOwnershipRecoveryMessage(recovery));
|
|
106799
|
+
}
|
|
106693
106800
|
for (const [key, state] of binaries.states) {
|
|
106694
106801
|
const record3 = workspace.state.records[key];
|
|
106695
106802
|
if (record3) record3.projectBinary = state;
|
|
@@ -106758,7 +106865,8 @@ async function finishFormat4Pull(args) {
|
|
|
106758
106865
|
const plannedLocalRecords = buildEmitRecordSet(document, plans, "emit");
|
|
106759
106866
|
for (const [key, record3] of staticValueSeedEmitRecords(
|
|
106760
106867
|
localStatus,
|
|
106761
|
-
new Set(plannedLocalRecords.keys())
|
|
106868
|
+
new Set(plannedLocalRecords.keys()),
|
|
106869
|
+
workspace.config.projectId
|
|
106762
106870
|
)) {
|
|
106763
106871
|
plannedLocalRecords.set(key, record3);
|
|
106764
106872
|
}
|
|
@@ -106769,6 +106877,9 @@ async function finishFormat4Pull(args) {
|
|
|
106769
106877
|
)
|
|
106770
106878
|
);
|
|
106771
106879
|
const localResult = emitProjectDocumentFilesV4(localRecords);
|
|
106880
|
+
for (const recovery of localResult.staticMemberOwnershipRecoveries ?? []) {
|
|
106881
|
+
warn(staticMemberOwnershipRecoveryMessage(recovery));
|
|
106882
|
+
}
|
|
106772
106883
|
const serverResult = conflictCount === 0 ? null : emitProjectDocumentFilesV4(
|
|
106773
106884
|
buildEmitRecordSet(document, plans, "server")
|
|
106774
106885
|
);
|
|
@@ -107206,6 +107317,7 @@ var init_pull = __esm({
|
|
|
107206
107317
|
init_project_file_pull();
|
|
107207
107318
|
init_dialogue_sources();
|
|
107208
107319
|
init_static_value_seed_records();
|
|
107320
|
+
init_static_member_ownership_recovery();
|
|
107209
107321
|
}
|
|
107210
107322
|
});
|
|
107211
107323
|
|
|
@@ -114040,7 +114152,7 @@ var init_registry2 = __esm({
|
|
|
114040
114152
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
114041
114153
|
formatVersion: 3,
|
|
114042
114154
|
contractVersion: "3.14",
|
|
114043
|
-
cliVersion: "0.36.
|
|
114155
|
+
cliVersion: "0.36.6",
|
|
114044
114156
|
projectFileUploadBatchSize: 32,
|
|
114045
114157
|
documentRecords: {
|
|
114046
114158
|
member: {
|
|
@@ -120642,7 +120754,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
120642
120754
|
async function main() {
|
|
120643
120755
|
const args = parseArgs(process.argv.slice(2));
|
|
120644
120756
|
if (args.command === "--version") {
|
|
120645
|
-
console.log("0.36.
|
|
120757
|
+
console.log("0.36.6");
|
|
120646
120758
|
return;
|
|
120647
120759
|
}
|
|
120648
120760
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -83,7 +83,7 @@ wrappers.
|
|
|
83
83
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
84
84
|
|
|
85
85
|
```html
|
|
86
|
-
<!-- reviewed-through-cli: 0.36.
|
|
86
|
+
<!-- reviewed-through-cli: 0.36.6 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|